Skip to content

Commit 6cbaf7e

Browse files
authored
feat: add support for ARRAY<STRUCT> to CloudCilentExecutor (#3544)
There are SPANNER_SYS tables that contain ARRAY<STRUCT> columns. Adding support for this in the CloudClientExecutor so that queries involving these tables do not throw an error.
1 parent dfc154e commit 6cbaf7e

File tree

1 file changed

+67
-34
lines changed

1 file changed

+67
-34
lines changed

google-cloud-spanner-executor/src/main/java/com/google/cloud/executor/spanner/CloudClientExecutor.java

+67-34
Original file line numberDiff line numberDiff line change
@@ -2842,61 +2842,75 @@ private Status processResults(
28422842
/** Convert a result row to a row proto(value list) for sending back to the client. */
28432843
private com.google.spanner.executor.v1.ValueList buildRow(
28442844
StructReader result, OutcomeSender sender) throws SpannerException {
2845-
com.google.spanner.executor.v1.ValueList.Builder rowBuilder =
2846-
com.google.spanner.executor.v1.ValueList.newBuilder();
2845+
sender.setRowType(buildStructType(result));
2846+
return buildStruct(result);
2847+
}
2848+
2849+
/** Construct a StructType for a given struct. This is used to set the row type. */
2850+
private com.google.spanner.v1.StructType buildStructType(StructReader struct) {
28472851
com.google.spanner.v1.StructType.Builder rowTypeBuilder =
28482852
com.google.spanner.v1.StructType.newBuilder();
2849-
for (int i = 0; i < result.getColumnCount(); ++i) {
2850-
com.google.cloud.spanner.Type columnType = result.getColumnType(i);
2853+
for (int i = 0; i < struct.getColumnCount(); ++i) {
2854+
com.google.cloud.spanner.Type columnType = struct.getColumnType(i);
28512855
rowTypeBuilder.addFields(
28522856
com.google.spanner.v1.StructType.Field.newBuilder()
2853-
.setName(result.getType().getStructFields().get(i).getName())
2857+
.setName(struct.getType().getStructFields().get(i).getName())
28542858
.setType(cloudTypeToTypeProto(columnType))
28552859
.build());
2860+
}
2861+
return rowTypeBuilder.build();
2862+
}
2863+
2864+
/** Convert a struct to a proto(value list) for constructing result rows and struct values. */
2865+
private com.google.spanner.executor.v1.ValueList buildStruct(StructReader struct) {
2866+
com.google.spanner.executor.v1.ValueList.Builder structBuilder =
2867+
com.google.spanner.executor.v1.ValueList.newBuilder();
2868+
for (int i = 0; i < struct.getColumnCount(); ++i) {
2869+
com.google.cloud.spanner.Type columnType = struct.getColumnType(i);
28562870
com.google.spanner.executor.v1.Value.Builder value =
28572871
com.google.spanner.executor.v1.Value.newBuilder();
2858-
if (result.isNull(i)) {
2872+
if (struct.isNull(i)) {
28592873
value.setIsNull(true);
28602874
} else {
28612875
switch (columnType.getCode()) {
28622876
case BOOL:
2863-
value.setBoolValue(result.getBoolean(i));
2877+
value.setBoolValue(struct.getBoolean(i));
28642878
break;
28652879
case FLOAT32:
2866-
value.setDoubleValue((double) result.getFloat(i));
2880+
value.setDoubleValue((double) struct.getFloat(i));
28672881
break;
28682882
case FLOAT64:
2869-
value.setDoubleValue(result.getDouble(i));
2883+
value.setDoubleValue(struct.getDouble(i));
28702884
break;
28712885
case INT64:
2872-
value.setIntValue(result.getLong(i));
2886+
value.setIntValue(struct.getLong(i));
28732887
break;
28742888
case STRING:
2875-
value.setStringValue(result.getString(i));
2889+
value.setStringValue(struct.getString(i));
28762890
break;
28772891
case BYTES:
2878-
value.setBytesValue(toByteString(result.getBytes(i)));
2892+
value.setBytesValue(toByteString(struct.getBytes(i)));
28792893
break;
28802894
case TIMESTAMP:
2881-
value.setTimestampValue(timestampToProto(result.getTimestamp(i)));
2895+
value.setTimestampValue(timestampToProto(struct.getTimestamp(i)));
28822896
break;
28832897
case DATE:
2884-
value.setDateDaysValue(daysFromDate(result.getDate(i)));
2898+
value.setDateDaysValue(daysFromDate(struct.getDate(i)));
28852899
break;
28862900
case NUMERIC:
2887-
String ascii = result.getBigDecimal(i).toPlainString();
2901+
String ascii = struct.getBigDecimal(i).toPlainString();
28882902
value.setStringValue(ascii);
28892903
break;
28902904
case JSON:
2891-
value.setStringValue(result.getJson(i));
2905+
value.setStringValue(struct.getJson(i));
28922906
break;
28932907
case ARRAY:
2894-
switch (result.getColumnType(i).getArrayElementType().getCode()) {
2908+
switch (struct.getColumnType(i).getArrayElementType().getCode()) {
28952909
case BOOL:
28962910
{
28972911
com.google.spanner.executor.v1.ValueList.Builder builder =
28982912
com.google.spanner.executor.v1.ValueList.newBuilder();
2899-
List<Boolean> values = result.getBooleanList(i);
2913+
List<Boolean> values = struct.getBooleanList(i);
29002914
for (Boolean booleanValue : values) {
29012915
com.google.spanner.executor.v1.Value.Builder valueProto =
29022916
com.google.spanner.executor.v1.Value.newBuilder();
@@ -2915,7 +2929,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
29152929
{
29162930
com.google.spanner.executor.v1.ValueList.Builder builder =
29172931
com.google.spanner.executor.v1.ValueList.newBuilder();
2918-
List<Float> values = result.getFloatList(i);
2932+
List<Float> values = struct.getFloatList(i);
29192933
for (Float floatValue : values) {
29202934
com.google.spanner.executor.v1.Value.Builder valueProto =
29212935
com.google.spanner.executor.v1.Value.newBuilder();
@@ -2934,7 +2948,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
29342948
{
29352949
com.google.spanner.executor.v1.ValueList.Builder builder =
29362950
com.google.spanner.executor.v1.ValueList.newBuilder();
2937-
List<Double> values = result.getDoubleList(i);
2951+
List<Double> values = struct.getDoubleList(i);
29382952
for (Double doubleValue : values) {
29392953
com.google.spanner.executor.v1.Value.Builder valueProto =
29402954
com.google.spanner.executor.v1.Value.newBuilder();
@@ -2953,7 +2967,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
29532967
{
29542968
com.google.spanner.executor.v1.ValueList.Builder builder =
29552969
com.google.spanner.executor.v1.ValueList.newBuilder();
2956-
List<Long> values = result.getLongList(i);
2970+
List<Long> values = struct.getLongList(i);
29572971
for (Long longValue : values) {
29582972
com.google.spanner.executor.v1.Value.Builder valueProto =
29592973
com.google.spanner.executor.v1.Value.newBuilder();
@@ -2972,7 +2986,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
29722986
{
29732987
com.google.spanner.executor.v1.ValueList.Builder builder =
29742988
com.google.spanner.executor.v1.ValueList.newBuilder();
2975-
List<String> values = result.getStringList(i);
2989+
List<String> values = struct.getStringList(i);
29762990
for (String stringValue : values) {
29772991
com.google.spanner.executor.v1.Value.Builder valueProto =
29782992
com.google.spanner.executor.v1.Value.newBuilder();
@@ -2991,7 +3005,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
29913005
{
29923006
com.google.spanner.executor.v1.ValueList.Builder builder =
29933007
com.google.spanner.executor.v1.ValueList.newBuilder();
2994-
List<ByteArray> values = result.getBytesList(i);
3008+
List<ByteArray> values = struct.getBytesList(i);
29953009
for (ByteArray byteArrayValue : values) {
29963010
com.google.spanner.executor.v1.Value.Builder valueProto =
29973011
com.google.spanner.executor.v1.Value.newBuilder();
@@ -3013,7 +3027,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
30133027
{
30143028
com.google.spanner.executor.v1.ValueList.Builder builder =
30153029
com.google.spanner.executor.v1.ValueList.newBuilder();
3016-
List<Date> values = result.getDateList(i);
3030+
List<Date> values = struct.getDateList(i);
30173031
for (Date dateValue : values) {
30183032
com.google.spanner.executor.v1.Value.Builder valueProto =
30193033
com.google.spanner.executor.v1.Value.newBuilder();
@@ -3033,7 +3047,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
30333047
{
30343048
com.google.spanner.executor.v1.ValueList.Builder builder =
30353049
com.google.spanner.executor.v1.ValueList.newBuilder();
3036-
List<Timestamp> values = result.getTimestampList(i);
3050+
List<Timestamp> values = struct.getTimestampList(i);
30373051
for (Timestamp timestampValue : values) {
30383052
com.google.spanner.executor.v1.Value.Builder valueProto =
30393053
com.google.spanner.executor.v1.Value.newBuilder();
@@ -3053,7 +3067,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
30533067
{
30543068
com.google.spanner.executor.v1.ValueList.Builder builder =
30553069
com.google.spanner.executor.v1.ValueList.newBuilder();
3056-
List<BigDecimal> values = result.getBigDecimalList(i);
3070+
List<BigDecimal> values = struct.getBigDecimalList(i);
30573071
for (BigDecimal bigDec : values) {
30583072
com.google.spanner.executor.v1.Value.Builder valueProto =
30593073
com.google.spanner.executor.v1.Value.newBuilder();
@@ -3072,7 +3086,7 @@ private com.google.spanner.executor.v1.ValueList buildRow(
30723086
{
30733087
com.google.spanner.executor.v1.ValueList.Builder builder =
30743088
com.google.spanner.executor.v1.ValueList.newBuilder();
3075-
List<String> values = result.getJsonList(i);
3089+
List<String> values = struct.getJsonList(i);
30763090
for (String stringValue : values) {
30773091
com.google.spanner.executor.v1.Value.Builder valueProto =
30783092
com.google.spanner.executor.v1.Value.newBuilder();
@@ -3087,28 +3101,47 @@ private com.google.spanner.executor.v1.ValueList buildRow(
30873101
com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.JSON).build());
30883102
}
30893103
break;
3104+
case STRUCT:
3105+
{
3106+
com.google.spanner.executor.v1.ValueList.Builder builder =
3107+
com.google.spanner.executor.v1.ValueList.newBuilder();
3108+
List<Struct> values = struct.getStructList(i);
3109+
for (StructReader structValue : values) {
3110+
com.google.spanner.executor.v1.Value.Builder valueProto =
3111+
com.google.spanner.executor.v1.Value.newBuilder();
3112+
if (structValue == null) {
3113+
builder.addValue(valueProto.setIsNull(true).build());
3114+
} else {
3115+
builder.addValue(valueProto.setStructValue(buildStruct(structValue))).build();
3116+
}
3117+
}
3118+
value.setArrayValue(builder.build());
3119+
value.setArrayType(
3120+
com.google.spanner.v1.Type.newBuilder().setCode(TypeCode.STRUCT).build());
3121+
}
3122+
break;
30903123
default:
30913124
throw SpannerExceptionFactory.newSpannerException(
30923125
ErrorCode.INVALID_ARGUMENT,
30933126
"Unsupported row array type: "
3094-
+ result.getColumnType(i)
3127+
+ struct.getColumnType(i)
30953128
+ " for result type "
3096-
+ result.getType().toString());
3129+
+ struct.getType().toString());
30973130
}
30983131
break;
30993132
default:
31003133
throw SpannerExceptionFactory.newSpannerException(
31013134
ErrorCode.INVALID_ARGUMENT,
31023135
"Unsupported row type: "
3103-
+ result.getColumnType(i)
3136+
+ struct.getColumnType(i)
31043137
+ " for result type "
3105-
+ result.getType().toString());
3138+
+ struct.getType().toString());
31063139
}
31073140
}
3108-
rowBuilder.addValue(value.build());
3141+
structBuilder.addValue(value.build());
31093142
}
3110-
sender.setRowType(rowTypeBuilder.build());
3111-
return rowBuilder.build();
3143+
;
3144+
return structBuilder.build();
31123145
}
31133146

31143147
/** Convert a ListValue proto to a list of cloud Value. */

0 commit comments

Comments
 (0)