1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.dbunit.database;
22
23 import java.sql.Connection;
24 import java.sql.DatabaseMetaData;
25 import java.sql.ResultSet;
26 import java.sql.ResultSetMetaData;
27 import java.sql.SQLException;
28
29 import org.dbunit.dataset.AbstractTableMetaData;
30 import org.dbunit.dataset.Column;
31 import org.dbunit.dataset.DataSetException;
32 import org.dbunit.dataset.DefaultTableMetaData;
33 import org.dbunit.dataset.datatype.DataType;
34 import org.dbunit.dataset.datatype.DataTypeException;
35 import org.dbunit.dataset.datatype.IDataTypeFactory;
36 import org.dbunit.util.SQLHelper;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public class ResultSetTableMetaData extends AbstractTableMetaData
71 {
72
73
74
75 private static final Logger logger = LoggerFactory.getLogger(DatabaseTableMetaData.class);
76
77
78
79
80 private DefaultTableMetaData wrappedTableMetaData;
81 private boolean _caseSensitiveMetaData;
82
83
84
85
86
87
88
89
90
91 public ResultSetTableMetaData(String tableName,
92 ResultSet resultSet, IDatabaseConnection connection, boolean caseSensitiveMetaData)
93 throws DataSetException, SQLException
94 {
95 super();
96 _caseSensitiveMetaData = caseSensitiveMetaData;
97 this.wrappedTableMetaData = createMetaData(tableName, resultSet, connection);
98
99 }
100
101
102
103
104
105
106
107
108
109
110 public ResultSetTableMetaData(String tableName,
111 ResultSet resultSet, IDataTypeFactory dataTypeFactory, boolean caseSensitiveMetaData)
112 throws DataSetException, SQLException
113 {
114 super();
115 _caseSensitiveMetaData = caseSensitiveMetaData;
116 this.wrappedTableMetaData = createMetaData(tableName, resultSet, dataTypeFactory, new DefaultMetadataHandler());
117 }
118
119
120 private DefaultTableMetaData createMetaData(String tableName,
121 ResultSet resultSet, IDatabaseConnection connection)
122 throws SQLException, DataSetException
123 {
124 if (logger.isTraceEnabled())
125 logger.trace("createMetaData(tableName={}, resultSet={}, connection={}) - start",
126 new Object[] { tableName, resultSet, connection });
127
128 DatabaseConfig dbConfig = connection.getConfig();
129 IMetadataHandler columnFactory = (IMetadataHandler)dbConfig.getProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER);
130 IDataTypeFactory typeFactory = super.getDataTypeFactory(connection);
131 return createMetaData(tableName, resultSet, typeFactory, columnFactory);
132 }
133
134 private DefaultTableMetaData createMetaData(String tableName,
135 ResultSet resultSet, IDataTypeFactory dataTypeFactory, IMetadataHandler columnFactory)
136 throws DataSetException, SQLException
137 {
138 if (logger.isTraceEnabled())
139 logger.trace("createMetaData(tableName={}, resultSet={}, dataTypeFactory={}, columnFactory={}) - start",
140 new Object[]{ tableName, resultSet, dataTypeFactory, columnFactory });
141
142 Connection connection = resultSet.getStatement().getConnection();
143 DatabaseMetaData databaseMetaData = connection.getMetaData();
144
145 ResultSetMetaData metaData = resultSet.getMetaData();
146 Column[] columns = new Column[metaData.getColumnCount()];
147 for (int i = 0; i < columns.length; i++)
148 {
149 int rsIndex = i+1;
150
151
152
153
154 columns[i] = createColumnFromDbMetaData(metaData, rsIndex, databaseMetaData, dataTypeFactory, columnFactory);
155
156
157
158 if(columns[i] == null)
159 {
160 columns[i] = createColumnFromRsMetaData(metaData, rsIndex, tableName, dataTypeFactory);
161 }
162 }
163
164 return new DefaultTableMetaData(tableName, columns);
165 }
166
167 private Column createColumnFromRsMetaData(ResultSetMetaData rsMetaData,
168 int rsIndex, String tableName, IDataTypeFactory dataTypeFactory)
169 throws SQLException, DataTypeException
170 {
171 if(logger.isTraceEnabled()){
172 logger.trace("createColumnFromRsMetaData(rsMetaData={}, rsIndex={}," +
173 " tableName={}, dataTypeFactory={}) - start",
174 new Object[]{rsMetaData, String.valueOf(rsIndex),
175 tableName, dataTypeFactory});
176 }
177
178 int columnType = rsMetaData.getColumnType(rsIndex);
179 String columnTypeName = rsMetaData.getColumnTypeName(rsIndex);
180 String columnName = rsMetaData.getColumnLabel(rsIndex);
181 int isNullable = rsMetaData.isNullable(rsIndex);
182
183 DataType dataType = dataTypeFactory.createDataType(
184 columnType, columnTypeName, tableName, columnName);
185
186 Column column = new Column(
187 columnName,
188 dataType,
189 columnTypeName,
190 Column.nullableValue(isNullable));
191 return column;
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213 private Column createColumnFromDbMetaData(ResultSetMetaData rsMetaData, int rsIndex,
214 DatabaseMetaData databaseMetaData, IDataTypeFactory dataTypeFactory,
215 IMetadataHandler metadataHandler)
216 throws SQLException, DataTypeException
217 {
218 if(logger.isTraceEnabled()){
219 logger.trace("createColumnFromMetaData(rsMetaData={}, rsIndex={}," +
220 " databaseMetaData={}, dataTypeFactory={}, columnFactory={}) - start",
221 new Object[]{rsMetaData, String.valueOf(rsIndex),
222 databaseMetaData, dataTypeFactory, metadataHandler});
223 }
224
225
226 String catalogName = rsMetaData.getCatalogName(rsIndex);
227 String schemaName = rsMetaData.getSchemaName(rsIndex);
228 String tableName = rsMetaData.getTableName(rsIndex);
229 String columnName = rsMetaData.getColumnLabel(rsIndex);
230
231
232 catalogName = trim(catalogName);
233 schemaName = trim(schemaName);
234 tableName = trim(tableName);
235 columnName = trim(columnName);
236
237
238
239
240
241 if(catalogName != null && catalogName.equals("")) {
242
243 catalogName = null;
244 }
245 if(schemaName != null && schemaName.equals("")) {
246 logger.debug("The 'schemaName' from the ResultSetMetaData is empty-string and not applicable hence. " +
247 "Will not try to lookup column properties via DatabaseMetaData.getColumns.");
248 return null;
249 }
250 if(tableName != null && tableName.equals("")) {
251 logger.debug("The 'tableName' from the ResultSetMetaData is empty-string and not applicable hence. " +
252 "Will not try to lookup column properties via DatabaseMetaData.getColumns.");
253 return null;
254 }
255
256 if(logger.isDebugEnabled())
257 logger.debug("All attributes from the ResultSetMetaData are valid, " +
258 "trying to lookup values in DatabaseMetaData. catalog={}, schema={}, table={}, column={}",
259 new Object[]{catalogName, schemaName, tableName, columnName} );
260
261
262
263 ResultSet columnsResultSet = metadataHandler.getColumns(databaseMetaData, schemaName, tableName);
264
265 try
266 {
267
268 scrollTo(columnsResultSet, metadataHandler, catalogName, schemaName, tableName, columnName);
269
270 Column column = SQLHelper.createColumn(columnsResultSet, dataTypeFactory, true);
271 return column;
272 }
273 catch(IllegalStateException e)
274 {
275 logger.warn("Cannot find column from ResultSetMetaData info via DatabaseMetaData. Returning null." +
276 " Even if this is expected to never happen it probably happened due to a JDBC driver bug." +
277 " To get around this you may want to configure a user defined " + IMetadataHandler.class, e);
278 return null;
279 }
280 finally
281 {
282 SQLHelper.close(columnsResultSet);
283 }
284 }
285
286
287
288
289
290
291
292
293 private String trim(String value)
294 {
295 return (value==null ? null : value.trim());
296 }
297
298 private void scrollTo(ResultSet columnsResultSet, IMetadataHandler metadataHandler,
299 String catalog, String schema, String table, String column)
300 throws SQLException
301 {
302 while(columnsResultSet.next())
303 {
304 boolean match = metadataHandler.matches(columnsResultSet, catalog, schema, table, column, _caseSensitiveMetaData);
305 if(match)
306 {
307
308 return;
309 }
310 }
311
312
313 String msg =
314 "Did not find column '" + column +
315 "' for <schema.table> '" + schema + "." + table +
316 "' in catalog '" + catalog + "' because names do not exactly match.";
317
318 throw new IllegalStateException(msg);
319 }
320
321 public Column[] getColumns() throws DataSetException {
322 return this.wrappedTableMetaData.getColumns();
323 }
324
325 public Column[] getPrimaryKeys() throws DataSetException {
326 return this.wrappedTableMetaData.getPrimaryKeys();
327 }
328
329 public String getTableName() {
330 return this.wrappedTableMetaData.getTableName();
331 }
332
333 public String toString()
334 {
335 final StringBuilder sb = new StringBuilder();
336 sb.append(getClass().getName()).append("[");
337 sb.append("wrappedTableMetaData=").append(this.wrappedTableMetaData);
338 sb.append("]");
339 return sb.toString();
340 }
341 }