4
4
5
5
package io .airbyte .integrations .destination .mysql ;
6
6
7
+ import static io .airbyte .cdk .integrations .base .JavaBaseConstants .COLUMN_NAME_AB_EXTRACTED_AT ;
8
+ import static io .airbyte .cdk .integrations .base .JavaBaseConstants .COLUMN_NAME_AB_LOADED_AT ;
9
+ import static io .airbyte .cdk .integrations .base .JavaBaseConstants .COLUMN_NAME_AB_META ;
10
+ import static io .airbyte .cdk .integrations .base .JavaBaseConstants .COLUMN_NAME_AB_RAW_ID ;
11
+ import static io .airbyte .cdk .integrations .base .JavaBaseConstants .COLUMN_NAME_DATA ;
12
+
7
13
import edu .umd .cs .findbugs .annotations .SuppressFBWarnings ;
8
14
import io .airbyte .cdk .db .jdbc .JdbcDatabase ;
9
15
import io .airbyte .cdk .integrations .base .JavaBaseConstants ;
15
21
import java .sql .SQLException ;
16
22
import java .sql .Statement ;
17
23
import java .util .List ;
24
+ import java .util .stream .Collectors ;
25
+ import java .util .stream .IntStream ;
18
26
19
27
@ SuppressFBWarnings (
20
28
value = {"SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE" },
@@ -34,47 +42,85 @@ public void insertRecordsInternal(final JdbcDatabase database,
34
42
final String schemaName ,
35
43
final String tmpTableName )
36
44
throws SQLException {
45
+ throw new UnsupportedOperationException ("Mysql requires V2" );
46
+ }
47
+
48
+ @ Override
49
+ protected void insertRecordsInternalV2 (final JdbcDatabase database ,
50
+ final List <PartialAirbyteMessage > records ,
51
+ final String schemaName ,
52
+ final String tableName )
53
+ throws Exception {
37
54
if (records .isEmpty ()) {
38
55
return ;
39
56
}
40
57
41
58
verifyLocalFileEnabled (database );
42
59
try {
43
- final File tmpFile = Files .createTempFile (tmpTableName + "-" , ".tmp" ).toFile ();
44
-
45
- loadDataIntoTable (database , records , schemaName , tmpTableName , tmpFile );
46
-
60
+ final File tmpFile = Files .createTempFile (tableName + "-" , ".tmp" ).toFile ();
61
+
62
+ loadDataIntoTable (
63
+ database ,
64
+ records ,
65
+ schemaName ,
66
+ tableName ,
67
+ tmpFile ,
68
+ COLUMN_NAME_AB_RAW_ID ,
69
+ COLUMN_NAME_DATA ,
70
+ COLUMN_NAME_AB_EXTRACTED_AT ,
71
+ COLUMN_NAME_AB_LOADED_AT ,
72
+ COLUMN_NAME_AB_META );
47
73
Files .delete (tmpFile .toPath ());
48
74
} catch (final IOException e ) {
49
75
throw new SQLException (e );
50
76
}
51
77
}
52
78
53
- @ Override
54
- protected void insertRecordsInternalV2 (final JdbcDatabase database ,
55
- final List <PartialAirbyteMessage > records ,
56
- final String schemaName ,
57
- final String tableName )
58
- throws Exception {
59
- throw new UnsupportedOperationException ("mysql does not yet support DV2" );
60
- }
61
-
62
79
private void loadDataIntoTable (final JdbcDatabase database ,
63
80
final List <PartialAirbyteMessage > records ,
64
81
final String schemaName ,
65
82
final String tmpTableName ,
66
- final File tmpFile )
83
+ final File tmpFile ,
84
+ final String ... columnNames )
67
85
throws SQLException {
68
86
database .execute (connection -> {
69
87
try {
70
88
writeBatchToFile (tmpFile , records );
71
89
72
90
final String absoluteFile = "'" + tmpFile .getAbsolutePath () + "'" ;
73
91
74
- final String query = String .format (
75
- "LOAD DATA LOCAL INFILE %s INTO TABLE %s.%s FIELDS TERMINATED BY ',' ENCLOSED BY '\" ' ESCAPED BY '\\ \" ' LINES TERMINATED BY '\\ r\\ n'" ,
76
- absoluteFile , schemaName , tmpTableName );
92
+ /*
93
+ * We want to generate a query like:
94
+ *
95
+ * LOAD DATA LOCAL INFILE '/a/b/c' INTO TABLE foo.bar FIELDS TERMINATED BY ',' ENCLOSED BY
96
+ * '"' ESCAPED BY '\"' LINES TERMINATED BY '\r\n' (@c0, @c1, @c2, @c3, @c4) SET _airybte_raw_id =
97
+ * NULLIF(@c0, ''), _airbyte_data = NULLIF(@c1, ''), _airbyte_extracted_at = NULLIF(@c2, ''),
98
+ * _airbyte_loaded_at = NULLIF(@c3, ''), _airbyte_meta = NULLIF(@c4, '')
99
+ *
100
+ * This is to avoid weird default values (e.g. 0000-00-00 00:00:00) when the value should be NULL.
101
+ */
102
+
103
+ final String colVarDecls = "("
104
+ + IntStream .range (0 , columnNames .length ).mapToObj (i -> "@c" + i ).collect (Collectors .joining ("," ))
105
+ + ")" ;
106
+ final String colAssignments = IntStream .range (0 , columnNames .length )
107
+ .mapToObj (i -> columnNames [i ] + " = NULLIF(@c" + i + ", '')" )
108
+ .collect (Collectors .joining ("," ));
77
109
110
+ final String query = String .format (
111
+ """
112
+ LOAD DATA LOCAL INFILE %s INTO TABLE %s.%s
113
+ FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '\\ "'
114
+ LINES TERMINATED BY '\\ r\\ n'
115
+ %s
116
+ SET
117
+ %s
118
+ """ ,
119
+ absoluteFile ,
120
+ schemaName ,
121
+ tmpTableName ,
122
+ colVarDecls ,
123
+ colAssignments );
78
124
try (final Statement stmt = connection .createStatement ()) {
79
125
stmt .execute (query );
80
126
}
@@ -129,16 +175,31 @@ private boolean checkIfLocalFileIsEnabled(final JdbcDatabase database) throws SQ
129
175
}
130
176
131
177
@ Override
132
- public String createTableQuery (final JdbcDatabase database , final String schemaName , final String tableName ) {
178
+ protected String createTableQueryV1 (String schemaName , String tableName ) {
179
+ throw new UnsupportedOperationException ("Mysql requires V2" );
180
+ }
181
+
182
+ @ Override
183
+ protected String createTableQueryV2 (String schemaName , String tableName ) {
133
184
// MySQL requires byte information with VARCHAR. Since we are using uuid as value for the column,
134
185
// 256 is enough
135
186
return String .format (
136
- "CREATE TABLE IF NOT EXISTS %s.%s ( \n "
137
- + "%s VARCHAR(256) PRIMARY KEY,\n "
138
- + "%s JSON,\n "
139
- + "%s TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6)\n "
140
- + ");\n " ,
141
- schemaName , tableName , JavaBaseConstants .COLUMN_NAME_AB_ID , JavaBaseConstants .COLUMN_NAME_DATA , JavaBaseConstants .COLUMN_NAME_EMITTED_AT );
187
+ """
188
+ CREATE TABLE IF NOT EXISTS %s.%s (\s
189
+ %s VARCHAR(256) PRIMARY KEY,
190
+ %s JSON,
191
+ %s TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6),
192
+ %s TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6),
193
+ %s JSON
194
+ );
195
+ """ ,
196
+ schemaName ,
197
+ tableName ,
198
+ JavaBaseConstants .COLUMN_NAME_AB_RAW_ID ,
199
+ JavaBaseConstants .COLUMN_NAME_DATA ,
200
+ JavaBaseConstants .COLUMN_NAME_AB_EXTRACTED_AT ,
201
+ JavaBaseConstants .COLUMN_NAME_AB_LOADED_AT ,
202
+ JavaBaseConstants .COLUMN_NAME_AB_META );
142
203
}
143
204
144
205
public static class VersionCompatibility {
0 commit comments