1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.dbunit.database;
23
24 import java.sql.Connection;
25 import java.sql.DatabaseMetaData;
26 import java.sql.ResultSet;
27 import java.sql.SQLException;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collections;
31 import java.util.List;
32
33 import org.dbunit.dataset.AbstractTableMetaData;
34 import org.dbunit.dataset.Column;
35 import org.dbunit.dataset.Columns;
36 import org.dbunit.dataset.DataSetException;
37 import org.dbunit.dataset.ITableMetaData;
38 import org.dbunit.dataset.NoSuchTableException;
39 import org.dbunit.dataset.datatype.IDataTypeFactory;
40 import org.dbunit.dataset.filter.IColumnFilter;
41 import org.dbunit.util.QualifiedTableName;
42 import org.dbunit.util.SQLHelper;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46
47
48
49
50
51
52
53
54
55
56 public class DatabaseTableMetaData extends AbstractTableMetaData
57 {
58
59
60
61
62 private static final Logger logger = LoggerFactory.getLogger(DatabaseTableMetaData.class);
63
64
65
66
67 private final QualifiedTableName _qualifiedTableNameSupport;
68 private final String _originalTableName;
69 private final IDatabaseConnection _connection;
70 private Column[] _columns;
71 private Column[] _primaryKeys;
72 private boolean _caseSensitiveMetaData;
73
74 private IColumnFilter lastKeyFilter;
75
76
77 DatabaseTableMetaData(String tableName, IDatabaseConnection connection) throws DataSetException
78 {
79 this(tableName, connection, true);
80 }
81
82
83
84
85
86
87
88
89
90
91 DatabaseTableMetaData(String tableName, IDatabaseConnection connection, boolean validate) throws DataSetException
92 {
93 this(tableName, connection, validate, false);
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107 DatabaseTableMetaData(final String tableName, IDatabaseConnection connection, boolean validate, boolean caseSensitiveMetaData) throws DataSetException
108 {
109 if (tableName == null) {
110 throw new NullPointerException("The parameter 'tableName' must not be null");
111 }
112 if (connection == null) {
113 throw new NullPointerException("The parameter 'connection' must not be null");
114 }
115
116 _connection = connection;
117 _caseSensitiveMetaData = caseSensitiveMetaData;
118
119 try
120 {
121 Connection jdbcConnection = connection.getConnection();
122 if(!caseSensitiveMetaData)
123 {
124 _originalTableName = SQLHelper.correctCase(tableName, jdbcConnection);
125 SQLHelper.logDebugIfValueChanged(tableName, _originalTableName, "Corrected table name:", DatabaseTableMetaData.class);
126 }
127 else
128 {
129 _originalTableName = tableName;
130 }
131
132
133 _qualifiedTableNameSupport = new QualifiedTableName(_originalTableName, _connection.getSchema());
134
135 if(validate)
136 {
137 String schemaName = _qualifiedTableNameSupport.getSchema();
138 String plainTableName = _qualifiedTableNameSupport.getTable();
139 logger.debug("Validating if table '{}' exists in schema '{}' ...", plainTableName, schemaName);
140 try {
141 DatabaseConfig config = connection.getConfig();
142 IMetadataHandler metadataHandler = (IMetadataHandler) config.getProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER);
143 DatabaseMetaData databaseMetaData = jdbcConnection.getMetaData();
144 if(!metadataHandler.tableExists(databaseMetaData, schemaName, plainTableName))
145 {
146 throw new NoSuchTableException("Did not find table '" + plainTableName + "' in schema '" + schemaName + "'");
147 }
148 }
149 catch (SQLException e)
150 {
151 throw new DataSetException("Exception while validation existence of table '" + plainTableName + "'", e);
152 }
153 }
154 else
155 {
156 logger.debug("Validation switched off. Will not check if table exists.");
157 }
158 }
159 catch (SQLException e)
160 {
161 throw new DataSetException("Exception while retrieving JDBC connection from dbunit connection '" + connection + "'", e);
162 }
163
164 }
165
166
167
168
169
170
171
172
173
174
175 public static ITableMetaData createMetaData(String tableName,
176 ResultSet resultSet, IDataTypeFactory dataTypeFactory)
177 throws DataSetException, SQLException
178 {
179 if (logger.isDebugEnabled())
180 {
181 logger.debug("createMetaData(tableName={}, resultSet={}, dataTypeFactory={}) - start",
182 new Object[]{ tableName, resultSet, dataTypeFactory });
183 }
184
185 return new ResultSetTableMetaData(tableName, resultSet, dataTypeFactory, false);
186 }
187
188
189
190
191
192
193
194
195
196
197
198
199 public static ITableMetaData createMetaData(String tableName,
200 ResultSet resultSet, IDatabaseConnection connection)
201 throws SQLException, DataSetException
202 {
203 if (logger.isDebugEnabled())
204 {
205 logger.debug("createMetaData(tableName={}, resultSet={}, connection={}) - start",
206 new Object[] { tableName, resultSet, connection });
207 }
208 return new ResultSetTableMetaData(tableName,resultSet,connection, false);
209 }
210
211 private String[] getPrimaryKeyNames() throws SQLException
212 {
213 logger.debug("getPrimaryKeyNames() - start");
214
215 String schemaName = _qualifiedTableNameSupport.getSchema();
216 String tableName = _qualifiedTableNameSupport.getTable();
217
218 Connection connection = _connection.getConnection();
219 DatabaseMetaData databaseMetaData = connection.getMetaData();
220
221 DatabaseConfig config = _connection.getConfig();
222 IMetadataHandler metadataHandler = (IMetadataHandler) config.getProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER);
223
224 ResultSet resultSet = metadataHandler.getPrimaryKeys(databaseMetaData, schemaName, tableName);
225
226 List list = new ArrayList();
227 try
228 {
229 while (resultSet.next())
230 {
231 String name = resultSet.getString(4);
232 int sequence = resultSet.getInt(5);
233 list.add(new PrimaryKeyData(name, sequence));
234 }
235 }
236 finally
237 {
238 resultSet.close();
239 }
240
241 Collections.sort(list);
242 String[] keys = new String[list.size()];
243 for (int i = 0; i < keys.length; i++)
244 {
245 PrimaryKeyData data = (PrimaryKeyData)list.get(i);
246 keys[i] = data.getName();
247 }
248
249 return keys;
250 }
251
252 private class PrimaryKeyData implements Comparable
253 {
254 private final String _name;
255 private final int _index;
256
257 public PrimaryKeyData(String name, int index)
258 {
259 _name = name;
260 _index = index;
261 }
262
263 public String getName()
264 {
265 logger.debug("getName() - start");
266
267 return _name;
268 }
269
270 public int getIndex()
271 {
272 return _index;
273 }
274
275
276
277
278 public int compareTo(Object o)
279 {
280 PrimaryKeyData data = (PrimaryKeyData)o;
281 return getIndex() - data.getIndex();
282 }
283 }
284
285
286
287
288 public String getTableName()
289 {
290
291
292
293
294
295
296 return this._originalTableName;
297 }
298
299 public Column[] getColumns() throws DataSetException
300 {
301 logger.debug("getColumns() - start");
302
303 if (_columns == null)
304 {
305 try
306 {
307
308 String schemaName = _qualifiedTableNameSupport.getSchema();
309 String tableName = _qualifiedTableNameSupport.getTable();
310
311 Connection jdbcConnection = _connection.getConnection();
312 DatabaseMetaData databaseMetaData = jdbcConnection.getMetaData();
313
314 DatabaseConfig config = _connection.getConfig();
315
316 IMetadataHandler metadataHandler = (IMetadataHandler)config.getProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER);
317 ResultSet resultSet = metadataHandler.getColumns(databaseMetaData, schemaName, tableName);
318
319 try
320 {
321 IDataTypeFactory dataTypeFactory = super.getDataTypeFactory(_connection);
322 boolean datatypeWarning = config.getFeature(
323 DatabaseConfig.FEATURE_DATATYPE_WARNING);
324
325 List columnList = new ArrayList();
326 while (resultSet.next())
327 {
328
329
330 boolean match = metadataHandler.matches(resultSet, schemaName, tableName, _caseSensitiveMetaData);
331 if(match)
332 {
333 Column column = SQLHelper.createColumn(resultSet, dataTypeFactory, datatypeWarning);
334 if(column != null)
335 {
336 columnList.add(column);
337 }
338 }
339 else
340 {
341 logger.debug("Skipping <schema.table> '" + resultSet.getString(2) + "." +
342 resultSet.getString(3) + "' because names do not exactly match.");
343 }
344 }
345
346 if (columnList.size() == 0)
347 {
348 logger.warn("No columns found for table '"+ tableName +"' that are supported by dbunit. " +
349 "Will return an empty column list");
350 }
351
352 _columns = (Column[])columnList.toArray(new Column[0]);
353 }
354 finally
355 {
356 resultSet.close();
357 }
358 }
359 catch (SQLException e)
360 {
361 throw new DataSetException(e);
362 }
363 }
364 return _columns;
365 }
366
367 private boolean primaryKeyFilterChanged(IColumnFilter keyFilter)
368 {
369 return (keyFilter != lastKeyFilter);
370 }
371
372 public Column[] getPrimaryKeys() throws DataSetException
373 {
374 logger.debug("getPrimaryKeys() - start");
375 DatabaseConfig config = _connection.getConfig();
376 IColumnFilter primaryKeysFilter = (IColumnFilter) config.getProperty(
377 DatabaseConfig.PROPERTY_PRIMARY_KEY_FILTER);
378
379 if (_primaryKeys == null || primaryKeyFilterChanged(primaryKeysFilter)) {
380 try {
381 lastKeyFilter = primaryKeysFilter;
382 if (primaryKeysFilter != null) {
383 _primaryKeys = Columns.getColumns(getTableName(), getColumns(),
384 primaryKeysFilter);
385 } else {
386 String[] pkNames = getPrimaryKeyNames();
387 _primaryKeys = Columns.getColumns(pkNames, getColumns());
388 }
389 }
390 catch (SQLException e)
391 {
392 throw new DataSetException(e);
393 }
394 }
395 return _primaryKeys;
396 }
397
398
399
400 public String toString()
401 {
402 try
403 {
404 String tableName = getTableName();
405 String columns = Arrays.asList(getColumns()).toString();
406 String primaryKeys = Arrays.asList(getPrimaryKeys()).toString();
407 return "table=" + tableName + ", cols=" + columns + ", pk=" + primaryKeys + "";
408 }
409 catch (DataSetException e)
410 {
411 return super.toString();
412 }
413 }
414 }