/*
Copyright (C) 2002 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.mysql.jdbc;
import java.sql.SQLException;
import java.sql.Types;
/**
* A ResultSetMetaData object can be used to find out about the types and
* properties of the columns in a ResultSet
*
* @see java.sql.ResultSetMetaData
* @author Mark Matthews
* @version $Id: ResultSetMetaData.java,v 1.12.2.5 2003/12/24 05:16:25 mmatthew Exp $
*/
public class ResultSetMetaData implements java.sql.ResultSetMetaData {
Field[] fields;
/**
* Initialise for a result with a tuple set and
* a field descriptor set
*
* @param fields the array of field descriptors
*/
public ResultSetMetaData(Field[] fields) {
this.fields = fields;
}
/**
* Is the column automatically numbered (and thus read-only)
*
* MySQL Auto-increment columns are not read only,
* so to conform to the spec, this method returns false.
*
* @param column the first column is 1, the second is 2...
* @return true if so
* @throws java.sql.SQLException if a database access error occurs
*/
public boolean isAutoIncrement(int column) throws java.sql.SQLException {
Field f = getField(column);
return f.isAutoIncrement();
}
/**
* Does a column's case matter? ASSUMPTION: Any field that is
* not obviously case insensitive is assumed to be case sensitive
*
* @param column the first column is 1, the second is 2...
* @return true if so
* @throws java.sql.SQLException if a database access error occurs
*/
public boolean isCaseSensitive(int column) throws java.sql.SQLException {
Field field = getField(column);
int sqlType = field.getSQLType();
switch (sqlType) {
case Types.BIT:
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
case Types.BIGINT:
case Types.FLOAT:
case Types.REAL:
case Types.DOUBLE:
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
return false;
case Types.CHAR:
case Types.VARCHAR:
return field.isBinary();
default:
return true;
}
}
/**
* What's a column's table's catalog name?
*
* @param column the first column is 1, the second is 2...
* @return catalog name, or "" if not applicable
* @throws java.sql.SQLException if a database access error occurs
*/
public String getCatalogName(int column) throws java.sql.SQLException {
Field f = getField(column);
String database = f.getDatabaseName();
return (database == null) ? "" : database;
}
//--------------------------JDBC 2.0-----------------------------------
/**
* JDBC 2.0
*
* <p>Return the fully qualified name of the Java class whose instances
* are manufactured if ResultSet.getObject() is called to retrieve a value
* from the column. ResultSet.getObject() may return a subClass of the
* class returned by this method.
*
* @param column the column number to retrieve information for
* @return the fully qualified name of the Java class whose instances
* are manufactured if ResultSet.getObject() is called to retrieve a value
* from the column.
*
* @throws SQLException if an error occurs
*/
public String getColumnClassName(int column) throws SQLException {
Field f = getField(column);
switch (f.getSQLType()) {
case Types.BIT:
return "java.lang.Boolean";
case Types.TINYINT:
if (f.isUnsigned()) {
return "java.lang.Integer";
} else {
return "java.lang.Byte";
}
case Types.SMALLINT:
if (f.isUnsigned()) {
return "java.lang.Integer";
} else {
return "java.lang.Short";
}
case Types.INTEGER:
if (f.isUnsigned()) {
return "java.lang.Long";
} else {
return "java.lang.Integer";
}
case Types.BIGINT:
return "java.lang.Long";
case Types.DECIMAL:
case Types.NUMERIC:
return "java.math.BigDecimal";
case Types.REAL:
case Types.FLOAT:
return "java.lang.Float";
case Types.DOUBLE:
return "java.lang.Double";
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
return "java.lang.String";
case Types.BINARY:
case Types.VARBINARY:
case Types.LONGVARBINARY:
if (!f.isBlob()) {
return "java.lang.String";
} else if (!f.isBinary()) {
return "java.lang.String";
} else {
return "java.lang.Object";
}
case Types.DATE:
return "java.sql.Date";
case Types.TIME:
return "java.sql.Time";
case Types.TIMESTAMP:
return "java.sql.Timestamp";
default:
return "java.lang.Object";
}
}
/**
* Whats the number of columns in the ResultSet?
*
* @return the number
* @throws java.sql.SQLException if a database access error occurs
*/
public int getColumnCount() throws java.sql.SQLException {
return fields.length;
}
/**
* What is the column's normal maximum width in characters?
*
* @param column the first column is 1, the second is 2, etc.
* @return the maximum width
* @throws java.sql.SQLException if a database access error occurs
*/
public int getColumnDisplaySize(int column) throws java.sql.SQLException {
return getField(column).getLength();
}
/**
* What is the suggested column title for use in printouts and
* displays?
*
* @param column the first column is 1, the second is 2, etc.
* @return the column label
* @throws java.sql.SQLException if a database access error occurs
*/
public String getColumnLabel(int column) throws java.sql.SQLException {
return getColumnName(column);
}
/**
* What's a column's name?
*
* @param column the first column is 1, the second is 2, etc.
* @return the column name
* @throws java.sql.SQLException if a databvase access error occurs
*/
public String getColumnName(int column) throws java.sql.SQLException {
return getField(column).getName();
}
/**
* What is a column's SQL Type? (java.sql.Type int)
*
* @param column the first column is 1, the second is 2, etc.
* @return the java.sql.Type value
* @throws java.sql.SQLException if a database access error occurs
* @see java.sql.Types
*/
public int getColumnType(int column) throws java.sql.SQLException {
return getField(column).getSQLType();
}
/**
* Whats is the column's data source specific type name?
*
* @param column the first column is 1, the second is 2, etc.
* @return the type name
* @throws java.sql.SQLException if a database access error occurs
*/
public String getColumnTypeName(int column) throws java.sql.SQLException {
int mysqlType = getField(column).getMysqlType();
switch (mysqlType) {
case MysqlDefs.FIELD_TYPE_DECIMAL:
return "DECIMAL";
case MysqlDefs.FIELD_TYPE_TINY:
return "TINY";
case MysqlDefs.FIELD_TYPE_SHORT:
return "SHORT";
case MysqlDefs.FIELD_TYPE_LONG:
return "LONG";
case MysqlDefs.FIELD_TYPE_FLOAT:
return "FLOAT";
case MysqlDefs.FIELD_TYPE_DOUBLE:
return "DOUBLE";
case MysqlDefs.FIELD_TYPE_NULL:
return "NULL";
case MysqlDefs.FIELD_TYPE_TIMESTAMP:
return "TIMESTAMP";
case MysqlDefs.FIELD_TYPE_LONGLONG:
return "LONGLONG";
case MysqlDefs.FIELD_TYPE_INT24:
return "INT";
case MysqlDefs.FIELD_TYPE_DATE:
return "DATE";
case MysqlDefs.FIELD_TYPE_TIME:
return "TIME";
case MysqlDefs.FIELD_TYPE_DATETIME:
return "DATETIME";
case MysqlDefs.FIELD_TYPE_TINY_BLOB:
return "TINYBLOB";
case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB:
return "MEDIUMBLOB";
case MysqlDefs.FIELD_TYPE_LONG_BLOB:
return "LONGBLOB";
case MysqlDefs.FIELD_TYPE_BLOB:
if (getField(column).isBinary()) {
return "BLOB";
} else {
return "TEXT";
}
case MysqlDefs.FIELD_TYPE_VAR_STRING:
return "VARCHAR";
case MysqlDefs.FIELD_TYPE_STRING:
return "CHAR";
case MysqlDefs.FIELD_TYPE_ENUM:
return "ENUM";
case MysqlDefs.FIELD_TYPE_SET:
return "SET";
case MysqlDefs.FIELD_TYPE_YEAR:
return "YEAR";
default:
return "UNKNOWN";
}
}
/**
* Is the column a cash value?
*
* @param column the first column is 1, the second is 2...
* @return true if its a cash column
* @throws java.sql.SQLException if a database access error occurs
*/
public boolean isCurrency(int column) throws java.sql.SQLException {
return false;
}
/**
* Will a write on this column definately succeed?
*
* @param column the first column is 1, the second is 2, etc..
* @return true if so
* @throws java.sql.SQLException if a database access error occurs
*/
public boolean isDefinitelyWritable(int column)
throws java.sql.SQLException {
return isWritable(column);
}
/**
* Can you put a NULL in this column?
*
* @param column the first column is 1, the second is 2...
* @return one of the columnNullable values
* @throws java.sql.SQLException if a database access error occurs
*/
public int isNullable(int column) throws java.sql.SQLException {
if (!getField(column).isNotNull()) {
return java.sql.ResultSetMetaData.columnNullable;
} else {
return java.sql.ResultSetMetaData.columnNoNulls;
}
}
/**
* What is a column's number of decimal digits.
*
* @param column the first column is 1, the second is 2...
* @return the precision
* @throws java.sql.SQLException if a database access error occurs
*/
public int getPrecision(int column) throws java.sql.SQLException {
Field f = getField(column);
if (isDecimalType(f.getSQLType())) {
if (f.getDecimals() > 0) {
return f.getLength() - 1 + f.getPrecisionAdjustFactor();
}
return f.getLength() + f.getPrecisionAdjustFactor();
}
return 0;
}
/**
* Is the column definitely not writable?
*
* @param column the first column is 1, the second is 2, etc.
* @return true if so
* @throws java.sql.SQLException if a database access error occurs
*/
public boolean isReadOnly(int column) throws java.sql.SQLException {
return false;
}
/**
* What is a column's number of digits to the right of the
* decimal point?
*
* @param column the first column is 1, the second is 2...
* @return the scale
* @throws java.sql.SQLException if a database access error occurs
*/
public int getScale(int column) throws java.sql.SQLException {
Field f = getField(column);
if (isDecimalType(f.getSQLType())) {
return f.getDecimals();
}
return 0;
}
/**
* What is a column's table's schema? This relies on us knowing
* the table name.
*
* The JDBC specification allows us to return "" if this is not
* applicable.
*
* @param column the first column is 1, the second is 2...
* @return the Schema
* @throws java.sql.SQLException if a database access error occurs
*/
public String getSchemaName(int column) throws java.sql.SQLException {
return "";
}
/**
* Can the column be used in a WHERE clause? Basically for
* this, I split the functions into two types: recognised
* types (which are always useable), and OTHER types (which
* may or may not be useable). The OTHER types, for now, I
* will assume they are useable. We should really query the
* catalog to see if they are useable.
*
* @param column the first column is 1, the second is 2...
* @return true if they can be used in a WHERE clause
* @throws java.sql.SQLException if a database access error occurs
*/
public boolean isSearchable(int column) throws java.sql.SQLException {
return true;
}
/**
* Is the column a signed number?
*
* @param column the first column is 1, the second is 2...
* @return true if so
* @throws java.sql.SQLException if a database access error occurs
*/
public boolean isSigned(int column) throws java.sql.SQLException {
Field f = getField(column);
int sqlType = f.getSQLType();
switch (sqlType) {
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
case Types.BIGINT:
case Types.FLOAT:
case Types.REAL:
case Types.DOUBLE:
case Types.NUMERIC:
case Types.DECIMAL:
return !f.isUnsigned();
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
return false;
default:
return false;
}
}
/**
* Whats a column's table's name?
*
* @param column the first column is 1, the second is 2...
* @return column name, or "" if not applicable
* @throws java.sql.SQLException if a database access error occurs
*/
public String getTableName(int column) throws java.sql.SQLException {
return getField(column).getTableName();
}
/**
* Is it possible for a write on the column to succeed?
*
* @param column the first column is 1, the second is 2, etc.
* @return true if so
* @throws java.sql.SQLException if a database access error occurs
*/
public boolean isWritable(int column) throws java.sql.SQLException {
return !isReadOnly(column);
}
// *********************************************************************
//
// END OF PUBLIC INTERFACE
//
// *********************************************************************
/**
* Returns the field instance for the given column index
*
* @param columnIndex the column number to retrieve a field instance for
* @return the field instance for the given column index
*
* @throws java.sql.SQLException if an error occurs
*/
protected Field getField(int columnIndex) throws java.sql.SQLException {
if ((columnIndex < 1) || (columnIndex > fields.length)) {
throw new java.sql.SQLException("Column index out of range.",
SQLError.SQL_STATE_INVALID_COLUMN_NUMBER);
}
return fields[columnIndex - 1];
}
/**
* Checks if the SQL Type is a Decimal/Number Type
* @param type SQL Type
*/
private static final boolean isDecimalType(int type) {
switch (type) {
case Types.BIT:
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
case Types.BIGINT:
case Types.FLOAT:
case Types.REAL:
case Types.DOUBLE:
case Types.NUMERIC:
case Types.DECIMAL:
return true;
}
return false;
}
}