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.operation;
23
24 import java.sql.SQLException;
25 import java.util.BitSet;
26
27 import org.dbunit.DatabaseUnitException;
28 import org.dbunit.database.DatabaseConfig;
29 import org.dbunit.database.IDatabaseConnection;
30 import org.dbunit.database.statement.IPreparedBatchStatement;
31 import org.dbunit.database.statement.IStatementFactory;
32 import org.dbunit.dataset.Column;
33 import org.dbunit.dataset.DataSetException;
34 import org.dbunit.dataset.IDataSet;
35 import org.dbunit.dataset.ITable;
36 import org.dbunit.dataset.ITableIterator;
37 import org.dbunit.dataset.ITableMetaData;
38 import org.dbunit.dataset.RowOutOfBoundsException;
39 import org.dbunit.dataset.datatype.DataType;
40 import org.dbunit.dataset.datatype.TypeCastException;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44
45
46
47
48
49
50
51 public abstract class AbstractBatchOperation extends AbstractOperation
52 {
53
54
55
56 private static final Logger logger =
57 LoggerFactory.getLogger(AbstractBatchOperation.class);
58
59 private static final BitSet EMPTY_BITSET = new BitSet();
60 protected boolean _reverseRowOrder = false;
61
62 static boolean isEmpty(ITable table) throws DataSetException
63 {
64 logger.debug("isEmpty(table={}) - start", table);
65
66 Column[] columns = table.getTableMetaData().getColumns();
67
68
69 if (columns.length == 0)
70 {
71 return true;
72 }
73
74
75 try
76 {
77 table.getValue(0, columns[0].getColumnName());
78 return false;
79 } catch (RowOutOfBoundsException e)
80 {
81
82 return true;
83 }
84 }
85
86
87
88
89
90 protected ITableIterator iterator(IDataSet dataSet)
91 throws DatabaseUnitException
92 {
93 return dataSet.iterator();
94 }
95
96
97
98
99
100 BitSet getIgnoreMapping(ITable table, int row) throws DataSetException
101 {
102 return EMPTY_BITSET;
103 }
104
105
106
107
108
109 boolean equalsIgnoreMapping(BitSet ignoreMapping, ITable table, int row)
110 throws DataSetException
111 {
112 return true;
113 }
114
115 abstract OperationData getOperationData(ITableMetaData metaData,
116 BitSet ignoreMapping, IDatabaseConnection connection)
117 throws DataSetException;
118
119
120
121
122 @Override
123 public void execute(IDatabaseConnection connection, IDataSet dataSet)
124 throws DatabaseUnitException, SQLException
125 {
126 logger.debug("execute(connection={}, dataSet={}) - start", connection,
127 dataSet);
128
129 DatabaseConfig databaseConfig = connection.getConfig();
130 IStatementFactory factory = (IStatementFactory) databaseConfig
131 .getProperty(DatabaseConfig.PROPERTY_STATEMENT_FACTORY);
132 boolean allowEmptyFields = connection.getConfig()
133 .getFeature(DatabaseConfig.FEATURE_ALLOW_EMPTY_FIELDS);
134
135
136 ITableIterator iterator = iterator(dataSet);
137 while (iterator.next())
138 {
139 ITable table = iterator.getTable();
140
141 String tableName = table.getTableMetaData().getTableName();
142 logger.trace("execute: processing table='{}'", tableName);
143
144
145 if (isEmpty(table))
146 {
147 continue;
148 }
149
150 ITableMetaData metaData =
151 getOperationMetaData(connection, table.getTableMetaData());
152 BitSet ignoreMapping = null;
153 OperationData operationData = null;
154 IPreparedBatchStatement statement = null;
155
156 try
157 {
158
159 int start = _reverseRowOrder ? table.getRowCount() - 1 : 0;
160 int increment = _reverseRowOrder ? -1 : 1;
161
162 try
163 {
164 for (int i = start;; i = i + increment)
165 {
166 int row = i;
167
168
169
170
171 if (ignoreMapping == null
172 || !equalsIgnoreMapping(ignoreMapping, table,
173 row))
174 {
175
176 if (statement != null)
177 {
178 statement.executeBatch();
179 statement.clearBatch();
180 statement.close();
181 }
182
183 ignoreMapping = getIgnoreMapping(table, row);
184 operationData = getOperationData(metaData,
185 ignoreMapping, connection);
186 statement = factory.createPreparedBatchStatement(
187 operationData.getSql(), connection);
188 }
189
190
191 Column[] columns = operationData.getColumns();
192 for (int j = 0; j < columns.length; j++)
193 {
194
195 if (!ignoreMapping.get(j))
196 {
197 Column column = columns[j];
198 String columnName = column.getColumnName();
199 try
200 {
201 DataType dataType = column.getDataType();
202 Object value =
203 table.getValue(row, columnName);
204
205 if ("".equals(value) && !allowEmptyFields)
206 {
207 handleColumnHasNoValue(tableName,
208 columnName);
209 }
210
211 statement.addValue(value, dataType);
212 } catch (TypeCastException e)
213 {
214 final String msg =
215 "Error casting value for table '"
216 + tableName
217 + "' and column '"
218 + columnName + "'";
219 logger.error("execute: {}", msg);
220 throw new TypeCastException(msg, e);
221 }
222 }
223 }
224 statement.addBatch();
225 }
226 } catch (RowOutOfBoundsException e)
227 {
228
229
230
231
232 }
233
234 statement.executeBatch();
235 statement.clearBatch();
236 } catch (SQLException e)
237 {
238 final String msg =
239 "Exception processing table name='" + tableName + "'";
240 throw new DatabaseUnitException(msg, e);
241 } finally
242 {
243 if (statement != null)
244 {
245 statement.close();
246 }
247 }
248 }
249 }
250
251 protected void handleColumnHasNoValue(String tableName, String columnName)
252 {
253 final String tableColumnName = tableName + "." + columnName;
254 final String msg = "table.column=" + tableColumnName
255 + " value is empty but must contain a value"
256 + " (to disable this feature check,"
257 + " set DatabaseConfig.FEATURE_ALLOW_EMPTY_FIELDS to true)";
258 logger.error("execute: {}", msg);
259
260 throw new IllegalArgumentException(msg);
261 }
262
263 @Override
264 public String toString()
265 {
266 final StringBuilder sb = new StringBuilder();
267 sb.append(getClass().getName()).append("[");
268 sb.append("_reverseRowOrder=").append(this._reverseRowOrder);
269 sb.append(", super=").append(super.toString());
270 sb.append("]");
271 return sb.toString();
272 }
273 }