KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > jdbc > typing > ColumnMetaDataImpl


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  * Copyright (C) 2003 XQuark Group.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
19  * You can also get it at http://www.gnu.org/licenses/lgpl.html
20  *
21  * For more information on this software, see http://www.xquark.org.
22  */

23
24 package org.xquark.jdbc.typing;
25
26 import java.sql.*;
27
28 import org.xquark.jdbc.typing.TypeMap;
29
30 /**
31  * This class maintains the meta information about a column in a relational
32  * table. This information is useful to verify the integrity constraints
33  * in the the relational tables.
34  *
35  * This class is the default JDBC implementation of ColumnMetaData that uses
36  * standard JDBC metadata functions.
37  */

38 public class ColumnMetaDataImpl implements ColumnMetaData
39 {
40     private static final String JavaDoc RCSRevision = "$Revision: 1.3 $";
41     private static final String JavaDoc RCSName = "$Name: $";
42
43     /** Whether the column belongs to the primary key */
44     protected short primaryKeySeq = -1;
45
46     /** Name of the primary key table when the column is a foreign key */
47     protected String JavaDoc refTable = null;
48
49     /** Name of the primary key column when the column is a foreign key */
50     protected String JavaDoc refColumn = null;
51
52     /** The name of the table that owns this column */
53     protected String JavaDoc tableName;
54
55     /** The name of this column */
56     protected String JavaDoc columnName;
57
58     /** The data type of this column */
59     protected DbType type = null;
60     
61     /** The native data type of this column */
62     protected TypeMap.SQLType sqlType = null;
63
64     /** Whether this column can be null */
65     protected boolean nullable;
66     
67     /** Default value */
68     protected String JavaDoc columnDef;
69
70     /** The ordinal position of this column within the table's definition */
71     protected int ordinalPosition;
72
73     /** Type creation string */
74     protected String JavaDoc typeDDLString;
75     
76     protected ColumnMetaDataImpl(){};
77     
78     /**
79      * Constructor.
80      *
81      * The constructor of the ColumnMetaData is called by AbstractConnection
82      * implementation.
83      * @param rs the result set of DatabaseMetadata.getColumns()
84      */

85     public ColumnMetaDataImpl(ResultSet rs, TypeMap typeMap,
86                               JDBCProperties properties)
87     throws SQLException
88     {
89         tableName = rs.getString(3);
90         columnName = rs.getString(4);
91         sqlType = typeMap.getType(rs.getString(6));
92         if (properties.useStaticMappingFromNativeType())
93             type = new DbType(rs.getInt(7), rs.getInt(9), sqlType);
94         else
95             type = new DbType(rs.getInt(5), rs.getInt(7), rs.getInt(9));
96         int tmp = rs.getInt(11);
97         nullable = (rs.getInt(11) == DatabaseMetaData.columnNullable)
98                     || sqlType.isAutoFill(); // process it like a nullable (no need to fill)
99
columnDef = rs.getString(13);
100         if (columnDef != null) {
101             if (columnDef.length() == 0)
102                 columnDef = null; // for MySQL that returns "" instead of null, bet it won't bother to generalize...
103
else if (columnDef.charAt(0) == '\'' && columnDef.charAt(columnDef.length() - 1) == '\'')
104                 columnDef = columnDef.substring(1, columnDef.length() - 1); // Oracle encloses string literal in quotes maybe distinguish it from numbers.
105
}
106         ordinalPosition = rs.getInt(17);
107         
108         switch (type.getJDBCType())
109         {
110             case Types.CLOB:
111             case Types.BLOB:
112                 type.setLOB(true);
113                 // no break
114
case Types.LONGVARCHAR:
115             case Types.LONGVARBINARY:
116                 type.setLongType(true);
117                 break;
118             default:
119         }
120         
121         // type creation string
122
typeDDLString = getTypeCreationString(
123                         getDataType(),
124                         typeMap,
125                         getColumnSize(),
126                         (int)getColumnSize(),
127                         getDecimalDigits());
128     }
129
130     public ColumnMetaDataImpl(ResultSetMetaData rs, int i, TypeMap typeMap,
131                               JDBCProperties properties)
132     throws SQLException
133     {
134         tableName = rs.getTableName(i);
135         columnName = rs.getColumnName(i);
136         sqlType = typeMap.getType(rs.getColumnTypeName(i));
137         if (properties.useStaticMappingFromNativeType())
138             type = new DbType(sqlType);
139         else
140             type = new DbType(rs.getColumnType(i));
141         nullable = (rs.isNullable(i) == ResultSetMetaData.columnNullable)
142                     || sqlType.isAutoFill(); // process it like a nullable (no need to fill)
143
ordinalPosition = i;
144         type.setLongType(rs.isSearchable(i));
145         type.setLOB(type.isLOB());
146         
147         type.setLength(rs.getColumnDisplaySize(i));
148         if (type.getLength() <= 0)
149             type.setLength(rs.getPrecision(i));
150         type.setScale(rs.getScale(i));
151
152         // type creation string
153
typeDDLString = getTypeCreationString(
154                         getDataType(),
155                         typeMap,
156                         getColumnSize(),
157                         (int)getColumnSize(),
158                         getDecimalDigits());
159     }
160     
161     /**
162      * Whether this column can be null.
163      */

164     public boolean isNullable()
165     {
166         return nullable;
167     }
168
169     public boolean isOptional()
170     {
171         return isNullable() || getDefaultValue() != null;
172     }
173
174     public String JavaDoc getTableName() { return tableName; }
175
176     public String JavaDoc getColumnName() { return columnName; }
177
178     public DbType getType() {
179         return type;
180     }
181     
182     public short getDataType() { return (short)type.getJDBCType(); }
183
184     public String JavaDoc getTypeName() { return type.getNativeType(); }
185
186     public long getColumnSize() { return type.getLength(); }
187
188     public int getDecimalDigits() { return type.getScale(); }
189
190     public String JavaDoc getDefaultValue() { return columnDef; }
191
192     public int getOrdinalPosition() { return ordinalPosition; }
193
194     public boolean isPrimaryKey() { return primaryKeySeq != -1; }
195
196     public short getPrimaryKeySeq() { return primaryKeySeq; }
197
198     public String JavaDoc getRefTable() { return refTable; }
199
200     public String JavaDoc getRefColumn() { return refColumn; }
201
202     public String JavaDoc toString()
203     {
204         return "#<Column "+getTableName()+"."+getColumnName()+">";
205     }
206
207     public void setPrimaryKeySeq(short seq) { primaryKeySeq = seq; }
208
209     public void setRefTable(String JavaDoc name) { refTable = name; }
210
211     public void setRefColumn(String JavaDoc name) { refColumn = name; }
212     
213     public String JavaDoc getTypeCreationString()
214     {
215         return typeDDLString;
216     }
217     
218     public boolean isLongType()
219     {
220         return type.isLongType();
221     }
222     
223     public boolean isLOB()
224     {
225         return type.isLOB();
226     }
227     
228     //////////////////////////////////////////////////////////////////////////
229
// PUBLIC STATIC UTILITIES
230
//////////////////////////////////////////////////////////////////////////
231
public static int findRealisticType(int type, long size, TypeMap typeMap)
232     {
233         switch (type) // switch according to "base" target JDBC type
234
{ // and try to analyse facets(restrictions) to find a 'smaller one'
235
case Types.VARCHAR :
236             case Types.LONGVARCHAR :
237                 if (size <= typeMap.getSize(Types.VARCHAR))
238                     type = Types.VARCHAR;
239                 else
240                     type = Types.LONGVARCHAR;
241                 break;
242             case Types.VARBINARY :
243             case Types.LONGVARBINARY :
244                 if (size <= typeMap.getSize(Types.VARBINARY))
245                     type = Types.VARBINARY;
246                 else
247                     type = Types.LONGVARBINARY;
248                 break;
249             default : // Nothing to do with VARCHAR, TIMESTAMP, REAL
250
}
251         return type;
252     }
253     
254     /* Generate the native SQL statement for column type specification. The
255      * optimum native type is chosen according to size parameters.
256      */

257     public static String JavaDoc getTypeDDL(int dataType, TypeMap typeMap,
258             long maxLength)
259     {
260         return getTypeDDLStatement(dataType, typeMap, maxLength, -1, -1);
261     }
262     
263     public static String JavaDoc getTypeDDL(int dataType, TypeMap typeMap,
264             int precision, int scale)
265     {
266         return getTypeDDLStatement(dataType, typeMap, -1, precision, scale);
267     }
268     
269     public static String JavaDoc getTypeDDL(int dataType, TypeMap typeMap,
270             int precision)
271     {
272         return getTypeDDLStatement(dataType, typeMap, -1, precision, -1);
273     }
274     
275     public static String JavaDoc getTypeDDL(int dataType, TypeMap typeMap)
276     {
277         return getTypeDDLStatement(dataType, typeMap, -1, -1, -1);
278     }
279     
280     /* Warning: no size adaptation is performed (unlike getTypeDDL()).*/
281     public static String JavaDoc getTypeCreationString(int dataType, TypeMap typeMap,
282     long maxLength, int precision, int scale)
283     {
284         String JavaDoc typeString;
285         
286         /* building precision and scale string */
287         switch (dataType) // switch according to target JDBC type for primitive type
288
{ // and try to analyse facets(restrictions) to find a 'smaller one'
289
case Types.CHAR : case Types.BINARY :
290             case Types.VARCHAR : case Types.VARBINARY :
291             case Types.DOUBLE : case Types.FLOAT :
292             case Types.NUMERIC : case Types.DECIMAL :
293                 typeString = getDefaultTypeCreationString(dataType, typeMap,
294                 maxLength, precision, scale);
295                 break;
296             default : // for other type just concatenate the creation metadada param
297
typeString = typeMap.getNativeTypeName(dataType);
298                 if (typeMap.getTypeParam(dataType) != null)
299                     typeString += typeMap.getTypeParam(dataType);
300         }
301         return typeString;
302     }
303     
304     //////////////////////////////////////////////////////////////////////////
305
// PRIVATE
306
//////////////////////////////////////////////////////////////////////////
307
private static String JavaDoc getTypeDDLStatement(int dataType, TypeMap typeMap,
308             long maxLength, int precision, int scale)
309     {
310         /* Adding maximum size for types needing it */
311         if (maxLength < 0)
312         {
313             switch (dataType) // switch according to target JDBC type for primitive type
314
{ // and try to analyse facets(restrictions) to find a 'smaller one'
315
case Types.CHAR : case Types.VARCHAR :
316                 case Types.VARBINARY : case Types.BINARY :
317                     maxLength = typeMap.getSize(dataType);
318                     break;
319                 default :
320             }
321         }
322         
323        return getTypeCreationString(
324             findRealisticType(dataType, maxLength, typeMap),
325             typeMap,
326             maxLength,
327             precision,
328             scale
329             );
330     }
331
332     /** Builds the database-specific string for type specification.
333      * It may be constructed by concatenation of typeName, size, and scale
334      * or in any other way.
335      * <B>A call to the static method loadTypeMetadata must have been
336      * performed before this method is able to return something.</B>
337      * @return a creation string assumed to be constructed
338      * as follows : typeName + '(' + size + ',' + scale + ')'
339      * null if loadTypeMetadata has not been called.
340      */

341     private static String JavaDoc getDefaultTypeCreationString(int dataType,
342     TypeMap typeMap, long maxLength, int precision, int scale)
343     {
344         String JavaDoc ret = null;
345         if (typeMap != null)
346         {
347             ret = typeMap.getNativeTypeName(dataType);
348             if (maxLength > 0)
349                 ret += "(" + maxLength + ")";
350             else if (precision > 0)
351             {
352                 ret += "(" + precision;
353                 if (scale > 0)
354                     ret += "," + scale;
355                 ret += ")";
356             }
357             else if (typeMap.getTypeParam(dataType) == null) // take the maximum authorized by the rdbms
358
{
359                 switch (dataType) // switch according to target JDBC type for primitive type
360
{
361                     case Types.NUMERIC : case Types.FLOAT :
362                     case Types.DOUBLE : case Types.DECIMAL :
363                         // do not add precision (max is implicit) // TO IMPROVE : build a flag for param needed
364
break;
365                     default : // for other type just concatenate the creation metadada param
366
ret += "(" + typeMap.getSize(dataType) + ")";
367                 }
368             }
369         }
370         return ret;
371     }
372     /**
373      * @return Returns the sqlType.
374      */

375     public TypeMap.SQLType getSqlType() {
376         return sqlType;
377     }
378 }
379
Popular Tags