diff --git a/src/main/java/org/duckdb/DuckDBAppender.java b/src/main/java/org/duckdb/DuckDBAppender.java index ac300563b..92448c2de 100644 --- a/src/main/java/org/duckdb/DuckDBAppender.java +++ b/src/main/java/org/duckdb/DuckDBAppender.java @@ -985,7 +985,13 @@ private Column nextColumn(Column curCol) { if (null == curCol.parent) { cols = columns; } else { - cols = curCol.parent.children; + if (DUCKDB_TYPE_UNION == curCol.parent.colType) { + curCol = curCol.parent; + // recurse up the union + return nextColumn(curCol); + } else { + cols = curCol.parent.children; + } } int nextColIdx = curCol.idx + 1; if (nextColIdx < cols.size()) { @@ -1004,11 +1010,7 @@ private Column nextColumn(Column curCol) { private void moveToNextColumn() throws SQLException { Column col = currentColumn(); this.prevColumn = currentColumn; - if (unionBegunInvariant()) { - this.currentColumn = nextColumn(col.parent); - } else { - this.currentColumn = nextColumn(col); - } + this.currentColumn = nextColumn(col); } // checks @@ -2127,11 +2129,6 @@ private boolean structCompletedInvariant() { prevColumn.idx == prevColumn.parent.children.size() - 1; } - private boolean unionBegunInvariant() { - return null != currentColumn && null != currentColumn.parent && - currentColumn.parent.colType == DUCKDB_TYPE_UNION; - } - private boolean unionCompletedInvariant() { return null != prevColumn && null != prevColumn.parent && prevColumn.parent.colType == DUCKDB_TYPE_UNION; } diff --git a/src/test/java/org/duckdb/TestAppenderComposite.java b/src/test/java/org/duckdb/TestAppenderComposite.java index d063e5f0c..ddcc1053c 100644 --- a/src/test/java/org/duckdb/TestAppenderComposite.java +++ b/src/test/java/org/duckdb/TestAppenderComposite.java @@ -480,6 +480,113 @@ public static void test_appender_union_nested() throws Exception { } } + public static void test_appender_union_struct() throws Exception { + try (DuckDBConnection conn = DriverManager.getConnection(JDBC_URL).unwrap(DuckDBConnection.class); + Statement stmt = conn.createStatement()) { + stmt.execute("CREATE TABLE tab1 (" + + "col1 INTEGER, " + + "col2 UNION(" + + " u1 STRUCT(" + + " s1 INTEGER, " + + " s2 INTEGER" + + " ), " + + " u2 INTEGER" + + " )" + + ")"); + + try (DuckDBAppender appender = conn.createAppender("tab1")) { + appender.beginRow() + .append(42) + .beginUnion("u1") + .beginStruct() + .append(43) + .append(44) + .endStruct() + .endUnion() + .endRow() + + .beginRow() + .append(45) + .beginUnion("u2") + .append(46) + .endUnion() + .endRow() + + .beginRow() + .append(47) + .beginUnion("u1") + .appendNull() + .endUnion() + .endRow() + + .beginRow() + .append(48) + .beginUnion("u2") + .appendNull() + .endUnion() + .endRow() + + .beginRow() + .append(49) + .appendNull() + .endRow() + + .beginRow() + .append(50) + .beginUnion("u1") + .beginStruct() + .append(51) + .append(52) + .endStruct() + .endUnion() + .endRow(); + } + + try (ResultSet rs = stmt.executeQuery("SELECT * FROM tab1 ORDER BY col1")) { + { + assertTrue(rs.next()); + assertEquals(rs.getInt(1), 42); + DuckDBStruct struct = (DuckDBStruct) rs.getObject(2); + Map map = struct.getMap(); + assertEquals(map.size(), 2); + assertEquals(map.get("s1"), 43); + assertEquals(map.get("s2"), 44); + } + + assertTrue(rs.next()); + assertEquals(rs.getInt(1), 45); + assertEquals(rs.getInt(2), 46); + + assertTrue(rs.next()); + assertEquals(rs.getInt(1), 47); + assertNull(rs.getObject(2)); + assertFalse(rs.wasNull()); + + assertTrue(rs.next()); + assertEquals(rs.getInt(1), 48); + assertNull(rs.getObject(2)); + assertFalse(rs.wasNull()); + + assertTrue(rs.next()); + assertEquals(rs.getInt(1), 49); + assertNull(rs.getObject(2)); + assertTrue(rs.wasNull()); + + { + assertTrue(rs.next()); + assertEquals(rs.getInt(1), 50); + DuckDBStruct struct = (DuckDBStruct) rs.getObject(2); + Map map = struct.getMap(); + assertEquals(map.size(), 2); + assertEquals(map.get("s1"), 51); + assertEquals(map.get("s2"), 52); + } + + assertFalse(rs.next()); + } + } + } + private static void assertFetchedStructEquals(Object dbs, Collection struct) throws Exception { DuckDBStruct dbStruct = (DuckDBStruct) dbs; Map map = dbStruct.getMap();