diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightStatement.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightStatement.java index 577aee3b4..ff3d060c5 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightStatement.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowFlightStatement.java @@ -52,6 +52,7 @@ public FlightInfo executeFlightInfoQuery() throws SQLException { } final Schema resultSetSchema = preparedStatement.getDataSetSchema(); + signature.columns.clear(); signature.columns.addAll( ConvertUtils.convertArrowFieldsToColumnMetaDataList(resultSetSchema.getFields())); setSignature(signature); diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ResultSetMetadataTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ResultSetMetadataTest.java index 4583194f5..700011310 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ResultSetMetadataTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ResultSetMetadataTest.java @@ -220,4 +220,23 @@ public void testShouldIsSearchable() throws SQLException { public void testShouldGetColumnTypesFromOutOfBoundIndex() { assertThrows(IndexOutOfBoundsException.class, () -> metadata.getColumnType(4)); } + + /** + * Regression test for issue #44: + * {@code ArrowFlightStatement#executeFlightInfoQuery} appends schema columns to the reused {@code + * Meta.Signature} without clearing the existing list. When the result has at least one endpoint, + * the {@code FlightStream} consumption path overwrites {@code signature.columns} from the actual + * stream schema and hides the duplication. With an empty endpoint list — the scenario reported + * against both Rust- and Denodo-based Flight SQL servers — that overwrite never runs and {@code + * ResultSetMetaData#getColumnCount()} reports double the schema width. + */ + @Test + public void testShouldNotDuplicateColumnsWhenFlightInfoHasNoEndpoints() throws SQLException { + try (Connection conn = FLIGHT_SERVER_TEST_EXTENSION.getConnection(false); + Statement st = conn.createStatement(); + ResultSet rs = + st.executeQuery(CoreMockedSqlProducers.LEGACY_REGULAR_NO_ENDPOINTS_SQL_CMD)) { + assertThat(rs.getMetaData().getColumnCount(), equalTo(1)); + } + } } diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/CoreMockedSqlProducers.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/CoreMockedSqlProducers.java index 7c1775569..9c5d972b1 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/CoreMockedSqlProducers.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/CoreMockedSqlProducers.java @@ -67,6 +67,8 @@ public final class CoreMockedSqlProducers { public static final String LEGACY_METADATA_SQL_CMD = "SELECT * FROM METADATA"; public static final String LEGACY_CANCELLATION_SQL_CMD = "SELECT * FROM TAKES_FOREVER"; public static final String LEGACY_REGULAR_WITH_EMPTY_SQL_CMD = "SELECT * FROM TEST_EMPTIES"; + public static final String LEGACY_REGULAR_NO_ENDPOINTS_SQL_CMD = + "SELECT * FROM TEST_NO_ENDPOINTS"; public static final String UUID_SQL_CMD = "SELECT * FROM UUID_TABLE"; public static final String UUID_PREPARED_SELECT_SQL_CMD = @@ -100,12 +102,22 @@ public static MockFlightSqlProducer getLegacyProducer() { addLegacyMetadataSqlCmdSupport(producer); addLegacyCancellationSqlCmdSupport(producer); addQueryWithEmbeddedEmptyRoot(producer); + addQueryWithNoEndpoints(producer); addUuidSqlCmdSupport(producer); addUuidPreparedSelectSqlCmdSupport(producer); addUuidPreparedUpdateSqlCmdSupport(producer); return producer; } + private static void addQueryWithNoEndpoints(final MockFlightSqlProducer producer) { + final Schema querySchema = + new Schema( + ImmutableList.of( + new Field("ID", new FieldType(true, new ArrowType.Int(64, true), null), null))); + producer.addSelectQuery( + LEGACY_REGULAR_NO_ENDPOINTS_SQL_CMD, querySchema, Collections.emptyList()); + } + /** * Gets a {@link MockFlightSqlProducer} configured with UUID test data. *