1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.dbunit.dataset;
22
23 import java.sql.Connection;
24 import java.sql.DatabaseMetaData;
25 import java.sql.SQLException;
26 import java.util.Collection;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.Map;
30
31 import org.dbunit.DatabaseUnitRuntimeException;
32 import org.dbunit.database.DatabaseConfig;
33 import org.dbunit.database.IDatabaseConnection;
34 import org.dbunit.dataset.datatype.IDataTypeFactory;
35 import org.dbunit.dataset.datatype.IDbProductRelatable;
36 import org.dbunit.dataset.filter.IColumnFilter;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40
41
42
43
44
45
46 public abstract class AbstractTableMetaData implements ITableMetaData
47 {
48
49 private Map _columnsToIndexes;
50
51
52
53
54 private static final Logger logger = LoggerFactory.getLogger(AbstractTableMetaData.class);
55
56
57
58
59 public AbstractTableMetaData()
60 {
61 }
62
63
64
65
66
67
68
69 protected static Column[] getPrimaryKeys(Column[] columns, String[] keyNames)
70 {
71 logger.debug("getPrimaryKeys(columns={}, keyNames={}) - start", columns, keyNames);
72 return Columns.getColumns(keyNames, columns);
73 }
74
75
76
77
78
79
80
81
82 protected static Column[] getPrimaryKeys(String tableName, Column[] columns,
83 IColumnFilter columnFilter)
84 {
85 if (logger.isDebugEnabled())
86 {
87 logger.debug("getPrimaryKeys(tableName={}, columns={}, columnFilter={}) - start",
88 tableName, columns, columnFilter);
89 }
90 return Columns.getColumns(tableName, columns, columnFilter);
91 }
92
93
94
95
96
97
98
99 public int getColumnIndex(String columnName) throws DataSetException
100 {
101 logger.debug("getColumnIndex(columnName={}) - start", columnName);
102
103 if(this._columnsToIndexes == null)
104 {
105
106 this._columnsToIndexes = createColumnIndexesMap(this.getColumns());
107 }
108
109 String columnNameUpperCase = columnName.toUpperCase();
110 Integer colIndex = (Integer) this._columnsToIndexes.get(columnNameUpperCase);
111 if(colIndex != null)
112 {
113 return colIndex.intValue();
114 }
115 else
116 {
117 throw new NoSuchColumnException(this.getTableName(), columnNameUpperCase,
118 " (Non-uppercase input column: " + columnName + ") in ColumnNameToIndexes cache map. " +
119 "Note that the map's column names are NOT case sensitive.");
120 }
121 }
122
123
124
125
126
127 private Map createColumnIndexesMap(Column[] columns)
128 {
129 Map colsToIndexes = new HashMap(columns.length);
130 for (int i = 0; i < columns.length; i++)
131 {
132 colsToIndexes.put(columns[i].getColumnName().toUpperCase(), i);
133 }
134 return colsToIndexes;
135 }
136
137
138
139
140
141
142
143 public IDataTypeFactory getDataTypeFactory(IDatabaseConnection connection)
144 throws SQLException
145 {
146 DatabaseConfig config = connection.getConfig();
147 Object factoryObj = config.getProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY);
148 if(!IDataTypeFactory.class.isAssignableFrom(factoryObj.getClass())) {
149 String msg = "Invalid datatype factory configured. Class '" +
150 factoryObj.getClass() + "' does not implement '" + IDataTypeFactory.class + "'.";
151 if(factoryObj instanceof String){
152 msg += " Ensure not to specify the fully qualified class name as String but the concrete " +
153 "instance of the datatype factory (for example 'new OracleDataTypeFactory()').";
154 }
155
156 throw new DatabaseUnitRuntimeException(msg);
157 }
158 IDataTypeFactory dataTypeFactory = (IDataTypeFactory)factoryObj;
159
160
161 Connection jdbcConnection = connection.getConnection();
162 DatabaseMetaData metaData = jdbcConnection.getMetaData();
163 String validationMessage = validateDataTypeFactory(dataTypeFactory, metaData);
164 if(validationMessage!=null){
165
166 logger.warn("Potential problem found: " + validationMessage);
167 }
168
169 return dataTypeFactory;
170 }
171
172
173
174
175
176
177
178
179
180 String validateDataTypeFactory(IDataTypeFactory dataTypeFactory, DatabaseMetaData metaData)
181 throws SQLException
182 {
183 if (!(dataTypeFactory instanceof IDbProductRelatable))
184 {
185 return null;
186 }
187 IDbProductRelatable productRelatable = (IDbProductRelatable) dataTypeFactory;
188 String databaseProductName = metaData.getDatabaseProductName();
189
190 Collection validDbProductCollection = productRelatable.getValidDbProducts();
191 if (validDbProductCollection != null)
192 {
193 String lowerCaseDbProductName = databaseProductName.toLowerCase();
194 for (Iterator iterator = validDbProductCollection.iterator(); iterator.hasNext();) {
195 String validDbProduct = ((String) iterator.next()).toLowerCase();
196 if(lowerCaseDbProductName.indexOf(validDbProduct) > -1) {
197 logger.debug("The current database '{}' fits to the configured data type factory '{}'. Validation successful.",
198 databaseProductName, dataTypeFactory);
199 return null;
200 }
201 }
202 }
203
204
205 String validationMessage = "The configured data type factory '" + dataTypeFactory.getClass() +
206 "' might cause problems with the current database '" + databaseProductName +
207 "' (e.g. some datatypes may not be supported properly). " +
208 "In rare cases you might see this message because the list of supported database " +
209 "products is incomplete (list=" + validDbProductCollection + "). " +
210 "If so please request a java-class update via the forums." +
211 "If you are using your own IDataTypeFactory extending " +
212 "DefaultDataTypeFactory, ensure that you override getValidDbProducts() " +
213 "to specify the supported database products.";
214 return validationMessage;
215 }
216 }