|
31 | 31 | import io.debezium.connector.mysql.MySqlConnectorConfig;
|
32 | 32 | import io.debezium.connector.mysql.MySqlDatabaseSchema;
|
33 | 33 | import io.debezium.connector.mysql.MySqlOffsetContext;
|
34 |
| -import io.debezium.connector.mysql.MySqlValueConverters; |
35 | 34 | import io.debezium.pipeline.EventDispatcher;
|
36 | 35 | import io.debezium.pipeline.source.AbstractSnapshotChangeEventSource;
|
37 | 36 | import io.debezium.pipeline.source.spi.ChangeEventSource;
|
38 | 37 | import io.debezium.pipeline.source.spi.SnapshotProgressListener;
|
39 | 38 | import io.debezium.pipeline.spi.ChangeRecordEmitter;
|
40 | 39 | import io.debezium.pipeline.spi.OffsetContext;
|
41 | 40 | import io.debezium.pipeline.spi.SnapshotResult;
|
42 |
| -import io.debezium.relational.Column; |
43 | 41 | import io.debezium.relational.RelationalSnapshotChangeEventSource;
|
44 | 42 | import io.debezium.relational.SnapshotChangeRecordEmitter;
|
45 | 43 | import io.debezium.relational.Table;
|
|
52 | 50 | import org.slf4j.Logger;
|
53 | 51 | import org.slf4j.LoggerFactory;
|
54 | 52 |
|
55 |
| -import java.io.UnsupportedEncodingException; |
56 |
| -import java.sql.Blob; |
57 | 53 | import java.sql.PreparedStatement;
|
58 | 54 | import java.sql.ResultSet;
|
| 55 | +import java.sql.ResultSetMetaData; |
59 | 56 | import java.sql.SQLException;
|
60 | 57 | import java.sql.Types;
|
61 | 58 | import java.time.Duration;
|
62 |
| -import java.util.Calendar; |
63 | 59 |
|
64 | 60 | public class MySqlSnapshotSplitReadTask extends AbstractSnapshotChangeEventSource {
|
65 | 61 |
|
@@ -146,7 +142,7 @@ protected SnapshotResult doExecute(
|
146 | 142 | "Snapshot step 3 - Determining high watermark {} for split {}",
|
147 | 143 | highWatermark,
|
148 | 144 | snapshotSplit);
|
149 |
| - ((SnapshotSplitChangeEventSourceContext) context).setHighWatermark(lowWatermark); |
| 145 | + ((SnapshotSplitChangeEventSourceContext) context).setHighWatermark(highWatermark); |
150 | 146 | dispatcher.dispatchWatermarkEvent(
|
151 | 147 | offsetContext.getPartition(), snapshotSplit, highWatermark, WatermarkKind.HIGH);
|
152 | 148 | return SnapshotResult.completed(ctx.offset);
|
@@ -220,9 +216,8 @@ private void createDataEventsForTable(
|
220 | 216 | rows++;
|
221 | 217 | final Object[] row = new Object[columnArray.getGreatestColumnPosition()];
|
222 | 218 | for (int i = 0; i < columnArray.getColumns().length; i++) {
|
223 |
| - Column actualColumn = table.columns().get(i); |
224 | 219 | row[columnArray.getColumns()[i].position() - 1] =
|
225 |
| - readField(rs, i + 1, actualColumn, table); |
| 220 | + readField(rs, i + 1); |
226 | 221 | }
|
227 | 222 | if (logTimer.expired()) {
|
228 | 223 | long stop = clock.currentTimeInMillis();
|
@@ -259,108 +254,15 @@ private Threads.Timer getTableScanLogTimer() {
|
259 | 254 | return Threads.timer(clock, LOG_INTERVAL);
|
260 | 255 | }
|
261 | 256 |
|
262 |
| - /** |
263 |
| - * Read JDBC return value and deal special type like time, timestamp. |
264 |
| - * |
265 |
| - * <p>Note https://issues.redhat.com/browse/DBZ-3238 has fixed this issue, please remove |
266 |
| - * this method once we bump Debezium version to 1.6 |
267 |
| - */ |
268 |
| - private Object readField(ResultSet rs, int fieldNo, Column actualColumn, Table actualTable) |
| 257 | + private Object readField( |
| 258 | + ResultSet rs, int columnIndex) |
269 | 259 | throws SQLException {
|
270 |
| - if (actualColumn.jdbcType() == Types.TIME) { |
271 |
| - return readTimeField(rs, fieldNo); |
272 |
| - } else if (actualColumn.jdbcType() == Types.DATE) { |
273 |
| - return readDateField(rs, fieldNo, actualColumn, actualTable); |
274 |
| - } |
275 |
| - // This is for DATETIME columns (a logical date + time without time zone) |
276 |
| - // by reading them with a calendar based on the default time zone, we make sure that the |
277 |
| - // value |
278 |
| - // is constructed correctly using the database's (or connection's) time zone |
279 |
| - else if (actualColumn.jdbcType() == Types.TIMESTAMP) { |
280 |
| - return readTimestampField(rs, fieldNo, actualColumn, actualTable); |
281 |
| - } |
282 |
| - // JDBC's rs.GetObject() will return a Boolean for all TINYINT(1) columns. |
283 |
| - // TINYINT columns are reprtoed as SMALLINT by JDBC driver |
284 |
| - else if (actualColumn.jdbcType() == Types.TINYINT |
285 |
| - || actualColumn.jdbcType() == Types.SMALLINT) { |
286 |
| - // It seems that rs.wasNull() returns false when default value is set and NULL is |
287 |
| - // inserted |
288 |
| - // We thus need to use getObject() to identify if the value was provided and if yes |
289 |
| - // then |
290 |
| - // read it again to get correct scale |
291 |
| - return rs.getObject(fieldNo) == null ? null : rs.getInt(fieldNo); |
292 |
| - } |
293 |
| - // DBZ-2673 |
294 |
| - // It is necessary to check the type names as types like ENUM and SET are |
295 |
| - // also reported as JDBC type char |
296 |
| - else if ("CHAR".equals(actualColumn.typeName()) |
297 |
| - || "VARCHAR".equals(actualColumn.typeName()) |
298 |
| - || "TEXT".equals(actualColumn.typeName())) { |
299 |
| - return rs.getBytes(fieldNo); |
| 260 | + final ResultSetMetaData metaData = rs.getMetaData(); |
| 261 | + final int columnType = metaData.getColumnType(columnIndex); |
| 262 | + if (columnType == Types.TIME) { |
| 263 | + return rs.getTimestamp(columnIndex); |
300 | 264 | } else {
|
301 |
| - return rs.getObject(fieldNo); |
302 |
| - } |
303 |
| - } |
304 |
| - |
305 |
| - /** |
306 |
| - * As MySQL connector/J implementation is broken for MySQL type "TIME" we have to use a |
307 |
| - * binary-ish workaround. https://issues.jboss.org/browse/DBZ-342 |
308 |
| - */ |
309 |
| - private Object readTimeField(ResultSet rs, int fieldNo) throws SQLException { |
310 |
| - Blob b = rs.getBlob(fieldNo); |
311 |
| - if (b == null) { |
312 |
| - return null; // Don't continue parsing time field if it is null |
313 |
| - } |
314 |
| - |
315 |
| - try { |
316 |
| - return MySqlValueConverters.stringToDuration( |
317 |
| - new String(b.getBytes(1, (int) (b.length())), "UTF-8")); |
318 |
| - } catch (UnsupportedEncodingException e) { |
319 |
| - LOG.error("Could not read MySQL TIME value as UTF-8"); |
320 |
| - throw new RuntimeException(e); |
321 |
| - } |
322 |
| - } |
323 |
| - |
324 |
| - /** |
325 |
| - * In non-string mode the date field can contain zero in any of the date part which we need |
326 |
| - * to handle as all-zero. |
327 |
| - */ |
328 |
| - private Object readDateField(ResultSet rs, int fieldNo, Column column, Table table) |
329 |
| - throws SQLException { |
330 |
| - Blob b = rs.getBlob(fieldNo); |
331 |
| - if (b == null) { |
332 |
| - return null; // Don't continue parsing date field if it is null |
333 |
| - } |
334 |
| - |
335 |
| - try { |
336 |
| - return MySqlValueConverters.stringToLocalDate( |
337 |
| - new String(b.getBytes(1, (int) (b.length())), "UTF-8"), column, table); |
338 |
| - } catch (UnsupportedEncodingException e) { |
339 |
| - LOG.error("Could not read MySQL TIME value as UTF-8"); |
340 |
| - throw new RuntimeException(e); |
341 |
| - } |
342 |
| - } |
343 |
| - |
344 |
| - /** |
345 |
| - * In non-string mode the time field can contain zero in any of the date part which we need |
346 |
| - * to handle as all-zero. |
347 |
| - */ |
348 |
| - private Object readTimestampField(ResultSet rs, int fieldNo, Column column, Table table) |
349 |
| - throws SQLException { |
350 |
| - Blob b = rs.getBlob(fieldNo); |
351 |
| - if (b == null) { |
352 |
| - return null; // Don't continue parsing timestamp field if it is null |
353 |
| - } |
354 |
| - |
355 |
| - try { |
356 |
| - return MySqlValueConverters.containsZeroValuesInDatePart( |
357 |
| - new String(b.getBytes(1, (int) (b.length())), "UTF-8"), |
358 |
| - column, |
359 |
| - table) ? null |
360 |
| - : rs.getTimestamp(fieldNo, Calendar.getInstance()); |
361 |
| - } catch (UnsupportedEncodingException e) { |
362 |
| - LOG.error("Could not read MySQL TIME value as UTF-8"); |
363 |
| - throw new RuntimeException(e); |
| 265 | + return rs.getObject(columnIndex); |
364 | 266 | }
|
365 | 267 | }
|
366 | 268 |
|
|
0 commit comments