19
19
import com .dqops .connectors .SourceTableModel ;
20
20
import com .dqops .connectors .duckdb .fileslisting .AwsTablesLister ;
21
21
import com .dqops .connectors .duckdb .fileslisting .LocalSystemTablesLister ;
22
+ import com .dqops .connectors .duckdb .schema .DuckDBDataTypeParser ;
23
+ import com .dqops .connectors .duckdb .schema .DuckDBField ;
22
24
import com .dqops .connectors .jdbc .AbstractJdbcSourceConnection ;
23
25
import com .dqops .connectors .jdbc .JdbcConnectionPool ;
24
26
import com .dqops .connectors .jdbc .JdbcQueryFailedException ;
@@ -66,6 +68,7 @@ public class DuckdbSourceConnection extends AbstractJdbcSourceConnection {
66
68
private static final Object registerExtensionsLock = new Object ();
67
69
private static boolean extensionsRegistered = false ;
68
70
private final DqoDuckdbConfiguration dqoDuckdbConfiguration ;
71
+ private final DuckDBDataTypeParser dataTypeParser ;
69
72
private static final Object settingsExecutionLock = new Object ();
70
73
private static final boolean settingsConfigured = false ;
71
74
private static final String temporaryDirectoryPrefix = "dqops_duckdb_temp_" ;
@@ -77,16 +80,19 @@ public class DuckdbSourceConnection extends AbstractJdbcSourceConnection {
77
80
* @param secretValueProvider Secret value provider for the environment variable expansion.
78
81
* @param homeLocationFindService Home location find service.
79
82
* @param dqoDuckdbConfiguration Configuration settings for duckdb.
83
+ * @param dataTypeParser Data type parser that parses the schema of structures.
80
84
*/
81
85
@ Autowired
82
86
public DuckdbSourceConnection (JdbcConnectionPool jdbcConnectionPool ,
83
87
SecretValueProvider secretValueProvider ,
84
88
DuckdbConnectionProvider duckdbConnectionProvider ,
85
89
HomeLocationFindService homeLocationFindService ,
86
- DqoDuckdbConfiguration dqoDuckdbConfiguration ) {
90
+ DqoDuckdbConfiguration dqoDuckdbConfiguration ,
91
+ DuckDBDataTypeParser dataTypeParser ) {
87
92
super (jdbcConnectionPool , secretValueProvider , duckdbConnectionProvider );
88
93
this .homeLocationFindService = homeLocationFindService ;
89
94
this .dqoDuckdbConfiguration = dqoDuckdbConfiguration ;
95
+ this .dataTypeParser = dataTypeParser ;
90
96
}
91
97
92
98
/**
@@ -412,7 +418,16 @@ public List<TableSpec> retrieveTableMetadata(String schemaName,
412
418
String dataType = colRow .getString ("column_type" );
413
419
boolean isNullable = Objects .equals (colRow .getString ("null" ), "YES" );
414
420
ColumnSpec columnSpec = prepareNewColumnSpec (dataType , isNullable );
421
+ if (dataType != null && (dataType .startsWith ("STRUCT" ) || dataType .startsWith ("UNION" ) || dataType .startsWith ("MAP" ))) {
422
+ columnSpec .setTypeSnapshot (new ColumnTypeSnapshotSpec (dataType , isNullable ));
423
+ }
415
424
tableSpec .getColumns ().put (columnName , columnSpec );
425
+
426
+ DuckDBField parsedField = this .dataTypeParser .parseFieldType (dataType , columnName );
427
+ if (parsedField .isStruct ()) {
428
+ String parentColumnPrefix = parsedField .isArray () ? columnName + "[0]" : columnName ;
429
+ addNestedFieldsFromStructs (parentColumnPrefix , parsedField , tableSpec .getColumns ());
430
+ }
416
431
}
417
432
} catch (Exception e ){
418
433
if (!e .getMessage ().contains ("SQL query failed: java.sql.SQLException: IO Error: No files found that match the pattern" )){
@@ -424,6 +439,28 @@ public List<TableSpec> retrieveTableMetadata(String schemaName,
424
439
return tableSpecs ;
425
440
}
426
441
442
+ /**
443
+ * Traverses a structure of nested fields inside STRUCT data types and adds all nested fields.
444
+ * @param parentColumnName Parent column name used as a prefix to access nested fields.
445
+ * @param structField DuckDB field schema that as parsed - must be a STRUCT field.
446
+ * @param targetColumnsMap Target column map to add generated columns.
447
+ */
448
+ private void addNestedFieldsFromStructs (String parentColumnName , DuckDBField structField , ColumnSpecMap targetColumnsMap ) {
449
+ if (structField .isStruct () && structField .getNestedFields () != null ) {
450
+ for (DuckDBField childField : structField .getNestedFields ()) {
451
+ ColumnSpec columnSpec = prepareNewColumnSpec (childField .getTypeName (), childField .isNullable ());
452
+ columnSpec .getTypeSnapshot ().setNested (true );
453
+ String nestedFieldName = parentColumnName + "." + childField .getFieldName ();
454
+ targetColumnsMap .put (nestedFieldName , columnSpec );
455
+
456
+ if (childField .isStruct ()) {
457
+ String childColumnPrefix = childField .isArray () ? nestedFieldName + "[0]" : nestedFieldName ;
458
+ addNestedFieldsFromStructs (childColumnPrefix , childField , targetColumnsMap );
459
+ }
460
+ }
461
+ }
462
+ }
463
+
427
464
/**
428
465
* Creates a new column spec.
429
466
* @param dataType A data type of the column.
0 commit comments