76
76
import org .slf4j .Logger ;
77
77
import org .slf4j .LoggerFactory ;
78
78
79
+ import javax .swing .RowFilter .Entry ;
80
+
79
81
import java .sql .Array ;
80
82
import java .sql .Connection ;
81
83
import java .sql .PreparedStatement ;
82
84
import java .sql .ResultSet ;
85
+ import java .sql .ResultSetMetaData ;
86
+ import java .sql .SQLDataException ;
83
87
import java .sql .SQLException ;
88
+ import java .sql .Struct ;
89
+ import java .sql .Timestamp ;
84
90
import java .util .ArrayList ;
85
91
import java .util .Arrays ;
92
+ import java .util .HashMap ;
86
93
import java .util .List ;
87
94
import java .util .Map ;
88
95
import java .util .concurrent .TimeUnit ;
@@ -135,14 +142,21 @@ protected JdbcCredentialProvider getCredentialProvider()
135
142
return null ;
136
143
}
137
144
145
+ protected java .util .Optional <Boolean > getAutoCommit ()
146
+ {
147
+ return java .util .Optional .of (false );
148
+ }
149
+
138
150
@ Override
139
151
public void readWithConstraint (BlockSpiller blockSpiller , ReadRecordsRequest readRecordsRequest , QueryStatusChecker queryStatusChecker )
140
152
throws Exception
141
153
{
142
- LOGGER .info ("{}: Catalog: {}, table {}, splits {}" , readRecordsRequest .getQueryId (), readRecordsRequest .getCatalogName (), readRecordsRequest .getTableName (),
154
+ LOGGER .info ("Read Record Request {}: Catalog: {}, table {}, splits {}" , readRecordsRequest .getQueryId (), readRecordsRequest .getCatalogName (), readRecordsRequest .getTableName (),
143
155
readRecordsRequest .getSplit ().getProperties ());
144
156
try (Connection connection = this .jdbcConnectionFactory .getConnection (getCredentialProvider ())) {
145
- connection .setAutoCommit (false ); // For consistency. This is needed to be false to enable streaming for some database types.
157
+ if (this .getAutoCommit ().isPresent ()) {
158
+ connection .setAutoCommit (this .getAutoCommit ().get ()); // For consistency. This is needed to be false to enable streaming for some database types.
159
+ }
146
160
try (PreparedStatement preparedStatement = buildSplitSql (connection , readRecordsRequest .getCatalogName (), readRecordsRequest .getTableName (),
147
161
readRecordsRequest .getSchema (), readRecordsRequest .getConstraints (), readRecordsRequest .getSplit ());
148
162
ResultSet resultSet = preparedStatement .executeQuery ()) {
@@ -153,6 +167,9 @@ public void readWithConstraint(BlockSpiller blockSpiller, ReadRecordsRequest rea
153
167
if (next .getType () instanceof ArrowType .List ) {
154
168
rowWriterBuilder .withFieldWriterFactory (next .getName (), makeFactory (next ));
155
169
}
170
+ else if (next .getType () instanceof ArrowType .Struct ) {
171
+ rowWriterBuilder .withFieldWriterFactory (next .getName (), makeStructFactory (next ));
172
+ }
156
173
else {
157
174
rowWriterBuilder .withExtractor (next .getName (), makeExtractor (next , resultSet , partitionValues ));
158
175
}
@@ -168,8 +185,9 @@ public void readWithConstraint(BlockSpiller blockSpiller, ReadRecordsRequest rea
168
185
rowsReturnedFromDatabase ++;
169
186
}
170
187
LOGGER .info ("{} rows returned by database." , rowsReturnedFromDatabase );
171
-
172
- connection .commit ();
188
+ if (this .getAutoCommit ().isPresent ()) {
189
+ connection .commit ();
190
+ }
173
191
}
174
192
}
175
193
}
@@ -193,6 +211,54 @@ protected FieldWriterFactory makeFactory(Field field)
193
211
};
194
212
}
195
213
214
+ public static void printResultSet (ResultSet rs ) throws SQLException
215
+ {
216
+ LOGGER .info ("Printing Record Handler Result Set:" );
217
+ ResultSetMetaData rsmd = rs .getMetaData ();
218
+ int columns = rsmd .getColumnCount ();
219
+
220
+ // Print the column names
221
+ String columnNames = "" ;
222
+ for (int i = 1 ; i <= columns ; i ++) {
223
+ columnNames += rsmd .getColumnName (i ) + ", " ;
224
+ }
225
+ LOGGER .info (columnNames );
226
+
227
+ // Print the column values
228
+ while (rs .next ()) {
229
+ String newColumn = "" ;
230
+ for (int i = 1 ; i <= columns ; i ++) {
231
+ newColumn += rs .getObject (i ) + ", " ;
232
+ }
233
+ LOGGER .info (newColumn );
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Create a field extractor for complex Nested type.
239
+ * @param field Field's metadata information.
240
+ * @return Extractor for the List type.
241
+ */
242
+ protected FieldWriterFactory makeStructFactory (Field field )
243
+ {
244
+ return (FieldVector vector , Extractor extractor , ConstraintProjector constraint ) ->
245
+ (FieldWriter ) (Object context , int rowNum ) ->
246
+ {
247
+ Object nestedObj = ((ResultSet ) context ).getObject (field .getName ());
248
+ if (!((ResultSet ) context ).wasNull () && nestedObj instanceof Struct ) {
249
+ Map <String , Object > renestedMap = new HashMap <>();
250
+ for (Object obj : ((Struct ) nestedObj ).getAttributes ()) {
251
+ Map .Entry <?, ?> entry = (Map .Entry <?, ?>) obj ;
252
+ String key = entry .getKey ().toString ();
253
+ Object value = entry .getValue ();
254
+ renestedMap .put (key , value );
255
+ }
256
+ BlockUtils .setComplexValue (vector , rowNum , FieldResolver .DEFAULT , renestedMap );
257
+ }
258
+ return true ;
259
+ };
260
+ }
261
+
196
262
/**
197
263
* Creates an Extractor for the given field. In this example the extractor just creates some random data.
198
264
*/
@@ -278,8 +344,17 @@ protected Extractor makeExtractor(Field field, ResultSet resultSet, Map<String,
278
344
case DATEMILLI :
279
345
return (DateMilliExtractor ) (Object context , NullableDateMilliHolder dst ) ->
280
346
{
281
- if (resultSet .getTimestamp (fieldName ) != null ) {
282
- dst .value = resultSet .getTimestamp (fieldName ).getTime ();
347
+ //try catch needed for OpenSearch type date which actually is returned as timestamp
348
+ try {
349
+ if (resultSet .getTimestamp (fieldName ) != null ) {
350
+ dst .value = resultSet .getTimestamp (fieldName ).getTime ();
351
+ }
352
+ }
353
+ catch (SQLDataException e ) {
354
+ //OpenSearch returns it as type String
355
+ if (resultSet .getString (fieldName ) != null ) {
356
+ dst .value = Timestamp .valueOf (resultSet .getString (fieldName )).getTime ();
357
+ }
283
358
}
284
359
dst .isSet = resultSet .wasNull () ? 0 : 1 ;
285
360
};
0 commit comments