Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: postgresql/jdbc1/ResultSetMetaData.java


1   package postgresql.jdbc1;
2   
3   // IMPORTANT NOTE: This file implements the JDBC 1 version of the driver.
4   // If you make any modifications to this file, you must make sure that the
5   // changes are also made (if relevent) to the related JDBC 2 class in the
6   // postgresql.jdbc2 package.
7   
8   import java.lang.*;
9   import java.util.*;
10  import postgresql.*;
11  import postgresql.util.*;
12  
13  // We explicitly import classes here as the original line:
14  //import java.sql.*;
15  // causes javac to get confused.
16  import java.sql.SQLException;
17  import java.sql.Types;
18  
19  /**
20   * A ResultSetMetaData object can be used to find out about the types and
21   * properties of the columns in a ResultSet
22   *
23   * @see java.sql.ResultSetMetaData
24   */
25  public class ResultSetMetaData implements java.sql.ResultSetMetaData 
26  {
27    Vector rows;
28    Field[] fields;
29    
30    /**
31     *  Initialise for a result with a tuple set and
32     *  a field descriptor set
33     *
34     * @param rows the Vector of rows returned by the ResultSet
35     * @param fields the array of field descriptors
36     */
37    public ResultSetMetaData(Vector rows, Field[] fields)
38    {
39      this.rows = rows;
40      this.fields = fields;
41    }
42    
43    /**
44     * Whats the number of columns in the ResultSet?
45     *
46     * @return the number
47     * @exception SQLException if a database access error occurs
48     */
49    public int getColumnCount() throws SQLException
50    {
51      return fields.length;
52    }
53    
54    /**
55     * Is the column automatically numbered (and thus read-only)
56     * I believe that PostgreSQL does not support this feature.
57     *
58     * @param column the first column is 1, the second is 2...
59     * @return true if so
60     * @exception SQLException if a database access error occurs
61     */
62    public boolean isAutoIncrement(int column) throws SQLException
63    {
64      return false;
65    }
66    
67    /**
68     * Does a column's case matter? ASSUMPTION: Any field that is
69     * not obviously case insensitive is assumed to be case sensitive
70     *
71     * @param column the first column is 1, the second is 2...
72     * @return true if so
73     * @exception SQLException if a database access error occurs
74     */
75    public boolean isCaseSensitive(int column) throws SQLException
76    {
77      int sql_type = getField(column).getSQLType();
78      
79      switch (sql_type)
80        {
81        case Types.SMALLINT:
82        case Types.INTEGER:
83        case Types.FLOAT:
84        case Types.REAL:
85        case Types.DOUBLE:
86        case Types.DATE:
87        case Types.TIME:
88        case Types.TIMESTAMP:
89    return false;
90        default:
91    return true;
92        }
93    }
94    
95    /**
96     * Can the column be used in a WHERE clause?  Basically for
97     * this, I split the functions into two types: recognised
98     * types (which are always useable), and OTHER types (which
99     * may or may not be useable).  The OTHER types, for now, I
100    * will assume they are useable.  We should really query the
101    * catalog to see if they are useable.
102    *
103    * @param column the first column is 1, the second is 2...
104    * @return true if they can be used in a WHERE clause
105    * @exception SQLException if a database access error occurs
106    */
107   public boolean isSearchable(int column) throws SQLException
108   {
109     int sql_type = getField(column).getSQLType();
110     
111     // This switch is pointless, I know - but it is a set-up
112     // for further expansion.    
113     switch (sql_type)
114       {
115       case Types.OTHER:
116   return true;
117       default:
118   return true;
119       }
120   }
121   
122   /**
123    * Is the column a cash value?  6.1 introduced the cash/money
124    * type, which haven't been incorporated as of 970414, so I
125    * just check the type name for both 'cash' and 'money'
126    *
127    * @param column the first column is 1, the second is 2...
128    * @return true if its a cash column
129    * @exception SQLException if a database access error occurs
130    */
131   public boolean isCurrency(int column) throws SQLException
132   {
133     String type_name = getField(column).getTypeName();
134     
135     return type_name.equals("cash") || type_name.equals("money");
136   }
137   
138   /**
139    * Can you put a NULL in this column?  I think this is always
140    * true in 6.1's case.  It would only be false if the field had
141    * been defined NOT NULL (system catalogs could be queried?)
142    *
143    * @param column the first column is 1, the second is 2...
144    * @return one of the columnNullable values
145    * @exception SQLException if a database access error occurs
146    */
147   public int isNullable(int column) throws SQLException
148   {
149     return columnNullable;  // We can always put NULL in
150   }
151   
152   /**
153    * Is the column a signed number? In PostgreSQL, all numbers
154    * are signed, so this is trivial.  However, strings are not
155    * signed (duh!)
156    * 
157    * @param column the first column is 1, the second is 2...
158    * @return true if so
159    * @exception SQLException if a database access error occurs
160    */
161   public boolean isSigned(int column) throws SQLException
162   {
163     int sql_type = getField(column).getSQLType();
164     
165     switch (sql_type)
166       {
167       case Types.SMALLINT:
168       case Types.INTEGER:
169       case Types.FLOAT:
170       case Types.REAL:
171       case Types.DOUBLE:
172   return true;
173       case Types.DATE:
174       case Types.TIME:
175       case Types.TIMESTAMP:
176   return false;  // I don't know about these?
177       default:
178   return false;
179       }
180   }
181   
182   /**
183    * What is the column's normal maximum width in characters?
184    *
185    * @param column the first column is 1, the second is 2, etc.
186    * @return the maximum width
187    * @exception SQLException if a database access error occurs
188    */
189   public int getColumnDisplaySize(int column) throws SQLException
190   {
191     Field f = getField(column);
192     String type_name = f.getTypeName();
193     int sql_type = f.getSQLType();
194     int typmod = f.mod;
195 
196     // I looked at other JDBC implementations and couldn't find a consistent
197     // interpretation of the "display size" for numeric values, so this is our's
198     // FIXME: currently, only types with a SQL92 or SQL3 pendant are implemented - jens@jens.de
199 
200     // fixed length data types
201     if (type_name.equals( "int2"      ))  return 6;  // -32768 to +32768 (5 digits and a sign)
202     if (type_name.equals( "int4"      ) 
203      || type_name.equals( "oid"       ))  return 11; // -2147483648 to +2147483647
204     if (type_name.equals( "int8"      ))  return 20; // -9223372036854775808 to +9223372036854775807
205     if (type_name.equals( "money"     ))  return 12; // MONEY = DECIMAL(9,2)
206     if (type_name.equals( "float4"    ))  return 11; // i checked it out ans wasn't able to produce more than 11 digits
207     if (type_name.equals( "float8"    ))  return 20; // dito, 20
208     if (type_name.equals( "char"      ))  return 1;
209     if (type_name.equals( "bool"      ))  return 1;
210     if (type_name.equals( "date"      ))  return 14; // "01/01/4713 BC" - "31/12/32767 AD"
211     if (type_name.equals( "time"      ))  return 8;  // 00:00:00-23:59:59
212     if (type_name.equals( "timestamp" ))  return 22; // hhmmm ... the output looks like this: 1999-08-03 22:22:08+02
213 
214     // variable length fields
215     typmod -= 4;
216     if (type_name.equals( "bpchar"    )
217      || type_name.equals( "varchar"   ))  return typmod; // VARHDRSZ=sizeof(int32)=4
218     if (type_name.equals( "numeric"   ))  return ( (typmod >>16) & 0xffff )
219                                            + 1 + ( typmod        & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits)
220 
221     // if we don't know better
222     return f.length;
223   }
224   
225   /**
226    * What is the suggested column title for use in printouts and
227    * displays?  We suggest the ColumnName!
228    *
229    * @param column the first column is 1, the second is 2, etc.
230    * @return the column label
231    * @exception SQLException if a database access error occurs
232    */
233   public String getColumnLabel(int column) throws SQLException
234   {
235     return getColumnName(column);
236   }
237   
238   /**
239    * What's a column's name?
240    *
241    * @param column the first column is 1, the second is 2, etc.
242    * @return the column name
243    * @exception SQLException if a database access error occurs
244    */
245   public String getColumnName(int column) throws SQLException
246   {
247     Field f = getField(column);
248     if(f!=null)
249       return f.name;
250     return "field"+column;
251   }
252   
253   /**
254    * What is a column's table's schema?  This relies on us knowing
255    * the table name....which I don't know how to do as yet.  The 
256    * JDBC specification allows us to return "" if this is not
257    * applicable.
258    *
259    * @param column the first column is 1, the second is 2...
260    * @return the Schema
261    * @exception SQLException if a database access error occurs
262    */
263   public String getSchemaName(int column) throws SQLException
264   {
265     return "";
266   }
267   
268   /**
269    * What is a column's number of decimal digits.
270    *
271    * @param column the first column is 1, the second is 2...
272    * @return the precision
273    * @exception SQLException if a database access error occurs
274    */
275   public int getPrecision(int column) throws SQLException
276   {
277     int sql_type = getField(column).getSQLType();
278     
279     switch (sql_type)
280       {
281       case Types.SMALLINT:
282   return 5;  
283       case Types.INTEGER:
284   return 10;
285       case Types.REAL:
286   return 8;
287       case Types.FLOAT:
288   return 16;
289       case Types.DOUBLE:
290   return 16;
291       case Types.VARCHAR:
292   return 0;
293       default:
294   return 0;
295       }
296   }
297   
298   /**
299    * What is a column's number of digits to the right of the
300    * decimal point?
301    *
302    * @param column the first column is 1, the second is 2...
303    * @return the scale
304    * @exception SQLException if a database access error occurs
305    */
306   public int getScale(int column) throws SQLException
307   {
308     int sql_type = getField(column).getSQLType();
309     
310     switch (sql_type)
311       {
312       case Types.SMALLINT:
313   return 0;
314       case Types.INTEGER:
315   return 0;
316       case Types.REAL:
317   return 8;
318       case Types.FLOAT:
319   return 16;
320       case Types.DOUBLE:
321   return 16;
322       case Types.VARCHAR:
323   return 0;
324       default:
325   return 0;
326       }
327   }
328   
329   /**
330    * Whats a column's table's name?  How do I find this out?  Both
331    * getSchemaName() and getCatalogName() rely on knowing the table
332    * Name, so we need this before we can work on them.
333    *
334    * @param column the first column is 1, the second is 2...
335    * @return column name, or "" if not applicable
336    * @exception SQLException if a database access error occurs
337    */
338   public String getTableName(int column) throws SQLException
339   {
340     return "";
341   }
342   
343   /**
344    * What's a column's table's catalog name?  As with getSchemaName(),
345    * we can say that if getTableName() returns n/a, then we can too -
346    * otherwise, we need to work on it.
347    * 
348    * @param column the first column is 1, the second is 2...
349    * @return catalog name, or "" if not applicable
350    * @exception SQLException if a database access error occurs
351    */
352   public String getCatalogName(int column) throws SQLException
353   {
354     return "";
355   }
356   
357   /**
358    * What is a column's SQL Type? (java.sql.Type int)
359    *
360    * @param column the first column is 1, the second is 2, etc.
361    * @return the java.sql.Type value
362    * @exception SQLException if a database access error occurs
363    * @see postgresql.Field#getSQLType
364    * @see java.sql.Types
365    */
366   public int getColumnType(int column) throws SQLException
367   {
368     return getField(column).getSQLType();
369   }
370   
371   /**
372    * Whats is the column's data source specific type name?
373    *
374    * @param column the first column is 1, the second is 2, etc.
375    * @return the type name
376    * @exception SQLException if a database access error occurs
377    */
378   public String getColumnTypeName(int column) throws SQLException
379   {
380     return getField(column).getTypeName();
381   }
382   
383   /**
384    * Is the column definitely not writable?  In reality, we would
385    * have to check the GRANT/REVOKE stuff for this to be effective,
386    * and I haven't really looked into that yet, so this will get
387    * re-visited.
388    *
389    * @param column the first column is 1, the second is 2, etc.
390    * @return true if so
391    * @exception SQLException if a database access error occurs
392    */
393   public boolean isReadOnly(int column) throws SQLException
394   {
395     return false;
396   }
397   
398   /**
399    * Is it possible for a write on the column to succeed?  Again, we
400    * would in reality have to check the GRANT/REVOKE stuff, which
401    * I haven't worked with as yet.  However, if it isn't ReadOnly, then
402    * it is obviously writable.
403    *
404    * @param column the first column is 1, the second is 2, etc.
405    * @return true if so
406    * @exception SQLException if a database access error occurs
407    */
408   public boolean isWritable(int column) throws SQLException
409   {
410     if (isReadOnly(column))
411       return true;
412     else
413       return false;
414   }
415   
416   /**
417    * Will a write on this column definately succeed?  Hmmm...this
418    * is a bad one, since the two preceding functions have not been
419    * really defined.  I cannot tell is the short answer.  I thus
420    * return isWritable() just to give us an idea.
421    *
422    * @param column the first column is 1, the second is 2, etc..
423    * @return true if so
424    * @exception SQLException if a database access error occurs
425    */
426   public boolean isDefinitelyWritable(int column) throws SQLException
427   {
428     return isWritable(column);
429   }
430   
431   // ********************************************************
432   //   END OF PUBLIC INTERFACE
433   // ********************************************************
434   
435   /**
436    * For several routines in this package, we need to convert
437    * a columnIndex into a Field[] descriptor.  Rather than do
438    * the same code several times, here it is.
439    * 
440    * @param columnIndex the first column is 1, the second is 2...
441    * @return the Field description
442    * @exception SQLException if a database access error occurs
443    */
444   private Field getField(int columnIndex) throws SQLException
445   {
446     if (columnIndex < 1 || columnIndex > fields.length)
447       throw new PSQLException("postgresql.res.colrange");
448     return fields[columnIndex - 1];
449   }
450 }
451