/* This file is part of VoltDB. * Copyright (C) 2008-2017 VoltDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with VoltDB. If not, see <http://www.gnu.org/licenses/>. */ package org.voltdb.jdbc; import java.sql.*; import org.voltdb.*; import org.voltdb.types.GeographyPointValue; public class JDBC4ResultSetMetaData implements java.sql.ResultSetMetaData { private final JDBC4ResultSet sourceResultSet; public JDBC4ResultSetMetaData(JDBC4ResultSet resultSet) { sourceResultSet = resultSet; } // Gets the designated column's table's catalog name. private static final String catalogName = ""; public String getCatalogName(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); return catalogName; } // Returns the fully-qualified name of the Java class whose instances are manufactured if the method ResultSet.getObject is called to retrieve a value from the column. public String getColumnClassName(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); VoltType type = sourceResultSet.table.getColumnType(column - 1); String result = type.getJdbcClass(); if (result == null) { throw SQLError.get(SQLError.TRANSLATION_NOT_FOUND, type); } return result; } // Returns the number of columns in this ResultSet object. public int getColumnCount() throws SQLException { sourceResultSet.checkClosed(); return sourceResultSet.columnCount; } // Indicates the designated column's normal maximum width in characters. // *NOTE* this is supposed to be based on the data in the returned table. // However, we're not in a position to inspect the entire table, so we're // just going to throw up best guesses here. I'm not moving this // into VoltType --izzy public int getColumnDisplaySize(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); VoltType type = sourceResultSet.table.getColumnType(column - 1); switch(type) { case TINYINT: return (new Byte(Byte.MIN_VALUE)).toString().length(); case SMALLINT: return (new Short(Short.MIN_VALUE)).toString().length(); case INTEGER: return (new Integer(Integer.MIN_VALUE)).toString().length(); case BIGINT: return (new Long(Long.MIN_VALUE)).toString().length(); case FLOAT: return (new Double(Double.MIN_VALUE)).toString().length(); case DECIMAL: return 40; case TIMESTAMP: return 32; case GEOGRAPHY_POINT: return GeographyPointValue.getValueDisplaySize(); case STRING: case VARBINARY: case GEOGRAPHY: return 128; // That is wrong: should be length in bytes / 3 (max bytes per char for UTF8), but we don't receive the length! default: throw SQLError.get(SQLError.TRANSLATION_NOT_FOUND, type); } } // Gets the designated column's suggested title for use in printouts and displays. public String getColumnLabel(int column) throws SQLException { return getColumnName(column); } // Get the designated column's name. public String getColumnName(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); return sourceResultSet.table.getColumnName(column - 1); } // Retrieves the designated column's SQL type. public int getColumnType(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); VoltType type = sourceResultSet.table.getColumnType(column - 1); // Types unknown to JDBC will return "OTHER" return type.getJdbcSqlType(); } // Retrieves the designated column's database-specific type name. public String getColumnTypeName(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); VoltType type = sourceResultSet.table.getColumnType(column - 1); String result = type.toSQLString().toUpperCase(); if (result == null) { // Types unknown to JDBC will return null, no other good // answer to give throw SQLError.get(SQLError.TRANSLATION_NOT_FOUND, type); } return type.toSQLString().toUpperCase(); } // Get the designated column's specified column size. public int getPrecision(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); VoltType type = sourceResultSet.table.getColumnType(column - 1); Integer result = type.getTypePrecisionAndRadix()[0]; if (result == null) { result = 0; } return result; } // Gets the designated column's number of digits to right of the decimal point. public int getScale(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); VoltType type = sourceResultSet.table.getColumnType(column - 1); Integer result = type.getMaximumScale(); if (result == null) { result = 0; } return result; } // Get the designated column's table's schema. private static final String schemaName = ""; public String getSchemaName(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); return schemaName; // No such notion with engine } // Gets the designated column's table name. private static final String tableName = "Resultset"; public String getTableName(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); return tableName; // No way to know without parsing the source SQL for joins or the detai;s of the procedure itself - this information is not in the metadata returned! } // Indicates whether the designated column is automatically numbered. public boolean isAutoIncrement(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); return false; // Not supported by DB engine. } // Indicates whether a column's case matters. public boolean isCaseSensitive(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); VoltType type = sourceResultSet.table.getColumnType(column - 1); return type.isCaseSensitive(); } // Indicates whether the designated column is a cash value. public boolean isCurrency(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); return false; } // Indicates whether a write on the designated column will definitely succeed. public boolean isDefinitelyWritable(int column) throws SQLException { return isWritable(column); } // Indicates the nullability of values in the designated column. public int isNullable(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); return ResultSetMetaData.columnNullableUnknown; // Not known from metadata - have to pick "unknown" } // Indicates whether the designated column is definitely not writable. public boolean isReadOnly(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); return true; // Always: resultSet cannot be updated and post back to DB. } // Indicates whether the designated column can be used in a where clause. public boolean isSearchable(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); return true; } // Indicates whether values in the designated column are signed numbers. public boolean isSigned(int column) throws SQLException { sourceResultSet.checkColumnBounds(column); VoltType type = sourceResultSet.table.getColumnType(column - 1); Boolean result = type.isUnsigned(); if (result == null) { // Null return value means 'not signed' as far as this interface goes return false; } return !result; } // Indicates whether it is possible for a write on the designated column to succeed. public boolean isWritable(int column) throws SQLException { return !isReadOnly(column); } // Returns true if this either implements the interface argument or is directly or indirectly a wrapper for an object that does. public boolean isWrapperFor(Class<?> iface) throws SQLException { return iface.isInstance(this); } // Returns an object that implements the given interface to allow access to non-standard methods, or standard methods not exposed by the proxy. public <T> T unwrap(Class<T> iface) throws SQLException { try { return iface.cast(this); } catch (ClassCastException cce) { throw SQLError.get(SQLError.ILLEGAL_ARGUMENT, iface.toString()); } } }