|
18 | 18 | package org.apache.seatunnel.connectors.seatunnel.cdc.mysql.utils;
|
19 | 19 |
|
20 | 20 | import org.apache.seatunnel.api.table.catalog.CatalogTable;
|
| 21 | +import org.apache.seatunnel.common.utils.SeaTunnelException; |
21 | 22 | import org.apache.seatunnel.connectors.cdc.base.utils.CatalogTableUtils;
|
22 | 23 | import org.apache.seatunnel.connectors.seatunnel.cdc.mysql.config.MySqlSourceConfig;
|
23 | 24 |
|
|
30 | 31 | import io.debezium.relational.history.TableChanges;
|
31 | 32 | import io.debezium.relational.history.TableChanges.TableChange;
|
32 | 33 | import io.debezium.schema.SchemaChangeEvent;
|
| 34 | +import lombok.extern.slf4j.Slf4j; |
33 | 35 |
|
34 | 36 | import java.sql.SQLException;
|
35 | 37 | import java.time.Instant;
|
36 | 38 | import java.util.HashMap;
|
37 | 39 | import java.util.List;
|
38 | 40 | import java.util.Map;
|
| 41 | +import java.util.concurrent.atomic.AtomicReference; |
39 | 42 |
|
40 | 43 | /** A component used to get schema by table path. */
|
| 44 | +@Slf4j |
41 | 45 | public class MySqlSchema {
|
42 | 46 | private static final String SHOW_CREATE_TABLE = "SHOW CREATE TABLE ";
|
43 | 47 | private static final String DESC_TABLE = "DESC ";
|
@@ -74,43 +78,84 @@ public TableChange getTableSchema(JdbcConnection jdbc, TableId tableId) {
|
74 | 78 | }
|
75 | 79 |
|
76 | 80 | private TableChange readTableSchema(JdbcConnection jdbc, TableId tableId) {
|
77 |
| - final Map<TableId, TableChange> tableChangeMap = new HashMap<>(); |
78 |
| - final String sql = SHOW_CREATE_TABLE + MySqlUtils.quote(tableId); |
| 81 | + Map<TableId, TableChange> tableChangeMap = new HashMap<>(); |
79 | 82 | try {
|
80 |
| - jdbc.query( |
81 |
| - sql, |
82 |
| - rs -> { |
83 |
| - if (rs.next()) { |
84 |
| - final String ddl = rs.getString(2); |
85 |
| - final MySqlOffsetContext offsetContext = |
86 |
| - MySqlOffsetContext.initial(connectorConfig); |
87 |
| - List<SchemaChangeEvent> schemaChangeEvents = |
88 |
| - databaseSchema.parseSnapshotDdl( |
89 |
| - ddl, tableId.catalog(), offsetContext, Instant.now()); |
90 |
| - for (SchemaChangeEvent schemaChangeEvent : schemaChangeEvents) { |
91 |
| - for (TableChange tableChange : |
92 |
| - schemaChangeEvent.getTableChanges()) { |
93 |
| - Table table = |
94 |
| - CatalogTableUtils.mergeCatalogTableConfig( |
95 |
| - tableChange.getTable(), tableMap.get(tableId)); |
96 |
| - TableChange newTableChange = |
97 |
| - new TableChange( |
98 |
| - TableChanges.TableChangeType.CREATE, table); |
99 |
| - tableChangeMap.put(tableId, newTableChange); |
100 |
| - } |
101 |
| - } |
102 |
| - } |
103 |
| - }); |
104 |
| - } catch (SQLException e) { |
105 |
| - throw new RuntimeException( |
106 |
| - String.format("Failed to read schema for table %s by running %s", tableId, sql), |
107 |
| - e); |
| 83 | + tableChangeMap = getTableSchemaByShowCreateTable(jdbc, tableId); |
| 84 | + if (tableChangeMap.isEmpty()) { |
| 85 | + log.debug("Load schema is empty for table {}", tableId); |
| 86 | + } |
| 87 | + } catch (Exception e) { |
| 88 | + log.debug("Ignore exception when execute `SHOW CREATE TABLE {}` failed", tableId, e); |
| 89 | + } |
| 90 | + if (tableChangeMap.isEmpty()) { |
| 91 | + try { |
| 92 | + log.info("Fallback to use `DESC {}` load schema", tableId); |
| 93 | + tableChangeMap = getTableSchemaByDescTable(jdbc, tableId); |
| 94 | + } catch (SQLException ex) { |
| 95 | + throw new SeaTunnelException( |
| 96 | + String.format("Failed to read schema for table %s", tableId), ex); |
| 97 | + } |
108 | 98 | }
|
109 | 99 | if (!tableChangeMap.containsKey(tableId)) {
|
110 |
| - throw new RuntimeException( |
111 |
| - String.format("Can't obtain schema for table %s by running %s", tableId, sql)); |
| 100 | + throw new RuntimeException(String.format("Can't obtain schema for table %s", tableId)); |
112 | 101 | }
|
113 | 102 |
|
114 | 103 | return tableChangeMap.get(tableId);
|
115 | 104 | }
|
| 105 | + |
| 106 | + private Map<TableId, TableChange> getTableSchemaByShowCreateTable( |
| 107 | + JdbcConnection jdbc, TableId tableId) throws SQLException { |
| 108 | + AtomicReference<String> ddl = new AtomicReference<>(); |
| 109 | + String sql = SHOW_CREATE_TABLE + MySqlUtils.quote(tableId); |
| 110 | + jdbc.query( |
| 111 | + sql, |
| 112 | + rs -> { |
| 113 | + rs.next(); |
| 114 | + ddl.set(rs.getString(2)); |
| 115 | + }); |
| 116 | + return parseSnapshotDdl(tableId, ddl.get()); |
| 117 | + } |
| 118 | + |
| 119 | + private Map<TableId, TableChange> getTableSchemaByDescTable( |
| 120 | + JdbcConnection jdbc, TableId tableId) throws SQLException { |
| 121 | + MySqlDdlBuilder ddlBuilder = new MySqlDdlBuilder(tableId); |
| 122 | + String sql = DESC_TABLE + MySqlUtils.quote(tableId); |
| 123 | + jdbc.query( |
| 124 | + sql, |
| 125 | + rs -> { |
| 126 | + while (rs.next()) { |
| 127 | + ddlBuilder.addColumn( |
| 128 | + MySqlDdlBuilder.Column.builder() |
| 129 | + .columnName(rs.getString("Field")) |
| 130 | + .columnType(rs.getString("Type")) |
| 131 | + .nullable(rs.getString("Null").equalsIgnoreCase("YES")) |
| 132 | + .primaryKey("PRI".equals(rs.getString("Key"))) |
| 133 | + .uniqueKey("UNI".equals(rs.getString("Key"))) |
| 134 | + .defaultValue(rs.getString("Default")) |
| 135 | + .extra(rs.getString("Extra")) |
| 136 | + .build()); |
| 137 | + } |
| 138 | + }); |
| 139 | + |
| 140 | + return parseSnapshotDdl(tableId, ddlBuilder.generateDdl()); |
| 141 | + } |
| 142 | + |
| 143 | + private Map<TableId, TableChange> parseSnapshotDdl(TableId tableId, String ddl) { |
| 144 | + Map<TableId, TableChange> tableChangeMap = new HashMap<>(); |
| 145 | + final MySqlOffsetContext offsetContext = MySqlOffsetContext.initial(connectorConfig); |
| 146 | + List<SchemaChangeEvent> schemaChangeEvents = |
| 147 | + databaseSchema.parseSnapshotDdl( |
| 148 | + ddl, tableId.catalog(), offsetContext, Instant.now()); |
| 149 | + for (SchemaChangeEvent schemaChangeEvent : schemaChangeEvents) { |
| 150 | + for (TableChange tableChange : schemaChangeEvent.getTableChanges()) { |
| 151 | + Table table = |
| 152 | + CatalogTableUtils.mergeCatalogTableConfig( |
| 153 | + tableChange.getTable(), tableMap.get(tableId)); |
| 154 | + TableChange newTableChange = |
| 155 | + new TableChange(TableChanges.TableChangeType.CREATE, table); |
| 156 | + tableChangeMap.put(tableId, newTableChange); |
| 157 | + } |
| 158 | + } |
| 159 | + return tableChangeMap; |
| 160 | + } |
116 | 161 | }
|
0 commit comments