Logo Search packages:      
Sourcecode: mysql-connector-java version File versions  Download package

ResultSetMetaData.java

/*
 Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
 

  The MySQL Connector/J is licensed under the terms of the GPLv2
  <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
  There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
  this software, see the FLOSS License Exception
  <http://www.mysql.com/about/legal/licensing/foss-exception.html>.

  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; version 2
  of the License.

  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., 51 Franklin St, Fifth
  Floor, Boston, MA 02110-1301  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
 * 
 * @author Mark Matthews
 * @version $Id: ResultSetMetaData.java,v 1.1.2.1 2005/05/13 18:58:38 mmatthews
 *          Exp $
 * 
 * @see java.sql.ResultSetMetaData
 */
00039 public class ResultSetMetaData implements java.sql.ResultSetMetaData {
      private static int clampedGetLength(Field f) {
            long fieldLength = f.getLength();

            if (fieldLength > Integer.MAX_VALUE) {
                  fieldLength = Integer.MAX_VALUE;
            }

            return (int) fieldLength;
      }

      /**
       * Checks if the SQL Type is a Decimal/Number Type
       * 
       * @param type
       *            SQL Type
       * 
       * @return ...
       */
00058       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;
      }

      Field[] fields;
      boolean useOldAliasBehavior = false;

      private ExceptionInterceptor exceptionInterceptor;
      
      /**
       * Initialise for a result with a tuple set and a field descriptor set
       * 
       * @param fields
       *            the array of field descriptors
       */
00087       public ResultSetMetaData(Field[] fields, boolean useOldAliasBehavior, ExceptionInterceptor exceptionInterceptor) {
            this.fields = fields;
            this.useOldAliasBehavior = useOldAliasBehavior;
            this.exceptionInterceptor = exceptionInterceptor;
      }

      /**
       * 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 SQLException
       *             if a database access error occurs
       */
00104       public String getCatalogName(int column) throws SQLException {
            Field f = getField(column);

            String database = f.getDatabaseName();

            return (database == null) ? "" : database; //$NON-NLS-1$
      }

      /**
       * What's the Java character encoding name for the given column?
       * 
       * @param column
       *            the first column is 1, the second is 2, etc.
       * 
       * @return the Java character encoding name for the given column, or null if
       *         no Java character encoding maps to the MySQL character set for
       *         the given column.
       * 
       * @throws SQLException
       *             if an invalid column index is given.
       */
00125       public String getColumnCharacterEncoding(int column) throws SQLException {
            String mysqlName = getColumnCharacterSet(column);

            String javaName = null;

            if (mysqlName != null) {
                  javaName = CharsetMapping.getJavaEncodingForMysqlEncoding(
                              mysqlName, null);
            }

            return javaName;
      }

      /**
       * What's the MySQL character set name for the given column?
       * 
       * @param column
       *            the first column is 1, the second is 2, etc.
       * 
       * @return the MySQL character set name for the given column
       * 
       * @throws SQLException
       *             if an invalid column index is given.
       */
00149       public String getColumnCharacterSet(int column) throws SQLException {
            return getField(column).getCharacterSet();
      }

      // --------------------------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.
       * </p>
       * 
       * @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
       */
00175       public String getColumnClassName(int column) throws SQLException {
            Field f = getField(column);

            return getClassNameForJavaType(f.getSQLType(), 
                        f.isUnsigned(), 
                        f.getMysqlType(), 
                        f.isBinary() || f.isBlob(),
                        f.isOpaqueBinary()); 
      }

      /**
       * Whats the number of columns in the ResultSet?
       * 
       * @return the number
       * 
       * @throws SQLException
       *             if a database access error occurs
       */
00193       public int getColumnCount() throws SQLException {
            return this.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 SQLException
       *             if a database access error occurs
       */
00208       public int getColumnDisplaySize(int column) throws SQLException {
            Field f = getField(column);

            int lengthInBytes = clampedGetLength(f);

            return lengthInBytes / f.getMaxBytesPerCharacter();
      }

      /**
       * 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 SQLException
       *             if a database access error occurs
       */
00227       public String getColumnLabel(int column) throws SQLException {
            if (this.useOldAliasBehavior) {
                  return getColumnName(column);
            }
            
            return getField(column).getColumnLabel();
      }

      /**
       * What's a column's name?
       * 
       * @param column
       *            the first column is 1, the second is 2, etc.
       * 
       * @return the column name
       * 
       * @throws SQLException
       *             if a databvase access error occurs
       */
00246       public String getColumnName(int column) throws SQLException {
            if (this.useOldAliasBehavior) {
                  return getField(column).getName();
      }

            String name = getField(column).getNameNoAliases();
            
            if (name != null && name.length() == 0) {
                  return getField(column).getName();
            }
            
            return name;
      }

      /**
       * 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 SQLException
       *             if a database access error occurs
       * 
       * @see java.sql.Types
       */
00273       public int getColumnType(int column) throws 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 SQLException
       *             if a database access error occurs
       */
00288       public String getColumnTypeName(int column) throws java.sql.SQLException {
            Field field = getField(column);

            int mysqlType = field.getMysqlType();
            int jdbcType = field.getSQLType();

            switch (mysqlType) {
            case MysqlDefs.FIELD_TYPE_BIT:
                  return "BIT";
            case MysqlDefs.FIELD_TYPE_DECIMAL:
            case MysqlDefs.FIELD_TYPE_NEW_DECIMAL:
                  return field.isUnsigned() ? "DECIMAL UNSIGNED" : "DECIMAL";

            case MysqlDefs.FIELD_TYPE_TINY:
                  return field.isUnsigned() ? "TINYINT UNSIGNED" : "TINYINT";

            case MysqlDefs.FIELD_TYPE_SHORT:
                  return field.isUnsigned() ? "SMALLINT UNSIGNED" : "SMALLINT";

            case MysqlDefs.FIELD_TYPE_LONG:
                  return field.isUnsigned() ? "INT UNSIGNED" : "INT";

            case MysqlDefs.FIELD_TYPE_FLOAT:
                  return field.isUnsigned() ? "FLOAT UNSIGNED" : "FLOAT";

            case MysqlDefs.FIELD_TYPE_DOUBLE:
                  return field.isUnsigned() ? "DOUBLE UNSIGNED" : "DOUBLE";

            case MysqlDefs.FIELD_TYPE_NULL:
                  return "NULL"; //$NON-NLS-1$

            case MysqlDefs.FIELD_TYPE_TIMESTAMP:
                  return "TIMESTAMP"; //$NON-NLS-1$       

            case MysqlDefs.FIELD_TYPE_LONGLONG:
                  return field.isUnsigned() ? "BIGINT UNSIGNED" : "BIGINT";

            case MysqlDefs.FIELD_TYPE_INT24:
                  return field.isUnsigned() ? "MEDIUMINT UNSIGNED" : "MEDIUMINT";

            case MysqlDefs.FIELD_TYPE_DATE:
                  return "DATE"; //$NON-NLS-1$       

            case MysqlDefs.FIELD_TYPE_TIME:
                  return "TIME"; //$NON-NLS-1$       

            case MysqlDefs.FIELD_TYPE_DATETIME:
                  return "DATETIME"; //$NON-NLS-1$      

            case MysqlDefs.FIELD_TYPE_TINY_BLOB:
                  return "TINYBLOB"; //$NON-NLS-1$

            case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB:
                  return "MEDIUMBLOB"; //$NON-NLS-1$

            case MysqlDefs.FIELD_TYPE_LONG_BLOB:
                  return "LONGBLOB"; //$NON-NLS-1$

            case MysqlDefs.FIELD_TYPE_BLOB:
                  if (getField(column).isBinary()) {
                        return "BLOB";//$NON-NLS-1$
                  }

                  return "TEXT";//$NON-NLS-1$

            case MysqlDefs.FIELD_TYPE_VARCHAR:
                  return "VARCHAR"; //$NON-NLS-1$

            case MysqlDefs.FIELD_TYPE_VAR_STRING:
                  if (jdbcType == Types.VARBINARY) {
                        return "VARBINARY";
                  }
                  
                  return "VARCHAR"; //$NON-NLS-1$

            case MysqlDefs.FIELD_TYPE_STRING:
                  if (jdbcType == Types.BINARY) {
                        return "BINARY";
                  }
                  
                  return "CHAR"; //$NON-NLS-1$

            case MysqlDefs.FIELD_TYPE_ENUM:
                  return "ENUM"; //$NON-NLS-1$

            case MysqlDefs.FIELD_TYPE_YEAR:
                  return "YEAR"; // $NON_NLS-1$

            case MysqlDefs.FIELD_TYPE_SET:
                  return "SET"; //$NON-NLS-1$
                  
            case MysqlDefs.FIELD_TYPE_GEOMETRY:
                  return "GEOMETRY"; //$NON-NLS-1$
                  
            default:
                  return "UNKNOWN"; //$NON-NLS-1$
            }
      }

      /**
       * 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 SQLException
       *             if an error occurs
       */
00398       protected Field getField(int columnIndex) throws SQLException {
            if ((columnIndex < 1) || (columnIndex > this.fields.length)) {
                  throw SQLError.createSQLException(Messages.getString("ResultSetMetaData.46"), //$NON-NLS-1$
                              SQLError.SQL_STATE_INVALID_COLUMN_NUMBER, this.exceptionInterceptor);
            }

            return this.fields[columnIndex - 1];
      }

      /**
       * What is a column's number of decimal digits.
       * 
       * @param column
       *            the first column is 1, the second is 2...
       * 
       * @return the precision
       * 
       * @throws SQLException
       *             if a database access error occurs
       */
00418       public int getPrecision(int column) throws SQLException {
            Field f = getField(column);

            // if (f.getMysqlType() == MysqlDefs.FIELD_TYPE_NEW_DECIMAL) {
            // return f.getLength();
            // }

            if (isDecimalType(f.getSQLType())) {
                  if (f.getDecimals() > 0) {
                        return clampedGetLength(f) - 1 + f.getPrecisionAdjustFactor();
                  }

                  return clampedGetLength(f) + f.getPrecisionAdjustFactor();
            }

            switch (f.getMysqlType()) {
            case MysqlDefs.FIELD_TYPE_TINY_BLOB:
            case MysqlDefs.FIELD_TYPE_BLOB:
            case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB:
            case MysqlDefs.FIELD_TYPE_LONG_BLOB:
                  return clampedGetLength(f); // this may change in the future
            // for now, the server only
            // returns FIELD_TYPE_BLOB for _all_
            // BLOB types, but varying lengths
            // indicating the _maximum_ size
            // for each BLOB type.
            default:
                  return clampedGetLength(f) / f.getMaxBytesPerCharacter();

            }
      }

      /**
       * 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 SQLException
       *             if a database access error occurs
       */
00461       public int getScale(int column) throws 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 SQLException
       *             if a database access error occurs
       */
00484       public String getSchemaName(int column) throws SQLException {
            return ""; //$NON-NLS-1$
      }

      /**
       * 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 SQLException
       *             if a database access error occurs
       */
00499       public String getTableName(int column) throws SQLException {
            if (this.useOldAliasBehavior) {
                  return getField(column).getTableName();
            }
            
            return getField(column).getTableNameNoAliases();
      }

      /**
       * Is the column automatically numbered (and thus read-only)
       * 
       * @param column
       *            the first column is 1, the second is 2...
       * 
       * @return true if so
       * 
       * @throws SQLException
       *             if a database access error occurs
       */
00518       public boolean isAutoIncrement(int column) throws SQLException {
            Field f = getField(column);

            return f.isAutoIncrement();
      }

      /**
       * Does a column's case matter?
       * 
       * @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
       */
00535       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:
            case Types.LONGVARCHAR:

                  if (field.isBinary()) {
                        return true;
                  }

                  String collationName = field.getCollation();

                  return ((collationName != null) && !collationName.endsWith("_ci"));

            default:
                  return true;
            }
      }

      /**
       * 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 SQLException
       *             if a database access error occurs
       */
00582       public boolean isCurrency(int column) throws 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 SQLException
       *             if a database access error occurs
       */
00597       public boolean isDefinitelyWritable(int column) throws 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 SQLException
       *             if a database access error occurs
       */
00612       public int isNullable(int column) throws SQLException {
            if (!getField(column).isNotNull()) {
                  return java.sql.ResultSetMetaData.columnNullable;
            }

            return java.sql.ResultSetMetaData.columnNoNulls;
      }

      /**
       * Is the column definitely not writable?
       * 
       * @param column
       *            the first column is 1, the second is 2, etc.
       * 
       * @return true if so
       * 
       * @throws SQLException
       *             if a database access error occurs
       */
00631       public boolean isReadOnly(int column) throws SQLException {
            return getField(column).isReadOnly();
      }

      /**
       * 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 SQLException
       *             if a database access error occurs
       */
00650       public boolean isSearchable(int column) throws 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 SQLException
       *             if a database access error occurs
       */
00665       public boolean isSigned(int column) throws 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;
            }
      }

      /**
       * 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 SQLException
       *             if a database access error occurs
       */
00702       public boolean isWritable(int column) throws SQLException {
            return !isReadOnly(column);
      }

      /**
       * Returns a string representation of this object
       * 
       * @return ...
       */
00711       public String toString() {
            StringBuffer toStringBuf = new StringBuffer();
            toStringBuf.append(super.toString());
            toStringBuf.append(" - Field level information: "); //$NON-NLS-1$

            for (int i = 0; i < this.fields.length; i++) {
                  toStringBuf.append("\n\t"); //$NON-NLS-1$
                  toStringBuf.append(this.fields[i].toString());
            }

            return toStringBuf.toString();
      }
      
      static String getClassNameForJavaType(int javaType, 
                  boolean isUnsigned, int mysqlTypeIfKnown, 
                  boolean isBinaryOrBlob,
                  boolean isOpaqueBinary) {
            switch (javaType) {
            case Types.BIT:
            case Types.BOOLEAN:
                  return "java.lang.Boolean"; //$NON-NLS-1$

            case Types.TINYINT:

                  if (isUnsigned) {
                        return "java.lang.Integer"; //$NON-NLS-1$
                  }

                  return "java.lang.Integer"; //$NON-NLS-1$

            case Types.SMALLINT:

                  if (isUnsigned) {
                        return "java.lang.Integer"; //$NON-NLS-1$
                  }

                  return "java.lang.Integer"; //$NON-NLS-1$

            case Types.INTEGER:

                  if (!isUnsigned || 
                              mysqlTypeIfKnown == MysqlDefs.FIELD_TYPE_INT24) {
                        return "java.lang.Integer"; //$NON-NLS-1$
                  }

                  return "java.lang.Long"; //$NON-NLS-1$

            case Types.BIGINT:

                  if (!isUnsigned) {
                        return "java.lang.Long"; //$NON-NLS-1$
                  }

                  return "java.math.BigInteger"; //$NON-NLS-1$

            case Types.DECIMAL:
            case Types.NUMERIC:
                  return "java.math.BigDecimal"; //$NON-NLS-1$

            case Types.REAL:
                  return "java.lang.Float"; //$NON-NLS-1$

            case Types.FLOAT:
            case Types.DOUBLE:
                  return "java.lang.Double"; //$NON-NLS-1$

            case Types.CHAR:
            case Types.VARCHAR:
            case Types.LONGVARCHAR:
                  if (!isOpaqueBinary) {
                        return "java.lang.String"; //$NON-NLS-1$
                  }

                  return "[B";

            case Types.BINARY:
            case Types.VARBINARY:
            case Types.LONGVARBINARY:

                  if (mysqlTypeIfKnown == MysqlDefs.FIELD_TYPE_GEOMETRY) {
                        return "[B";
                  } else if (isBinaryOrBlob) {
                        return "[B";
                  } else {
                        return "java.lang.String";
                  }

            case Types.DATE:
                  return "java.sql.Date"; //$NON-NLS-1$

            case Types.TIME:
                  return "java.sql.Time"; //$NON-NLS-1$

            case Types.TIMESTAMP:
                  return "java.sql.Timestamp"; //$NON-NLS-1$

            default:
                  return "java.lang.Object"; //$NON-NLS-1$
            }
      }
      
      /**
     * Returns true if this either implements the interface argument or is directly or indirectly a wrapper
     * for an object that does. Returns false otherwise. If this implements the interface then return true,
     * else if this is a wrapper then return the result of recursively calling <code>isWrapperFor</code> on the wrapped
     * object. If this does not implement the interface and is not a wrapper, return false.
     * This method should be implemented as a low-cost operation compared to <code>unwrap</code> so that
     * callers can use this method to avoid expensive <code>unwrap</code> calls that may fail. If this method
     * returns true then calling <code>unwrap</code> with the same argument should succeed.
     *
     * @param interfaces a Class defining an interface.
     * @return true if this implements the interface or directly or indirectly wraps an object that does.
     * @throws java.sql.SQLException  if an error occurs while determining whether this is a wrapper
     * for an object with the given interface.
     * @since 1.6
     */
00827       public boolean isWrapperFor(Class iface) throws SQLException {
            // This works for classes that aren't actually wrapping
            // anything
            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.
     * The result may be either the object found to implement the interface or a proxy for that object.
     * If the receiver implements the interface then that is the object. If the receiver is a wrapper
     * and the wrapped object implements the interface then that is the object. Otherwise the object is
     *  the result of calling <code>unwrap</code> recursively on the wrapped object. If the receiver is not a
     * wrapper and does not implement the interface, then an <code>SQLException</code> is thrown.
     *
     * @param iface A Class defining an interface that the result must implement.
     * @return an object that implements the interface. May be a proxy for the actual implementing object.
     * @throws java.sql.SQLException If no object found that implements the interface 
     * @since 1.6
     */
00847       public Object unwrap(Class iface) throws java.sql.SQLException {
      try {
            // This works for classes that aren't actually wrapping
            // anything
            return Util.cast(iface, this);
        } catch (ClassCastException cce) {
            throw SQLError.createSQLException("Unable to unwrap to " + iface.toString(), 
                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
        }
    }
}

Generated by  Doxygen 1.6.0   Back to index