Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * $Id: FBResultSetMetaData.java 58482 2013-08-10 14:37:31Z mrotteveel $
   * 
   * Firebird Open Source J2ee connector - jdbc driver
   *
   * Distributable under LGPL license.
   * You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
   *
   * 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
  * LGPL License for more details.
  *
  * This file was created by members of the firebird development team.
  * All individual contributions remain the Copyright (C) of those
  * individuals.  Contributors to this file are either listed here or
  * can be obtained from a CVS history command.
  *
  * All rights reserved.
  */
 package org.firebirdsql.jdbc;
 
 import java.sql.*;
 import java.sql.Date;
 import java.util.*;
 
Implementation of java.sql.ResultSetMetaData interface.

Author(s):
David Jencks
Mark Rotteveel
 
 public class FBResultSetMetaData implements FirebirdResultSetMetaData {
 
     private final XSQLVAR[] xsqlvars;
     private Map extendedInfo;
     private final GDSHelper connection;
     private final ColumnStrategy columnStrategy;

    
Creates a new FBResultSetMetaData instance.

Parameters:
xsqlvars a XSQLVAR[] value
connection a AbstractConnection value
Throws:
java.sql.SQLException if an error occurs TODO Need another constructor for metadata from constructed result set, where we supply the ext field info.
 
     protected FBResultSetMetaData(XSQLVAR[] xsqlvarsGDSHelper connectionthrows SQLException {
         this. = xsqlvars;
         this. = connection;
         
         // Decide how to handle column names and column labels
         if (connection != null && connection.getDatabaseParameterBuffer().hasArgument(.)) {
         } else {
              = .;
         }
     }
 
     private String getIscEncoding() {
         if ( != null)
             return .getIscEncoding();
         else
             return "NONE";
     }

    
Returns the number of columns in this ResultSet object.

Returns:
the number of columns
 
     public  int getColumnCount() {
         return .;
     }


    
Indicates whether the designated column is automatically numbered, thus read-only.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
true if so; false otherwise
 
     public  boolean isAutoIncrement(int column) {
         return false;
     }


    
Indicates whether a column's case matters.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
true if so; false otherwise
Throws:
java.sql.SQLException if a database access error occurs
    public  boolean isCaseSensitive(int columnthrows  SQLException {
        return true;
    }


    
Indicates whether the designated column can be used in a where clause.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
true if so; false otherwise
Throws:
java.sql.SQLException if a database access error occurs
    public  boolean isSearchable(int columnthrows  SQLException {
        if (((getXsqlvar(column). & ~1) == .)
            || ((getXsqlvar(column). & ~1) == .)) {
            return false;
        }
        else {
            return true;
        }
    }


    
Indicates whether the designated column is a cash value.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
true if so; false otherwise
Throws:
java.sql.SQLException if a database access error occurs
    public  boolean isCurrency(int columnthrows  SQLException {
        return false;
    }


    
Indicates the nullability of values in the designated column.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
the nullability status of the given column; one of columnNoNulls, columnNullable or columnNullableUnknown
Throws:
java.sql.SQLException if a database access error occurs
    public  int isNullable(int columnthrows  SQLException {
        if ((getXsqlvar(column). & 1) == 1) {
            return ;
        }
        else {
            return ;
        }
    }


    
The constant indicating that a column does not allow NULL values.
    int columnNoNulls = 0;

    
The constant indicating that a column allows NULL values.
    int columnNullable = 1;

    
The constant indicating that the nullability of a column's values is unknown.
    int columnNullableUnknown = 2;

    
Indicates whether values in the designated column are signed numbers.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
true if so; false otherwise
Throws:
java.sql.SQLException if a database access error occurs
    public  boolean isSigned(int columnthrows  SQLException {
        switch (getXsqlvar(column). & ~1) {
            case .:
            case .:
            case .:
            case .:
            case .:
            case .:
                return true;
            default:
                return false;
        }
    }


    
Indicates the designated column's normal maximum width in characters.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
the normal maximum number of characters allowed as the width of the designated column
Throws:
java.sql.SQLException if a database access error occurs
    public  int getColumnDisplaySize(int columnthrows  SQLException {
        int colType = getColumnType(column);
        switch (colType){
            case .:
            case .: {
                ExtendedFieldInfo fieldInfo = getExtFieldInfo(column);
                if (fieldInfo == null)
                    return estimatePrecision(column);
                else
                    return fieldInfo.fieldPrecision;
            }
            case .:
            case .: {
                XSQLVAR var = getXsqlvar(column);
                int charset = var.sqlsubtype & 0xFF;
                int charSetSize = charset == 127 /* CS_dynamic */ ?
                    EncodingFactory.getIscEncodingSize(getIscEncoding()) :
                    EncodingFactory.getCharacterSetSize(charset);
                return var.sqllen / charSetSize;
            }
            case .:
                return 9;
            case .:
                return 17;
            case .:
                return 11;
            case .:
                return 21;
            case .:
                return 6;
            case .:
                return 10;
            case .:
                return 8;
            case .:
                return 19;
            case .:
                return 1;
            default:
               return 0;
            }
        }


    
Gets the designated column's suggested title for use in printouts and displays.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
the suggested column title
Throws:
java.sql.SQLException if a database access error occurs
    public  String getColumnLabel(int columnthrows  SQLException {
        return .getColumnLabel(getXsqlvar(column));
    }


    
Get the designated column's name.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
column name
Throws:
java.sql.SQLException if a database access error occurs
    public  String getColumnName(int columnthrows  SQLException {
        return .getColumnName(getXsqlvar(column));
    }
    public String getSourceColumnName(int columnthrows SQLException {
        String result = getXsqlvar(column).;
        
        if (result == null)
            result = "";
        
        return result;
    }

    
Get the designated column's table's schema.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
schema name or "" if not applicable
Throws:
java.sql.SQLException if a database access error occurs
    public  String getSchemaName(int columnthrows  SQLException {
        //not really implemented
        return "";
    }


    
Get the designated column's number of decimal digits.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
precision
Throws:
java.sql.SQLException if a database access error occurs
    public  int getPrecision(int columnthrows  SQLException {
        int colType = getColumnType(column);
        switch (colType){
            case .:
            case .: {
                ExtendedFieldInfo fieldInfo = getExtFieldInfo(column);
                if (fieldInfo == null)
                    return estimatePrecision(column);
                else
                    return fieldInfo.fieldPrecision;
            }
            case .:
            case .: {
                XSQLVAR var = getXsqlvar(column);
                int charset = var.sqlsubtype & 0xFF;
                int charSetSize = charset == 127 /* CS_dynamic */ ?
                    EncodingFactory.getIscEncodingSize(getIscEncoding()) :
                    EncodingFactory.getCharacterSetSize(charset);
                return var.sqllen / charSetSize;
            }
            case .:
                return 7;
            case .:
                return 15;
            case .:
                return 10;
            case .:
                return 19;
            case .:
                return 5;
            case .:
                return 10;
            case .:
                return 8;
            case .:
                return 19;
            case .:
                return 1;
            default:
                return 0;
            }
        }


    
Gets the designated column's number of digits to right of the decimal point.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
scale
Throws:
java.sql.SQLException if a database access error occurs
    public  int getScale(int columnthrows  SQLException {
        return getXsqlvar(column). * (-1);
    }


    
Gets the designated column's table name.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
table name or "" if not applicable
Throws:
java.sql.SQLException if a database access error occurs
    public  String getTableName(int columnthrows  SQLException {
        String result = getXsqlvar(column).;
        if (result == nullresult = "";
        return result;
    }

    
Gets the designated column's table alias.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
table alias or "" if not applicable
Throws:
java.sql.SQLException if a database access error occurs
    public String getTableAlias(int columnthrows SQLException {
        String result = getXsqlvar(column).;
        if (result == nullresult = getTableName(column);
        return result;
    }

    
    
Gets the designated column's table's catalog name.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
column name or "" if not applicable
Throws:
java.sql.SQLException if a database access error occurs
    public String getCatalogName(int columnthrows  SQLException {
        return "";
    }


    
Retrieves the designated column's SQL type.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
SQL type from java.sql.Types
Throws:
java.sql.SQLException if a database access error occurs
See also:
java.sql.Types
    public  int getColumnType(int columnthrows  SQLException {
        int sqltype = getXsqlvar(column). & ~1;
        int sqlscale = getXsqlvar(column).;
        int sqlsubtype = getXsqlvar(column).;
        if (sqlscale < 0) {
            switch (sqltype) {
                case .:
                case .:
                case .:
                case .:
                    // NOTE: can't be BIGINT because of scale
                    if (sqlsubtype == 2)
                        return .;
                    else
                        return .;
                default:
                    break;
            }
        }
        switch (sqltype) {
            case .:
                return .;
            case .:
                return .;
            case .:
            case .:
                return .;
            case .:
                return .;
            case .:
                return .;
            case .:
                return .;
            case .:
                return .;
            case .:
                return .;
            case .:
                return .;
            case .:
                if (sqlsubtype == 1)
                    return .;
                else if (sqlsubtype == 2)
                    return .;
                else
                    return .;
            case .:
                if (sqlsubtype < 0)
                    return .;
                else if (sqlsubtype == 0 || sqlsubtype > 1)
                    return .;
                else if (sqlsubtype == 1)
                    return .;
                else
                    return .;
            case .:
                return .;
            case .:
                return .;
            default:
                return .;
        }
    }


    
Retrieves the designated column's database-specific type name.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
type name used by the database. If the column type is a user-defined type, then a fully-qualified type name is returned.
Throws:
java.sql.SQLException if a database access error occurs
    public  String getColumnTypeName(int columnthrows  SQLException {    	
        // Must return the same value as DatabaseMetaData getColumns Type_Name
        int sqltype = getXsqlvar(column). & ~1;
        int sqlscale = getXsqlvar(column).;
        int sqlsubtype = getXsqlvar(column).;
        if (sqlscale < 0) {
            switch (sqltype) {
                case .:
                case .:
                case .:
                case .:
                    // NOTE: can't be BIGINT because of scale
                    if (sqlsubtype == 2)
                        return "DECIMAL";
                    else
                        return "NUMERIC";
                default:
                    break;
            }
        }
        switch (sqltype) {
            case .:
                return "SMALLINT";
            case .:
                return "INTEGER";
            case .:
            case .:
                return "DOUBLE PRECISION";
            case .:
                return "FLOAT";
            case .:
                return "CHAR";
            case .:
                return "VARCHAR";
            case .:
                return "TIMESTAMP";
            case .:
                return "TIME";
            case .:
                return "DATE";
            case .:
                //this might need some help for long mapping
                if (sqlsubtype == 1)
                    return "NUMERIC";
                else if (sqlsubtype == 2)
                    return "DECIMAL";
                else
                    return "BIGINT";
            case .:
                if (sqlsubtype < 0)
                    return "BLOB SUB_TYPE <0";
                else if (sqlsubtype == 0)
                    return "BLOB SUB_TYPE 0";
                else if (sqlsubtype == 1)
                    return "BLOB SUB_TYPE 1";
                else
                    return "BLOB SUB_TYPE " + sqlsubtype;
            case .:
                return "ARRAY";
            case .:
                return "BOOLEAN";
            default:
                return "NULL";
        }
        
    }



    
Indicates whether the designated column is definitely not writable.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
true if so; false otherwise
Throws:
java.sql.SQLException if a database access error occurs
    public  boolean isReadOnly(int columnthrows  SQLException {
        //Need to consider priveleges!!
        return false;
    }


    
Indicates whether it is possible for a write on the designated column to succeed.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
true if so; false otherwise
Throws:
java.sql.SQLException if a database access error occurs
    public  boolean isWritable(int columnthrows  SQLException {
        //Needs priveleges???
        return true;
    }

    
Indicates whether a write on the designated column will definitely succeed.

Parameters:
column the first column is 1, the second is 2, ...
Returns:
true if so; false otherwise
Throws:
java.sql.SQLException if a database access error occurs
    public  boolean isDefinitelyWritable(int columnthrows  SQLException {
        //Need to consider privileges!!!
        return true;
    }
    //--------------------------JDBC 2.0-----------------------------------

    

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. ResultSet.getObject may return a subclass of the class returned by this method.

Returns:
the fully-qualified name of the class in the Java programming language that would be used by the method ResultSet.getObject to retrieve the value in the specified column. This is the class name used for custom mapping.
Throws:
java.sql.SQLException if a database access error occurs
Since:
1.2
See also:
What Is in the JDBC 2.0 API
    public String getColumnClassName(int columnthrows  SQLException {
        switch (getXsqlvar(column). & ~1) {
            
            case .:
            case .:
                return String.class.getName();
            
            case .:
            case .:
                return Integer.class.getName();
            
            case .:
            case .:
            case .:
                return Double.class.getName();
            
            case .:
                return Timestamp.class.getName();
            
            case .:
                
                XSQLVAR field = getXsqlvar(column);
                
                if (field.sqlsubtype < 0)
                    return Blob.class.getName();
                
                if (field.sqlsubtype == 1)
                    return String.class.getName();
                
                else
                    return byte[].class.getName();
            case .:
                return Array.class.getName();
            
            case .:
                return Long.class.getName();
            
            case .:
                return Time.class.getName();
            
            case .:
                return Date.class.getName();
            
            case .:
                if (getXsqlvar(column). == 0) {
                    return Long.class.getName();
                }
                else {
                    return BigDecimal.class.getName();
                }
            case .:
                return Boolean.class.getName();
            default:
                throw new FBSQLException("Unknown SQL type.",
                        .);
        }
    }
    //private methods
    private XSQLVAR getXsqlvar(int columnIndex) {
        //return stmt.getOutSqlda().sqlvar[columnIndex - 1];
        return [columnIndex - 1];
    }
    private ExtendedFieldInfo getExtFieldInfo(int columnIndex)
        throws SQLException
    {
        if ( == null)
        {
            this. = getExtendedFieldInfo();
        } // end of if ()
        FieldKey key = new FieldKey(
            getXsqlvar(columnIndex).,
            getXsqlvar(columnIndex).);
        return (ExtendedFieldInfo).get(key);
    }
    private int estimatePrecision(int columnIndex) {
        int sqltype = getXsqlvar(columnIndex). & ~1;
        // TODO: Why unused?
        int sqlscale = getXsqlvar(columnIndex).;
        switch(sqltype) {
            case . : return 5;
            case . : return 10;
            case . : return 19;
            case . : return 19;
            default : return 0;
        }
    }
    private static final String GET_FIELD_INFO = "SELECT "
        + "  RF.RDB$RELATION_NAME as RELATION_NAME"
        + ", RF.RDB$FIELD_NAME as FIELD_NAME"
        + ", F.RDB$FIELD_LENGTH as FIELD_LENGTH"
        + ", F.RDB$FIELD_PRECISION as FIELD_PRECISION"
        + ", F.RDB$FIELD_SCALE as FIELD_SCALE"
        + ", F.RDB$FIELD_SUB_TYPE as FIELD_SUB_TYPE"
        + ", F.RDB$CHARACTER_LENGTH as CHAR_LEN"
        + ", F.RDB$CHARACTER_SET_ID as CHARACTER_SET_ID"
        + " FROM"
        + "  RDB$RELATION_FIELDS RF "
        + ", RDB$FIELDS F "
        + " WHERE "
        + "  RF.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME"
        + " AND"
        + "  RF.RDB$FIELD_NAME = ?"
        + " AND"
        + "  RF.RDB$RELATION_NAME = ?"
        ;

    
This class is an old-fashion data structure that stores additional information about fields in a database.
    private static class ExtendedFieldInfo {
    	// TODO Find out why there are unused fields here
        String relationName;
        String fieldName;
        int fieldLength;
        int fieldPrecision;
        int fieldScale;
        int fieldSubtype;
        int characterLength;
        int characterSetId;
    }

    
This class should be used as a composite key in an internal field mapping structures.
    private static final class FieldKey {
        private String relationName;
        private String fieldName;

        
Create instance of this class for the specified relation and field names.

Parameters:
relationName relation name.
fieldName field name.
        FieldKey(String relationNameString fieldName) {
            this. = relationName;
            this. = fieldName;
        }

        
Check if obj is equal to this object.

Parameters:
obj object to check.
Returns:
true if obj is instance of this class and has equal relation and field names.
        public boolean equals(Object obj) {
            if (obj == thisreturn true;
            if (obj == null || !(obj instanceof FieldKey)) return false;
            FieldKey that = (FieldKey)obj;
            
            return ( != null ? .equals(that.relationName) : that.relationName == null
            		&&
            		( != null ? .equals(that.fieldName) : that.fieldName == null);
        }

        
Get hash code of this instance.

Returns:
combination of hash codes of relationName field and fieldName field.
        public int hashCode() {
            int result = 971;
            result = 23 * result + ( != null ? .hashCode() : 0);
            result = 23 * result + ( != null ? .hashCode() : 0);
            return result;
        }
    }

    
This method retrieves extended information from the system tables in a database. Since this method is expensinve, use it with care.

Returns:
mapping between FBResultSetMetaData.FieldKey instances and FBResultSetMetaData.ExtendedFieldInfo instances.
Throws:
java.sql.SQLException if extended field information cannot be obtained.
    private Map getExtendedFieldInfo(GDSHelper gdsHelperthrows SQLException {
        if (gdsHelper == nullreturn .;
        //
        // Apparently there is a limit in the UNION
        // It is necesary to split in several querys
        // Although the problem reported with 93 UNION use only 70
        //
        int pending = .;
        HashMap result = new HashMap();
        while (pending > 0){
            StringBuffer sb = new StringBuffer();
            ArrayList params = new ArrayList();
            int maxLength = (pending>70) ? 70 : pending;
            for (int i = 0; i < maxLengthi++) {
                String relationName = [i].;
                String fieldName = [i].;
                if (relationName == null || fieldName == nullcontinue;
                sb.append();
                params.add(fieldName);
                params.add(relationName);
                if (i < maxLength - 1)
                    sb.append("\n").append("UNION").append("\n");
            }
            FBDatabaseMetaData metaData = new FBDatabaseMetaData(gdsHelper);
            ResultSet rs = metaData.doQuery(sb.toString(), params);
            try {
                while(rs.next()) {
                    ExtendedFieldInfo fieldInfo = new ExtendedFieldInfo();
                    fieldInfo.relationName = rs.getString("RELATION_NAME");
                    fieldInfo.fieldName = rs.getString("FIELD_NAME");
                    fieldInfo.fieldLength = rs.getInt("FIELD_LENGTH");
                    fieldInfo.fieldPrecision = rs.getInt("FIELD_PRECISION");
                    fieldInfo.fieldScale = rs.getInt("FIELD_SCALE");
                    fieldInfo.fieldSubtype = rs.getInt("FIELD_SUB_TYPE");
                    fieldInfo.characterSetId = rs.getInt("CHARACTER_SET_ID");
                    fieldInfo.characterLength = rs.getInt("CHAR_LEN");
                    if (rs.wasNull())
                        fieldInfo.characterLength =
                            fieldInfo.fieldLength /
                            EncodingFactory.getCharacterSetSize(fieldInfo.characterSetId);
                    result.put(
                        new FieldKey(fieldInfo.relationNamefieldInfo.fieldName),
                        fieldInfo);
                }
            } finally {
                rs.close();
            }
            pending -= maxLength;
        }
        return result;
    }
    
    public boolean isWrapperFor(Class<?> ifacethrows SQLException {
        return iface != null && iface.isAssignableFrom(getClass());
    }
    public <T> T unwrap(Class<T> ifacethrows SQLException {
        if (!isWrapperFor(iface))
            throw new FBDriverNotCapableException();
        
        return iface.cast(this);
    }
    
    
Strategy for retrieving column labels and column names
    private enum ColumnStrategy {
        
Default, JDBC-compliant, strategy for column naming.

columnLabel is the AS clause (xsqlvar.aliasname) if specified, otherwise xsqlvar.sqlname.

columnName is xsqlvar.sqlname if specified, otherwise xsqlvar.aliasname (TODO: change this?)

        DEFAULT {
            @Override
            String getColumnName(XSQLVAR xsqlvar) {
                if (xsqlvar.sqlname == null) {
                    return getColumnLabel(xsqlvar);
                } else {
                    return xsqlvar.sqlname;
                }
            }
        },
        
Alternative strategy for column naming (related to columnLabelForName connection property)

This strategy is not JDBC-compliant, but is provided as a workaround for use with com.sun.rowset.CachedRowSetImpl and for people expecting the old behavior.

columnLabel is the AS clause (xsqlvar.aliasname) if specified, otherwise xsqlvar.sqlname.

columnName is identical to columnLabel.

        COLUMN_LABEL_FOR_NAME {
            @Override
            String getColumnName(XSQLVAR xsqlvar) {
                return getColumnLabel(xsqlvar);
            }
        }        
        ;       
        
        
Retrieve the columnName for the specified column.

Parameters:
xsqlvar Column XSQLVAR
Returns:
value for the columnName
        abstract String getColumnName(XSQLVAR xsqlvar);
        
        
Retrieve the columnLabel for the specified column.

Parameters:
xsqlvar Column XSQLVAR
Returns:
value for the columnLabel
        String getColumnLabel(XSQLVAR xsqlvar) {
            if (xsqlvar.aliasname != null) {
                return xsqlvar.aliasname;
            } else if (xsqlvar.sqlname != null) {
                return xsqlvar.sqlname;
            } else {
                return "";
            }
        }
    }
New to GrepCode? Check out our FAQ X