diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java index fdbea3335b9..789e0945e17 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java @@ -67,7 +67,6 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.stream.Collectors; import javax.annotation.Nullable; /** Implementation of {@link ResultSet}. */ @@ -547,88 +546,24 @@ private static Struct decodeStructValue(Type structType, ListValue structValue) static Object decodeArrayValue(Type elementType, ListValue listValue) { switch (elementType.getCode()) { - case BOOL: - // Use a view: element conversion is virtually free. - return Lists.transform( - listValue.getValuesList(), - input -> input.getKindCase() == KindCase.NULL_VALUE ? null : input.getBoolValue()); case INT64: // For int64/float64 types, use custom containers. These avoid wrapper object // creation for non-null arrays. return new Int64Array(listValue); case FLOAT64: return new Float64Array(listValue); + case BOOL: case NUMERIC: - { - // Materialize list: element conversion is expensive and should happen only once. - ArrayList list = new ArrayList<>(listValue.getValuesCount()); - for (com.google.protobuf.Value value : listValue.getValuesList()) { - list.add( - value.getKindCase() == KindCase.NULL_VALUE - ? null - : new BigDecimal(value.getStringValue())); - } - return list; - } case PG_NUMERIC: case STRING: case JSON: case PG_JSONB: - return listValue.getValuesList().stream() - .map( - input -> - input.getKindCase() == KindCase.NULL_VALUE ? null : input.getStringValue()) - .collect(Collectors.toList()); case BYTES: - { - // Materialize list: element conversion is expensive and should happen only once. - ArrayList list = new ArrayList<>(listValue.getValuesCount()); - for (com.google.protobuf.Value value : listValue.getValuesList()) { - list.add( - value.getKindCase() == KindCase.NULL_VALUE - ? null - : ByteArray.fromBase64(value.getStringValue())); - } - return list; - } case TIMESTAMP: - { - // Materialize list: element conversion is expensive and should happen only once. - ArrayList list = new ArrayList<>(listValue.getValuesCount()); - for (com.google.protobuf.Value value : listValue.getValuesList()) { - list.add( - value.getKindCase() == KindCase.NULL_VALUE - ? null - : Timestamp.parseTimestamp(value.getStringValue())); - } - return list; - } case DATE: - { - // Materialize list: element conversion is expensive and should happen only once. - ArrayList list = new ArrayList<>(listValue.getValuesCount()); - for (com.google.protobuf.Value value : listValue.getValuesList()) { - list.add( - value.getKindCase() == KindCase.NULL_VALUE - ? null - : Date.parseDate(value.getStringValue())); - } - return list; - } - case STRUCT: - { - ArrayList list = new ArrayList<>(listValue.getValuesCount()); - for (com.google.protobuf.Value value : listValue.getValuesList()) { - if (value.getKindCase() == KindCase.NULL_VALUE) { - list.add(null); - } else { - ListValue structValue = value.getListValue(); - list.add(decodeStructValue(elementType, structValue)); - } - } - return list; - } + return Lists.transform( + listValue.getValuesList(), input -> decodeValue(elementType, input)); default: throw new AssertionError("Unhandled type code: " + elementType.getCode()); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java index a96c95cb953..b767bd6d82c 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java @@ -178,10 +178,18 @@ default Value getValue(String columnName) { */ boolean[] getBooleanArray(String columnName); - /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.bool())}. */ + /** + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.bool())}. The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. + */ List getBooleanList(int columnIndex); - /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.bool())}. */ + /** + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.bool())}. The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. + */ List getBooleanList(String columnName); /** @@ -200,10 +208,18 @@ default Value getValue(String columnName) { */ long[] getLongArray(String columnName); - /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.int64())}. */ + /** + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.int64())}. The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. + */ List getLongList(int columnIndex); - /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.int64())}. */ + /** + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.int64())}. The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. + */ List getLongList(String columnName); /** @@ -223,84 +239,136 @@ default Value getValue(String columnName) { double[] getDoubleArray(String columnName); /** - * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.float64())}. + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.float64())} The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. */ List getDoubleList(int columnIndex); /** - * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.float64())}. + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.float64())} The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. */ List getDoubleList(String columnName); /** - * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.numeric())}. + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.numeric())} The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. */ List getBigDecimalList(int columnIndex); /** - * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.numeric())}. + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.numeric())} The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. */ List getBigDecimalList(String columnName); - /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.string())}. */ + /** + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.string())}. The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. + */ List getStringList(int columnIndex); - /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.string())}. */ + /** + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.string())}. The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. + */ List getStringList(String columnName); - /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.json())}. */ + /** + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.json())}. The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. + */ default List getJsonList(int columnIndex) { throw new UnsupportedOperationException("method should be overwritten"); }; - /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.json())}. */ + /** + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.json())}. The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. + */ default List getJsonList(String columnName) { throw new UnsupportedOperationException("method should be overwritten"); }; /** - * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.pgJsonb())}. + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.pgJsonb())} The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. */ default List getPgJsonbList(int columnIndex) { throw new UnsupportedOperationException("method should be overwritten"); }; /** - * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.pgJsonb())}. + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.pgJsonb())} The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. */ default List getPgJsonbList(String columnName) { throw new UnsupportedOperationException("method should be overwritten"); }; - /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.bytes())}. */ + /** + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.bytes())}. The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. + */ List getBytesList(int columnIndex); - /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.bytes())}. */ + /** + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.bytes())}. The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. + */ List getBytesList(String columnName); /** - * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.timestamp())}. + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.timestamp())} + * The list returned by this method is lazily constructed. Create a copy of it if you intend to + * access each element in the list multiple times. */ List getTimestampList(int columnIndex); /** - * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.timestamp())}. + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.timestamp())} + * The list returned by this method is lazily constructed. Create a copy of it if you intend to + * access each element in the list multiple times. */ List getTimestampList(String columnName); - /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.date())}. */ + /** + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.date())}. The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. + */ List getDateList(int columnIndex); - /** Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.date())}. */ + /** + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.date())}. The + * list returned by this method is lazily constructed. Create a copy of it if you intend to access + * each element in the list multiple times. + */ List getDateList(String columnName); /** - * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.struct(...))}. + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.struct(...))} + * The list returned by this method is lazily constructed. Create a copy of it if you intend to + * access each element in the list multiple times. */ List getStructList(int columnIndex); /** - * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.struct(...))}. + * Returns the value of a non-{@code NULL} column with type {@code Type.array(Type.struct(...))} + * The list returned by this method is lazily constructed. Create a copy of it if you intend to + * access each element in the list multiple times. */ List getStructList(String columnName); }