package postgresql; import java.lang.*; import java.sql.*; import java.util.*; import postgresql.*; /** * A ResultSetMetaData object can be used to find out about the types and * properties of the columns in a ResultSet * * @see java.sql.ResultSetMetaData */ public class ResultSetMetaData implements java.sql.ResultSetMetaData { Vector rows; Field[] fields; /** * Initialise for a result with a tuple set and * a field descriptor set * * @param rows the Vector of rows returned by the ResultSet * @param fields the array of field descriptors */ public ResultSetMetaData(Vector rows, Field[] fields) { this.rows = rows; this.fields = fields; } /** * Whats the number of columns in the ResultSet? * * @return the number * @exception SQLException if a database access error occurs */ public int getColumnCount() throws SQLException { return fields.length; } /** * Is the column automatically numbered (and thus read-only) * I believe that PostgreSQL does not support this feature. * * @param column the first column is 1, the second is 2... * @return true if so * @exception SQLException if a database access error occurs */ public boolean isAutoIncrement(int column) throws SQLException { return false; } /** * 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 * @exception SQLException if a database access error occurs */ public boolean isCaseSensitive(int column) throws SQLException { int sql_type = getField(column).getSQLType(); switch (sql_type) { case Types.SMALLINT: case Types.INTEGER: case Types.FLOAT: case Types.REAL: case Types.DOUBLE: case Types.DATE: case Types.TIME: case Types.TIMESTAMP: return false; default: return true; } } /** * 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 * @exception SQLException if a database access error occurs */ public boolean isSearchable(int column) throws SQLException { int sql_type = getField(column).getSQLType(); // This switch is pointless, I know - but it is a set-up // for further expansion. switch (sql_type) { case Types.OTHER: return true; default: return true; } } /** * Is the column a cash value? 6.1 introduced the cash/money * type, which haven't been incorporated as of 970414, so I * just check the type name for both 'cash' and 'money' * * @param column the first column is 1, the second is 2... * @return true if its a cash column * @exception SQLException if a database access error occurs */ public boolean isCurrency(int column) throws SQLException { String type_name = getField(column).getTypeName(); if (type_name.equals("cash")) return true; if (type_name.equals("money")) return true; return false; } /** * Can you put a NULL in this column? I think this is always * true in 6.1's case. It would only be false if the field had * been defined NOT NULL (system catalogs could be queried?) * * @param column the first column is 1, the second is 2... * @return one of the columnNullable values * @exception SQLException if a database access error occurs */ public int isNullable(int column) throws SQLException { return columnNullable; // We can always put NULL in } /** * Is the column a signed number? In PostgreSQL, all numbers * are signed, so this is trivial. However, strings are not * signed (duh!) * * @param column the first column is 1, the second is 2... * @return true if so * @exception SQLException if a database access error occurs */ public boolean isSigned(int column) throws SQLException { int sql_type = getField(column).getSQLType(); switch (sql_type) { case Types.SMALLINT: case Types.INTEGER: case Types.FLOAT: case Types.REAL: case Types.DOUBLE: return true; case Types.DATE: case Types.TIME: case Types.TIMESTAMP: return false; // I don't know about these? default: return false; } } /** * 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 * @exception SQLException if a database access error occurs */ public int getColumnDisplaySize(int column) throws SQLException { int max = getColumnLabel(column).length(); int i; for (i = 0 ; i < rows.size(); ++i) { byte[][] x = (byte[][])(rows.elementAt(i)); if(x[column-1]!=null) { int xl = x[column - 1].length; if (xl > max) max = xl; } } return max; } /** * What is the suggested column title for use in printouts and * displays? We suggest the ColumnName! * * @param column the first column is 1, the second is 2, etc. * @return the column label * @exception SQLException if a database access error occurs */ public String getColumnLabel(int column) throws 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 * @exception SQLException if a databvase access error occurs */ public String getColumnName(int column) throws SQLException { return getField(column).name; } /** * What is a column's table's schema? This relies on us knowing * the table name....which I don't know how to do as yet. 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 * @exception SQLException if a database access error occurs */ public String getSchemaName(int column) throws SQLException { String table_name = getTableName(column); // If the table name is invalid, so are we. if (table_name.equals("")) return ""; return ""; // Ok, so I don't know how to // do this as yet. } /** * What is a column's number of decimal digits. * * @param column the first column is 1, the second is 2... * @return the precision * @exception SQLException if a database access error occurs */ public int getPrecision(int column) throws SQLException { int sql_type = getField(column).getSQLType(); switch (sql_type) { case Types.SMALLINT: return 5; case Types.INTEGER: return 10; case Types.REAL: return 8; case Types.FLOAT: return 16; case Types.DOUBLE: return 16; default: return 0; } } /** * 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 * @exception SQLException if a database access error occurs */ public int getScale(int column) throws SQLException { int sql_type = getField(column).getSQLType(); switch (sql_type) { case Types.SMALLINT: return 0; case Types.INTEGER: return 0; case Types.REAL: return 8; case Types.FLOAT: return 16; case Types.DOUBLE: return 16; default: return 0; } } /** * Whats a column's table's name? How do I find this out? Both * getSchemaName() and getCatalogName() rely on knowing the table * Name, so we need this before we can work on them. * * @param column the first column is 1, the second is 2... * @return column name, or "" if not applicable * @exception SQLException if a database access error occurs */ public String getTableName(int column) throws SQLException { return ""; } /** * What's a column's table's catalog name? As with getSchemaName(), * we can say that if getTableName() returns n/a, then we can too - * otherwise, we need to work on it. * * @param column the first column is 1, the second is 2... * @return catalog name, or "" if not applicable * @exception SQLException if a database access error occurs */ public String getCatalogName(int column) throws SQLException { String table_name = getTableName(column); if (table_name.equals("")) return ""; return ""; // As with getSchemaName(), this // is just the start of it. } /** * 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 * @exception SQLException if a database access error occurs * @see postgresql.Field#getSQLType * @see java.sql.Types */ 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 * @exception SQLException if a database access error occurs */ public String getColumnTypeName(int column) throws SQLException { return getField(column).getTypeName(); } /** * Is the column definitely not writable? In reality, we would * have to check the GRANT/REVOKE stuff for this to be effective, * and I haven't really looked into that yet, so this will get * re-visited. * * @param column the first column is 1, the second is 2, etc. * @return true if so * @exception SQLException if a database access error occurs */ public boolean isReadOnly(int column) throws SQLException { return false; } /** * Is it possible for a write on the column to succeed? Again, we * would in reality have to check the GRANT/REVOKE stuff, which * I haven't worked with as yet. However, if it isn't ReadOnly, then * it is obviously writable. * * @param column the first column is 1, the second is 2, etc. * @return true if so * @exception SQLException if a database access error occurs */ public boolean isWritable(int column) throws SQLException { if (isReadOnly(column)) return true; else return false; } /** * Will a write on this column definately succeed? Hmmm...this * is a bad one, since the two preceding functions have not been * really defined. I cannot tell is the short answer. I thus * return isWritable() just to give us an idea. * * @param column the first column is 1, the second is 2, etc.. * @return true if so * @exception SQLException if a database access error occurs */ public boolean isDefinitelyWritable(int column) throws SQLException { return isWritable(column); } // ******************************************************** // END OF PUBLIC INTERFACE // ******************************************************** /** * For several routines in this package, we need to convert * a columnIndex into a Field[] descriptor. Rather than do * the same code several times, here it is. * * @param columnIndex the first column is 1, the second is 2... * @return the Field description * @exception SQLException if a database access error occurs */ private Field getField(int columnIndex) throws SQLException { if (columnIndex < 1 || columnIndex > fields.length) throw new SQLException("Column index out of range"); return fields[columnIndex - 1]; } }