Skip to content

Commit 066f6dc

Browse files
committed
feat: support unrecognized types
1 parent 9123db5 commit 066f6dc

File tree

11 files changed

+980
-97
lines changed

11 files changed

+980
-97
lines changed

google-cloud-spanner/src/main/java/com/google/cloud/ByteArrayHelper.java

Lines changed: 0 additions & 28 deletions
This file was deleted.

google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import com.google.api.client.util.ExponentialBackOff;
2727
import com.google.api.gax.retrying.RetrySettings;
2828
import com.google.cloud.ByteArray;
29-
import com.google.cloud.ByteArrayHelper;
3029
import com.google.cloud.Date;
3130
import com.google.cloud.Timestamp;
3231
import com.google.cloud.spanner.Type.StructField;
@@ -39,6 +38,7 @@
3938
import com.google.common.util.concurrent.Uninterruptibles;
4039
import com.google.protobuf.ByteString;
4140
import com.google.protobuf.ListValue;
41+
import com.google.protobuf.NullValue;
4242
import com.google.protobuf.Value.KindCase;
4343
import com.google.spanner.v1.PartialResultSet;
4444
import com.google.spanner.v1.ResultSetMetadata;
@@ -74,6 +74,8 @@
7474
/** Implementation of {@link ResultSet}. */
7575
abstract class AbstractResultSet<R> extends AbstractStructReader implements ResultSet {
7676
private static final Tracer tracer = Tracing.getTracer();
77+
private static final com.google.protobuf.Value NULL_VALUE =
78+
com.google.protobuf.Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build();
7779

7880
interface Listener {
7981
/**
@@ -362,7 +364,7 @@ static class LazyByteArray implements Serializable {
362364
new AbstractLazyInitializer<ByteArray>() {
363365
@Override
364366
protected ByteArray initialize() {
365-
return ByteArrayHelper.wrap(DECODER.decode(base64String));
367+
return ByteArray.copyFrom(DECODER.decode(base64String));
366368
}
367369
};
368370

@@ -566,6 +568,8 @@ private static Object decodeValue(Type fieldType, com.google.protobuf.Value prot
566568
checkType(fieldType, proto, KindCase.LIST_VALUE);
567569
ListValue structValue = proto.getListValue();
568570
return decodeStructValue(fieldType, structValue);
571+
case UNRECOGNIZED:
572+
return proto;
569573
default:
570574
throw new AssertionError("Unhandled type code: " + fieldType.getCode());
571575
}
@@ -675,7 +679,11 @@ protected String getPgJsonbInternal(int columnIndex) {
675679

676680
@Override
677681
protected ByteArray getBytesInternal(int columnIndex) {
678-
return ((LazyByteArray) rowData.get(columnIndex)).getByteArray();
682+
return getLazyBytesInternal(columnIndex).getByteArray();
683+
}
684+
685+
LazyByteArray getLazyBytesInternal(int columnIndex) {
686+
return (LazyByteArray) rowData.get(columnIndex);
679687
}
680688

681689
@Override
@@ -712,13 +720,16 @@ protected Value getValueInternal(int columnIndex) {
712720
case PG_JSONB:
713721
return Value.pgJsonb(isNull ? null : getPgJsonbInternal(columnIndex));
714722
case BYTES:
715-
return Value.bytes(isNull ? null : getBytesInternal(columnIndex));
723+
return Value.lazyBytes(isNull ? null : getLazyBytesInternal(columnIndex));
716724
case TIMESTAMP:
717725
return Value.timestamp(isNull ? null : getTimestampInternal(columnIndex));
718726
case DATE:
719727
return Value.date(isNull ? null : getDateInternal(columnIndex));
720728
case STRUCT:
721729
return Value.struct(isNull ? null : getStructInternal(columnIndex));
730+
case UNRECOGNIZED:
731+
return Value.untyped(
732+
isNull ? NULL_VALUE : (com.google.protobuf.Value) rowData.get(columnIndex));
722733
case ARRAY:
723734
final Type elementType = columnType.getArrayElementType();
724735
switch (elementType.getCode()) {

google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -170,20 +170,17 @@ public BigDecimal getBigDecimal(String columnName) {
170170
public String getString(int columnIndex) {
171171
checkNonNullOfTypes(
172172
columnIndex,
173-
Arrays.asList(Type.string(), Type.pgNumeric(), Type.bytes()),
173+
Arrays.asList(Type.string(), Type.pgNumeric()),
174174
columnIndex,
175-
"STRING, NUMERIC, BYTES");
175+
"STRING, NUMERIC");
176176
return getStringInternal(columnIndex);
177177
}
178178

179179
@Override
180180
public String getString(String columnName) {
181181
int columnIndex = getColumnIndex(columnName);
182182
checkNonNullOfTypes(
183-
columnIndex,
184-
Arrays.asList(Type.string(), Type.pgNumeric(), Type.bytes()),
185-
columnName,
186-
"STRING, NUMERIC, BYTES");
183+
columnIndex, Arrays.asList(Type.string(), Type.pgNumeric()), columnName, "STRING, NUMERIC");
187184
return getStringInternal(columnIndex);
188185
}
189186

@@ -254,7 +251,6 @@ public Date getDate(String columnName) {
254251

255252
@Override
256253
public Value getValue(int columnIndex) {
257-
checkNonNull(columnIndex, columnIndex);
258254
return getValueInternal(columnIndex);
259255
}
260256

google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Map.Entry;
3434
import java.util.Objects;
3535
import java.util.TreeMap;
36+
import javax.annotation.Nonnull;
3637
import javax.annotation.Nullable;
3738
import javax.annotation.concurrent.Immutable;
3839

@@ -71,6 +72,10 @@ public final class Type implements Serializable {
7172
private static final int AMBIGUOUS_FIELD = -1;
7273
private static final long serialVersionUID = -3076152125004114582L;
7374

75+
static Type unrecognized(com.google.spanner.v1.Type proto) {
76+
return new Type(proto);
77+
}
78+
7479
/** Returns the descriptor for the {@code BOOL type}. */
7580
public static Type bool() {
7681
return TYPE_BOOL;
@@ -190,6 +195,7 @@ public static Type struct(StructField... fields) {
190195
return new Type(Code.STRUCT, null, ImmutableList.copyOf(fields));
191196
}
192197

198+
private final com.google.spanner.v1.Type proto;
193199
private final Code code;
194200
private final Type arrayElementType;
195201
private final ImmutableList<StructField> structFields;
@@ -204,13 +210,23 @@ private Type(
204210
Code code,
205211
@Nullable Type arrayElementType,
206212
@Nullable ImmutableList<StructField> structFields) {
213+
this.proto = null;
207214
this.code = code;
208215
this.arrayElementType = arrayElementType;
209216
this.structFields = structFields;
210217
}
211218

219+
private Type(@Nonnull com.google.spanner.v1.Type proto) {
220+
this.proto = proto;
221+
this.code = Code.UNRECOGNIZED;
222+
this.arrayElementType =
223+
proto.hasArrayElementType() ? new Type(proto.getArrayElementType()) : null;
224+
this.structFields = null;
225+
}
226+
212227
/** Enumerates the categories of types. */
213228
public enum Code {
229+
UNRECOGNIZED(TypeCode.UNRECOGNIZED),
214230
BOOL(TypeCode.BOOL),
215231
INT64(TypeCode.INT64),
216232
NUMERIC(TypeCode.NUMERIC),
@@ -258,8 +274,7 @@ TypeAnnotationCode getTypeAnnotationCode() {
258274

259275
static Code fromProto(TypeCode typeCode, TypeAnnotationCode typeAnnotationCode) {
260276
Code code = protoToCode.get(new SimpleEntry<>(typeCode, typeAnnotationCode));
261-
checkArgument(code != null, "Invalid code: %s<%s>", typeCode, typeAnnotationCode);
262-
return code;
277+
return code == null ? Code.UNRECOGNIZED : code;
263278
}
264279

265280
@Override
@@ -325,7 +340,7 @@ public Code getCode() {
325340
* @throws IllegalStateException if {@code code() != Code.ARRAY}
326341
*/
327342
public Type getArrayElementType() {
328-
Preconditions.checkState(code == Code.ARRAY, "Illegal call for non-ARRAY type");
343+
Preconditions.checkState(arrayElementType != null, "Illegal call for non-ARRAY type");
329344
return arrayElementType;
330345
}
331346

@@ -378,7 +393,7 @@ public int getFieldIndex(String fieldName) {
378393
}
379394

380395
void toString(StringBuilder b) {
381-
if (code == Code.ARRAY) {
396+
if (code == Code.ARRAY || (proto != null && proto.hasArrayElementType())) {
382397
b.append("ARRAY<");
383398
arrayElementType.toString(b);
384399
b.append('>');
@@ -393,6 +408,11 @@ void toString(StringBuilder b) {
393408
f.getType().toString(b);
394409
}
395410
b.append('>');
411+
} else if (proto != null) {
412+
b.append(proto.getCode().name());
413+
if (proto.getTypeAnnotation() != TYPE_ANNOTATION_CODE_UNSPECIFIED) {
414+
b.append("<").append(proto.getTypeAnnotation().name()).append(">");
415+
}
396416
} else {
397417
b.append(code.toString());
398418
}
@@ -414,17 +434,26 @@ public boolean equals(Object o) {
414434
return false;
415435
}
416436
Type that = (Type) o;
437+
if (proto != null) {
438+
return Objects.equals(proto, that.proto);
439+
}
417440
return code == that.code
418441
&& Objects.equals(arrayElementType, that.arrayElementType)
419442
&& Objects.equals(structFields, that.structFields);
420443
}
421444

422445
@Override
423446
public int hashCode() {
447+
if (proto != null) {
448+
return proto.hashCode();
449+
}
424450
return Objects.hash(code, arrayElementType, structFields);
425451
}
426452

427453
com.google.spanner.v1.Type toProto() {
454+
if (proto != null) {
455+
return proto;
456+
}
428457
com.google.spanner.v1.Type.Builder proto = com.google.spanner.v1.Type.newBuilder();
429458
proto.setCode(code.getTypeCode());
430459
proto.setTypeAnnotation(code.getTypeAnnotationCode());
@@ -490,8 +519,9 @@ static Type fromProto(com.google.spanner.v1.Type proto) {
490519
fields.add(StructField.of(name, fromProto(field.getType())));
491520
}
492521
return struct(fields);
522+
case UNRECOGNIZED:
493523
default:
494-
throw new AssertionError("Unimplemented case: " + type);
524+
return unrecognized(proto);
495525
}
496526
}
497527
}

0 commit comments

Comments
 (0)