Skip to content

Commit 8314c19

Browse files
GH-737: [FlightSQL] Allow returning column remarks in FlightSQL's CommandGetTables (#727)
Resolves #737 ## What's Changed This is an implementation of apache/arrow#46110 for Java
1 parent b9e37f0 commit 8314c19

File tree

7 files changed

+80
-12
lines changed

7 files changed

+80
-12
lines changed

arrow-format/FlightSql.proto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,7 @@ message CommandGetDbSchemas {
12121212
* - ARROW:FLIGHT:SQL:IS_CASE_SENSITIVE - "1" indicates if the column is case-sensitive, "0" otherwise.
12131213
* - ARROW:FLIGHT:SQL:IS_READ_ONLY - "1" indicates if the column is read only, "0" otherwise.
12141214
* - ARROW:FLIGHT:SQL:IS_SEARCHABLE - "1" indicates if the column is searchable via WHERE clause, "0" otherwise.
1215+
* - ARROW:FLIGHT:SQL:REMARKS - A comment describing the column.
12151216
* The returned data should be ordered by catalog_name, db_schema_name, table_name, then table_type, followed by table_schema if requested.
12161217
*/
12171218
message CommandGetTables {
@@ -1678,6 +1679,7 @@ message ActionEndSavepointRequest {
16781679
* - ARROW:FLIGHT:SQL:IS_CASE_SENSITIVE - "1" indicates if the column is case-sensitive, "0" otherwise.
16791680
* - ARROW:FLIGHT:SQL:IS_READ_ONLY - "1" indicates if the column is read only, "0" otherwise.
16801681
* - ARROW:FLIGHT:SQL:IS_SEARCHABLE - "1" indicates if the column is searchable via WHERE clause, "0" otherwise.
1682+
* - ARROW:FLIGHT:SQL:REMARKS - A comment describing the column.
16811683
* - GetFlightInfo: execute the query.
16821684
*/
16831685
message CommandStatementQuery {
@@ -1703,6 +1705,7 @@ message CommandStatementQuery {
17031705
* - ARROW:FLIGHT:SQL:IS_CASE_SENSITIVE - "1" indicates if the column is case-sensitive, "0" otherwise.
17041706
* - ARROW:FLIGHT:SQL:IS_READ_ONLY - "1" indicates if the column is read only, "0" otherwise.
17051707
* - ARROW:FLIGHT:SQL:IS_SEARCHABLE - "1" indicates if the column is searchable via WHERE clause, "0" otherwise.
1708+
* - ARROW:FLIGHT:SQL:REMARKS - A comment describing the column.
17061709
* - GetFlightInfo: execute the query.
17071710
* - DoPut: execute the query.
17081711
*/
@@ -1739,6 +1742,7 @@ message TicketStatementQuery {
17391742
* - ARROW:FLIGHT:SQL:IS_CASE_SENSITIVE - "1" indicates if the column is case-sensitive, "0" otherwise.
17401743
* - ARROW:FLIGHT:SQL:IS_READ_ONLY - "1" indicates if the column is read only, "0" otherwise.
17411744
* - ARROW:FLIGHT:SQL:IS_SEARCHABLE - "1" indicates if the column is searchable via WHERE clause, "0" otherwise.
1745+
* - ARROW:FLIGHT:SQL:REMARKS - A comment describing the column.
17421746
*
17431747
* If the schema is retrieved after parameter values have been bound with DoPut, then the server should account
17441748
* for the parameters when determining the schema.

flight/flight-integration-tests/src/main/java/org/apache/arrow/flight/integration/tests/FlightSqlScenarioProducer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ static Schema getQuerySchema() {
9898
.isSearchable(true)
9999
.catalogName("catalog_test")
100100
.precision(100)
101+
.remarks("test column")
101102
.build()
102103
.getMetadataMap()),
103104
null)));
@@ -126,6 +127,7 @@ static Schema getQueryWithTransactionSchema() {
126127
.isSearchable(true)
127128
.catalogName("catalog_test")
128129
.precision(100)
130+
.remarks("test column")
129131
.build()
130132
.getMetadataMap()),
131133
null)));

flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/ArrowDatabaseMetadata.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,7 @@ private int setGetColumnsVectorSchemaRootFromFields(
10661066
(VarCharVector) currentRoot.getVector("IS_AUTOINCREMENT");
10671067
final VarCharVector isGeneratedColumnVector =
10681068
(VarCharVector) currentRoot.getVector("IS_GENERATEDCOLUMN");
1069+
final VarCharVector remarksVector = (VarCharVector) currentRoot.getVector("REMARKS");
10691070

10701071
for (int i = 0; i < tableColumnsSize; i++, ordinalIndex++) {
10711072
final Field field = tableColumns.get(i);
@@ -1139,6 +1140,11 @@ private int setGetColumnsVectorSchemaRootFromFields(
11391140
isAutoincrementVector.setSafe(insertIndex, EMPTY_BYTE_ARRAY);
11401141
}
11411142

1143+
String remarks = columnMetadata.getRemarks();
1144+
if (remarks != null) {
1145+
remarksVector.setSafe(insertIndex, remarks.getBytes(CHARSET));
1146+
}
1147+
11421148
// Fields also don't hold information about IS_AUTOINCREMENT and IS_GENERATEDCOLUMN,
11431149
// so we're setting an empty string (as bytes), which means it couldn't be determined.
11441150
isGeneratedColumnVector.setSafe(insertIndex, EMPTY_BYTE_ARRAY);

flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/ConvertUtils.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ public static void setOnColumnMetaDataBuilder(
136136
if (searchable != null) {
137137
builder.setSearchable(searchable);
138138
}
139+
final String remarks = columnMetadata.getRemarks();
140+
if (remarks != null) {
141+
builder.setLabel(remarks);
142+
}
139143
}
140144

141145
/**

flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ArrowDatabaseMetadataTest.java

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import static java.util.stream.Collectors.toList;
2727
import static java.util.stream.IntStream.range;
2828
import static org.apache.arrow.driver.jdbc.utils.MockFlightSqlProducer.serializeSchema;
29-
import static org.apache.arrow.flight.sql.impl.FlightSql.CommandGetCrossReference;
3029
import static org.apache.arrow.flight.sql.impl.FlightSql.SqlSupportsConvert.SQL_CONVERT_BIGINT_VALUE;
3130
import static org.apache.arrow.flight.sql.impl.FlightSql.SqlSupportsConvert.SQL_CONVERT_BIT_VALUE;
3231
import static org.apache.arrow.flight.sql.impl.FlightSql.SqlSupportsConvert.SQL_CONVERT_INTEGER_VALUE;
@@ -55,9 +54,11 @@
5554
import org.apache.arrow.driver.jdbc.utils.ResultSetTestUtils;
5655
import org.apache.arrow.driver.jdbc.utils.ThrowableAssertionUtils;
5756
import org.apache.arrow.flight.FlightProducer.ServerStreamListener;
57+
import org.apache.arrow.flight.sql.FlightSqlColumnMetadata;
5858
import org.apache.arrow.flight.sql.FlightSqlProducer.Schemas;
5959
import org.apache.arrow.flight.sql.impl.FlightSql;
6060
import org.apache.arrow.flight.sql.impl.FlightSql.CommandGetCatalogs;
61+
import org.apache.arrow.flight.sql.impl.FlightSql.CommandGetCrossReference;
6162
import org.apache.arrow.flight.sql.impl.FlightSql.CommandGetDbSchemas;
6263
import org.apache.arrow.flight.sql.impl.FlightSql.CommandGetExportedKeys;
6364
import org.apache.arrow.flight.sql.impl.FlightSql.CommandGetImportedKeys;
@@ -79,6 +80,7 @@
7980
import org.apache.arrow.vector.types.Types;
8081
import org.apache.arrow.vector.types.pojo.ArrowType;
8182
import org.apache.arrow.vector.types.pojo.Field;
83+
import org.apache.arrow.vector.types.pojo.FieldType;
8284
import org.apache.arrow.vector.types.pojo.Schema;
8385
import org.apache.arrow.vector.util.Text;
8486
import org.junit.jupiter.api.AfterAll;
@@ -322,7 +324,7 @@ public class ArrowDatabaseMetadataTest {
322324
expectedGetColumnsDecimalDigits.get(i % 3),
323325
expectedGetColumnsRadix.get(i % 3),
324326
!Objects.equals(expectedGetColumnsIsNullable.get(i % 3), "NO") ? 1 : 0,
325-
null,
327+
format("column description #%d", (i % 3) + 1),
326328
null,
327329
null,
328330
null,
@@ -419,17 +421,44 @@ public static void setUpBeforeClass() throws SQLException {
419421
try (final BufferAllocator allocator = new RootAllocator();
420422
final VectorSchemaRoot root =
421423
VectorSchemaRoot.create(Schemas.GET_TABLES_SCHEMA, allocator)) {
424+
final Field field1 =
425+
new Field(
426+
"column_1",
427+
new FieldType(
428+
true,
429+
ArrowType.Decimal.createDecimal(5, 2, 128),
430+
null,
431+
new FlightSqlColumnMetadata.Builder()
432+
.remarks("column description #1")
433+
.build()
434+
.getMetadataMap()),
435+
null);
436+
final Field field2 =
437+
new Field(
438+
"column_2",
439+
new FieldType(
440+
true,
441+
new ArrowType.Timestamp(TimeUnit.NANOSECOND, "UTC"),
442+
null,
443+
new FlightSqlColumnMetadata.Builder()
444+
.remarks("column description #2")
445+
.build()
446+
.getMetadataMap()),
447+
null);
448+
final Field field3 =
449+
new Field(
450+
"column_3",
451+
new FieldType(
452+
false,
453+
Types.MinorType.INT.getType(),
454+
null,
455+
new FlightSqlColumnMetadata.Builder()
456+
.remarks("column description #3")
457+
.build()
458+
.getMetadataMap()),
459+
null);
422460
final byte[] filledTableSchemaBytes =
423-
copyFrom(
424-
serializeSchema(
425-
new Schema(
426-
Arrays.asList(
427-
Field.nullable(
428-
"column_1", ArrowType.Decimal.createDecimal(5, 2, 128)),
429-
Field.nullable(
430-
"column_2",
431-
new ArrowType.Timestamp(TimeUnit.NANOSECOND, "UTC")),
432-
Field.notNullable("column_3", Types.MinorType.INT.getType())))))
461+
copyFrom(serializeSchema(new Schema(Arrays.asList(field1, field2, field3))))
433462
.toByteArray();
434463
final VarCharVector catalogName = (VarCharVector) root.getVector("catalog_name");
435464
final VarCharVector schemaName = (VarCharVector) root.getVector("db_schema_name");

flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/ConvertUtilsTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public void testShouldSetOnColumnMetaDataBuilder() {
4646
.isSearchable(true)
4747
.precision(20)
4848
.scale(10)
49+
.remarks("test column")
4950
.build();
5051
ConvertUtils.setOnColumnMetaDataBuilder(builder, expectedColumnMetaData.getMetadataMap());
5152
assertBuilder(builder, expectedColumnMetaData);
@@ -119,5 +120,6 @@ private void assertBuilder(
119120
assertThat(flightSqlColumnMetaData.isReadOnly(), equalTo(builder.getReadOnly()));
120121
assertThat(precision == null ? 0 : precision, equalTo(builder.getPrecision()));
121122
assertThat(scale == null ? 0 : scale, equalTo(builder.getScale()));
123+
assertThat(flightSqlColumnMetaData.getRemarks(), equalTo(builder.getLabel()));
122124
}
123125
}

flight/flight-sql/src/main/java/org/apache/arrow/flight/sql/FlightSqlColumnMetadata.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public class FlightSqlColumnMetadata {
5353
private static final String IS_CASE_SENSITIVE = "ARROW:FLIGHT:SQL:IS_CASE_SENSITIVE";
5454
private static final String IS_READ_ONLY = "ARROW:FLIGHT:SQL:IS_READ_ONLY";
5555
private static final String IS_SEARCHABLE = "ARROW:FLIGHT:SQL:IS_SEARCHABLE";
56+
private static final String REMARKS = "ARROW:FLIGHT:SQL:REMARKS";
5657

5758
private static final String BOOLEAN_TRUE_STR = "1";
5859
private static final String BOOLEAN_FALSE_STR = "0";
@@ -193,6 +194,15 @@ public Boolean isSearchable() {
193194
return stringToBoolean(value);
194195
}
195196

197+
/**
198+
* Returns the comment describing the column.
199+
*
200+
* @return The comment describing the column.
201+
*/
202+
public String getRemarks() {
203+
return metadataMap.get(REMARKS);
204+
}
205+
196206
/** Builder of FlightSqlColumnMetadata, used on FlightSqlProducer implementations. */
197207
public static class Builder {
198208
private final Map<String, String> metadataMap;
@@ -312,6 +322,17 @@ public Builder isSearchable(boolean isSearchable) {
312322
return this;
313323
}
314324

325+
/**
326+
* Sets the comment describing the column.
327+
*
328+
* @param remarks The comment describing the column.
329+
* @return This builder.
330+
*/
331+
public Builder remarks(String remarks) {
332+
metadataMap.put(REMARKS, remarks);
333+
return this;
334+
}
335+
315336
/**
316337
* Builds a new instance of FlightSqlColumnMetadata.
317338
*

0 commit comments

Comments
 (0)