getBigDecimalListInternal(int columnIndex) {
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Mutation.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Mutation.java
index 73995a20df..6c869c549f 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Mutation.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Mutation.java
@@ -364,6 +364,8 @@ public int hashCode() {
* mutation equality to check for modifications before committing. We noticed that when NaNs where
* used the template would always indicate a modification was present, when it turned out not to
* be the case. For more information see b/206339664.
+ *
+ * Similar change is being done while calculating `Value.hashCode()`.
*/
private boolean areValuesEqual(List values, List otherValues) {
if (values == null && otherValues == null) {
@@ -385,9 +387,19 @@ private boolean areValuesEqual(List values, List otherValues) {
}
private boolean isNaN(Value value) {
- return !value.isNull()
- && value.getType().equals(Type.float64())
- && Double.isNaN(value.getFloat64());
+ return !value.isNull() && (isFloat64NaN(value) || isFloat32NaN(value));
+ }
+
+ // Checks if the Float64 value is either a "Double" or a "Float" NaN.
+ // Refer the comment above `areValuesEqual` for more details.
+ private boolean isFloat64NaN(Value value) {
+ return value.getType().equals(Type.float64()) && Double.isNaN(value.getFloat64());
+ }
+
+ // Checks if the Float32 value is either a "Double" or a "Float" NaN.
+ // Refer the comment above `areValuesEqual` for more details.
+ private boolean isFloat32NaN(Value value) {
+ return value.getType().equals(Type.float32()) && Float.isNaN(value.getFloat32());
}
static void toProto(Iterable mutations, List out) {
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java
index a6cc7c729e..3d12cf5ad2 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java
@@ -236,6 +236,16 @@ public long getLong(String columnName) {
return getCurrentRowAsStruct().getLong(columnName);
}
+ @Override
+ public float getFloat(int columnIndex) {
+ return getCurrentRowAsStruct().getFloat(columnIndex);
+ }
+
+ @Override
+ public float getFloat(String columnName) {
+ return getCurrentRowAsStruct().getFloat(columnName);
+ }
+
@Override
public double getDouble(int columnIndex) {
return getCurrentRowAsStruct().getDouble(columnIndex);
@@ -388,6 +398,26 @@ public List getLongList(String columnName) {
return getCurrentRowAsStruct().getLongList(columnName);
}
+ @Override
+ public float[] getFloatArray(int columnIndex) {
+ return getCurrentRowAsStruct().getFloatArray(columnIndex);
+ }
+
+ @Override
+ public float[] getFloatArray(String columnName) {
+ return getCurrentRowAsStruct().getFloatArray(columnName);
+ }
+
+ @Override
+ public List getFloatList(int columnIndex) {
+ return getCurrentRowAsStruct().getFloatList(columnIndex);
+ }
+
+ @Override
+ public List getFloatList(String columnName) {
+ return getCurrentRowAsStruct().getFloatList(columnName);
+ }
+
@Override
public double[] getDoubleArray(int columnIndex) {
return getCurrentRowAsStruct().getDoubleArray(columnIndex);
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java
index 40c30148d0..0e65fa7f1b 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java
@@ -27,6 +27,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Booleans;
import com.google.common.primitives.Doubles;
+import com.google.common.primitives.Floats;
import com.google.common.primitives.Longs;
import com.google.protobuf.AbstractMessage;
import com.google.protobuf.ProtocolMessageEnum;
@@ -180,6 +181,11 @@ protected long getLongInternal(int columnIndex) {
return values.get(columnIndex).getInt64();
}
+ @Override
+ protected float getFloatInternal(int columnIndex) {
+ return values.get(columnIndex).getFloat32();
+ }
+
@Override
protected double getDoubleInternal(int columnIndex) {
return values.get(columnIndex).getFloat64();
@@ -261,6 +267,16 @@ protected List getLongListInternal(int columnIndex) {
return values.get(columnIndex).getInt64Array();
}
+ @Override
+ protected float[] getFloatArrayInternal(int columnIndex) {
+ return Floats.toArray(getFloatListInternal(columnIndex));
+ }
+
+ @Override
+ protected List getFloatListInternal(int columnIndex) {
+ return values.get(columnIndex).getFloat32Array();
+ }
+
@Override
protected double[] getDoubleArrayInternal(int columnIndex) {
return Doubles.toArray(getDoubleListInternal(columnIndex));
@@ -382,6 +398,8 @@ private Object getAsObject(int columnIndex) {
case INT64:
case ENUM:
return getLongInternal(columnIndex);
+ case FLOAT32:
+ return getFloatInternal(columnIndex);
case FLOAT64:
return getDoubleInternal(columnIndex);
case NUMERIC:
@@ -410,6 +428,8 @@ private Object getAsObject(int columnIndex) {
case INT64:
case ENUM:
return getLongListInternal(columnIndex);
+ case FLOAT32:
+ return getFloatListInternal(columnIndex);
case FLOAT64:
return getDoubleListInternal(columnIndex);
case NUMERIC:
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 fd8cb77f39..f9967db045 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
@@ -123,6 +123,22 @@ public interface StructReader {
*/
long getLong(String columnName);
+ /**
+ * @param columnIndex index of the column
+ * @return the value of a non-{@code NULL} column with type {@link Type#float32()}.
+ */
+ default float getFloat(int columnIndex) {
+ throw new UnsupportedOperationException("method should be overwritten");
+ }
+
+ /**
+ * @param columnName name of the column
+ * @return the value of a non-{@code NULL} column with type {@link Type#float32()}.
+ */
+ default float getFloat(String columnName) {
+ throw new UnsupportedOperationException("method should be overwritten");
+ }
+
/**
* @param columnIndex index of the column
* @return the value of a non-{@code NULL} column with type {@link Type#float64()}.
@@ -361,6 +377,44 @@ default Value getValue(String columnName) {
*/
List getLongList(String columnName);
+ /**
+ * @param columnIndex index of the column
+ * @return the value of a non-{@code NULL} column with type {@code Type.array(Type.float32())}.
+ * @throws NullPointerException if any element of the array value is {@code NULL}. If the array
+ * may contain {@code NULL} values, use {@link #getFloatList(int)} instead.
+ */
+ default float[] getFloatArray(int columnIndex) {
+ throw new UnsupportedOperationException("method should be overwritten");
+ }
+
+ /**
+ * @param columnName name of the column
+ * @return the value of a non-{@code NULL} column with type {@code Type.array(Type.float32())}.
+ * @throws NullPointerException if any element of the array value is {@code NULL}. If the array
+ * may contain {@code NULL} values, use {@link #getFloatList(String)} instead.
+ */
+ default float[] getFloatArray(String columnName) {
+ throw new UnsupportedOperationException("method should be overwritten");
+ }
+
+ /**
+ * @param columnIndex index of the column
+ * @return the value of a non-{@code NULL} column with type {@code Type.array(Type.float32())} 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 getFloatList(int columnIndex) {
+ throw new UnsupportedOperationException("method should be overwritten");
+ }
+
+ /**
+ * @param columnName name of the column
+ * @return the value of a non-{@code NULL} column with type {@code Type.array(Type.float32())} 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 getFloatList(String columnName);
+
/**
* @param columnIndex index of the column
* @return the value of a non-{@code NULL} column with type {@code Type.array(Type.float64())}.
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java
index 348db5d04a..5d871227f5 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java
@@ -48,6 +48,7 @@
public final class Type implements Serializable {
private static final Type TYPE_BOOL = new Type(Code.BOOL, null, null);
private static final Type TYPE_INT64 = new Type(Code.INT64, null, null);
+ private static final Type TYPE_FLOAT32 = new Type(Code.FLOAT32, null, null);
private static final Type TYPE_FLOAT64 = new Type(Code.FLOAT64, null, null);
private static final Type TYPE_NUMERIC = new Type(Code.NUMERIC, null, null);
private static final Type TYPE_PG_NUMERIC = new Type(Code.PG_NUMERIC, null, null);
@@ -59,6 +60,7 @@ public final class Type implements Serializable {
private static final Type TYPE_DATE = new Type(Code.DATE, null, null);
private static final Type TYPE_ARRAY_BOOL = new Type(Code.ARRAY, TYPE_BOOL, null);
private static final Type TYPE_ARRAY_INT64 = new Type(Code.ARRAY, TYPE_INT64, null);
+ private static final Type TYPE_ARRAY_FLOAT32 = new Type(Code.ARRAY, TYPE_FLOAT32, null);
private static final Type TYPE_ARRAY_FLOAT64 = new Type(Code.ARRAY, TYPE_FLOAT64, null);
private static final Type TYPE_ARRAY_NUMERIC = new Type(Code.ARRAY, TYPE_NUMERIC, null);
private static final Type TYPE_ARRAY_PG_NUMERIC = new Type(Code.ARRAY, TYPE_PG_NUMERIC, null);
@@ -89,9 +91,17 @@ public static Type int64() {
return TYPE_INT64;
}
+ /**
+ * Returns the descriptor for the {@code FLOAT32} type: a floating point type with the same value
+ * domain as a Java {@code float}.
+ */
+ public static Type float32() {
+ return TYPE_FLOAT32;
+ }
+
/**
* Returns the descriptor for the {@code FLOAT64} type: a floating point type with the same value
- * domain as a Java {code double}.
+ * domain as a Java {@code double}.
*/
public static Type float64() {
return TYPE_FLOAT64;
@@ -174,6 +184,8 @@ public static Type array(Type elementType) {
return TYPE_ARRAY_BOOL;
case INT64:
return TYPE_ARRAY_INT64;
+ case FLOAT32:
+ return TYPE_ARRAY_FLOAT32;
case FLOAT64:
return TYPE_ARRAY_FLOAT64;
case NUMERIC:
@@ -264,6 +276,7 @@ public enum Code {
NUMERIC(TypeCode.NUMERIC, "unknown"),
PG_NUMERIC(TypeCode.NUMERIC, "numeric", TypeAnnotationCode.PG_NUMERIC),
FLOAT64(TypeCode.FLOAT64, "double precision"),
+ FLOAT32(TypeCode.FLOAT32, "real"),
STRING(TypeCode.STRING, "character varying"),
JSON(TypeCode.JSON, "unknown"),
PG_JSONB(TypeCode.JSON, "jsonb", TypeAnnotationCode.PG_JSONB),
@@ -565,6 +578,8 @@ static Type fromProto(com.google.spanner.v1.Type proto) {
return bool();
case INT64:
return int64();
+ case FLOAT32:
+ return float32();
case FLOAT64:
return float64();
case NUMERIC:
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java
index 3f0155e4a5..49a6c1e7bc 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java
@@ -149,6 +149,20 @@ public static Value int64(long v) {
return new Int64Impl(false, v);
}
+ /**
+ * Returns a {@code FLOAT32} value.
+ *
+ * @param v the value, which may be null
+ */
+ public static Value float32(@Nullable Float v) {
+ return new Float32Impl(v == null, v == null ? 0 : v);
+ }
+
+ /** Returns a {@code FLOAT32} value. */
+ public static Value float32(float v) {
+ return new Float32Impl(false, v);
+ }
+
/**
* Returns a {@code FLOAT64} value.
*
@@ -454,6 +468,40 @@ public static Value int64Array(@Nullable Iterable v) {
return int64ArrayFactory.create(v);
}
+ /**
+ * Returns an {@code ARRAY} value.
+ *
+ * @param v the source of element values, which may be null to produce a value for which {@code
+ * isNull()} is {@code true}
+ */
+ public static Value float32Array(@Nullable float[] v) {
+ return float32Array(v, 0, v == null ? 0 : v.length);
+ }
+
+ /**
+ * Returns an {@code ARRAY} value that takes its elements from a region of an array.
+ *
+ * @param v the source of element values, which may be null to produce a value for which {@code
+ * isNull()} is {@code true}
+ * @param pos the start position of {@code v} to copy values from. Ignored if {@code v} is {@code
+ * null}.
+ * @param length the number of values to copy from {@code v}. Ignored if {@code v} is {@code
+ * null}.
+ */
+ public static Value float32Array(@Nullable float[] v, int pos, int length) {
+ return float32ArrayFactory.create(v, pos, length);
+ }
+
+ /**
+ * Returns an {@code ARRAY} value.
+ *
+ * @param v the source of element values. This may be {@code null} to produce a value for which
+ * {@code isNull()} is {@code true}. Individual elements may also be {@code null}.
+ */
+ public static Value float32Array(@Nullable Iterable v) {
+ return float32ArrayFactory.create(v);
+ }
+
/**
* Returns an {@code ARRAY} value.
*
@@ -729,6 +777,13 @@ private Value() {}
*/
public abstract long getInt64();
+ /**
+ * Returns the value of a {@code FLOAT32}-typed instance.
+ *
+ * @throws IllegalStateException if {@code isNull()} or the value is not of the expected type
+ */
+ public abstract float getFloat32();
+
/**
* Returns the value of a {@code FLOAT64}-typed instance.
*
@@ -835,6 +890,14 @@ public T getProtoEnum(
*/
public abstract List getInt64Array();
+ /**
+ * Returns the value of an {@code ARRAY}-typed instance. While the returned list itself
+ * will never be {@code null}, elements of that list may be null.
+ *
+ * @throws IllegalStateException if {@code isNull()} or the value is not of the expected type
+ */
+ public abstract List getFloat32Array();
+
/**
* Returns the value of an {@code ARRAY}-typed instance. While the returned list itself
* will never be {@code null}, elements of that list may be null.
@@ -1052,6 +1115,23 @@ Value newValue(boolean isNull, BitSet nulls, long[] values) {
return new Int64ArrayImpl(isNull, nulls, values);
}
};
+ private static final PrimitiveArrayValueFactory float32ArrayFactory =
+ new PrimitiveArrayValueFactory() {
+ @Override
+ float[] newArray(int size) {
+ return new float[size];
+ }
+
+ @Override
+ void set(float[] arr, int i, Float value) {
+ arr[i] = value;
+ }
+
+ @Override
+ Value newValue(boolean isNull, BitSet nulls, float[] values) {
+ return new Float32ArrayImpl(isNull, nulls, values);
+ }
+ };
private static final PrimitiveArrayValueFactory float64ArrayFactory =
new PrimitiveArrayValueFactory() {
@Override
@@ -1122,6 +1202,11 @@ public long getInt64() {
throw defaultGetter(Type.int64());
}
+ @Override
+ public float getFloat32() {
+ throw defaultGetter(Type.float32());
+ }
+
@Override
public double getFloat64() {
throw defaultGetter(Type.float64());
@@ -1181,6 +1266,11 @@ public List getInt64Array() {
throw defaultGetter(Type.array(Type.int64()));
}
+ @Override
+ public List getFloat32Array() {
+ throw defaultGetter(Type.array(Type.float32()));
+ }
+
@Override
public List getFloat64Array() {
throw defaultGetter(Type.array(Type.float64()));
@@ -1285,9 +1375,29 @@ public final boolean equals(Object o) {
@Override
public final int hashCode() {
- int result = Objects.hash(getType(), isNull);
+ Type typeToHash = getType();
+ int valueHash = isNull ? 0 : valueHash();
+
+ /**
+ * We are relaxing equality values here, making sure that Double.NaNs and Float.NaNs are equal
+ * to each other. This is because our Cloud Spanner Import / Export template in Apache Beam
+ * uses the mutation equality to check for modifications before committing. We noticed that
+ * when NaNs where used the template would always indicate a modification was present, when it
+ * turned out not to be the case.
+ *
+ * With FLOAT32 being introduced, we want to ensure the backward compatibility of the NaN
+ * equality checks that existed for FLOAT64. We're promoting the type to FLOAT64 while
+ * calculating the type hash when the value is a NaN. We're doing a similar type promotion
+ * while calculating valueHash of Float32 type. Note that this is not applicable for composite
+ * types containing FLOAT32.
+ */
+ if (type.getCode() == Type.Code.FLOAT32 && !isNull && Float.isNaN(getFloat32())) {
+ typeToHash = Type.float64();
+ }
+
+ int result = Objects.hash(typeToHash, isNull);
if (!isNull) {
- result = 31 * result + valueHash();
+ result = 31 * result + valueHash;
}
return result;
}
@@ -1492,6 +1602,50 @@ int valueHash() {
}
}
+ private static class Float32Impl extends AbstractValue {
+ private final float value;
+
+ private Float32Impl(boolean isNull, float value) {
+ super(isNull, Type.float32());
+ this.value = value;
+ }
+
+ @Override
+ public float getFloat32() {
+ checkNotNull();
+ return value;
+ }
+
+ @Override
+ com.google.protobuf.Value valueToProto() {
+ return com.google.protobuf.Value.newBuilder().setNumberValue(value).build();
+ }
+
+ @Override
+ void valueToString(StringBuilder b) {
+ b.append(value);
+ }
+
+ @Override
+ boolean valueEquals(Value v) {
+ // NaN == NaN always returns false, so we need a custom check.
+ if (Float.isNaN(this.value)) {
+ return Float.isNaN(((Float32Impl) v).value);
+ }
+ return ((Float32Impl) v).value == value;
+ }
+
+ @Override
+ int valueHash() {
+ // For backward compatibility of NaN equality checks with Float64 NaNs.
+ // Refer the comment in `Value.hashCode()` for more details.
+ if (!isNull() && Float.isNaN(value)) {
+ return Double.valueOf(Double.NaN).hashCode();
+ }
+ return Float.valueOf(value).hashCode();
+ }
+ }
+
private static class Float64Impl extends AbstractValue {
private final double value;
@@ -2106,6 +2260,46 @@ int arrayHash() {
}
}
+ private static class Float32ArrayImpl extends PrimitiveArrayImpl {
+ private final float[] values;
+
+ private Float32ArrayImpl(boolean isNull, BitSet nulls, float[] values) {
+ super(isNull, Type.float32(), nulls);
+ this.values = values;
+ }
+
+ @Override
+ public List getFloat32Array() {
+ return getArray();
+ }
+
+ @Override
+ boolean valueEquals(Value v) {
+ Float32ArrayImpl that = (Float32ArrayImpl) v;
+ return Arrays.equals(values, that.values);
+ }
+
+ @Override
+ int size() {
+ return values.length;
+ }
+
+ @Override
+ Float getValue(int i) {
+ return values[i];
+ }
+
+ @Override
+ com.google.protobuf.Value getValueAsProto(int i) {
+ return com.google.protobuf.Value.newBuilder().setNumberValue(values[i]).build();
+ }
+
+ @Override
+ int arrayHash() {
+ return Arrays.hashCode(values);
+ }
+ }
+
private static class Float64ArrayImpl extends PrimitiveArrayImpl {
private final double[] values;
@@ -2588,6 +2782,8 @@ private Value getValue(int fieldIndex) {
return Value.pgJsonb(value.getPgJsonb(fieldIndex));
case BYTES:
return Value.bytes(value.getBytes(fieldIndex));
+ case FLOAT32:
+ return Value.float32(value.getFloat(fieldIndex));
case FLOAT64:
return Value.float64(value.getDouble(fieldIndex));
case NUMERIC:
@@ -2622,6 +2818,8 @@ private Value getValue(int fieldIndex) {
case BYTES:
case PROTO:
return Value.bytesArray(value.getBytesList(fieldIndex));
+ case FLOAT32:
+ return Value.float32Array(value.getFloatList(fieldIndex));
case FLOAT64:
return Value.float64Array(value.getDoubleList(fieldIndex));
case NUMERIC:
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ValueBinder.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ValueBinder.java
index 9915e12175..d675686ffe 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ValueBinder.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/ValueBinder.java
@@ -81,6 +81,16 @@ public R to(@Nullable Long value) {
return handle(Value.int64(value));
}
+ /** Binds to {@code Value.float32(value)} */
+ public R to(float value) {
+ return handle(Value.float32(value));
+ }
+
+ /** Binds to {@code Value.float32(value)} */
+ public R to(@Nullable Float value) {
+ return handle(Value.float32(value));
+ }
+
/** Binds to {@code Value.float64(value)} */
public R to(double value) {
return handle(Value.float64(value));
@@ -198,6 +208,21 @@ public R toInt64Array(@Nullable Iterable values) {
return handle(Value.int64Array(values));
}
+ /** Binds to {@code Value.float32Array(values)} */
+ public R toFloat32Array(@Nullable float[] values) {
+ return handle(Value.float32Array(values));
+ }
+
+ /** Binds to {@code Value.float32Array(values, pos, length)} */
+ public R toFloat32Array(@Nullable float[] values, int pos, int length) {
+ return handle(Value.float32Array(values, pos, length));
+ }
+
+ /** Binds to {@code Value.float32Array(values)} */
+ public R toFloat32Array(@Nullable Iterable values) {
+ return handle(Value.float32Array(values));
+ }
+
/** Binds to {@code Value.float64Array(values)} */
public R toFloat64Array(@Nullable double[] values) {
return handle(Value.float64Array(values));
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java
index e9aed66b6b..8ff367b248 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionImpl.java
@@ -678,10 +678,6 @@ public void setStatementTag(String tag) {
*/
private void checkSetRetryAbortsInternallyAvailable() {
ConnectionPreconditions.checkState(!isClosed(), CLOSED_ERROR_MSG);
- ConnectionPreconditions.checkState(isInTransaction(), "This connection has no transaction");
- ConnectionPreconditions.checkState(
- getTransactionMode() == TransactionMode.READ_WRITE_TRANSACTION,
- "RetryAbortsInternally is only available for read-write transactions");
ConnectionPreconditions.checkState(
!isTransactionStarted(),
"RetryAbortsInternally cannot be set after the transaction has started");
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java
index 268661aef9..8bca0b2834 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ConnectionOptions.java
@@ -39,6 +39,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
+import io.opentelemetry.api.OpenTelemetry;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -484,6 +485,7 @@ public static class Builder {
private List statementExecutionInterceptors =
Collections.emptyList();
private SpannerOptionsConfigurator configurator;
+ private OpenTelemetry openTelemetry;
private Builder() {}
@@ -633,6 +635,11 @@ Builder setCredentials(Credentials credentials) {
return this;
}
+ public Builder setOpenTelemetry(OpenTelemetry openTelemetry) {
+ this.openTelemetry = openTelemetry;
+ return this;
+ }
+
/** @return the {@link ConnectionOptions} */
public ConnectionOptions build() {
Preconditions.checkState(this.uri != null, "Connection URI is required");
@@ -691,6 +698,7 @@ public static Builder newBuilder() {
private final boolean retryAbortsInternally;
private final boolean useVirtualThreads;
private final boolean useVirtualGrpcTransportThreads;
+ private final OpenTelemetry openTelemetry;
private final List statementExecutionInterceptors;
private final SpannerOptionsConfigurator configurator;
@@ -792,6 +800,7 @@ private ConnectionOptions(Builder builder) {
this.retryAbortsInternally = parseRetryAbortsInternally(this.uri);
this.useVirtualThreads = parseUseVirtualThreads(this.uri);
this.useVirtualGrpcTransportThreads = parseUseVirtualGrpcTransportThreads(this.uri);
+ this.openTelemetry = builder.openTelemetry;
this.statementExecutionInterceptors =
Collections.unmodifiableList(builder.statementExecutionInterceptors);
this.configurator = builder.configurator;
@@ -856,6 +865,14 @@ private static Integer parseIntegerProperty(String propertyName, String value) {
return null;
}
+ /**
+ * @return an instance of OpenTelemetry. If OpenTelemetry object is not set then null
+ * will be returned.
+ */
+ OpenTelemetry getOpenTelemetry() {
+ return this.openTelemetry;
+ }
+
SpannerOptionsConfigurator getConfigurator() {
return configurator;
}
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java
index 1b15ec5082..b5e4060ddd 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java
@@ -180,6 +180,12 @@ public long getLong(String columnName) {
return delegate.getLong(columnName);
}
+ @Override
+ public float getFloat(int columnIndex) {
+ Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL);
+ return delegate.getFloat(columnIndex);
+ }
+
@Override
public double getDouble(int columnIndex) {
Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL);
@@ -198,6 +204,12 @@ public BigDecimal getBigDecimal(int columnIndex) {
return delegate.getBigDecimal(columnIndex);
}
+ @Override
+ public float getFloat(String columnName) {
+ Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL);
+ return delegate.getFloat(columnName);
+ }
+
@Override
public double getDouble(String columnName) {
Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL);
@@ -336,6 +348,30 @@ public List getLongList(String columnName) {
return delegate.getLongList(columnName);
}
+ @Override
+ public float[] getFloatArray(int columnIndex) {
+ Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL);
+ return delegate.getFloatArray(columnIndex);
+ }
+
+ @Override
+ public float[] getFloatArray(String columnName) {
+ Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL);
+ return delegate.getFloatArray(columnName);
+ }
+
+ @Override
+ public List getFloatList(int columnIndex) {
+ Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL);
+ return delegate.getFloatList(columnIndex);
+ }
+
+ @Override
+ public List getFloatList(String columnName) {
+ Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL);
+ return delegate.getFloatList(columnName);
+ }
+
@Override
public double[] getDoubleArray(int columnIndex) {
Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL);
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSet.java
index a8de14e512..bd7c794a0f 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSet.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSet.java
@@ -189,6 +189,18 @@ public long getLong(String columnName) {
return delegate.getLong(columnName);
}
+ @Override
+ public float getFloat(int columnIndex) {
+ checkClosed();
+ return delegate.getFloat(columnIndex);
+ }
+
+ @Override
+ public float getFloat(String columnName) {
+ checkClosed();
+ return delegate.getFloat(columnName);
+ }
+
@Override
public double getDouble(int columnIndex) {
checkClosed();
@@ -345,6 +357,30 @@ public List getLongList(String columnName) {
return delegate.getLongList(columnName);
}
+ @Override
+ public float[] getFloatArray(int columnIndex) {
+ checkClosed();
+ return delegate.getFloatArray(columnIndex);
+ }
+
+ @Override
+ public float[] getFloatArray(String columnName) {
+ checkClosed();
+ return delegate.getFloatArray(columnName);
+ }
+
+ @Override
+ public List getFloatList(int columnIndex) {
+ checkClosed();
+ return delegate.getFloatList(columnIndex);
+ }
+
+ @Override
+ public List getFloatList(String columnName) {
+ checkClosed();
+ return delegate.getFloatList(columnName);
+ }
+
@Override
public double[] getDoubleArray(int columnIndex) {
checkClosed();
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java
index da8da78d92..b4ac7cf3a3 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SpannerPool.java
@@ -29,6 +29,7 @@
import com.google.common.base.Preconditions;
import com.google.common.base.Ticker;
import io.grpc.ManagedChannelBuilder;
+import io.opentelemetry.api.OpenTelemetry;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -156,6 +157,7 @@ static class SpannerPoolKey {
private final String databaseRole;
private final boolean routeToLeader;
private final boolean useVirtualGrpcTransportThreads;
+ private final OpenTelemetry openTelemetry;
@VisibleForTesting
static SpannerPoolKey of(ConnectionOptions options) {
@@ -183,6 +185,7 @@ private SpannerPoolKey(ConnectionOptions options) throws IOException {
this.userAgent = options.getUserAgent();
this.routeToLeader = options.isRouteToLeader();
this.useVirtualGrpcTransportThreads = options.isUseVirtualGrpcTransportThreads();
+ this.openTelemetry = options.getOpenTelemetry();
}
@Override
@@ -201,7 +204,8 @@ public boolean equals(Object o) {
&& Objects.equals(this.userAgent, other.userAgent)
&& Objects.equals(this.routeToLeader, other.routeToLeader)
&& Objects.equals(
- this.useVirtualGrpcTransportThreads, other.useVirtualGrpcTransportThreads);
+ this.useVirtualGrpcTransportThreads, other.useVirtualGrpcTransportThreads)
+ && Objects.equals(this.openTelemetry, other.openTelemetry);
}
@Override
@@ -216,7 +220,8 @@ public int hashCode() {
this.databaseRole,
this.userAgent,
this.routeToLeader,
- this.useVirtualGrpcTransportThreads);
+ this.useVirtualGrpcTransportThreads,
+ this.openTelemetry);
}
}
@@ -349,6 +354,9 @@ Spanner createSpanner(SpannerPoolKey key, ConnectionOptions options) {
.setDatabaseRole(options.getDatabaseRole())
.setCredentials(options.getCredentials());
builder.setSessionPoolOption(key.sessionPoolOptions);
+ if (key.openTelemetry != null) {
+ builder.setOpenTelemetry(key.openTelemetry);
+ }
if (key.numChannels != null) {
builder.setNumChannels(key.numChannels);
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractLatencyBenchmark.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractLatencyBenchmark.java
new file mode 100644
index 0000000000..d7edf64030
--- /dev/null
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractLatencyBenchmark.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.spanner;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public abstract class AbstractLatencyBenchmark {
+
+ /** Utility to print latency numbers. It computes metrics such as Average, P50, P95 and P99. */
+ public void printResults(List results) {
+ if (results == null) {
+ return;
+ }
+ List orderedResults = new ArrayList<>(results);
+ Collections.sort(orderedResults);
+ System.out.println();
+ System.out.printf("Total number of queries: %d\n", orderedResults.size());
+ System.out.printf("Avg: %fs\n", avg(results));
+ System.out.printf("P50: %fs\n", percentile(50, orderedResults));
+ System.out.printf("P95: %fs\n", percentile(95, orderedResults));
+ System.out.printf("P99: %fs\n", percentile(99, orderedResults));
+ }
+
+ private double percentile(int percentile, List orderedResults) {
+ int index = percentile * orderedResults.size() / 100;
+ Duration value = orderedResults.get(index);
+ Double convertedValue = convertDurationToFractionInSeconds(value);
+ return convertedValue;
+ }
+
+ /** Returns the average duration in seconds from a list of duration values. */
+ private double avg(List results) {
+ return results.stream()
+ .collect(Collectors.averagingDouble(this::convertDurationToFractionInSeconds));
+ }
+
+ private double convertDurationToFractionInSeconds(Duration duration) {
+ long seconds = duration.getSeconds();
+ long nanos = duration.getNano();
+ double fraction = (double) nanos / 1_000_000_000;
+ double value = seconds + fraction;
+ return value;
+ }
+}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java
index 4fc3c67ceb..16dd51a36a 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java
@@ -58,6 +58,11 @@ protected long getLongInternal(int columnIndex) {
return 0;
}
+ @Override
+ protected float getFloatInternal(int columnIndex) {
+ return 0f;
+ }
+
@Override
protected double getDoubleInternal(int columnIndex) {
return 0;
@@ -134,6 +139,16 @@ protected List getLongListInternal(int columnIndex) {
return null;
}
+ @Override
+ protected float[] getFloatArrayInternal(int columnIndex) {
+ return null;
+ }
+
+ @Override
+ protected List getFloatListInternal(int columnIndex) {
+ return null;
+ }
+
@Override
protected double[] getDoubleArrayInternal(int columnIndex) {
return null;
@@ -222,6 +237,13 @@ public static Collection parameters() {
Collections.singletonList("getValue")
},
{Type.int64(), "getLongInternal", 123L, "getLong", Collections.singletonList("getValue")},
+ {
+ Type.float32(),
+ "getFloatInternal",
+ 2.0f,
+ "getFloat",
+ Collections.singletonList("getValue")
+ },
{
Type.float64(),
"getDoubleInternal",
@@ -306,6 +328,20 @@ public static Collection parameters() {
"getLongList",
Arrays.asList("getLongArray", "getValue")
},
+ {
+ Type.array(Type.float32()),
+ "getFloatArrayInternal",
+ new float[] {1.0f, 2.0f},
+ "getFloatArray",
+ Arrays.asList("getFloatList", "getValue")
+ },
+ {
+ Type.array(Type.float32()),
+ "getFloatListInternal",
+ Arrays.asList(2.0f, 4.0f),
+ "getFloatList",
+ Arrays.asList("getFloatArray", "getValue")
+ },
{
Type.array(Type.float64()),
"getDoubleArrayInternal",
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncResultSetImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncResultSetImplTest.java
index 9a6bafa7bf..98497fbf14 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncResultSetImplTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncResultSetImplTest.java
@@ -193,9 +193,9 @@ public void withCallback() throws InterruptedException {
});
}
finishedLatch.await();
- // There should be between 1 and 4 callbacks, depending on the timing of the threads.
+ // There should be between 1 and 5 callbacks, depending on the timing of the threads.
// Normally, there should be just 1 callback.
- assertThat(callbackCounter.get()).isIn(Range.closed(1, 4));
+ assertThat(callbackCounter.get()).isIn(Range.closed(1, 5));
assertThat(rowCounter.get()).isEqualTo(3);
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BenchmarkingUtilityScripts.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BenchmarkingUtilityScripts.java
new file mode 100644
index 0000000000..75e0ca3da0
--- /dev/null
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/BenchmarkingUtilityScripts.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.spanner;
+
+import com.google.api.gax.rpc.ServerStream;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningScheduledExecutorService;
+import com.google.rpc.Code;
+import com.google.spanner.v1.BatchWriteResponse;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Hosts a bunch of utility methods/scripts that can be used while performing benchmarks to load
+ * data, report latency metrics, etc.
+ *
+ * Table schema used here: CREATE TABLE FOO ( id INT64 NOT NULL, BAZ INT64, BAR INT64, ) PRIMARY
+ * KEY(id);
+ */
+@Category(SlowTest.class)
+@RunWith(JUnit4.class)
+public class BenchmarkingUtilityScripts {
+
+ // TODO(developer): Add your values here for PROJECT_ID, INSTANCE_ID, DATABASE_ID
+ // TODO(developer): By default these values are blank and should be replaced before a run.
+ private static final String PROJECT_ID = "";
+ private static final String INSTANCE_ID = "";
+ private static final String DATABASE_ID = "";
+ private static final String SERVER_URL = "https://staging-wrenchworks.sandbox.googleapis.com";
+ private static DatabaseClient client;
+ private static Spanner spanner;
+
+ @BeforeClass
+ public static void beforeClass() {
+ final SpannerOptions.Builder optionsBuilder =
+ SpannerOptions.newBuilder()
+ .setProjectId(PROJECT_ID)
+ .setAutoThrottleAdministrativeRequests();
+ if (!SERVER_URL.isEmpty()) {
+ optionsBuilder.setHost(SERVER_URL);
+ }
+ final SpannerOptions options = optionsBuilder.build();
+ spanner = options.getService();
+ client = spanner.getDatabaseClient(DatabaseId.of(PROJECT_ID, INSTANCE_ID, DATABASE_ID));
+
+ // Delete all existing data from the table
+ client.write(ImmutableList.of(Mutation.delete("FOO", KeySet.all())));
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ spanner.close();
+ }
+
+ /**
+ * A utility which bulk inserts 10^6 records into the database in batches. The method assumes that
+ * the instance/database/table is already created. It does not perform any admin operations.
+ *
+ *
Table schema used here: CREATE TABLE FOO ( id INT64 NOT NULL, BAZ INT64, BAR INT64, )
+ * PRIMARY KEY(id);
+ */
+ @Test
+ public void bulkInsertTestData() {
+ int key = 0;
+ List mutationGroups = new ArrayList<>();
+ for (int batch = 0; batch < 100; batch++) {
+ List mutations = new LinkedList<>();
+ for (int i = 0; i < 10000; i++) {
+ mutations.add(
+ Mutation.newInsertBuilder("FOO")
+ .set("id")
+ .to(key)
+ .set("BAZ")
+ .to(1)
+ .set("BAR")
+ .to(2)
+ .build());
+ key++;
+ }
+ mutationGroups.add(MutationGroup.of(mutations));
+ }
+ ServerStream responses = client.batchWriteAtLeastOnce(mutationGroups);
+ for (BatchWriteResponse response : responses) {
+ if (response.getStatus().getCode() == Code.OK_VALUE) {
+ System.out.printf(
+ "Mutation group indexes %s have been applied with commit timestamp %s",
+ response.getIndexesList(), response.getCommitTimestamp());
+ } else {
+ System.out.printf(
+ "Mutation group indexes %s could not be applied with error code %s and "
+ + "error message %s",
+ response.getIndexesList(),
+ Code.forNumber(response.getStatus().getCode()),
+ response.getStatus().getMessage());
+ }
+ }
+ }
+
+ /** Collects all results from a collection of future objects. */
+ public static List collectResults(
+ final ListeningScheduledExecutorService service,
+ final List>> results,
+ final int numOperations,
+ final Duration timeoutDuration)
+ throws Exception {
+ service.shutdown();
+ if (!service.awaitTermination(timeoutDuration.toMinutes(), TimeUnit.MINUTES)) {
+ throw new TimeoutException();
+ }
+ List allResults = new ArrayList<>(numOperations);
+ for (Future> result : results) {
+ allResults.addAll(result.get());
+ }
+ return allResults;
+ }
+}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java
index 8dfbb986eb..7cba80edd8 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java
@@ -4083,6 +4083,7 @@ public void testGetAllTypesAsString() {
int col = 0;
assertAsString("true", resultSet, col++);
assertAsString("100", resultSet, col++);
+ assertAsString("-3.14", resultSet, col++);
assertAsString("3.14", resultSet, col++);
assertAsString("6.626", resultSet, col++);
assertAsString("test-string", resultSet, col++);
@@ -4100,6 +4101,15 @@ public void testGetAllTypesAsString() {
String.format("%d", Long.MAX_VALUE), String.format("%d", Long.MIN_VALUE), "NULL"),
resultSet,
col++);
+ assertAsString(
+ ImmutableList.of(
+ "NULL",
+ Float.valueOf(Float.MAX_VALUE).toString(),
+ Float.valueOf(Float.MIN_VALUE).toString(),
+ "NaN",
+ "3.14"),
+ resultSet,
+ col++);
assertAsString(ImmutableList.of("NULL", "-12345.6789", "3.14"), resultSet, col++);
assertAsString(ImmutableList.of("6.626", "NULL", "-8.9123"), resultSet, col++);
assertAsString(ImmutableList.of("test-string1", "NULL", "test-string2"), resultSet, col++);
@@ -4561,6 +4571,7 @@ private ListValue getRows(Dialect dialect) {
ListValue.newBuilder()
.addValues(com.google.protobuf.Value.newBuilder().setBoolValue(true).build())
.addValues(com.google.protobuf.Value.newBuilder().setStringValue("100").build())
+ .addValues(com.google.protobuf.Value.newBuilder().setNumberValue(-3.14f).build())
.addValues(com.google.protobuf.Value.newBuilder().setNumberValue(3.14d).build())
.addValues(com.google.protobuf.Value.newBuilder().setStringValue("6.626").build())
.addValues(com.google.protobuf.Value.newBuilder().setStringValue("test-string").build())
@@ -4609,6 +4620,31 @@ private ListValue getRows(Dialect dialect) {
.setNullValue(NullValue.NULL_VALUE)
.build())
.build()))
+ .addValues(
+ com.google.protobuf.Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addValues(
+ com.google.protobuf.Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build())
+ .addValues(
+ com.google.protobuf.Value.newBuilder()
+ .setNumberValue(Float.MAX_VALUE)
+ .build())
+ .addValues(
+ com.google.protobuf.Value.newBuilder()
+ .setNumberValue(Float.MIN_VALUE)
+ .build())
+ .addValues(
+ com.google.protobuf.Value.newBuilder()
+ .setStringValue("NaN")
+ .build())
+ .addValues(
+ com.google.protobuf.Value.newBuilder()
+ .setNumberValue(3.14f)
+ .build())
+ .build()))
.addValues(
com.google.protobuf.Value.newBuilder()
.setListValue(
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DefaultBenchmark.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DefaultBenchmark.java
new file mode 100644
index 0000000000..84578dd323
--- /dev/null
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DefaultBenchmark.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.spanner;
+
+import static com.google.cloud.spanner.BenchmarkingUtilityScripts.collectResults;
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningScheduledExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import org.openjdk.jmh.annotations.AuxCounters;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Level;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Warmup;
+
+/**
+ * Benchmarks for measuring existing latencies of various APIs using the Java Client. The benchmarks
+ * are bound to the Maven profile `benchmark` and can be executed like this: mvn clean test
+ * -DskipTests -Pbenchmark -Dbenchmark.name=DefaultBenchmark
+ *
Test Table Schema :
+ *
+ * CREATE TABLE FOO ( id INT64 NOT NULL, BAZ INT64, BAR INT64, ) PRIMARY KEY(id);
+ *
+ *
Below are a few considerations here: 1. We use all default options for this test because that
+ * is what most customers would be using. 2. The test schema uses a numeric primary key. To ensure
+ * that the reads/updates are distributed across a large query space, we insert 10^5 records.
+ * Utility at {@link BenchmarkingUtilityScripts} can be used for loading data. 3. For queries, we
+ * make sure that the query is sampled randomly across a large query space. This ensure we don't
+ * cause hot-spots. 4. For avoid cold start issues, we execute 1 query/update and ignore its latency
+ * from the final reported metrics.
+ */
+@BenchmarkMode(Mode.AverageTime)
+@Fork(value = 1, warmups = 0)
+@Measurement(batchSize = 1, iterations = 1, timeUnit = TimeUnit.MILLISECONDS)
+@OutputTimeUnit(TimeUnit.SECONDS)
+@Warmup(iterations = 1)
+public class DefaultBenchmark extends AbstractLatencyBenchmark {
+
+ private static final String SELECT_QUERY = "SELECT ID FROM FOO WHERE ID = @id";
+ private static final String UPDATE_QUERY = "UPDATE FOO SET BAR=1 WHERE ID = @id";
+ private static final String ID_COLUMN_NAME = "id";
+
+ /**
+ * Used to determine how many concurrent requests are allowed. For ex - To simulate a low QPS
+ * scenario, using 1 thread means there will be 1 request. Use a value > 1 to have concurrent
+ * requests.
+ */
+ private static final int PARALLEL_THREADS = 1;
+
+ /**
+ * Total number of reads per test run for 1 thread. Increasing the value here will increase the
+ * duration of the benchmark. For ex - With PARALLEL_THREADS = 2, TOTAL_READS_PER_RUN = 200, there
+ * will be 400 read requests (200 on each thread).
+ */
+ private static final int TOTAL_READS_PER_RUN = 12000;
+
+ /**
+ * Total number of writes per test run for 1 thread. Increasing the value here will increase the
+ * duration of the benchmark. For ex - With PARALLEL_THREADS = 2, TOTAL_WRITES_PER_RUN = 200,
+ * there will be 400 write requests (200 on each thread).
+ */
+ private static final int TOTAL_WRITES_PER_RUN = 4000;
+
+ /**
+ * Number of requests which are used to initialise/warmup the benchmark. The latency number of
+ * these runs are ignored from the final reported results.
+ */
+ private static final int WARMUP_REQUEST_COUNT = 1;
+
+ /**
+ * Numbers of records in the sample table used in the benchmark. This is used in this benchmark to
+ * randomly choose a primary key and ensure that the reads are randomly distributed. This is done
+ * to ensure we don't end up reading/writing the same table record (leading to hot-spotting).
+ */
+ private static final int TOTAL_RECORDS = 1000000;
+
+ @State(Scope.Thread)
+ @AuxCounters(org.openjdk.jmh.annotations.AuxCounters.Type.EVENTS)
+ public static class BenchmarkState {
+
+ // TODO(developer): Add your values here for PROJECT_ID, INSTANCE_ID, DATABASE_ID
+ private static final String INSTANCE_ID = "";
+ private static final String DATABASE_ID = "";
+ private static final String SERVER_URL = "https://staging-wrenchworks.sandbox.googleapis.com";
+ private Spanner spanner;
+ private DatabaseClientImpl client;
+
+ @Setup(Level.Iteration)
+ public void setup() throws Exception {
+ SpannerOptions options =
+ SpannerOptions.newBuilder()
+ .setSessionPoolOption(
+ SessionPoolOptions.newBuilder()
+ .setWaitForMinSessions(org.threeten.bp.Duration.ofSeconds(20))
+ .build())
+ .setHost(SERVER_URL)
+ .build();
+ spanner = options.getService();
+ client =
+ (DatabaseClientImpl)
+ spanner.getDatabaseClient(
+ DatabaseId.of(options.getProjectId(), INSTANCE_ID, DATABASE_ID));
+ }
+
+ @TearDown(Level.Iteration)
+ public void teardown() throws Exception {
+ spanner.close();
+ }
+ }
+
+ /** Measures the time needed to execute a burst of queries. */
+ @Benchmark
+ public void burstQueries(final BenchmarkState server) throws Exception {
+ final DatabaseClientImpl client = server.client;
+ SessionPool pool = client.pool;
+ assertThat(pool.totalSessions())
+ .isEqualTo(server.spanner.getOptions().getSessionPoolOptions().getMinSessions());
+
+ ListeningScheduledExecutorService service =
+ MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(PARALLEL_THREADS));
+ List>> results = new ArrayList<>(PARALLEL_THREADS);
+ for (int i = 0; i < PARALLEL_THREADS; i++) {
+ results.add(service.submit(() -> runBenchmarksForQueries(server, TOTAL_READS_PER_RUN)));
+ }
+ collectResultsAndPrint(service, results, TOTAL_READS_PER_RUN);
+ }
+
+ /** Measures the time needed to execute a burst of read and write requests. */
+ @Benchmark
+ public void burstQueriesAndWrites(final BenchmarkState server) throws Exception {
+ final DatabaseClientImpl client = server.client;
+ SessionPool pool = client.pool;
+ assertThat(pool.totalSessions())
+ .isEqualTo(server.spanner.getOptions().getSessionPoolOptions().getMinSessions());
+
+ ListeningScheduledExecutorService service =
+ MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(PARALLEL_THREADS));
+ List>> results = new ArrayList<>(PARALLEL_THREADS);
+ for (int i = 0; i < PARALLEL_THREADS; i++) {
+ results.add(service.submit(() -> runBenchmarksForQueries(server, TOTAL_READS_PER_RUN)));
+ }
+ for (int i = 0; i < PARALLEL_THREADS; i++) {
+ results.add(service.submit(() -> runBenchmarkForUpdates(server, TOTAL_WRITES_PER_RUN)));
+ }
+
+ collectResultsAndPrint(service, results, TOTAL_READS_PER_RUN + TOTAL_WRITES_PER_RUN);
+ }
+
+ /** Measures the time needed to execute a burst of read and write requests. */
+ @Benchmark
+ public void burstUpdates(final BenchmarkState server) throws Exception {
+ final DatabaseClientImpl client = server.client;
+ SessionPool pool = client.pool;
+ assertThat(pool.totalSessions())
+ .isEqualTo(server.spanner.getOptions().getSessionPoolOptions().getMinSessions());
+
+ ListeningScheduledExecutorService service =
+ MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(PARALLEL_THREADS));
+ List>> results = new ArrayList<>(PARALLEL_THREADS);
+ for (int i = 0; i < PARALLEL_THREADS; i++) {
+ results.add(service.submit(() -> runBenchmarkForUpdates(server, TOTAL_WRITES_PER_RUN)));
+ }
+
+ collectResultsAndPrint(service, results, TOTAL_WRITES_PER_RUN);
+ }
+
+ private List runBenchmarksForQueries(
+ final BenchmarkState server, int numberOfOperations) {
+ List results = new ArrayList<>(numberOfOperations);
+ // Execute one query to make sure everything has been warmed up.
+ executeWarmup(server);
+
+ for (int i = 0; i < numberOfOperations; i++) {
+ results.add(executeQuery(server));
+ }
+ return results;
+ }
+
+ private void executeWarmup(final BenchmarkState server) {
+ for (int i = 0; i < WARMUP_REQUEST_COUNT; i++) {
+ executeQuery(server);
+ }
+ }
+
+ private java.time.Duration executeQuery(final BenchmarkState server) {
+ Stopwatch watch = Stopwatch.createStarted();
+
+ try (ResultSet rs = server.client.singleUse().executeQuery(getRandomisedReadStatement())) {
+ while (rs.next()) {
+ int count = rs.getColumnCount();
+ }
+ }
+ return watch.elapsed();
+ }
+
+ private List runBenchmarkForUpdates(
+ final BenchmarkState server, int numberOfOperations) {
+ List results = new ArrayList<>(numberOfOperations);
+ // Execute one query to make sure everything has been warmed up.
+ executeWarmup(server);
+
+ // Execute one update to make sure everything has been warmed up.
+ executeUpdate(server);
+
+ for (int i = 0; i < numberOfOperations; i++) {
+ results.add(executeUpdate(server));
+ }
+ return results;
+ }
+
+ private Duration executeUpdate(final BenchmarkState server) {
+ Stopwatch watch = Stopwatch.createStarted();
+
+ TransactionRunner runner = server.client.readWriteTransaction();
+ runner.run(transaction -> transaction.executeUpdate(getRandomisedUpdateStatement()));
+
+ return watch.elapsed();
+ }
+
+ static Statement getRandomisedReadStatement() {
+ int randomKey = ThreadLocalRandom.current().nextInt(TOTAL_RECORDS);
+ return Statement.newBuilder(SELECT_QUERY).bind(ID_COLUMN_NAME).to(randomKey).build();
+ }
+
+ static Statement getRandomisedUpdateStatement() {
+ int randomKey = ThreadLocalRandom.current().nextInt(TOTAL_RECORDS);
+ return Statement.newBuilder(UPDATE_QUERY).bind(ID_COLUMN_NAME).to(randomKey).build();
+ }
+
+ void collectResultsAndPrint(
+ ListeningScheduledExecutorService service,
+ List>> results,
+ int numOperationsPerThread)
+ throws Exception {
+ final List collectResults =
+ collectResults(
+ service, results, numOperationsPerThread * PARALLEL_THREADS, Duration.ofMinutes(60));
+ printResults(collectResults);
+ }
+}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java
index cb73618d99..5e6a4ffc2c 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java
@@ -537,6 +537,8 @@ public void serialization() {
Value.int64(null),
Value.float64(1.0),
Value.float64(null),
+ Value.float32(1.0f),
+ Value.float32(null),
Value.bytes(ByteArray.fromBase64("abcd")),
Value.bytesFromBase64(
Base64.getEncoder().encodeToString("test".getBytes(StandardCharsets.UTF_8))),
@@ -554,6 +556,8 @@ public void serialization() {
Value.int64Array((long[]) null),
Value.float64Array(new double[] {1.1, 2.2, 3.3}),
Value.float64Array((double[]) null),
+ Value.float32Array(new float[] {1.1f, 2.2f, 3.3f}),
+ Value.float32Array((float[]) null),
Value.bytesArray(Arrays.asList(ByteArray.fromBase64("abcd"), null)),
Value.bytesArrayFromBase64(
Arrays.asList(
@@ -655,6 +659,22 @@ public void getDouble() {
assertThat(resultSet.getDouble(0)).isWithin(0.0).of(Double.MAX_VALUE);
}
+ @Test
+ public void getFloat() {
+ consumer.onPartialResultSet(
+ PartialResultSet.newBuilder()
+ .setMetadata(makeMetadata(Type.struct(Type.StructField.of("f", Type.float32()))))
+ .addValues(Value.float32(Float.MIN_VALUE).toProto())
+ .addValues(Value.float32(Float.MAX_VALUE).toProto())
+ .build());
+ consumer.onCompleted();
+
+ assertThat(resultSet.next()).isTrue();
+ assertThat(resultSet.getFloat(0)).isWithin(0.0f).of(Float.MIN_VALUE);
+ assertThat(resultSet.next()).isTrue();
+ assertThat(resultSet.getFloat(0)).isWithin(0.0f).of(Float.MAX_VALUE);
+ }
+
@Test
public void getBigDecimal() {
consumer.onPartialResultSet(
@@ -877,6 +897,25 @@ public void getDoubleArray() {
.inOrder();
}
+ @Test
+ public void getFloatArray() {
+ float[] floatArray = {Float.MAX_VALUE, Float.MIN_VALUE, 111, 333, 444, 0, -1, -2234};
+
+ consumer.onPartialResultSet(
+ PartialResultSet.newBuilder()
+ .setMetadata(
+ makeMetadata(Type.struct(Type.StructField.of("f", Type.array(Type.float32())))))
+ .addValues(Value.float32Array(floatArray).toProto())
+ .build());
+ consumer.onCompleted();
+
+ assertThat(resultSet.next()).isTrue();
+ assertThat(resultSet.getFloatArray(0))
+ .usingTolerance(0.0)
+ .containsExactly(floatArray)
+ .inOrder();
+ }
+
@Test
public void getBigDecimalList() {
List bigDecimalsList = new ArrayList<>();
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InlineBeginTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InlineBeginTransactionTest.java
index c7f5e39606..c67c008467 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InlineBeginTransactionTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InlineBeginTransactionTest.java
@@ -37,6 +37,7 @@
import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
import com.google.cloud.spanner.TransactionRunner.TransactionCallable;
import com.google.cloud.spanner.TransactionRunnerImpl.TransactionContextImpl;
+import com.google.cloud.spanner.connection.RandomResultSetGenerator;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.protobuf.AbstractMessage;
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java
index f27aa405aa..7073ebd28e 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MockSpannerServiceImpl.java
@@ -1284,6 +1284,9 @@ private Statement buildStatement(
case DATE:
builder.bind(fieldName).toDateArray(null);
break;
+ case FLOAT32:
+ builder.bind(fieldName).toFloat32Array((Iterable) null);
+ break;
case FLOAT64:
builder.bind(fieldName).toFloat64Array((Iterable) null);
break;
@@ -1327,6 +1330,9 @@ private Statement buildStatement(
case DATE:
builder.bind(fieldName).to((Date) null);
break;
+ case FLOAT32:
+ builder.bind(fieldName).to((Float) null);
+ break;
case FLOAT64:
builder.bind(fieldName).to((Double) null);
break;
@@ -1392,6 +1398,14 @@ private Statement buildStatement(
GrpcStruct.decodeArrayValue(
com.google.cloud.spanner.Type.date(), value.getListValue()));
break;
+ case FLOAT32:
+ builder
+ .bind(fieldName)
+ .toFloat32Array(
+ (Iterable)
+ GrpcStruct.decodeArrayValue(
+ com.google.cloud.spanner.Type.float32(), value.getListValue()));
+ break;
case FLOAT64:
builder
.bind(fieldName)
@@ -1475,6 +1489,9 @@ private Statement buildStatement(
case DATE:
builder.bind(fieldName).to(Date.parseDate(value.getStringValue()));
break;
+ case FLOAT32:
+ builder.bind(fieldName).to((float) value.getNumberValue());
+ break;
case FLOAT64:
builder.bind(fieldName).to(value.getNumberValue());
break;
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutationTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutationTest.java
index f38b5e47b8..0cfb57d4a2 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutationTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutationTest.java
@@ -211,12 +211,37 @@ public void equalsAndHashCode() {
Mutation.delete("T1", KeySet.singleKey(Key.of("k"))), Mutation.delete("T1", Key.of("k")));
// Test NaNs
+ // Refer the comment in `Value.hashCode()` for more details on NaN equality.
tester.addEqualityGroup(
Mutation.newInsertBuilder("T1").set("C").to(Double.NaN).build(),
Mutation.newInsertBuilder("T1").set("C").to(Value.float64(Double.NaN)).build(),
Mutation.newInsertBuilder("T1").set("C").to(Float.NaN).build(),
- Mutation.newInsertBuilder("T1").set("C").to(Value.float64(Float.NaN)).build());
+ Mutation.newInsertBuilder("T1").set("C").to(Value.float64(Float.NaN)).build(),
+ Mutation.newInsertBuilder("T1").set("C").to(Value.float32(Float.NaN)).build());
+ // Test NaN arrays
+ tester.addEqualityGroup(
+ Mutation.newInsertBuilder("T1").set("C").toFloat32Array(new float[] {Float.NaN}).build(),
+ Mutation.newInsertBuilder("T1")
+ .set("C")
+ .toFloat32Array(new float[] {Float.NaN}, 0, 1)
+ .build(),
+ Mutation.newInsertBuilder("T1")
+ .set("C")
+ .toFloat32Array(Collections.singletonList(Float.NaN))
+ .build(),
+ Mutation.newInsertBuilder("T1")
+ .set("C")
+ .to(Value.float32Array(new float[] {Float.NaN}))
+ .build(),
+ Mutation.newInsertBuilder("T1")
+ .set("C")
+ .to(Value.float32Array(new float[] {Float.NaN}, 0, 1))
+ .build(),
+ Mutation.newInsertBuilder("T1")
+ .set("C")
+ .to(Value.float32Array(Collections.singletonList(Float.NaN)))
+ .build());
tester.addEqualityGroup(
Mutation.newInsertBuilder("T1").set("C").toFloat64Array(new double[] {Double.NaN}).build(),
Mutation.newInsertBuilder("T1").set("C").toFloat64Array(new double[] {Float.NaN}).build(),
@@ -270,6 +295,11 @@ public void equalsAndHashCode() {
.set("C")
.toFloat64Array(Arrays.asList(null, (double) Float.NaN))
.build());
+ tester.addEqualityGroup(
+ Mutation.newInsertBuilder("T1")
+ .set("C")
+ .toFloat32Array(Arrays.asList(null, Float.NaN))
+ .build());
tester.testEquals();
}
@@ -523,11 +553,17 @@ private Mutation.WriteBuilder appendAllTypes(Mutation.WriteBuilder builder) {
.to((Long) null)
.set("intValue")
.to(Value.int64(1L))
- .set("float")
+ .set("float32")
+ .to(42.1f)
+ .set("float32Null")
+ .to((Float) null)
+ .set("float32Value")
+ .to(Value.float32(10f))
+ .set("float64")
.to(42.1)
- .set("floatNull")
+ .set("float64Null")
.to((Double) null)
- .set("floatValue")
+ .set("float64Value")
.to(Value.float64(10D))
.set("string")
.to("str")
@@ -583,11 +619,17 @@ private Mutation.WriteBuilder appendAllTypes(Mutation.WriteBuilder builder) {
.toInt64Array((long[]) null)
.set("intArrValue")
.to(Value.int64Array(ImmutableList.of(1L, 2L)))
- .set("floatArr")
+ .set("float32Arr")
+ .toFloat32Array(new float[] {1.1f, 2.2f, 3.3f})
+ .set("float32ArrNull")
+ .toFloat32Array((float[]) null)
+ .set("float32ArrValue")
+ .to(Value.float32Array(ImmutableList.of(10.1F, 10.2F, 10.3F)))
+ .set("float64Arr")
.toFloat64Array(new double[] {1.1, 2.2, 3.3})
- .set("floatArrNull")
+ .set("float64ArrNull")
.toFloat64Array((double[]) null)
- .set("floatArrValue")
+ .set("float64ArrValue")
.to(Value.float64Array(ImmutableList.of(10.1D, 10.2D, 10.3D)))
.set("stringArr")
.toStringArray(ImmutableList.of("one", "two"))
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RandomResultSetGenerator.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RandomResultSetGenerator.java
index b5bbb9dd49..058429d3ba 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RandomResultSetGenerator.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/RandomResultSetGenerator.java
@@ -31,12 +31,15 @@
import com.google.spanner.v1.TypeCode;
import java.util.Random;
+/** @deprecated Use {@link com.google.cloud.spanner.connection.RandomResultSetGenerator} instead. */
+@Deprecated
public class RandomResultSetGenerator {
private static final Type[] TYPES =
new Type[] {
Type.newBuilder().setCode(TypeCode.BOOL).build(),
Type.newBuilder().setCode(TypeCode.INT64).build(),
Type.newBuilder().setCode(TypeCode.FLOAT64).build(),
+ Type.newBuilder().setCode(TypeCode.FLOAT32).build(),
Type.newBuilder().setCode(TypeCode.STRING).build(),
Type.newBuilder().setCode(TypeCode.BYTES).build(),
Type.newBuilder().setCode(TypeCode.DATE).build(),
@@ -53,6 +56,10 @@ public class RandomResultSetGenerator {
.setCode(TypeCode.ARRAY)
.setArrayElementType(Type.newBuilder().setCode(TypeCode.FLOAT64))
.build(),
+ Type.newBuilder()
+ .setCode(TypeCode.ARRAY)
+ .setArrayElementType(Type.newBuilder().setCode(TypeCode.FLOAT32))
+ .build(),
Type.newBuilder()
.setCode(TypeCode.ARRAY)
.setArrayElementType(Type.newBuilder().setCode(TypeCode.STRING))
@@ -138,6 +145,9 @@ private void setRandomValue(Value.Builder builder, Type type) {
case FLOAT64:
builder.setNumberValue(random.nextDouble());
break;
+ case FLOAT32:
+ builder.setNumberValue(random.nextFloat());
+ break;
case INT64:
builder.setStringValue(String.valueOf(random.nextLong()));
break;
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadAsyncTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadAsyncTest.java
index bb8d130914..6801c82b66 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadAsyncTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadAsyncTest.java
@@ -298,9 +298,12 @@ public void readOnlyTransaction() throws Exception {
values2 = rs.toListAsync(input -> input.getString("Value"), executor);
}
}
+
+ ApiFuture>> allValuesAsList =
+ ApiFutures.allAsList(Arrays.asList(values1, values2));
ApiFuture> allValues =
ApiFutures.transform(
- ApiFutures.allAsList(Arrays.asList(values1, values2)),
+ allValuesAsList,
input ->
Iterables.mergeSorted(
input,
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadFormatTestRunner.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadFormatTestRunner.java
index a72c9872fa..8d97d9d894 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadFormatTestRunner.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadFormatTestRunner.java
@@ -170,6 +170,9 @@ private void assertRow(Struct actualRow, JSONArray expectedRow) throws Exception
case INT64:
assertThat(actualRow.getLong(i)).isEqualTo(expectedRow.getLong(i));
break;
+ case FLOAT32:
+ assertThat(actualRow.getFloat(i)).isEqualTo(expectedRow.getFloat(i));
+ break;
case FLOAT64:
assertThat(actualRow.getDouble(i)).isEqualTo(expectedRow.getDouble(i));
break;
@@ -208,6 +211,9 @@ private List> getRawList(Struct actualRow, int index, Type elementType) {
case INT64:
rawList = actualRow.getLongList(index);
break;
+ case FLOAT32:
+ rawList = actualRow.getFloatList(index);
+ break;
case FLOAT64:
rawList = actualRow.getDoubleList(index);
break;
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResultSetsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResultSetsTest.java
index 8e1f257594..454bd3c70a 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResultSetsTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResultSetsTest.java
@@ -31,6 +31,7 @@
import com.google.cloud.spanner.SingerProto.Genre;
import com.google.cloud.spanner.SingerProto.SingerInfo;
import com.google.common.primitives.Doubles;
+import com.google.common.primitives.Floats;
import com.google.common.primitives.Longs;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.protobuf.AbstractMessage;
@@ -53,6 +54,7 @@ public class ResultSetsTest {
@Test
public void resultSetIteration() {
double doubleVal = 1.2;
+ float floatVal = 6.626f;
BigDecimal bigDecimalVal = BigDecimal.valueOf(123, 2);
String stringVal = "stringVal";
String jsonVal = "{\"color\":\"red\",\"value\":\"#f00\"}";
@@ -71,6 +73,7 @@ public void resultSetIteration() {
boolean[] boolArray = {true, false, true, true, false};
long[] longArray = {Long.MAX_VALUE, Long.MIN_VALUE, 0, 1, -1};
double[] doubleArray = {Double.MIN_VALUE, Double.MAX_VALUE, 0, 1, -1, 1.2341};
+ float[] floatArray = {Float.MIN_VALUE, Float.MAX_VALUE, 0, 1, -1, 1.2341f};
BigDecimal[] bigDecimalArray = {
BigDecimal.valueOf(1, Integer.MAX_VALUE),
BigDecimal.valueOf(1, Integer.MIN_VALUE),
@@ -102,6 +105,7 @@ public void resultSetIteration() {
Type.StructField.of("f2", Type.int64()),
Type.StructField.of("f3", Type.bool()),
Type.StructField.of("doubleVal", Type.float64()),
+ Type.StructField.of("floatVal", Type.float32()),
Type.StructField.of("bigDecimalVal", Type.numeric()),
Type.StructField.of("stringVal", Type.string()),
Type.StructField.of("jsonVal", Type.json()),
@@ -116,6 +120,7 @@ public void resultSetIteration() {
Type.StructField.of("boolArray", Type.array(Type.bool())),
Type.StructField.of("longArray", Type.array(Type.int64())),
Type.StructField.of("doubleArray", Type.array(Type.float64())),
+ Type.StructField.of("floatArray", Type.array(Type.float32())),
Type.StructField.of("bigDecimalArray", Type.array(Type.numeric())),
Type.StructField.of("byteArray", Type.array(Type.bytes())),
Type.StructField.of("timestampArray", Type.array(Type.timestamp())),
@@ -138,6 +143,8 @@ public void resultSetIteration() {
.to(Value.bool(true))
.set("doubleVal")
.to(Value.float64(doubleVal))
+ .set("floatVal")
+ .to(Value.float32(floatVal))
.set("bigDecimalVal")
.to(Value.numeric(bigDecimalVal))
.set("stringVal")
@@ -162,6 +169,8 @@ public void resultSetIteration() {
.to(Value.int64Array(longArray))
.set("doubleArray")
.to(Value.float64Array(doubleArray))
+ .set("floatArray")
+ .to(Value.float32Array(floatArray))
.set("bigDecimalArray")
.to(Value.numericArray(Arrays.asList(bigDecimalArray)))
.set("byteArray")
@@ -195,6 +204,8 @@ public void resultSetIteration() {
.to(Value.bool(null))
.set("doubleVal")
.to(Value.float64(doubleVal))
+ .set("floatVal")
+ .to(Value.float32(floatVal))
.set("bigDecimalVal")
.to(Value.numeric(bigDecimalVal))
.set("stringVal")
@@ -219,6 +230,8 @@ public void resultSetIteration() {
.to(Value.int64Array(longArray))
.set("doubleArray")
.to(Value.float64Array(doubleArray))
+ .set("floatArray")
+ .to(Value.float32Array(floatArray))
.set("bigDecimalArray")
.to(Value.numericArray(Arrays.asList(bigDecimalArray)))
.set("byteArray")
@@ -274,6 +287,10 @@ public void resultSetIteration() {
assertThat(rs.getValue("doubleVal").getFloat64()).isWithin(0.0).of(doubleVal);
assertThat(rs.getDouble(columnIndex)).isWithin(0.0).of(doubleVal);
assertThat(rs.getValue(columnIndex++).getFloat64()).isWithin(0.0).of(doubleVal);
+ assertThat(rs.getFloat(columnIndex)).isWithin(0.0f).of(floatVal);
+ assertThat(rs.getValue(columnIndex++).getFloat32()).isWithin(0.0f).of(floatVal);
+ assertThat(rs.getFloat("floatVal")).isWithin(0.0f).of(floatVal);
+ assertThat(rs.getValue("floatVal").getFloat32()).isWithin(0.0f).of(floatVal);
assertThat(rs.getBigDecimal("bigDecimalVal")).isEqualTo(new BigDecimal("1.23"));
assertThat(rs.getValue("bigDecimalVal")).isEqualTo(Value.numeric(new BigDecimal("1.23")));
assertThat(rs.getBigDecimal(columnIndex)).isEqualTo(new BigDecimal("1.23"));
@@ -338,6 +355,17 @@ public void resultSetIteration() {
assertThat(rs.getValue("doubleArray")).isEqualTo(Value.float64Array(doubleArray));
assertThat(rs.getDoubleList(columnIndex++)).isEqualTo(Doubles.asList(doubleArray));
assertThat(rs.getDoubleList("doubleArray")).isEqualTo(Doubles.asList(doubleArray));
+
+ assertThat(rs.getFloatArray(columnIndex)).usingTolerance(0.0f).containsAtLeast(floatArray);
+ assertThat(rs.getValue(columnIndex)).isEqualTo(Value.float32Array(floatArray));
+ assertThat(rs.getFloatArray("floatArray"))
+ .usingTolerance(0.0f)
+ .containsExactly(floatArray)
+ .inOrder();
+ assertThat(rs.getValue("floatArray")).isEqualTo(Value.float32Array(floatArray));
+ assertThat(rs.getFloatList(columnIndex++)).isEqualTo(Floats.asList(floatArray));
+ assertThat(rs.getFloatList("floatArray")).isEqualTo(Floats.asList(floatArray));
+
assertThat(rs.getBigDecimalList(columnIndex)).isEqualTo(Arrays.asList(bigDecimalArray));
assertThat(rs.getValue(columnIndex++))
.isEqualTo(Value.numericArray(Arrays.asList(bigDecimalArray)));
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TypeTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TypeTest.java
index 11b708ed48..6eedc058c5 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TypeTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/TypeTest.java
@@ -110,6 +110,16 @@ Type newType() {
}.test();
}
+ @Test
+ public void float32() {
+ new ScalarTypeTester(Type.Code.FLOAT32, TypeCode.FLOAT32) {
+ @Override
+ Type newType() {
+ return Type.float32();
+ }
+ }.test();
+ }
+
@Test
public void float64() {
new ScalarTypeTester(Type.Code.FLOAT64, TypeCode.FLOAT64) {
@@ -307,6 +317,16 @@ Type newElementType() {
}.test();
}
+ @Test
+ public void float32Array() {
+ new ArrayTypeTester(Type.Code.FLOAT32, TypeCode.FLOAT32, true) {
+ @Override
+ Type newElementType() {
+ return Type.float32();
+ }
+ }.test();
+ }
+
@Test
public void float64Array() {
new ArrayTypeTester(Type.Code.FLOAT64, TypeCode.FLOAT64, true) {
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueBinderTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueBinderTest.java
index d50814e84d..204880bf7d 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueBinderTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueBinderTest.java
@@ -265,6 +265,14 @@ public static Long defaultLongWrapper() {
return 1234L;
}
+ public static float defaultFloatPrimitive() {
+ return 1.0f;
+ }
+
+ public static Float defaultFloatWrapper() {
+ return 1.0f;
+ }
+
public static double defaultDoublePrimitive() {
return 1.0;
}
@@ -329,6 +337,14 @@ public static Iterable defaultLongIterable() {
return Arrays.asList(1L, 2L);
}
+ public static float[] defaultFloatArray() {
+ return new float[] {1.0f, 2.0f};
+ }
+
+ public static Iterable defaultFloatIterable() {
+ return Arrays.asList(1.0f, 2.0f);
+ }
+
public static double[] defaultDoubleArray() {
return new double[] {1.0, 2.0};
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java
index 5176013cf3..460c646807 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java
@@ -185,6 +185,38 @@ public void int64WrapperNull() {
assertEquals("NULL", v.getAsString());
}
+ @Test
+ public void float32() {
+ Value v = Value.float32(1.23f);
+ assertThat(v.getType()).isEqualTo(Type.float32());
+ assertThat(v.isNull()).isFalse();
+ assertThat(v.getFloat32()).isWithin(0.0001f).of(1.23f);
+ assertThat(v.toString()).isEqualTo("1.23");
+ assertEquals("1.23", v.getAsString());
+ assertEquals(Value.float32(Float.NaN), Value.float32(Float.NaN));
+ }
+
+ @Test
+ public void float32Wrapper() {
+ Value v = Value.float32(Float.valueOf(1.23f));
+ assertThat(v.getType()).isEqualTo(Type.float32());
+ assertThat(v.isNull()).isFalse();
+ assertThat(v.getFloat32()).isWithin(0.0001f).of(1.23f);
+ assertThat(v.toString()).isEqualTo("1.23");
+ assertEquals("1.23", v.getAsString());
+ }
+
+ @Test
+ public void float32WrapperNull() {
+ Value v = Value.float32(null);
+ assertThat(v.getType()).isEqualTo(Type.float32());
+ assertThat(v.isNull()).isTrue();
+ assertThat(v.toString()).isEqualTo(NULL_STRING);
+ IllegalStateException e = assertThrows(IllegalStateException.class, v::getFloat32);
+ assertThat(e.getMessage()).contains("null value");
+ assertEquals("NULL", v.getAsString());
+ }
+
@Test
public void float64() {
Value v = Value.float64(1.23);
@@ -193,6 +225,7 @@ public void float64() {
assertThat(v.getFloat64()).isWithin(0.0001).of(1.23);
assertThat(v.toString()).isEqualTo("1.23");
assertEquals("1.23", v.getAsString());
+ assertEquals(Value.float64(Double.NaN), Value.float64(Double.NaN));
}
@Test
@@ -236,6 +269,7 @@ public void pgNumeric() {
assertEquals(1234.5678D, value.getFloat64(), 0.00001);
assertEquals("1234.5678", value.toString());
assertEquals("1234.5678", value.getAsString());
+ assertEquals(Value.pgNumeric("NaN"), Value.pgNumeric("NaN"));
}
@Test
@@ -863,6 +897,60 @@ public void int64ArrayNullTryGetBool() {
assertThat(e.getMessage()).contains("Expected: BOOL actual: ARRAY");
}
+ @Test
+ public void float32Array() {
+ Value v = Value.float32Array(new float[] {.1f, .2f});
+ assertThat(v.isNull()).isFalse();
+ assertThat(v.getFloat32Array()).containsExactly(.1f, .2f).inOrder();
+ assertThat(v.toString()).isEqualTo("[0.1,0.2]");
+ assertEquals("[0.1,0.2]", v.getAsString());
+ }
+
+ @Test
+ public void float32ArrayRange() {
+ Value v = Value.float32Array(new float[] {.1f, .2f, .3f, .4f, .5f}, 1, 3);
+ assertThat(v.isNull()).isFalse();
+ assertThat(v.getFloat32Array()).containsExactly(.2f, .3f, .4f).inOrder();
+ assertThat(v.toString()).isEqualTo("[0.2,0.3,0.4]");
+ assertEquals("[0.2,0.3,0.4]", v.getAsString());
+ }
+
+ @Test
+ public void float32ArrayNull() {
+ Value v = Value.float32Array((float[]) null);
+ assertThat(v.isNull()).isTrue();
+ assertThat(v.toString()).isEqualTo(NULL_STRING);
+ IllegalStateException e = assertThrows(IllegalStateException.class, v::getFloat32Array);
+ assertThat(e.getMessage()).contains("null value");
+ assertEquals("NULL", v.getAsString());
+ }
+
+ @Test
+ public void float32ArrayWrapper() {
+ Value v = Value.float32Array(Arrays.asList(.1f, null, .3f));
+ assertThat(v.isNull()).isFalse();
+ assertThat(v.getFloat32Array()).containsExactly(.1f, null, .3f).inOrder();
+ assertThat(v.toString()).isEqualTo("[0.1,NULL,0.3]");
+ assertEquals("[0.1,NULL,0.3]", v.getAsString());
+ }
+
+ @Test
+ public void float32ArrayWrapperNull() {
+ Value v = Value.float32Array((Iterable) null);
+ assertThat(v.isNull()).isTrue();
+ assertThat(v.toString()).isEqualTo(NULL_STRING);
+ IllegalStateException e = assertThrows(IllegalStateException.class, v::getFloat32Array);
+ assertThat(e.getMessage()).contains("null value");
+ assertEquals("NULL", v.getAsString());
+ }
+
+ @Test
+ public void float32ArrayTryGetFloat64Array() {
+ Value value = Value.float32Array(Collections.singletonList(.1f));
+ IllegalStateException e = assertThrows(IllegalStateException.class, value::getFloat64Array);
+ assertThat(e.getMessage()).contains("Expected: ARRAY actual: ARRAY");
+ }
+
@Test
public void float64Array() {
Value v = Value.float64Array(new double[] {.1, .2});
@@ -1426,6 +1514,13 @@ public void testValueToProto() {
com.google.protobuf.Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build(),
Value.int64(null).toProto());
+ assertEquals(
+ com.google.protobuf.Value.newBuilder().setNumberValue(3.14f).build(),
+ Value.float32(3.14f).toProto());
+ assertEquals(
+ com.google.protobuf.Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build(),
+ Value.float32(null).toProto());
+
assertEquals(
com.google.protobuf.Value.newBuilder().setNumberValue(3.14d).build(),
Value.float64(3.14d).toProto());
@@ -1512,6 +1607,18 @@ public void testValueToProto() {
.build())))
.build(),
Value.int64Array(Arrays.asList(1L, null)).toProto());
+ assertEquals(
+ com.google.protobuf.Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addAllValues(
+ Arrays.asList(
+ com.google.protobuf.Value.newBuilder().setNumberValue(3.14f).build(),
+ com.google.protobuf.Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build())))
+ .build(),
+ Value.float32Array(Arrays.asList(3.14f, null)).toProto());
assertEquals(
com.google.protobuf.Value.newBuilder()
.setListValue(
@@ -1667,6 +1774,29 @@ public void testValueToProto() {
.build(),
Value.struct(Struct.newBuilder().add(Value.int64Array(Arrays.asList(1L, null))).build())
.toProto());
+ assertEquals(
+ com.google.protobuf.Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addValues(
+ com.google.protobuf.Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addAllValues(
+ Arrays.asList(
+ com.google.protobuf.Value.newBuilder()
+ .setNumberValue(3.14f)
+ .build(),
+ com.google.protobuf.Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build()))
+ .build())
+ .build())
+ .build())
+ .build(),
+ Value.struct(
+ Struct.newBuilder().add(Value.float32Array(Arrays.asList(3.14f, null))).build())
+ .toProto());
assertEquals(
com.google.protobuf.Value.newBuilder()
.setListValue(
@@ -1872,6 +2002,10 @@ public void testEqualsHashCode() {
tester.addEqualityGroup(Value.int64(456));
tester.addEqualityGroup(Value.int64(null));
+ tester.addEqualityGroup(Value.float32(1.23f), Value.float32(Float.valueOf(1.23f)));
+ tester.addEqualityGroup(Value.float32(4.56f));
+ tester.addEqualityGroup(Value.float32(null));
+
tester.addEqualityGroup(Value.float64(1.23), Value.float64(Double.valueOf(1.23)));
tester.addEqualityGroup(Value.float64(4.56));
tester.addEqualityGroup(Value.float64(null));
@@ -1938,6 +2072,14 @@ public void testEqualsHashCode() {
tester.addEqualityGroup(Value.int64Array(Collections.singletonList(3L)));
tester.addEqualityGroup(Value.int64Array((Iterable) null));
+ tester.addEqualityGroup(
+ Value.float32Array(Arrays.asList(.1f, .2f)),
+ Value.float32Array(new float[] {.1f, .2f}),
+ Value.float32Array(new float[] {.0f, .1f, .2f, .3f}, 1, 2),
+ Value.float32Array(plainIterable(.1f, .2f)));
+ tester.addEqualityGroup(Value.float32Array(Collections.singletonList(.3f)));
+ tester.addEqualityGroup(Value.float32Array((Iterable) null));
+
tester.addEqualityGroup(
Value.float64Array(Arrays.asList(.1, .2)),
Value.float64Array(new double[] {.1, .2}),
@@ -2009,6 +2151,11 @@ public void testGetAsString() {
assertEquals(String.valueOf(Long.MAX_VALUE), Value.int64(Long.MAX_VALUE).getAsString());
assertEquals(String.valueOf(Long.MIN_VALUE), Value.int64(Long.MIN_VALUE).getAsString());
+ assertEquals("3.14", Value.float32(3.14f).getAsString());
+ assertEquals("NaN", Value.float32(Float.NaN).getAsString());
+ assertEquals(String.valueOf(Float.MIN_VALUE), Value.float32(Float.MIN_VALUE).getAsString());
+ assertEquals(String.valueOf(Float.MAX_VALUE), Value.float32(Float.MAX_VALUE).getAsString());
+
assertEquals("3.14", Value.float64(3.14d).getAsString());
assertEquals("NaN", Value.float64(Double.NaN).getAsString());
assertEquals(String.valueOf(Double.MIN_VALUE), Value.float64(Double.MIN_VALUE).getAsString());
@@ -2052,6 +2199,9 @@ public void serialization() {
reserializeAndAssert(Value.int64(123));
reserializeAndAssert(Value.int64(null));
+ reserializeAndAssert(Value.float32(1.23f));
+ reserializeAndAssert(Value.float32(null));
+
reserializeAndAssert(Value.float64(1.23));
reserializeAndAssert(Value.float64(null));
@@ -2089,6 +2239,10 @@ public void serialization() {
reserializeAndAssert(Value.int64Array(new long[] {1L, 2L}));
reserializeAndAssert(Value.int64Array((Iterable) null));
+ reserializeAndAssert(Value.float32Array(new float[] {.1f, .2f}));
+ reserializeAndAssert(Value.float32Array(BrokenSerializationList.of(.1f, .2f, .3f)));
+ reserializeAndAssert(Value.float32Array((Iterable) null));
+
reserializeAndAssert(Value.float64Array(new double[] {.1, .2}));
reserializeAndAssert(Value.float64Array(BrokenSerializationList.of(.1, .2, .3)));
reserializeAndAssert(Value.float64Array((Iterable) null));
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractMockServerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractMockServerTest.java
index af67859b4a..9af443293a 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractMockServerTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AbstractMockServerTest.java
@@ -19,7 +19,6 @@
import com.google.cloud.spanner.ForceCloseSpannerFunction;
import com.google.cloud.spanner.MockSpannerServiceImpl;
import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
-import com.google.cloud.spanner.RandomResultSetGenerator;
import com.google.cloud.spanner.Statement;
import com.google.cloud.spanner.admin.database.v1.MockDatabaseAdminImpl;
import com.google.cloud.spanner.admin.instance.v1.MockInstanceAdminImpl;
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AllTypesMockServerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AllTypesMockServerTest.java
new file mode 100644
index 0000000000..44ae730f8c
--- /dev/null
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AllTypesMockServerTest.java
@@ -0,0 +1,683 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.spanner.connection;
+
+import static org.junit.Assert.*;
+
+import com.google.cloud.ByteArray;
+import com.google.cloud.Date;
+import com.google.cloud.Timestamp;
+import com.google.cloud.spanner.Dialect;
+import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.SingerProto.Genre;
+import com.google.cloud.spanner.SingerProto.SingerInfo;
+import com.google.cloud.spanner.Statement;
+import com.google.common.collect.ImmutableList;
+import com.google.protobuf.ListValue;
+import com.google.protobuf.NullValue;
+import com.google.protobuf.Value;
+import com.google.spanner.v1.ExecuteSqlRequest;
+import com.google.spanner.v1.Type;
+import com.google.spanner.v1.TypeCode;
+import java.math.BigDecimal;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/** Tests that all types can be read from Spanner and sent to Spanner. */
+@RunWith(Parameterized.class)
+public class AllTypesMockServerTest extends AbstractMockServerTest {
+
+ @Parameters(name = "dialect = {0}")
+ public static Object[] data() {
+ return Dialect.values();
+ }
+
+ @Parameter public Dialect dialect;
+
+ private Dialect currentDialect;
+
+ public static final Statement SELECT_STATEMENT = Statement.of("select * from all_types");
+
+ public static final boolean BOOL_VALUE = true;
+ public static final long INT64_VALUE = 1L;
+ public static final float FLOAT32_VALUE = 3.14f;
+ public static final double FLOAT64_VALUE = 3.14d;
+ public static final BigDecimal NUMERIC_VALUE = new BigDecimal("3.14");
+ public static final String PG_NUMERIC_VALUE = "3.14";
+ public static final String STRING_VALUE = "test-string";
+ public static final String JSON_VALUE = "{\"key1\":\"value1\", \"key2\":\"value2\"}";
+ public static final byte[] BYTES_VALUE = "test-bytes".getBytes(StandardCharsets.UTF_8);
+ public static final Date DATE_VALUE = Date.fromYearMonthDay(2024, 3, 2);
+ public static final Timestamp TIMESTAMP_VALUE =
+ Timestamp.parseTimestamp("2024-03-02T07:07:00.20982735Z");
+
+ public static final List BOOL_ARRAY_VALUE = Arrays.asList(true, null, false);
+ public static final List INT64_ARRAY_VALUE =
+ Arrays.asList(100L, null, 200L, Long.MIN_VALUE, Long.MAX_VALUE);
+ public static final List FLOAT32_ARRAY_VALUE =
+ Arrays.asList(
+ -3.14f, null, 6.626f, Float.MIN_VALUE, Float.MAX_VALUE, Float.MIN_NORMAL, Float.NaN);
+ public static final List FLOAT64_ARRAY_VALUE =
+ Arrays.asList(
+ -3.14d, null, 6.626d, Double.MIN_VALUE, Double.MAX_VALUE, Double.MIN_NORMAL, Double.NaN);
+ public static final List NUMERIC_ARRAY_VALUE =
+ Arrays.asList(
+ new BigDecimal("-3.14"),
+ null,
+ new BigDecimal("99.99"),
+ BigDecimal.ZERO,
+ new BigDecimal("1e-9"),
+ new BigDecimal("-9.9999999999999999999999999999999999999E+28"),
+ new BigDecimal("9.9999999999999999999999999999999999999E+28"));
+ public static final List PG_NUMERIC_ARRAY_VALUE =
+ Arrays.asList(
+ "-3.14",
+ null,
+ "99.99",
+ "NaN",
+ "1e-9",
+ "-9.9999999999999999999999999999999999999E+28",
+ "9.9999999999999999999999999999999999999E+28");
+ public static final List STRING_ARRAY_VALUE =
+ Arrays.asList("test-string1", null, "test-string2");
+ public static final List JSON_ARRAY_VALUE =
+ Arrays.asList(
+ "{\"key1\":\"value1.1\", \"key2\":\"value1.2\"}",
+ null,
+ "{\"key1\":\"value3.1\", \"key2\":\"value3.2\"}");
+ public static final List BYTES_ARRAY_VALUE =
+ Arrays.asList(ByteArray.copyFrom("test-bytes1"), null, ByteArray.copyFrom("test-bytes2"));
+ public static final List DATE_ARRAY_VALUE =
+ Arrays.asList(
+ Date.fromYearMonthDay(2024, 3, 1),
+ null,
+ Date.fromYearMonthDay(2024, 3, 3),
+ Date.fromYearMonthDay(1, 1, 1),
+ Date.fromYearMonthDay(9999, 12, 31));
+ public static final List TIMESTAMP_ARRAY_VALUE =
+ Arrays.asList(
+ Timestamp.parseTimestamp("2024-03-01T07:07:00.20982735Z"),
+ null,
+ Timestamp.parseTimestamp("2024-03-03T07:07:00Z"),
+ Timestamp.MIN_VALUE,
+ Timestamp.MAX_VALUE);
+
+ @Before
+ public void setupDialect() {
+ if (currentDialect != dialect) {
+ mockSpanner.putStatementResult(StatementResult.detectDialectResult(dialect));
+ setupAllTypesResultSet(dialect);
+ mockSpanner.putStatementResult(StatementResult.update(createInsertStatement(dialect), 1L));
+ SpannerPool.closeSpannerPool();
+ currentDialect = dialect;
+ }
+ }
+
+ private void setupAllTypesResultSet(Dialect dialect) {
+ // Use RandomResultSetGenerator to generate metadata for a ResultSet with all types.
+ // This guarantees that this test will fail if a new type is added to RandomResultSetGenerator,
+ // but not added to this test.
+ // The columns in the result set are:
+ // COL1: BOOL
+ // COL2: INT64
+ // COL3: FLOAT32
+ // COL4: FLOAT64
+ // COL5: NUMERIC / PG_NUMERIC
+ // COL6: STRING
+ // COL7: JSON / PG_JSONB
+ // COL8: BYTES
+ // COL9: DATE
+ // COL10: TIMESTAMP
+ // COL11-20: ARRAY<..> for the types above.
+ // Only for GoogleSQL:
+ // COL21: PROTO
+ // COL22: ENUM
+ // COL23: ARRAY
+ // COL24: ARRAY
+ ListValue.Builder row1Builder =
+ ListValue.newBuilder()
+ .addValues(Value.newBuilder().setBoolValue(BOOL_VALUE))
+ .addValues(Value.newBuilder().setStringValue(String.valueOf(INT64_VALUE)).build())
+ .addValues(Value.newBuilder().setNumberValue(FLOAT32_VALUE))
+ .addValues(Value.newBuilder().setNumberValue(FLOAT64_VALUE))
+ .addValues(
+ Value.newBuilder()
+ .setStringValue(
+ dialect == Dialect.POSTGRESQL
+ ? PG_NUMERIC_VALUE
+ : NUMERIC_VALUE.toEngineeringString()))
+ .addValues(Value.newBuilder().setStringValue(STRING_VALUE))
+ .addValues(Value.newBuilder().setStringValue(JSON_VALUE))
+ .addValues(
+ Value.newBuilder().setStringValue(Base64.getEncoder().encodeToString(BYTES_VALUE)))
+ .addValues(Value.newBuilder().setStringValue(DATE_VALUE.toString()))
+ .addValues(Value.newBuilder().setStringValue(TIMESTAMP_VALUE.toString()))
+ .addValues(
+ Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addAllValues(
+ BOOL_ARRAY_VALUE.stream()
+ .map(
+ b ->
+ b == null
+ ? Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build()
+ : Value.newBuilder().setBoolValue(b).build())
+ .collect(Collectors.toList()))
+ .build()))
+ .addValues(
+ Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addAllValues(
+ INT64_ARRAY_VALUE.stream()
+ .map(
+ l ->
+ l == null
+ ? Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build()
+ : Value.newBuilder()
+ .setStringValue(String.valueOf(l))
+ .build())
+ .collect(Collectors.toList()))
+ .build()))
+ .addValues(
+ Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addAllValues(
+ FLOAT32_ARRAY_VALUE.stream()
+ .map(
+ f -> {
+ if (f == null) {
+ return Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build();
+ } else if (Float.isNaN(f)) {
+ return Value.newBuilder().setStringValue("NaN").build();
+ } else {
+ return Value.newBuilder().setNumberValue(f).build();
+ }
+ })
+ .collect(Collectors.toList()))
+ .build()))
+ .addValues(
+ Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addAllValues(
+ FLOAT64_ARRAY_VALUE.stream()
+ .map(
+ d -> {
+ if (d == null) {
+ return Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build();
+ } else if (Double.isNaN(d)) {
+ return Value.newBuilder().setStringValue("NaN").build();
+ } else {
+ return Value.newBuilder().setNumberValue(d).build();
+ }
+ })
+ .collect(Collectors.toList()))
+ .build()))
+ .addValues(
+ Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addAllValues(
+ dialect == Dialect.POSTGRESQL
+ ? PG_NUMERIC_ARRAY_VALUE.stream()
+ .map(
+ string ->
+ string == null
+ ? Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build()
+ : Value.newBuilder()
+ .setStringValue(string)
+ .build())
+ .collect(Collectors.toList())
+ : NUMERIC_ARRAY_VALUE.stream()
+ .map(
+ bigDecimal ->
+ bigDecimal == null
+ ? Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build()
+ : Value.newBuilder()
+ .setStringValue(
+ bigDecimal.toEngineeringString())
+ .build())
+ .collect(Collectors.toList()))
+ .build()))
+ .addValues(
+ Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addAllValues(
+ STRING_ARRAY_VALUE.stream()
+ .map(
+ string ->
+ string == null
+ ? Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build()
+ : Value.newBuilder().setStringValue(string).build())
+ .collect(Collectors.toList()))
+ .build()))
+ .addValues(
+ Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addAllValues(
+ JSON_ARRAY_VALUE.stream()
+ .map(
+ json ->
+ json == null
+ ? Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build()
+ : Value.newBuilder().setStringValue(json).build())
+ .collect(Collectors.toList()))
+ .build()))
+ .addValues(
+ Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addAllValues(
+ BYTES_ARRAY_VALUE.stream()
+ .map(
+ byteArray ->
+ byteArray == null
+ ? Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build()
+ : Value.newBuilder()
+ .setStringValue(
+ Base64.getEncoder()
+ .encodeToString(
+ byteArray.toByteArray()))
+ .build())
+ .collect(Collectors.toList()))
+ .build()))
+ .addValues(
+ Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addAllValues(
+ DATE_ARRAY_VALUE.stream()
+ .map(
+ date ->
+ date == null
+ ? Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build()
+ : Value.newBuilder()
+ .setStringValue(date.toString())
+ .build())
+ .collect(Collectors.toList()))
+ .build()))
+ .addValues(
+ Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addAllValues(
+ TIMESTAMP_ARRAY_VALUE.stream()
+ .map(
+ timestamp ->
+ timestamp == null
+ ? Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build()
+ : Value.newBuilder()
+ .setStringValue(timestamp.toString())
+ .build())
+ .collect(Collectors.toList()))
+ .build()));
+
+ if (dialect == Dialect.GOOGLE_STANDARD_SQL) {
+ // Add PROTO values.
+ row1Builder
+ .addValues(
+ Value.newBuilder()
+ .setStringValue(
+ Base64.getEncoder()
+ .encodeToString(
+ SingerInfo.newBuilder()
+ .setSingerId(1L)
+ .setNationality("unknown")
+ .setBirthDate("1986-09-30")
+ .setGenre(Genre.POP)
+ .build()
+ .toByteArray()))
+ .build())
+ .addValues(Value.newBuilder().setStringValue(String.valueOf(Genre.JAZZ_VALUE)).build())
+ .addValues(
+ Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addValues(
+ Value.newBuilder()
+ .setStringValue(
+ Base64.getEncoder()
+ .encodeToString(
+ SingerInfo.newBuilder()
+ .setSingerId(1L)
+ .setGenre(Genre.FOLK)
+ .setBirthDate("200-01-01")
+ .setNationality("no")
+ .build()
+ .toByteArray()))
+ .build())
+ .addValues(Value.newBuilder().setNullValue(NullValue.NULL_VALUE))
+ .addValues(
+ Value.newBuilder()
+ .setStringValue(
+ Base64.getEncoder()
+ .encodeToString(
+ SingerInfo.newBuilder()
+ .setSingerId(2L)
+ .setGenre(Genre.JAZZ)
+ .setBirthDate("200-01-02")
+ .setNationality("dk")
+ .build()
+ .toByteArray()))
+ .build())
+ .build())
+ .build())
+ .addValues(
+ Value.newBuilder()
+ .setListValue(
+ ListValue.newBuilder()
+ .addValues(
+ Value.newBuilder()
+ .setStringValue(String.valueOf(Genre.ROCK_VALUE))
+ .build())
+ .addValues(Value.newBuilder().setNullValue(NullValue.NULL_VALUE))
+ .addValues(
+ Value.newBuilder()
+ .setStringValue(String.valueOf(Genre.ROCK_VALUE))
+ .build())
+ .build())
+ .build());
+ }
+
+ com.google.spanner.v1.ResultSet resultSet =
+ com.google.spanner.v1.ResultSet.newBuilder()
+ .setMetadata(
+ RandomResultSetGenerator.generateAllTypesMetadata(
+ RandomResultSetGenerator.generateAllTypes(dialect)))
+ .addRows(row1Builder.build())
+ .build();
+ mockSpanner.putStatementResults(StatementResult.query(SELECT_STATEMENT, resultSet));
+ }
+
+ public static Statement createInsertStatement(Dialect dialect) {
+ Statement.Builder builder = Statement.newBuilder("insert into all_types (");
+ builder.append(
+ IntStream.rangeClosed(1, RandomResultSetGenerator.generateAllTypes(dialect).length)
+ .mapToObj(col -> "COL" + col)
+ .collect(Collectors.joining(", ", "", ") values (")));
+ builder.append(
+ IntStream.rangeClosed(1, RandomResultSetGenerator.generateAllTypes(dialect).length)
+ .mapToObj(col -> "@p" + col)
+ .collect(Collectors.joining(", ", "", ")")));
+ int param = 0;
+ return builder
+ .bind("p" + ++param)
+ .to(BOOL_VALUE)
+ .bind("p" + ++param)
+ .to(INT64_VALUE)
+ .bind("p" + ++param)
+ .to(FLOAT32_VALUE)
+ .bind("p" + ++param)
+ .to(FLOAT64_VALUE)
+ .bind("p" + ++param)
+ .to(
+ dialect == Dialect.POSTGRESQL
+ ? com.google.cloud.spanner.Value.pgNumeric(PG_NUMERIC_VALUE)
+ : com.google.cloud.spanner.Value.numeric(NUMERIC_VALUE))
+ .bind("p" + ++param)
+ .to(STRING_VALUE)
+ .bind("p" + ++param)
+ .to(
+ dialect == Dialect.POSTGRESQL
+ ? com.google.cloud.spanner.Value.pgJsonb(JSON_VALUE)
+ : com.google.cloud.spanner.Value.json(JSON_VALUE))
+ .bind("p" + ++param)
+ .to(ByteArray.copyFrom(BYTES_VALUE))
+ .bind("p" + ++param)
+ .to(DATE_VALUE)
+ .bind("p" + ++param)
+ .to(TIMESTAMP_VALUE)
+ .bind("p" + ++param)
+ .toBoolArray(BOOL_ARRAY_VALUE)
+ .bind("p" + ++param)
+ .toInt64Array(INT64_ARRAY_VALUE)
+ .bind("p" + ++param)
+ .toFloat32Array(FLOAT32_ARRAY_VALUE)
+ .bind("p" + ++param)
+ .toFloat64Array(FLOAT64_ARRAY_VALUE)
+ .bind("p" + ++param)
+ .to(
+ dialect == Dialect.POSTGRESQL
+ ? com.google.cloud.spanner.Value.pgNumericArray(PG_NUMERIC_ARRAY_VALUE)
+ : com.google.cloud.spanner.Value.numericArray(NUMERIC_ARRAY_VALUE))
+ .bind("p" + ++param)
+ .toStringArray(STRING_ARRAY_VALUE)
+ .bind("p" + ++param)
+ .to(
+ dialect == Dialect.POSTGRESQL
+ ? com.google.cloud.spanner.Value.pgJsonbArray(JSON_ARRAY_VALUE)
+ : com.google.cloud.spanner.Value.jsonArray(JSON_ARRAY_VALUE))
+ .bind("p" + ++param)
+ .toBytesArray(BYTES_ARRAY_VALUE)
+ .bind("p" + ++param)
+ .toDateArray(DATE_ARRAY_VALUE)
+ .bind("p" + ++param)
+ .toTimestampArray(TIMESTAMP_ARRAY_VALUE)
+ .build();
+ }
+
+ @After
+ public void clearRequests() {
+ mockSpanner.clearRequests();
+ }
+
+ @Test
+ public void testSelectAllTypes() {
+ try (Connection connection = createConnection()) {
+ try (ResultSet resultSet = connection.executeQuery(SELECT_STATEMENT)) {
+ assertTrue(resultSet.next());
+
+ int col = -1;
+ assertEquals(BOOL_VALUE, resultSet.getBoolean(++col));
+ assertEquals(INT64_VALUE, resultSet.getLong(++col));
+ assertEquals(FLOAT32_VALUE, resultSet.getFloat(++col), 0.0f);
+ assertEquals(FLOAT64_VALUE, resultSet.getDouble(++col), 0.0d);
+ if (dialect == Dialect.POSTGRESQL) {
+ assertEquals(PG_NUMERIC_VALUE, resultSet.getString(++col));
+ } else {
+ assertEquals(NUMERIC_VALUE, resultSet.getBigDecimal(++col));
+ }
+ assertEquals(STRING_VALUE, resultSet.getString(++col));
+ assertEquals(
+ JSON_VALUE,
+ dialect == Dialect.POSTGRESQL ? resultSet.getPgJsonb(++col) : resultSet.getJson(++col));
+ assertArrayEquals(BYTES_VALUE, resultSet.getBytes(++col).toByteArray());
+ assertEquals(DATE_VALUE, resultSet.getDate(++col));
+ assertEquals(TIMESTAMP_VALUE, resultSet.getTimestamp(++col));
+
+ assertEquals(BOOL_ARRAY_VALUE, resultSet.getBooleanList(++col));
+ assertEquals(INT64_ARRAY_VALUE, resultSet.getLongList(++col));
+ assertEquals(FLOAT32_ARRAY_VALUE, resultSet.getFloatList(++col));
+ assertEquals(FLOAT64_ARRAY_VALUE, resultSet.getDoubleList(++col));
+ if (dialect == Dialect.POSTGRESQL) {
+ assertEquals(PG_NUMERIC_ARRAY_VALUE, resultSet.getStringList(++col));
+ } else {
+ assertEquals(NUMERIC_ARRAY_VALUE, resultSet.getBigDecimalList(++col));
+ }
+ assertEquals(STRING_ARRAY_VALUE, resultSet.getStringList(++col));
+ assertEquals(
+ JSON_ARRAY_VALUE,
+ dialect == Dialect.POSTGRESQL
+ ? resultSet.getPgJsonbList(++col)
+ : resultSet.getJsonList(++col));
+ assertEquals(BYTES_ARRAY_VALUE, resultSet.getBytesList(++col));
+ assertEquals(DATE_ARRAY_VALUE, resultSet.getDateList(++col));
+ assertEquals(TIMESTAMP_ARRAY_VALUE, resultSet.getTimestampList(++col));
+
+ assertFalse(resultSet.next());
+ }
+ }
+ }
+
+ @Test
+ public void testInsertAllTypes() {
+ try (Connection connection = createConnection()) {
+ assertEquals(1L, connection.executeUpdate(createInsertStatement(dialect)));
+
+ assertEquals(1, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
+ ExecuteSqlRequest request = mockSpanner.getRequestsOfType(ExecuteSqlRequest.class).get(0);
+ Map paramTypes = request.getParamTypesMap();
+ Map params = request.getParams().getFieldsMap();
+ assertEquals(20, paramTypes.size());
+ assertEquals(20, params.size());
+
+ // Verify param types.
+ ImmutableList expectedTypes =
+ ImmutableList.of(
+ TypeCode.BOOL,
+ TypeCode.INT64,
+ TypeCode.FLOAT32,
+ TypeCode.FLOAT64,
+ TypeCode.NUMERIC,
+ TypeCode.STRING,
+ TypeCode.JSON,
+ TypeCode.BYTES,
+ TypeCode.DATE,
+ TypeCode.TIMESTAMP);
+ for (int col = 0; col < expectedTypes.size(); col++) {
+ assertEquals(expectedTypes.get(col), paramTypes.get("p" + (col + 1)).getCode());
+ int arrayCol = col + expectedTypes.size();
+ assertEquals(TypeCode.ARRAY, paramTypes.get("p" + (arrayCol + 1)).getCode());
+ assertEquals(
+ expectedTypes.get(col),
+ paramTypes.get("p" + (arrayCol + 1)).getArrayElementType().getCode());
+ }
+
+ // Verify param values.
+ int col = 0;
+ assertEquals(BOOL_VALUE, params.get("p" + ++col).getBoolValue());
+ assertEquals(String.valueOf(INT64_VALUE), params.get("p" + ++col).getStringValue());
+ assertEquals(FLOAT32_VALUE, params.get("p" + ++col).getNumberValue(), 0.0d);
+ assertEquals(FLOAT64_VALUE, params.get("p" + ++col).getNumberValue(), 0.0d);
+ assertEquals(
+ dialect == Dialect.POSTGRESQL ? PG_NUMERIC_VALUE : NUMERIC_VALUE.toEngineeringString(),
+ params.get("p" + ++col).getStringValue());
+ assertEquals(STRING_VALUE, params.get("p" + ++col).getStringValue());
+ assertEquals(JSON_VALUE, params.get("p" + ++col).getStringValue());
+ assertEquals(
+ Base64.getEncoder().encodeToString(BYTES_VALUE),
+ params.get("p" + ++col).getStringValue());
+ assertEquals(DATE_VALUE.toString(), params.get("p" + ++col).getStringValue());
+ assertEquals(TIMESTAMP_VALUE.toString(), params.get("p" + ++col).getStringValue());
+
+ assertEquals(
+ BOOL_ARRAY_VALUE,
+ params.get("p" + ++col).getListValue().getValuesList().stream()
+ .map(value -> value.hasNullValue() ? null : value.getBoolValue())
+ .collect(Collectors.toList()));
+ assertEquals(
+ INT64_ARRAY_VALUE,
+ params.get("p" + ++col).getListValue().getValuesList().stream()
+ .map(value -> value.hasNullValue() ? null : Long.valueOf(value.getStringValue()))
+ .collect(Collectors.toList()));
+ assertEquals(
+ FLOAT32_ARRAY_VALUE,
+ params.get("p" + ++col).getListValue().getValuesList().stream()
+ .map(value -> value.hasNullValue() ? null : (float) value.getNumberValue())
+ .collect(Collectors.toList()));
+ assertEquals(
+ FLOAT64_ARRAY_VALUE,
+ params.get("p" + ++col).getListValue().getValuesList().stream()
+ .map(value -> value.hasNullValue() ? null : value.getNumberValue())
+ .collect(Collectors.toList()));
+ if (dialect == Dialect.POSTGRESQL) {
+ assertEquals(
+ PG_NUMERIC_ARRAY_VALUE,
+ params.get("p" + ++col).getListValue().getValuesList().stream()
+ .map(value -> value.hasNullValue() ? null : value.getStringValue())
+ .collect(Collectors.toList()));
+ } else {
+ assertEquals(
+ NUMERIC_ARRAY_VALUE,
+ params.get("p" + ++col).getListValue().getValuesList().stream()
+ .map(value -> value.hasNullValue() ? null : new BigDecimal(value.getStringValue()))
+ .collect(Collectors.toList()));
+ }
+ assertEquals(
+ STRING_ARRAY_VALUE,
+ params.get("p" + ++col).getListValue().getValuesList().stream()
+ .map(value -> value.hasNullValue() ? null : value.getStringValue())
+ .collect(Collectors.toList()));
+ assertEquals(
+ JSON_ARRAY_VALUE,
+ params.get("p" + ++col).getListValue().getValuesList().stream()
+ .map(value -> value.hasNullValue() ? null : value.getStringValue())
+ .collect(Collectors.toList()));
+ assertEquals(
+ BYTES_ARRAY_VALUE,
+ params.get("p" + ++col).getListValue().getValuesList().stream()
+ .map(
+ value ->
+ value.hasNullValue() ? null : ByteArray.fromBase64(value.getStringValue()))
+ .collect(Collectors.toList()));
+ assertEquals(
+ DATE_ARRAY_VALUE,
+ params.get("p" + ++col).getListValue().getValuesList().stream()
+ .map(value -> value.hasNullValue() ? null : Date.parseDate(value.getStringValue()))
+ .collect(Collectors.toList()));
+ assertEquals(
+ TIMESTAMP_ARRAY_VALUE,
+ params.get("p" + ++col).getListValue().getValuesList().stream()
+ .map(
+ value ->
+ value.hasNullValue()
+ ? null
+ : Timestamp.parseTimestamp(value.getStringValue()))
+ .collect(Collectors.toList()));
+ }
+ }
+}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ChecksumResultSetTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ChecksumResultSetTest.java
index 4e8fb0cfcb..759f058aa0 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ChecksumResultSetTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ChecksumResultSetTest.java
@@ -57,6 +57,8 @@ public class ChecksumResultSetTest {
.to(2 * 2)
.set("doubleVal")
.to(Value.float64(3.14d * 2d))
+ .set("floatVal")
+ .to(Value.float32(3.14f * 3f))
.set("bigDecimalVal")
.to(Value.numeric(BigDecimal.valueOf(123 * 2, 2)))
.set("pgNumericVal")
@@ -83,6 +85,8 @@ public class ChecksumResultSetTest {
.to(Value.int64Array(Arrays.asList(2L, null, 1L, 0L)))
.set("doubleArray")
.to(Value.float64Array(Arrays.asList(3.14d, null, 6.6626d, 10.1d)))
+ .set("floatArray")
+ .to(Value.float32Array(Arrays.asList(2.71f, null, 6.6626f, 10.1f)))
.set("bigDecimalArray")
.to(Value.numericArray(Arrays.asList(BigDecimal.TEN, null, BigDecimal.ONE)))
.set("pgNumericArray")
@@ -128,6 +132,7 @@ public void testRetry() {
Type.StructField.of("boolVal", Type.bool()),
Type.StructField.of("longVal", Type.int64()),
Type.StructField.of("doubleVal", Type.float64()),
+ Type.StructField.of("floatVal", Type.float32()),
Type.StructField.of("bigDecimalVal", Type.numeric()),
Type.StructField.of("pgNumericVal", Type.pgNumeric()),
Type.StructField.of("stringVal", Type.string()),
@@ -143,6 +148,7 @@ public void testRetry() {
Type.StructField.of("boolArray", Type.array(Type.bool())),
Type.StructField.of("longArray", Type.array(Type.int64())),
Type.StructField.of("doubleArray", Type.array(Type.float64())),
+ Type.StructField.of("floatArray", Type.array(Type.float32())),
Type.StructField.of("bigDecimalArray", Type.array(Type.numeric())),
Type.StructField.of("pgNumericArray", Type.array(Type.pgNumeric())),
Type.StructField.of("byteArray", Type.array(Type.bytes())),
@@ -164,6 +170,8 @@ public void testRetry() {
.to(2)
.set("doubleVal")
.to(Value.float64(3.14d))
+ .set("floatVal")
+ .to(Value.float32(2.71f))
.set("bigDecimalVal")
.to(Value.numeric(BigDecimal.valueOf(123, 2)))
.set("pgNumericVal")
@@ -190,6 +198,8 @@ public void testRetry() {
.to(Value.int64Array(Arrays.asList(1L, null, 2L)))
.set("doubleArray")
.to(Value.float64Array(Arrays.asList(3.14d, null, 6.6626d)))
+ .set("floatArray")
+ .to(Value.float32Array(Arrays.asList(2.71f, null, 6.6626f)))
.set("bigDecimalArray")
.to(Value.numericArray(Arrays.asList(BigDecimal.ONE, null, BigDecimal.TEN)))
.set("pgNumericArray")
@@ -238,6 +248,8 @@ public void testRetry() {
.to((Long) null)
.set("doubleVal")
.to((Double) null)
+ .set("floatVal")
+ .to((Float) null)
.set("bigDecimalVal")
.to((BigDecimal) null)
.set("pgNumericVal")
@@ -264,6 +276,8 @@ public void testRetry() {
.toInt64Array((Iterable) null)
.set("doubleArray")
.toFloat64Array((Iterable) null)
+ .set("floatArray")
+ .toFloat32Array((Iterable) null)
.set("bigDecimalArray")
.toNumericArray(null)
.set("pgNumericArray")
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java
index 0b54b35225..015927440d 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ConnectionImplTest.java
@@ -1863,6 +1863,50 @@ public void testCheckResultTypeAllowed() {
checkResultTypeAllowed(parser.parse(Statement.of(start)), allowedResultTypes);
}
+ @Test
+ public void testSetRetryAbortsInternally() {
+ try (ConnectionImpl connection =
+ createConnection(
+ ConnectionOptions.newBuilder()
+ .setCredentials(NoCredentials.getInstance())
+ .setUri(URI)
+ .build())) {
+ assertFalse("Read-only should be disabled by default", connection.isReadOnly());
+ assertTrue("Autocommit should be enabled by default", connection.isAutocommit());
+ assertFalse(
+ "Retry aborts internally should be disabled by default on test connections",
+ connection.isRetryAbortsInternally());
+
+ // It should be possible to change this value also when in auto-commit mode.
+ connection.setRetryAbortsInternally(true);
+ assertTrue(connection.isRetryAbortsInternally());
+
+ // It should be possible to change this value also when in transactional mode, as long as
+ // there is no active transaction.
+ connection.setAutocommit(false);
+ connection.setRetryAbortsInternally(false);
+ assertFalse(connection.isRetryAbortsInternally());
+
+ // It should be possible to change the value when in read-only mode.
+ connection.setReadOnly(true);
+ connection.setRetryAbortsInternally(true);
+ assertTrue(connection.isRetryAbortsInternally());
+
+ // It should not be possible to change the value when there is an active transaction.
+ connection.setReadOnly(false);
+ connection.setAutocommit(false);
+ connection.execute(Statement.of(SELECT));
+ assertThrows(SpannerException.class, () -> connection.setRetryAbortsInternally(false));
+ // Verify that the value did not change.
+ assertTrue(connection.isRetryAbortsInternally());
+
+ // Rolling back the connection should allow us to set the property again.
+ connection.rollback();
+ connection.setRetryAbortsInternally(false);
+ assertFalse(connection.isRetryAbortsInternally());
+ }
+ }
+
private void assertThrowResultNotAllowed(
AbstractStatementParser parser, String sql, ImmutableSet allowedResultTypes) {
SpannerException exception =
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/MergedResultSetTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/MergedResultSetTest.java
index 3cf717e176..8a309115c7 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/MergedResultSetTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/MergedResultSetTest.java
@@ -150,7 +150,7 @@ public void testAllResultsAreReturned() {
if (numPartitions == 0) {
assertEquals(0, resultSet.getColumnCount());
} else {
- assertEquals(22, resultSet.getColumnCount());
+ assertEquals(24, resultSet.getColumnCount());
assertEquals(Type.bool(), resultSet.getColumnType(0));
assertEquals(Type.bool(), resultSet.getColumnType("COL0"));
assertEquals(10, resultSet.getColumnIndex("COL10"));
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/PartitionedQueryMockServerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/PartitionedQueryMockServerTest.java
index e5731ff0f6..2536b74f10 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/PartitionedQueryMockServerTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/PartitionedQueryMockServerTest.java
@@ -58,15 +58,20 @@ public static Object[] data() {
@Parameter public Dialect dialect;
+ private Dialect currentDialect;
+
@Before
public void setupDialect() {
- mockSpanner.putStatementResult(StatementResult.detectDialectResult(dialect));
+ if (currentDialect != dialect) {
+ mockSpanner.putStatementResult(StatementResult.detectDialectResult(dialect));
+ SpannerPool.closeSpannerPool();
+ currentDialect = dialect;
+ }
}
@After
public void clearRequests() {
mockSpanner.clearRequests();
- SpannerPool.closeSpannerPool();
}
@Test
@@ -349,9 +354,9 @@ public void testRunEmptyPartitionedQuery() {
statement, PartitionOptions.newBuilder().setMaxPartitions(maxPartitions).build())) {
assertFalse(resultSet.next());
assertNotNull(resultSet.getMetadata());
- assertEquals(22, resultSet.getMetadata().getRowType().getFieldsCount());
+ assertEquals(24, resultSet.getMetadata().getRowType().getFieldsCount());
assertNotNull(resultSet.getType());
- assertEquals(22, resultSet.getType().getStructFields().size());
+ assertEquals(24, resultSet.getType().getStructFields().size());
}
}
assertEquals(1, mockSpanner.countRequestsOfType(CreateSessionRequest.class));
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/RandomResultSetGenerator.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/RandomResultSetGenerator.java
index 2067d36b5e..ef38df0db3 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/RandomResultSetGenerator.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/RandomResultSetGenerator.java
@@ -51,6 +51,7 @@ public static Type[] generateAllTypes(Dialect dialect) {
Arrays.asList(
Type.newBuilder().setCode(TypeCode.BOOL).build(),
Type.newBuilder().setCode(TypeCode.INT64).build(),
+ Type.newBuilder().setCode(TypeCode.FLOAT32).build(),
Type.newBuilder().setCode(TypeCode.FLOAT64).build(),
dialect == Dialect.POSTGRESQL
? Type.newBuilder()
@@ -76,6 +77,10 @@ public static Type[] generateAllTypes(Dialect dialect) {
.setCode(TypeCode.ARRAY)
.setArrayElementType(Type.newBuilder().setCode(TypeCode.INT64))
.build(),
+ Type.newBuilder()
+ .setCode(TypeCode.ARRAY)
+ .setArrayElementType(Type.newBuilder().setCode(TypeCode.FLOAT32))
+ .build(),
Type.newBuilder()
.setCode(TypeCode.ARRAY)
.setArrayElementType(Type.newBuilder().setCode(TypeCode.FLOAT64))
@@ -229,6 +234,13 @@ private void setRandomValue(Value.Builder builder, Type type) {
random.nextInt(2019) + 1, random.nextInt(11) + 1, random.nextInt(28) + 1);
builder.setStringValue(date.toString());
break;
+ case FLOAT32:
+ if (randomNaN()) {
+ builder.setNumberValue(Float.NaN);
+ } else {
+ builder.setNumberValue(random.nextFloat());
+ }
+ break;
case FLOAT64:
if (randomNaN()) {
builder.setNumberValue(Double.NaN);
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerPoolTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerPoolTest.java
index ed68f05c5f..b11c1f19be 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerPoolTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/SpannerPoolTest.java
@@ -39,6 +39,8 @@
import com.google.cloud.spanner.connection.SpannerPool.SpannerPoolKey;
import com.google.common.base.Ticker;
import com.google.common.testing.FakeTicker;
+import io.opentelemetry.api.OpenTelemetry;
+import io.opentelemetry.sdk.OpenTelemetrySdk;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;
@@ -69,6 +71,10 @@ public class SpannerPoolTest {
private ConnectionOptions options7 = mock(ConnectionOptions.class);
private ConnectionOptions options8 = mock(ConnectionOptions.class);
+ private ConnectionOptions optionsOpenTelemetry1 = mock(ConnectionOptions.class);
+ private ConnectionOptions optionsOpenTelemetry2 = mock(ConnectionOptions.class);
+ private ConnectionOptions optionsOpenTelemetry3 = mock(ConnectionOptions.class);
+
private SpannerPool createSubjectAndMocks() {
return createSubjectAndMocks(0L, Ticker.systemTicker());
}
@@ -83,6 +89,9 @@ Spanner createSpanner(SpannerPoolKey key, ConnectionOptions options) {
}
};
+ OpenTelemetry openTelemetry1 = OpenTelemetrySdk.builder().build();
+ OpenTelemetry openTelemetry2 = OpenTelemetrySdk.builder().build();
+
when(options1.getCredentialsUrl()).thenReturn(credentials1);
when(options1.getProjectId()).thenReturn("test-project-1");
when(options2.getCredentialsUrl()).thenReturn(credentials2);
@@ -101,6 +110,13 @@ Spanner createSpanner(SpannerPoolKey key, ConnectionOptions options) {
when(options8.getProjectId()).thenReturn("test-project-3");
when(options8.isRouteToLeader()).thenReturn(false);
+ when(optionsOpenTelemetry1.getProjectId()).thenReturn("test-project-1");
+ when(optionsOpenTelemetry1.getOpenTelemetry()).thenReturn(openTelemetry1);
+ when(optionsOpenTelemetry2.getProjectId()).thenReturn("test-project-1");
+ when(optionsOpenTelemetry2.getOpenTelemetry()).thenReturn(openTelemetry1);
+ when(optionsOpenTelemetry3.getProjectId()).thenReturn("test-project-1");
+ when(optionsOpenTelemetry3.getOpenTelemetry()).thenReturn(openTelemetry2);
+
return pool;
}
@@ -498,4 +514,21 @@ public void testSpannerPoolKeyEquality() {
assertEquals(key3, key4);
assertNotEquals(key4, key5);
}
+
+ @Test
+ public void testOpenTelemetry() {
+ SpannerPool pool = createSubjectAndMocks();
+ Spanner spanner1;
+ Spanner spanner2;
+
+ // assert equal
+ spanner1 = pool.getSpanner(optionsOpenTelemetry1, connection1);
+ spanner2 = pool.getSpanner(optionsOpenTelemetry2, connection2);
+ assertEquals(spanner1, spanner2);
+
+ // assert not equal
+ spanner1 = pool.getSpanner(optionsOpenTelemetry1, connection1);
+ spanner2 = pool.getSpanner(optionsOpenTelemetry3, connection2);
+ assertNotEquals(spanner1, spanner2);
+ }
}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITAsyncExamplesTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITAsyncExamplesTest.java
index 5a22c64009..87f26da904 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITAsyncExamplesTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITAsyncExamplesTest.java
@@ -344,9 +344,12 @@ public void readOnlyTransaction() throws Exception {
values2 = rs.toListAsync(input -> input.getString("StringValue"), executor);
}
}
+
+ ApiFuture>> allAsListValues =
+ ApiFutures.allAsList(Arrays.asList(values1, values2));
ApiFuture> allValues =
ApiFutures.transform(
- ApiFutures.allAsList(Arrays.asList(values1, values2)),
+ allAsListValues,
input ->
Iterables.mergeSorted(
input, Comparator.comparing(o -> Integer.valueOf(o.substring(1)))),
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITFloat32Test.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITFloat32Test.java
new file mode 100644
index 0000000000..de2640b86c
--- /dev/null
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITFloat32Test.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.spanner.it;
+
+import static com.google.cloud.spanner.testing.EmulatorSpannerHelper.isUsingEmulator;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import com.google.cloud.Timestamp;
+import com.google.cloud.spanner.Database;
+import com.google.cloud.spanner.DatabaseClient;
+import com.google.cloud.spanner.Dialect;
+import com.google.cloud.spanner.IntegrationTestEnv;
+import com.google.cloud.spanner.Key;
+import com.google.cloud.spanner.Mutation;
+import com.google.cloud.spanner.ParallelIntegrationTest;
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.Statement;
+import com.google.cloud.spanner.Struct;
+import com.google.cloud.spanner.TimestampBound;
+import com.google.cloud.spanner.Value;
+import com.google.cloud.spanner.connection.ConnectionOptions;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@Category(ParallelIntegrationTest.class)
+@RunWith(Parameterized.class)
+public class ITFloat32Test {
+
+ @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv();
+
+ @Parameterized.Parameters(name = "Dialect = {0}")
+ public static List data() {
+ return Arrays.asList(
+ new DialectTestParameter(Dialect.GOOGLE_STANDARD_SQL),
+ new DialectTestParameter(Dialect.POSTGRESQL));
+ }
+
+ @Parameterized.Parameter() public DialectTestParameter dialect;
+
+ private static DatabaseClient googleStandardSQLClient;
+ private static DatabaseClient postgreSQLClient;
+
+ private static final String[] GOOGLE_STANDARD_SQL_SCHEMA =
+ new String[] {
+ "CREATE TABLE T ("
+ + " Key STRING(MAX) NOT NULL,"
+ + " Float32Value FLOAT32,"
+ + " Float32ArrayValue ARRAY,"
+ + ") PRIMARY KEY (Key)"
+ };
+
+ private static final String[] POSTGRESQL_SCHEMA =
+ new String[] {
+ "CREATE TABLE T ("
+ + " Key VARCHAR PRIMARY KEY,"
+ + " Float32Value REAL,"
+ + " Float32ArrayValue REAL[]"
+ + ")"
+ };
+
+ private static DatabaseClient client;
+
+ private static boolean isUsingCloudDevel() {
+ String jobType = System.getenv("JOB_TYPE");
+
+ // Assumes that the jobType contains the string "cloud-devel" to signal that
+ // the environment is cloud-devel.
+ return !isNullOrEmpty(jobType) && jobType.contains("cloud-devel");
+ }
+
+ @BeforeClass
+ public static void setUpDatabase()
+ throws ExecutionException, InterruptedException, TimeoutException {
+ assumeTrue("FLOAT32 is currently only supported in cloud-devel", isUsingCloudDevel());
+ assumeFalse("Emulator does not support FLOAT32 yet", isUsingEmulator());
+
+ Database googleStandardSQLDatabase =
+ env.getTestHelper().createTestDatabase(GOOGLE_STANDARD_SQL_SCHEMA);
+
+ googleStandardSQLClient = env.getTestHelper().getDatabaseClient(googleStandardSQLDatabase);
+
+ Database postgreSQLDatabase =
+ env.getTestHelper()
+ .createTestDatabase(Dialect.POSTGRESQL, Arrays.asList(POSTGRESQL_SCHEMA));
+ postgreSQLClient = env.getTestHelper().getDatabaseClient(postgreSQLDatabase);
+ }
+
+ @Before
+ public void before() {
+ client =
+ dialect.dialect == Dialect.GOOGLE_STANDARD_SQL ? googleStandardSQLClient : postgreSQLClient;
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ ConnectionOptions.closeSpanner();
+ }
+
+ /** Sequence used to generate unique keys. */
+ private static int seq;
+
+ private static String uniqueString() {
+ return String.format("k%04d", seq++);
+ }
+
+ private String lastKey;
+
+ private Timestamp write(Mutation m) {
+ return client.write(Collections.singletonList(m));
+ }
+
+ private Mutation.WriteBuilder baseInsert() {
+ return Mutation.newInsertOrUpdateBuilder("T").set("Key").to(lastKey = uniqueString());
+ }
+
+ private Struct readRow(String table, String key, String... columns) {
+ return client
+ .singleUse(TimestampBound.strong())
+ .readRow(table, Key.of(key), Arrays.asList(columns));
+ }
+
+ private Struct readLastRow(String... columns) {
+ return readRow("T", lastKey, columns);
+ }
+
+ @Test
+ public void writeFloat32() {
+ write(baseInsert().set("Float32Value").to(2.0f).build());
+ Struct row = readLastRow("Float32Value");
+ assertFalse(row.isNull(0));
+ assertEquals(2.0f, row.getFloat(0), 0.0f);
+ }
+
+ @Test
+ public void writeFloat32NonNumbers() {
+
+ write(baseInsert().set("Float32Value").to(Float.NEGATIVE_INFINITY).build());
+ Struct row = readLastRow("Float32Value");
+ assertFalse(row.isNull(0));
+ assertEquals(Float.NEGATIVE_INFINITY, row.getFloat(0), 0.0f);
+
+ write(baseInsert().set("Float32Value").to(Float.POSITIVE_INFINITY).build());
+ row = readLastRow("Float32Value");
+ assertFalse(row.isNull(0));
+ assertEquals(Float.POSITIVE_INFINITY, row.getFloat(0), 0.0);
+
+ write(baseInsert().set("Float32Value").to(Float.NaN).build());
+ row = readLastRow("Float32Value");
+ assertFalse(row.isNull(0));
+ assertTrue(Float.isNaN(row.getFloat(0)));
+ }
+
+ @Test
+ public void writeFloat32Null() {
+ write(baseInsert().set("Float32Value").to((Float) null).build());
+ Struct row = readLastRow("Float32Value");
+ assertTrue(row.isNull(0));
+ }
+
+ @Test
+ public void writeFloat32ArrayNull() {
+ write(baseInsert().set("Float32ArrayValue").toFloat32Array((float[]) null).build());
+ Struct row = readLastRow("Float32ArrayValue");
+ assertTrue(row.isNull(0));
+ }
+
+ @Test
+ public void writeFloat32ArrayEmpty() {
+ write(baseInsert().set("Float32ArrayValue").toFloat32Array(new float[] {}).build());
+ Struct row = readLastRow("Float32ArrayValue");
+ assertFalse(row.isNull(0));
+ assertTrue(row.getFloatList(0).isEmpty());
+ }
+
+ @Test
+ public void writeFloat32Array() {
+ write(
+ baseInsert()
+ .set("Float32ArrayValue")
+ .toFloat32Array(Arrays.asList(null, 1.0f, 2.0f))
+ .build());
+ Struct row = readLastRow("Float32ArrayValue");
+ assertFalse(row.isNull(0));
+ assertEquals(row.getFloatList(0), Arrays.asList(null, 1.0f, 2.0f));
+ assertThrows(NullPointerException.class, () -> row.getFloatArray(0));
+ }
+
+ @Test
+ public void writeFloat32ArrayNoNulls() {
+ write(baseInsert().set("Float32ArrayValue").toFloat32Array(Arrays.asList(1.0f, 2.0f)).build());
+ Struct row = readLastRow("Float32ArrayValue");
+ assertFalse(row.isNull(0));
+ assertEquals(2, row.getFloatArray(0).length);
+ assertEquals(1.0f, row.getFloatArray(0)[0], 0.0f);
+ assertEquals(2.0f, row.getFloatArray(0)[1], 0.0f);
+ }
+
+ private String getInsertStatementWithLiterals() {
+ String statement = "INSERT INTO T (Key, Float32Value, Float32ArrayValue) VALUES ";
+
+ if (dialect.dialect == Dialect.POSTGRESQL) {
+ statement +=
+ "('dml1', 3.14::float8, array[1.1]::float4[]), "
+ + "('dml2', '3.14'::float4, array[3.14::float4, 3.14::float8]::float4[]), "
+ + "('dml3', 'nan'::real, array['inf'::real, (3.14::float8)::float4, 1.2, '-inf']::float4[]), "
+ + "('dml4', 1.175494e-38::real, array[1.175494e-38, 3.4028234e38, -3.4028234e38]::real[]), "
+ + "('dml5', null, null)";
+ } else {
+ statement +=
+ "('dml1', 3.14, [CAST(1.1 AS FLOAT32)]), "
+ + "('dml2', CAST('3.14' AS FLOAT32), array[CAST(3.14 AS FLOAT32), 3.14]), "
+ + "('dml3', CAST('nan' AS FLOAT32), array[CAST('inf' AS FLOAT32), CAST(CAST(3.14 AS FLOAT64) AS FLOAT32), 1.2, CAST('-inf' AS FLOAT32)]), "
+ + "('dml4', 1.175494e-38, [CAST(1.175494e-38 AS FLOAT32), 3.4028234e38, -3.4028234e38]), "
+ + "('dml5', null, null)";
+ }
+ return statement;
+ }
+
+ @Test
+ public void float32Literals() {
+ client
+ .readWriteTransaction()
+ .run(
+ transaction -> {
+ transaction.executeUpdate(Statement.of(getInsertStatementWithLiterals()));
+ return null;
+ });
+
+ verifyContents("dml");
+ }
+
+ private String getInsertStatementWithParameters() {
+ String pgStatement =
+ "INSERT INTO T (Key, Float32Value, Float32ArrayValue) VALUES "
+ + "('param1', $1, $2), "
+ + "('param2', $3, $4), "
+ + "('param3', $5, $6), "
+ + "('param4', $7, $8), "
+ + "('param5', $9, $10)";
+
+ return (dialect.dialect == Dialect.POSTGRESQL) ? pgStatement : pgStatement.replace("$", "@p");
+ }
+
+ @Test
+ public void float32Parameter() {
+ client
+ .readWriteTransaction()
+ .run(
+ transaction -> {
+ transaction.executeUpdate(
+ Statement.newBuilder(getInsertStatementWithParameters())
+ .bind("p1")
+ .to(Value.float32(3.14f))
+ .bind("p2")
+ .to(Value.float32Array(Arrays.asList(1.1f)))
+ .bind("p3")
+ .to(Value.float32(3.14f))
+ .bind("p4")
+ .to(Value.float32Array(new float[] {3.14f, 3.14f}))
+ .bind("p5")
+ .to(Value.float32(Float.NaN))
+ .bind("p6")
+ .to(
+ Value.float32Array(
+ Arrays.asList(
+ Float.POSITIVE_INFINITY, 3.14f, 1.2f, Float.NEGATIVE_INFINITY)))
+ .bind("p7")
+ .to(Value.float32(Float.MIN_NORMAL))
+ .bind("p8")
+ .to(
+ Value.float32Array(
+ Arrays.asList(
+ Float.MIN_NORMAL, Float.MAX_VALUE, -1 * Float.MAX_VALUE)))
+ .bind("p9")
+ .to(Value.float32(null))
+ .bind("p10")
+ .to(Value.float32Array((float[]) null))
+ .build());
+ return null;
+ });
+
+ verifyContents("param");
+ }
+
+ private String getInsertStatementForUntypedParameters() {
+ if (dialect.dialect == Dialect.POSTGRESQL) {
+ return "INSERT INTO T (key, float32value, float32arrayvalue) VALUES "
+ + "('untyped1', ($1)::float4, ($2)::float4[])";
+ }
+ return "INSERT INTO T (Key, Float32Value, Float32ArrayValue) VALUES "
+ + "('untyped1', CAST(@p1 AS FLOAT32), CAST(@p2 AS ARRAY))";
+ }
+
+ @Test
+ public void float32UntypedParameter() {
+ client
+ .readWriteTransaction()
+ .run(
+ transaction -> {
+ transaction.executeUpdate(
+ Statement.newBuilder(getInsertStatementForUntypedParameters())
+ .bind("p1")
+ .to(
+ Value.untyped(
+ com.google.protobuf.Value.newBuilder()
+ .setNumberValue((double) 3.14f)
+ .build()))
+ .bind("p2")
+ .to(
+ Value.untyped(
+ com.google.protobuf.Value.newBuilder()
+ .setListValue(
+ com.google.protobuf.ListValue.newBuilder()
+ .addValues(
+ com.google.protobuf.Value.newBuilder()
+ .setNumberValue((double) Float.MIN_NORMAL)))
+ .build()))
+ .build());
+ return null;
+ });
+
+ Struct row = readRow("T", "untyped1", "Float32Value", "Float32ArrayValue");
+ // Float32Value
+ assertFalse(row.isNull(0));
+ assertEquals(3.14f, row.getFloat(0), 0.00001f);
+ // Float32ArrayValue
+ assertFalse(row.isNull(1));
+ assertEquals(1, row.getFloatList(1).size());
+ assertEquals(Float.MIN_NORMAL, row.getFloatList(1).get(0), 0.00001f);
+ }
+
+ private void verifyContents(String keyPrefix) {
+ try (ResultSet resultSet =
+ client
+ .singleUse()
+ .executeQuery(
+ Statement.of(
+ "SELECT Key AS key, Float32Value AS float32value, Float32ArrayValue AS float32arrayvalue FROM T WHERE Key LIKE '{keyPrefix}%' ORDER BY key"
+ .replace("{keyPrefix}", keyPrefix)))) {
+
+ assertTrue(resultSet.next());
+
+ assertEquals(3.14f, resultSet.getFloat("float32value"), 0.00001f);
+ assertEquals(Value.float32(3.14f), resultSet.getValue("float32value"));
+
+ assertArrayEquals(new float[] {1.1f}, resultSet.getFloatArray("float32arrayvalue"), 0.00001f);
+
+ assertTrue(resultSet.next());
+
+ assertEquals(3.14f, resultSet.getFloat("float32value"), 0.00001f);
+ assertEquals(Arrays.asList(3.14f, 3.14f), resultSet.getFloatList("float32arrayvalue"));
+ assertEquals(
+ Value.float32Array(new float[] {3.14f, 3.14f}), resultSet.getValue("float32arrayvalue"));
+
+ assertTrue(resultSet.next());
+ assertTrue(Float.isNaN(resultSet.getFloat("float32value")));
+ assertTrue(Float.isNaN(resultSet.getValue("float32value").getFloat32()));
+ assertEquals(
+ Arrays.asList(Float.POSITIVE_INFINITY, 3.14f, 1.2f, Float.NEGATIVE_INFINITY),
+ resultSet.getFloatList("float32arrayvalue"));
+ assertEquals(
+ Value.float32Array(
+ Arrays.asList(Float.POSITIVE_INFINITY, 3.14f, 1.2f, Float.NEGATIVE_INFINITY)),
+ resultSet.getValue("float32arrayvalue"));
+
+ assertTrue(resultSet.next());
+ assertEquals(Float.MIN_NORMAL, resultSet.getFloat("float32value"), 0.00001f);
+ assertEquals(Float.MIN_NORMAL, resultSet.getValue("float32value").getFloat32(), 0.00001f);
+ assertEquals(3, resultSet.getFloatList("float32arrayvalue").size());
+ assertEquals(Float.MIN_NORMAL, resultSet.getFloatList("float32arrayvalue").get(0), 0.00001);
+ assertEquals(Float.MAX_VALUE, resultSet.getFloatList("float32arrayvalue").get(1), 0.00001f);
+ assertEquals(
+ -1 * Float.MAX_VALUE, resultSet.getFloatList("float32arrayvalue").get(2), 0.00001f);
+ assertEquals(3, resultSet.getValue("float32arrayvalue").getFloat32Array().size());
+
+ assertTrue(resultSet.next());
+ assertTrue(resultSet.isNull("float32value"));
+ assertTrue(resultSet.isNull("float32arrayvalue"));
+
+ assertFalse(resultSet.next());
+ }
+ }
+}
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java
index a691fbf78b..170ce75e69 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITQueryTest.java
@@ -17,6 +17,7 @@
package com.google.cloud.spanner.it;
import static com.google.cloud.spanner.testing.EmulatorSpannerHelper.isUsingEmulator;
+import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.truth.Truth.assertThat;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
@@ -254,6 +255,36 @@ public void bindInt64Null() {
assertThat(row.isNull(0)).isTrue();
}
+ // TODO: Remove once FLOAT32 is supported in production.
+ private static boolean isUsingCloudDevel() {
+ String jobType = System.getenv("JOB_TYPE");
+
+ // Assumes that the jobType contains the string "cloud-devel" to signal that
+ // the environment is cloud-devel.
+ return !isNullOrEmpty(jobType) && jobType.contains("cloud-devel");
+ }
+
+ @Test
+ public void bindFloat32() {
+ assumeFalse("Emulator does not support FLOAT32 yet", isUsingEmulator());
+ assumeTrue("FLOAT32 is currently only supported in cloud-devel", isUsingCloudDevel());
+
+ Struct row =
+ execute(Statement.newBuilder(selectValueQuery).bind("p1").to(2.0f), Type.float32());
+ assertThat(row.isNull(0)).isFalse();
+ assertThat(row.getFloat(0)).isWithin(0.0f).of(2.0f);
+ }
+
+ @Test
+ public void bindFloat32Null() {
+ assumeFalse("Emulator does not support FLOAT32 yet", isUsingEmulator());
+ assumeTrue("FLOAT32 is currently only supported in cloud-devel", isUsingCloudDevel());
+
+ Struct row =
+ execute(Statement.newBuilder(selectValueQuery).bind("p1").to((Float) null), Type.float32());
+ assertThat(row.isNull(0)).isTrue();
+ }
+
@Test
public void bindFloat64() {
Struct row = execute(Statement.newBuilder(selectValueQuery).bind("p1").to(2.0), Type.float64());
@@ -497,6 +528,58 @@ public void bindInt64ArrayNull() {
assertThat(row.isNull(0)).isTrue();
}
+ @Test
+ public void bindFloat32Array() {
+ assumeFalse("Emulator does not support FLOAT32 yet", isUsingEmulator());
+ assumeTrue("FLOAT32 is currently only supported in cloud-devel", isUsingCloudDevel());
+
+ Struct row =
+ execute(
+ Statement.newBuilder(selectValueQuery)
+ .bind("p1")
+ .toFloat32Array(
+ asList(
+ null,
+ 1.0f,
+ 2.0f,
+ Float.NEGATIVE_INFINITY,
+ Float.POSITIVE_INFINITY,
+ Float.NaN)),
+ Type.array(Type.float32()));
+ assertThat(row.isNull(0)).isFalse();
+ assertThat(row.getFloatList(0))
+ .containsExactly(
+ null, 1.0f, 2.0f, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NaN)
+ .inOrder();
+ }
+
+ @Test
+ public void bindFloat32ArrayEmpty() {
+ assumeFalse("Emulator does not support FLOAT32 yet", isUsingEmulator());
+ assumeTrue("FLOAT32 is currently only supported in cloud-devel", isUsingCloudDevel());
+
+ Struct row =
+ execute(
+ Statement.newBuilder(selectValueQuery)
+ .bind("p1")
+ .toFloat32Array(Collections.emptyList()),
+ Type.array(Type.float32()));
+ assertThat(row.isNull(0)).isFalse();
+ assertThat(row.getFloatList(0)).containsExactly();
+ }
+
+ @Test
+ public void bindFloat32ArrayNull() {
+ assumeFalse("Emulator does not support FLOAT32 yet", isUsingEmulator());
+ assumeTrue("FLOAT32 is currently only supported in cloud-devel", isUsingCloudDevel());
+
+ Struct row =
+ execute(
+ Statement.newBuilder(selectValueQuery).bind("p1").toFloat32Array((float[]) null),
+ Type.array(Type.float32()));
+ assertThat(row.isNull(0)).isTrue();
+ }
+
@Test
public void bindFloat64Array() {
Struct row =
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionTest.java
index 2cfb9cbbc5..ea60b9fb64 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITTransactionTest.java
@@ -298,7 +298,6 @@ public void readAbort() throws Exception {
} catch (SpannerException e) {
if (e.getErrorCode() == ErrorCode.ABORTED) {
assertThat(e).isInstanceOf(AbortedException.class);
- assertThat(e.getRetryDelayInMillis()).isNotEqualTo(-1L);
}
throw new RuntimeException("Swallowed exception: " + e.getMessage());
}
@@ -338,7 +337,6 @@ public void readAbort() throws Exception {
} catch (SpannerException e) {
if (e.getErrorCode() == ErrorCode.ABORTED) {
assertThat(e).isInstanceOf(AbortedException.class);
- assertThat(e.getRetryDelayInMillis()).isNotEqualTo(-1L);
}
throw new RuntimeException("Swallowed exception: " + e.getMessage());
}
diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml
index fe0aae9d55..e55efda7d9 100644
--- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml
+++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
grpc-google-cloud-spanner-admin-database-v1
- 6.60.1
+ 6.61.0
grpc-google-cloud-spanner-admin-database-v1
GRPC library for grpc-google-cloud-spanner-admin-database-v1
com.google.cloud
google-cloud-spanner-parent
- 6.60.1
+ 6.61.0
diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml
index 7d4e7ec962..aead92c9a1 100644
--- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml
+++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
grpc-google-cloud-spanner-admin-instance-v1
- 6.60.1
+ 6.61.0
grpc-google-cloud-spanner-admin-instance-v1
GRPC library for grpc-google-cloud-spanner-admin-instance-v1
com.google.cloud
google-cloud-spanner-parent
- 6.60.1
+ 6.61.0
diff --git a/grpc-google-cloud-spanner-executor-v1/pom.xml b/grpc-google-cloud-spanner-executor-v1/pom.xml
index 5d508b1cc2..cc007bd888 100644
--- a/grpc-google-cloud-spanner-executor-v1/pom.xml
+++ b/grpc-google-cloud-spanner-executor-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
grpc-google-cloud-spanner-executor-v1
- 6.60.1
+ 6.61.0
grpc-google-cloud-spanner-executor-v1
GRPC library for google-cloud-spanner
com.google.cloud
google-cloud-spanner-parent
- 6.60.1
+ 6.61.0
diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml
index 399a04ef7b..941536483c 100644
--- a/grpc-google-cloud-spanner-v1/pom.xml
+++ b/grpc-google-cloud-spanner-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
grpc-google-cloud-spanner-v1
- 6.60.1
+ 6.61.0
grpc-google-cloud-spanner-v1
GRPC library for grpc-google-cloud-spanner-v1
com.google.cloud
google-cloud-spanner-parent
- 6.60.1
+ 6.61.0
diff --git a/pom.xml b/pom.xml
index ef95e28fbf..bb0fb156d0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.google.cloud
google-cloud-spanner-parent
pom
- 6.60.1
+ 6.61.0
Google Cloud Spanner Parent
https://github.com/googleapis/java-spanner
@@ -14,7 +14,7 @@
com.google.cloud
sdk-platform-java-config
- 3.25.0
+ 3.27.0
@@ -61,47 +61,47 @@
com.google.api.grpc
proto-google-cloud-spanner-admin-instance-v1
- 6.60.1
+ 6.61.0
com.google.api.grpc
proto-google-cloud-spanner-executor-v1
- 6.60.1
+ 6.61.0
com.google.api.grpc
grpc-google-cloud-spanner-executor-v1
- 6.60.1
+ 6.61.0
com.google.api.grpc
proto-google-cloud-spanner-v1
- 6.60.1
+ 6.61.0
com.google.api.grpc
proto-google-cloud-spanner-admin-database-v1
- 6.60.1
+ 6.61.0
com.google.api.grpc
grpc-google-cloud-spanner-v1
- 6.60.1
+ 6.61.0
com.google.api.grpc
grpc-google-cloud-spanner-admin-instance-v1
- 6.60.1
+ 6.61.0
com.google.api.grpc
grpc-google-cloud-spanner-admin-database-v1
- 6.60.1
+ 6.61.0
com.google.cloud
google-cloud-spanner
- 6.60.1
+ 6.61.0
@@ -121,7 +121,7 @@
com.google.truth
truth
- 1.4.1
+ 1.4.2
test
diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml
index 0514be006b..5e6f00a6fc 100644
--- a/proto-google-cloud-spanner-admin-database-v1/pom.xml
+++ b/proto-google-cloud-spanner-admin-database-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
proto-google-cloud-spanner-admin-database-v1
- 6.60.1
+ 6.61.0
proto-google-cloud-spanner-admin-database-v1
PROTO library for proto-google-cloud-spanner-admin-database-v1
com.google.cloud
google-cloud-spanner-parent
- 6.60.1
+ 6.61.0
diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml
index 9fe5dad3a6..205dfdcc1b 100644
--- a/proto-google-cloud-spanner-admin-instance-v1/pom.xml
+++ b/proto-google-cloud-spanner-admin-instance-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
proto-google-cloud-spanner-admin-instance-v1
- 6.60.1
+ 6.61.0
proto-google-cloud-spanner-admin-instance-v1
PROTO library for proto-google-cloud-spanner-admin-instance-v1
com.google.cloud
google-cloud-spanner-parent
- 6.60.1
+ 6.61.0
diff --git a/proto-google-cloud-spanner-executor-v1/pom.xml b/proto-google-cloud-spanner-executor-v1/pom.xml
index 4e560822d1..e8dcec3683 100644
--- a/proto-google-cloud-spanner-executor-v1/pom.xml
+++ b/proto-google-cloud-spanner-executor-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
proto-google-cloud-spanner-executor-v1
- 6.60.1
+ 6.61.0
proto-google-cloud-spanner-executor-v1
Proto library for google-cloud-spanner
com.google.cloud
google-cloud-spanner-parent
- 6.60.1
+ 6.61.0
diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml
index dafe631172..7c9f074e92 100644
--- a/proto-google-cloud-spanner-v1/pom.xml
+++ b/proto-google-cloud-spanner-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
proto-google-cloud-spanner-v1
- 6.60.1
+ 6.61.0
proto-google-cloud-spanner-v1
PROTO library for proto-google-cloud-spanner-v1
com.google.cloud
google-cloud-spanner-parent
- 6.60.1
+ 6.61.0
diff --git a/samples/README.md b/samples/README.md
index 9f961354d9..914c455b46 100644
--- a/samples/README.md
+++ b/samples/README.md
@@ -34,7 +34,7 @@ You can run a given `ClassName` via:
## Tutorial
### Running the tutorial
- mvn exec:java -Dexec.mainClass=com.example.spanner.SpannerSample -Dexec.args=" my-instance my-database"
+ mvn exec:java -Dexec.mainClass=com.example.spanner.admin.archived.SpannerSample -Dexec.args=" my-instance my-database"
## Tracing sample
`TracingSample.java` demonstrates how to export traces generated by client library to StackDriver and to /tracez page.
diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml
index af217d9bd4..fb290694d6 100644
--- a/samples/install-without-bom/pom.xml
+++ b/samples/install-without-bom/pom.xml
@@ -33,7 +33,7 @@
com.google.cloud
google-cloud-spanner
- 6.60.0
+ 6.60.1
@@ -100,7 +100,7 @@
com.google.truth
truth
- 1.4.1
+ 1.4.2
test
@@ -147,8 +147,8 @@
java-client-mr-integration-test
nam11
us-east1
- cmek-test-key-ring
- cmek-test-key
+ java-client-integration-test-cmek-ring
+ java-client-integration-test-cmek-key
mysample
quick-db
diff --git a/samples/native-image/pom.xml b/samples/native-image/pom.xml
index 0c72603f1a..ea90374c40 100644
--- a/samples/native-image/pom.xml
+++ b/samples/native-image/pom.xml
@@ -51,7 +51,7 @@
com.google.truth
truth
- 1.4.1
+ 1.4.2
test
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index cc31362f1a..298e4eab43 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -32,7 +32,7 @@
com.google.cloud
google-cloud-spanner
- 6.60.1
+ 6.61.0
@@ -99,7 +99,7 @@
com.google.truth
truth
- 1.4.1
+ 1.4.2
test
@@ -146,8 +146,8 @@
java-client-mr-integration-test
nam11
us-east1
- cmek-test-key-ring
- cmek-test-key
+ java-client-integration-test-cmek-ring
+ java-client-integration-test-cmek-key
mysample
mysample-instance
quick-db
diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index 5dbe22f146..0d149d8e78 100644
--- a/samples/snippets/pom.xml
+++ b/samples/snippets/pom.xml
@@ -111,7 +111,7 @@
com.google.truth
truth
- 1.4.1
+ 1.4.2
test
@@ -165,7 +165,7 @@
false
- com.example.spanner.SpannerSample
+ com.example.spanner.admin.archived.SpannerSample
true
lib/
@@ -182,8 +182,8 @@
java-client-mr-integration-test
nam11
us-east1
- cmek-test-key-ring
- cmek-test-key
+ java-client-integration-test-cmek-ring
+ java-client-integration-test-cmek-key
mysample
quick-db
diff --git a/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java b/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java
index 2d65974099..75e85f5f85 100644
--- a/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java
+++ b/samples/snippets/src/main/java/com/example/spanner/AddAndDropDatabaseRole.java
@@ -17,12 +17,12 @@
package com.example.spanner;
// [START spanner_add_and_drop_database_role]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -34,54 +34,46 @@ static void addAndDropDatabaseRole() {
String projectId = "my-project";
String instanceId = "my-instance";
String databaseId = "my-database";
- String parentRole = "my-new-parent-role";
- String childRole = "my-new-child-role";
+ String parentRole = "parent_role";
+ String childRole = "child_role";
addAndDropDatabaseRole(projectId, instanceId, databaseId, parentRole, childRole);
}
static void addAndDropDatabaseRole(
- String projectId, String instanceId, String databaseId, String parentRole, String childRole) {
+ String projectId, String instanceId, String databaseId,
+ String parentRole, String childRole) {
try (Spanner spanner =
- SpannerOptions.newBuilder()
- .setProjectId(projectId)
- .build()
- .getService()) {
- final DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
- OperationFuture operation =
- adminClient.updateDatabaseDdl(
- instanceId,
- databaseId,
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ System.out.println("Waiting for role create operation to complete...");
+ databaseAdminClient.updateDatabaseDdlAsync(
+ DatabaseName.of(projectId, instanceId, databaseId),
ImmutableList.of(
- "CREATE ROLE " + parentRole,
- "GRANT SELECT ON TABLE Albums TO ROLE " + parentRole,
- "CREATE ROLE " + childRole,
- "GRANT ROLE " + parentRole + " TO ROLE " + childRole),
- null);
- try {
- System.out.println("Waiting for role create operation to complete...");
- operation.get(5, TimeUnit.MINUTES);
- System.out.printf(
- "Created roles %s and %s and granted privileges%n", parentRole, childRole);
- // Delete role and membership.
- operation =
- adminClient.updateDatabaseDdl(
- instanceId,
- databaseId,
- ImmutableList.of(
- "REVOKE ROLE " + parentRole + " FROM ROLE " + childRole,
- "DROP ROLE " + childRole),
- null);
- System.out.println("Waiting for role revoke & drop operation to complete...");
- operation.get(5, TimeUnit.MINUTES);
- System.out.printf("Revoked privileges and dropped role %s%n", childRole);
- } catch (ExecutionException | TimeoutException e) {
- System.out.printf(
- "Error: AddAndDropDatabaseRole failed with error message %s\n", e.getMessage());
- e.printStackTrace();
- } catch (InterruptedException e) {
- System.out.println(
- "Error: Waiting for AddAndDropDatabaseRole operation to finish was interrupted");
- }
+ String.format("CREATE ROLE %s", parentRole),
+ String.format("GRANT SELECT ON TABLE Albums TO ROLE %s", parentRole),
+ String.format("CREATE ROLE %s", childRole),
+ String.format("GRANT ROLE %s TO ROLE %s", parentRole, childRole)))
+ .get(5, TimeUnit.MINUTES);
+ System.out.printf(
+ "Created roles %s and %s and granted privileges%n", parentRole, childRole);
+ // Delete role and membership.
+ System.out.println("Waiting for role revoke & drop operation to complete...");
+ databaseAdminClient.updateDatabaseDdlAsync(
+ DatabaseName.of(projectId, instanceId, databaseId),
+ ImmutableList.of(
+ String.format("REVOKE ROLE %s FROM ROLE %s", parentRole, childRole),
+ String.format("DROP ROLE %s", childRole))).get(5, TimeUnit.MINUTES);
+ System.out.printf("Revoked privileges and dropped role %s%n", childRole);
+ } catch (ExecutionException | TimeoutException e) {
+ System.out.printf(
+ "Error: AddAndDropDatabaseRole failed with error message %s\n", e.getMessage());
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ System.out.println(
+ "Error: Waiting for AddAndDropDatabaseRole operation to finish was interrupted");
}
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/AddJsonColumnSample.java b/samples/snippets/src/main/java/com/example/spanner/AddJsonColumnSample.java
index 8be919ddad..c87b25ff47 100644
--- a/samples/snippets/src/main/java/com/example/spanner/AddJsonColumnSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/AddJsonColumnSample.java
@@ -17,12 +17,12 @@
package com.example.spanner;
// [START spanner_add_json_column]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.concurrent.ExecutionException;
class AddJsonColumnSample {
@@ -33,25 +33,24 @@ static void addJsonColumn() throws InterruptedException, ExecutionException {
String instanceId = "my-instance";
String databaseId = "my-database";
- try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
- addJsonColumn(adminClient, instanceId, databaseId);
- }
+ addJsonColumn(projectId, instanceId, databaseId);
}
- static void addJsonColumn(DatabaseAdminClient adminClient, String instanceId, String databaseId)
+ static void addJsonColumn(String projectId, String instanceId, String databaseId)
throws InterruptedException, ExecutionException {
- OperationFuture operation =
- adminClient.updateDatabaseDdl(
- instanceId,
- databaseId,
- ImmutableList.of("ALTER TABLE Venues ADD COLUMN VenueDetails JSON"),
- null);
- // Wait for the operation to finish.
- // This will throw an ExecutionException if the operation fails.
- operation.get();
- System.out.printf("Successfully added column `VenueDetails`%n");
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ // Wait for the operation to finish.
+ // This will throw an ExecutionException if the operation fails.
+ databaseAdminClient.updateDatabaseDdlAsync(
+ DatabaseName.of(projectId, instanceId, databaseId),
+ ImmutableList.of("ALTER TABLE Venues ADD COLUMN VenueDetails JSON")).get();
+ System.out.printf("Successfully added column `VenueDetails`%n");
+ }
}
}
// [END spanner_add_json_column]
diff --git a/samples/snippets/src/main/java/com/example/spanner/AddJsonbColumnSample.java b/samples/snippets/src/main/java/com/example/spanner/AddJsonbColumnSample.java
index e8152c4fa0..ab2607c498 100644
--- a/samples/snippets/src/main/java/com/example/spanner/AddJsonbColumnSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/AddJsonbColumnSample.java
@@ -17,12 +17,12 @@
package com.example.spanner;
// [START spanner_postgresql_jsonb_add_column]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.concurrent.ExecutionException;
class AddJsonbColumnSample {
@@ -33,25 +33,25 @@ static void addJsonbColumn() throws InterruptedException, ExecutionException {
String instanceId = "my-instance";
String databaseId = "my-database";
- try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
- addJsonbColumn(adminClient, instanceId, databaseId);
- }
+ addJsonbColumn(projectId, instanceId, databaseId);
}
- static void addJsonbColumn(DatabaseAdminClient adminClient, String instanceId, String databaseId)
+ static void addJsonbColumn(String projectId, String instanceId, String databaseId)
throws InterruptedException, ExecutionException {
- OperationFuture operation =
- adminClient.updateDatabaseDdl(
- instanceId,
- databaseId,
- ImmutableList.of("ALTER TABLE Venues ADD COLUMN VenueDetails JSONB"),
- null);
- // Wait for the operation to finish.
- // This will throw an ExecutionException if the operation fails.
- operation.get();
- System.out.printf("Successfully added column `VenueDetails`%n");
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ // JSONB datatype is only supported with PostgreSQL-dialect databases.
+ // Wait for the operation to finish.
+ // This will throw an ExecutionException if the operation fails.
+ databaseAdminClient.updateDatabaseDdlAsync(
+ DatabaseName.of(projectId, instanceId, databaseId),
+ ImmutableList.of("ALTER TABLE Venues ADD COLUMN VenueDetails JSONB")).get();
+ System.out.printf("Successfully added column `VenueDetails`%n");
+ }
}
}
// [END spanner_postgresql_jsonb_add_column]
diff --git a/samples/snippets/src/main/java/com/example/spanner/AddNumericColumnSample.java b/samples/snippets/src/main/java/com/example/spanner/AddNumericColumnSample.java
index 7d29cdf15d..00cfb848e7 100644
--- a/samples/snippets/src/main/java/com/example/spanner/AddNumericColumnSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/AddNumericColumnSample.java
@@ -17,12 +17,12 @@
package com.example.spanner;
// [START spanner_add_numeric_column]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.concurrent.ExecutionException;
class AddNumericColumnSample {
@@ -33,26 +33,24 @@ static void addNumericColumn() throws InterruptedException, ExecutionException {
String instanceId = "my-instance";
String databaseId = "my-database";
- try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
- addNumericColumn(adminClient, instanceId, databaseId);
- }
+ addNumericColumn(projectId, instanceId, databaseId);
}
- static void addNumericColumn(
- DatabaseAdminClient adminClient, String instanceId, String databaseId)
+ static void addNumericColumn(String projectId, String instanceId, String databaseId)
throws InterruptedException, ExecutionException {
- OperationFuture operation =
- adminClient.updateDatabaseDdl(
- instanceId,
- databaseId,
- ImmutableList.of("ALTER TABLE Venues ADD COLUMN Revenue NUMERIC"),
- null);
- // Wait for the operation to finish.
- // This will throw an ExecutionException if the operation fails.
- operation.get();
- System.out.printf("Successfully added column `Revenue`%n");
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ // Wait for the operation to finish.
+ // This will throw an ExecutionException if the operation fails.
+ databaseAdminClient.updateDatabaseDdlAsync(
+ DatabaseName.of(projectId, instanceId, databaseId),
+ ImmutableList.of("ALTER TABLE Venues ADD COLUMN Revenue NUMERIC")).get();
+ System.out.printf("Successfully added column `Revenue`%n");
+ }
}
}
// [END spanner_add_numeric_column]
diff --git a/samples/snippets/src/main/java/com/example/spanner/AlterSequenceSample.java b/samples/snippets/src/main/java/com/example/spanner/AlterSequenceSample.java
index 6b9014a26f..641449ace9 100644
--- a/samples/snippets/src/main/java/com/example/spanner/AlterSequenceSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/AlterSequenceSample.java
@@ -17,7 +17,7 @@
package com.example.spanner;
// [START spanner_alter_sequence]
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.ResultSet;
@@ -25,13 +25,16 @@
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class AlterSequenceSample {
+
static void alterSequence() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
@@ -42,17 +45,14 @@ static void alterSequence() {
static void alterSequence(String projectId, String instanceId, String databaseId) {
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- final DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
- dbAdminClient
- .updateDatabaseDdl(
- instanceId,
- databaseId,
+ databaseAdminClient
+ .updateDatabaseDdlAsync(DatabaseName.of(projectId, instanceId, databaseId),
ImmutableList.of(
"ALTER SEQUENCE Seq SET OPTIONS "
- + "(skip_range_min = 1000, skip_range_max = 5000000)"),
- null)
+ + "(skip_range_min = 1000, skip_range_max = 5000000)"))
.get(5, TimeUnit.MINUTES);
System.out.println(
diff --git a/samples/snippets/src/main/java/com/example/spanner/AlterTableWithForeignKeyDeleteCascadeSample.java b/samples/snippets/src/main/java/com/example/spanner/AlterTableWithForeignKeyDeleteCascadeSample.java
index 1caf26fb28..6950e6a4fa 100644
--- a/samples/snippets/src/main/java/com/example/spanner/AlterTableWithForeignKeyDeleteCascadeSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/AlterTableWithForeignKeyDeleteCascadeSample.java
@@ -17,10 +17,12 @@
package com.example.spanner;
// [START spanner_alter_table_with_foreign_key_delete_cascade]
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.database.v1.DatabaseName;
class AlterTableWithForeignKeyDeleteCascadeSample {
@@ -30,30 +32,28 @@ static void alterForeignKeyDeleteCascadeConstraint() {
String instanceId = "my-instance";
String databaseId = "my-database";
- try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
- alterForeignKeyDeleteCascadeConstraint(adminClient, instanceId, databaseId);
- }
+ alterForeignKeyDeleteCascadeConstraint(projectId, instanceId, databaseId);
}
static void alterForeignKeyDeleteCascadeConstraint(
- DatabaseAdminClient adminClient, String instanceId, String databaseId) {
- adminClient.updateDatabaseDdl(
- instanceId,
- databaseId,
- ImmutableList.of(
- "ALTER TABLE ShoppingCarts\n"
- + " ADD CONSTRAINT FKShoppingCartsCustomerName\n"
- + " FOREIGN KEY (CustomerName)\n"
- + " REFERENCES Customers(CustomerName)\n"
- + " ON DELETE CASCADE\n"),
- null);
- System.out.printf(
- String.format(
- "Altered ShoppingCarts table with FKShoppingCartsCustomerName\n"
- + "foreign key constraint on database %s on instance %s",
- databaseId, instanceId));
+ String projectId, String instanceId, String databaseId) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ databaseAdminClient.updateDatabaseDdlAsync(DatabaseName.of(projectId, instanceId,
+ databaseId),
+ ImmutableList.of(
+ "ALTER TABLE ShoppingCarts\n"
+ + " ADD CONSTRAINT FKShoppingCartsCustomerName\n"
+ + " FOREIGN KEY (CustomerName)\n"
+ + " REFERENCES Customers(CustomerName)\n"
+ + " ON DELETE CASCADE\n"));
+ System.out.printf(
+ String.format(
+ "Altered ShoppingCarts table with FKShoppingCartsCustomerName\n"
+ + "foreign key constraint on database %s on instance %s",
+ databaseId, instanceId));
+ }
}
}
// [END spanner_alter_table_with_foreign_key_delete_cascade]
diff --git a/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java b/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java
index 795edcb15a..c6ee706687 100644
--- a/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java
@@ -18,84 +18,80 @@
// [START spanner_copy_backup]
-import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.Timestamp;
-import com.google.cloud.spanner.Backup;
-import com.google.cloud.spanner.BackupId;
-import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
-import com.google.spanner.admin.database.v1.CopyBackupMetadata;
-import java.time.LocalDateTime;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.spanner.admin.database.v1.Backup;
+import com.google.spanner.admin.database.v1.BackupName;
+import com.google.spanner.admin.database.v1.InstanceName;
+import java.time.Instant;
import java.time.OffsetDateTime;
+import java.time.ZoneId;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class CopyBackupSample {
+
static void copyBackup() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
String sourceBackupId = "my-backup";
String destinationBackupId = "my-destination-backup";
+
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
copyBackup(databaseAdminClient, projectId, instanceId, sourceBackupId, destinationBackupId);
}
}
static void copyBackup(
- DatabaseAdminClient databaseAdminClient,
- String projectId,
- String instanceId,
- String sourceBackupId,
- String destinationBackupId) {
+ DatabaseAdminClient databaseAdminClient,
+ String projectId,
+ String instanceId,
+ String sourceBackupId,
+ String destinationBackupId) {
Timestamp expireTime =
- Timestamp.ofTimeMicroseconds(
- TimeUnit.MICROSECONDS.convert(
- System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14),
- TimeUnit.MILLISECONDS));
- // Creates a copy of an existing backup.
- Backup destinationBackup =
- databaseAdminClient
- .newBackupBuilder(BackupId.of(projectId, instanceId, destinationBackupId))
- .setExpireTime(expireTime)
- .build();
+ Timestamp.ofTimeMicroseconds(
+ TimeUnit.MICROSECONDS.convert(
+ System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14),
+ TimeUnit.MILLISECONDS));
// Initiate the request which returns an OperationFuture.
- System.out.println("Copying backup [" + destinationBackup.getId() + "]...");
- OperationFuture operation =
- databaseAdminClient.copyBackup(
- BackupId.of(projectId, instanceId, sourceBackupId), destinationBackup);
+ System.out.println("Copying backup [" + destinationBackupId + "]...");
+ Backup destinationBackup;
try {
+ // Creates a copy of an existing backup.
// Wait for the backup operation to complete.
- destinationBackup = operation.get();
- System.out.println("Copied backup [" + destinationBackup.getId() + "]");
+ destinationBackup = databaseAdminClient.copyBackupAsync(
+ InstanceName.of(projectId, instanceId), destinationBackupId,
+ BackupName.of(projectId, instanceId, sourceBackupId), expireTime.toProto()).get();
+ System.out.println("Copied backup [" + destinationBackup.getName() + "]");
} catch (ExecutionException e) {
throw (SpannerException) e.getCause();
} catch (InterruptedException e) {
throw SpannerExceptionFactory.propagateInterrupt(e);
}
// Load the metadata of the new backup from the server.
- destinationBackup = destinationBackup.reload();
+ destinationBackup = databaseAdminClient.getBackup(destinationBackup.getName());
System.out.println(
- String.format(
- "Backup %s of size %d bytes was copied at %s for version of database at %s",
- destinationBackup.getId().getName(),
- destinationBackup.getSize(),
- LocalDateTime.ofEpochSecond(
- destinationBackup.getProto().getCreateTime().getSeconds(),
- destinationBackup.getProto().getCreateTime().getNanos(),
- OffsetDateTime.now().getOffset()),
- LocalDateTime.ofEpochSecond(
- destinationBackup.getProto().getVersionTime().getSeconds(),
- destinationBackup.getProto().getVersionTime().getNanos(),
- OffsetDateTime.now().getOffset())));
- return;
+ String.format(
+ "Backup %s of size %d bytes was copied at %s for version of database at %s",
+ destinationBackup.getName(),
+ destinationBackup.getSizeBytes(),
+ OffsetDateTime.ofInstant(
+ Instant.ofEpochSecond(destinationBackup.getCreateTime().getSeconds(),
+ destinationBackup.getCreateTime().getNanos()),
+ ZoneId.systemDefault()),
+ OffsetDateTime.ofInstant(
+ Instant.ofEpochSecond(destinationBackup.getVersionTime().getSeconds(),
+ destinationBackup.getVersionTime().getNanos()),
+ ZoneId.systemDefault())));
}
}
// [END spanner_copy_backup]
diff --git a/samples/snippets/src/main/java/com/example/spanner/CreateBackupWithEncryptionKey.java b/samples/snippets/src/main/java/com/example/spanner/CreateBackupWithEncryptionKey.java
index b2a00ae2ad..e2c7b17061 100644
--- a/samples/snippets/src/main/java/com/example/spanner/CreateBackupWithEncryptionKey.java
+++ b/samples/snippets/src/main/java/com/example/spanner/CreateBackupWithEncryptionKey.java
@@ -18,17 +18,18 @@
// [START spanner_create_backup_with_encryption_key]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.Timestamp;
-import com.google.cloud.spanner.Backup;
-import com.google.cloud.spanner.BackupId;
-import com.google.cloud.spanner.DatabaseAdminClient;
-import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
-import com.google.cloud.spanner.encryption.EncryptionConfigs;
-import com.google.spanner.admin.database.v1.CreateBackupMetadata;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.protobuf.Timestamp;
+import com.google.spanner.admin.database.v1.Backup;
+import com.google.spanner.admin.database.v1.BackupName;
+import com.google.spanner.admin.database.v1.CreateBackupEncryptionConfig;
+import com.google.spanner.admin.database.v1.CreateBackupEncryptionConfig.EncryptionType;
+import com.google.spanner.admin.database.v1.CreateBackupRequest;
+import com.google.spanner.admin.database.v1.DatabaseName;
+import com.google.spanner.admin.database.v1.InstanceName;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -37,7 +38,7 @@
public class CreateBackupWithEncryptionKey {
- static void createBackupWithEncryptionKey() throws InterruptedException {
+ static void createBackupWithEncryptionKey() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
@@ -47,8 +48,8 @@ static void createBackupWithEncryptionKey() throws InterruptedException {
"projects/" + projectId + "/locations//keyRings//cryptoKeys/";
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient adminClient = spanner.createDatabaseAdminClient()) {
createBackupWithEncryptionKey(
adminClient,
projectId,
@@ -60,24 +61,29 @@ static void createBackupWithEncryptionKey() throws InterruptedException {
}
static Void createBackupWithEncryptionKey(DatabaseAdminClient adminClient,
- String projectId, String instanceId, String databaseId, String backupId, String kmsKeyName)
- throws InterruptedException {
+ String projectId, String instanceId, String databaseId, String backupId, String kmsKeyName) {
// Set expire time to 14 days from now.
- final Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert(
- System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS));
- final Backup backupToCreate = adminClient
- .newBackupBuilder(BackupId.of(projectId, instanceId, backupId))
- .setDatabase(DatabaseId.of(projectId, instanceId, databaseId))
- .setExpireTime(expireTime)
- .setEncryptionConfig(EncryptionConfigs.customerManagedEncryption(kmsKeyName))
- .build();
- final OperationFuture operation = adminClient
- .createBackup(backupToCreate);
+ final Timestamp expireTime =
+ Timestamp.newBuilder().setSeconds(TimeUnit.MILLISECONDS.toSeconds((
+ System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14)))).build();
+ final BackupName backupName = BackupName.of(projectId, instanceId, backupId);
+ Backup backup = Backup.newBuilder()
+ .setName(backupName.toString())
+ .setDatabase(DatabaseName.of(projectId, instanceId, databaseId).toString())
+ .setExpireTime(expireTime).build();
- Backup backup;
+ final CreateBackupRequest request =
+ CreateBackupRequest.newBuilder()
+ .setParent(InstanceName.of(projectId, instanceId).toString())
+ .setBackupId(backupId)
+ .setBackup(backup)
+ .setEncryptionConfig(
+ CreateBackupEncryptionConfig.newBuilder()
+ .setEncryptionType(EncryptionType.CUSTOMER_MANAGED_ENCRYPTION)
+ .setKmsKeyName(kmsKeyName).build()).build();
try {
System.out.println("Waiting for operation to complete...");
- backup = operation.get(1200, TimeUnit.SECONDS);
+ backup = adminClient.createBackupAsync(request).get(1200, TimeUnit.SECONDS);
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
throw SpannerExceptionFactory.asSpannerException(e.getCause());
@@ -89,14 +95,13 @@ static Void createBackupWithEncryptionKey(DatabaseAdminClient adminClient,
// If the operation timed out propagates the timeout
throw SpannerExceptionFactory.propagateTimeout(e);
}
-
System.out.printf(
"Backup %s of size %d bytes was created at %s using encryption key %s%n",
- backup.getId().getName(),
- backup.getSize(),
+ backup.getName(),
+ backup.getSizeBytes(),
LocalDateTime.ofEpochSecond(
- backup.getProto().getCreateTime().getSeconds(),
- backup.getProto().getCreateTime().getNanos(),
+ backup.getCreateTime().getSeconds(),
+ backup.getCreateTime().getNanos(),
OffsetDateTime.now().getOffset()),
kmsKeyName
);
diff --git a/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithDefaultLeaderSample.java b/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithDefaultLeaderSample.java
index fa3354dd9c..33917685cd 100644
--- a/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithDefaultLeaderSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithDefaultLeaderSample.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2021 Google LLC
+ * Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,60 +18,51 @@
//[START spanner_create_database_with_default_leader]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.Database;
-import com.google.cloud.spanner.DatabaseAdminClient;
-import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
-import com.google.cloud.spanner.SpannerOptions;
-import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
-import java.util.Arrays;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.database.v1.CreateDatabaseRequest;
+import com.google.spanner.admin.database.v1.Database;
+import java.io.IOException;
import java.util.concurrent.ExecutionException;
public class CreateDatabaseWithDefaultLeaderSample {
- static void createDatabaseWithDefaultLeader() {
+ static void createDatabaseWithDefaultLeader() throws IOException {
// TODO(developer): Replace these variables before running the sample.
- final String projectId = "my-project";
- final String instanceId = "my-instance";
- final String databaseId = "my-database";
+ final String instanceName = "projects/my-project/instances/my-instance-id";
+ final String databaseId = "my-database-name";
final String defaultLeader = "my-default-leader";
- createDatabaseWithDefaultLeader(projectId, instanceId, databaseId, defaultLeader);
+ createDatabaseWithDefaultLeader(instanceName, databaseId, defaultLeader);
}
- static void createDatabaseWithDefaultLeader(
- String projectId, String instanceId, String databaseId, String defaultLeader) {
- try (Spanner spanner = SpannerOptions
- .newBuilder()
- .setProjectId(projectId)
- .build()
- .getService()) {
- final DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
- final OperationFuture operation = databaseAdminClient
- .createDatabase(
- instanceId,
- databaseId,
- Arrays.asList(
- "CREATE TABLE Singers ("
- + " SingerId INT64 NOT NULL,"
- + " FirstName STRING(1024),"
- + " LastName STRING(1024),"
- + " SingerInfo BYTES(MAX)"
- + ") PRIMARY KEY (SingerId)",
- "CREATE TABLE Albums ("
- + " SingerId INT64 NOT NULL,"
- + " AlbumId INT64 NOT NULL,"
- + " AlbumTitle STRING(MAX)"
- + ") PRIMARY KEY (SingerId, AlbumId),"
- + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE",
- "ALTER DATABASE " + "`" + databaseId + "`"
- + " SET OPTIONS ( default_leader = '" + defaultLeader + "' )"
- )
- );
- final Database database = operation.get();
- System.out.println("Created database [" + database.getId() + "]");
- System.out.println("\tDefault leader: " + database.getDefaultLeader());
+ static void createDatabaseWithDefaultLeader(String instanceName, String databaseId,
+ String defaultLeader) throws IOException {
+ try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
+ Database createdDatabase =
+ databaseAdminClient.createDatabaseAsync(
+ CreateDatabaseRequest.newBuilder()
+ .setParent(instanceName)
+ .setCreateStatement("CREATE DATABASE `" + databaseId + "`")
+ .addAllExtraStatements(
+ ImmutableList.of("CREATE TABLE Singers ("
+ + " SingerId INT64 NOT NULL,"
+ + " FirstName STRING(1024),"
+ + " LastName STRING(1024),"
+ + " SingerInfo BYTES(MAX)"
+ + ") PRIMARY KEY (SingerId)",
+ "CREATE TABLE Albums ("
+ + " SingerId INT64 NOT NULL,"
+ + " AlbumId INT64 NOT NULL,"
+ + " AlbumTitle STRING(MAX)"
+ + ") PRIMARY KEY (SingerId, AlbumId),"
+ + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE",
+ "ALTER DATABASE " + "`" + databaseId + "`"
+ + " SET OPTIONS ( default_leader = '" + defaultLeader + "' )"))
+ .build()).get();
+ System.out.println("Created database [" + createdDatabase.getName() + "]");
+ System.out.println("\tDefault leader: " + createdDatabase.getDefaultLeader());
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
throw (SpannerException) e.getCause();
@@ -82,4 +73,4 @@ static void createDatabaseWithDefaultLeader(
}
}
}
-//[END spanner_create_database_with_default_leader]
+//[END spanner_create_database_with_default_leader]
\ No newline at end of file
diff --git a/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithEncryptionKey.java b/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithEncryptionKey.java
index 7d3850933b..c06e9c3eba 100644
--- a/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithEncryptionKey.java
+++ b/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithEncryptionKey.java
@@ -18,16 +18,15 @@
// [START spanner_create_database_with_encryption_key]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.Database;
-import com.google.cloud.spanner.DatabaseAdminClient;
-import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
-import com.google.cloud.spanner.encryption.EncryptionConfigs;
-import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
-import java.util.Arrays;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.database.v1.CreateDatabaseRequest;
+import com.google.spanner.admin.database.v1.Database;
+import com.google.spanner.admin.database.v1.EncryptionConfig;
+import com.google.spanner.admin.database.v1.InstanceName;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -43,8 +42,8 @@ static void createDatabaseWithEncryptionKey() {
"projects/" + projectId + "/locations//keyRings//cryptoKeys/";
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient adminClient = spanner.createDatabaseAdminClient()) {
createDatabaseWithEncryptionKey(
adminClient,
projectId,
@@ -56,32 +55,35 @@ static void createDatabaseWithEncryptionKey() {
static void createDatabaseWithEncryptionKey(DatabaseAdminClient adminClient,
String projectId, String instanceId, String databaseId, String kmsKeyName) {
- final Database databaseToCreate = adminClient
- .newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId))
- .setEncryptionConfig(EncryptionConfigs.customerManagedEncryption(kmsKeyName))
+ InstanceName instanceName = InstanceName.of(projectId, instanceId);
+ CreateDatabaseRequest request = CreateDatabaseRequest.newBuilder()
+ .setParent(instanceName.toString())
+ .setCreateStatement("CREATE DATABASE `" + databaseId + "`")
+ .setEncryptionConfig(EncryptionConfig.newBuilder().setKmsKeyName(kmsKeyName).build())
+ .addAllExtraStatements(
+ ImmutableList.of(
+ "CREATE TABLE Singers ("
+ + " SingerId INT64 NOT NULL,"
+ + " FirstName STRING(1024),"
+ + " LastName STRING(1024),"
+ + " SingerInfo BYTES(MAX)"
+ + ") PRIMARY KEY (SingerId)",
+ "CREATE TABLE Albums ("
+ + " SingerId INT64 NOT NULL,"
+ + " AlbumId INT64 NOT NULL,"
+ + " AlbumTitle STRING(MAX)"
+ + ") PRIMARY KEY (SingerId, AlbumId),"
+ + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE"
+ ))
.build();
- final OperationFuture operation = adminClient
- .createDatabase(databaseToCreate, Arrays.asList(
- "CREATE TABLE Singers ("
- + " SingerId INT64 NOT NULL,"
- + " FirstName STRING(1024),"
- + " LastName STRING(1024),"
- + " SingerInfo BYTES(MAX)"
- + ") PRIMARY KEY (SingerId)",
- "CREATE TABLE Albums ("
- + " SingerId INT64 NOT NULL,"
- + " AlbumId INT64 NOT NULL,"
- + " AlbumTitle STRING(MAX)"
- + ") PRIMARY KEY (SingerId, AlbumId),"
- + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE"
- ));
try {
System.out.println("Waiting for operation to complete...");
- Database createdDatabase = operation.get(120, TimeUnit.SECONDS);
+ Database createdDatabase =
+ adminClient.createDatabaseAsync(request).get(120, TimeUnit.SECONDS);
System.out.printf(
"Database %s created with encryption key %s%n",
- createdDatabase.getId(),
+ createdDatabase.getName(),
createdDatabase.getEncryptionConfig().getKmsKeyName()
);
} catch (ExecutionException e) {
diff --git a/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithVersionRetentionPeriodSample.java b/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithVersionRetentionPeriodSample.java
index 1eaa7c403d..888fe62588 100644
--- a/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithVersionRetentionPeriodSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithVersionRetentionPeriodSample.java
@@ -18,15 +18,15 @@
// [START spanner_create_database_with_version_retention_period]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.Database;
-import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
-import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
-import java.util.Arrays;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.common.collect.Lists;
+import com.google.spanner.admin.database.v1.CreateDatabaseRequest;
+import com.google.spanner.admin.database.v1.Database;
+import com.google.spanner.admin.database.v1.InstanceName;
import java.util.concurrent.ExecutionException;
public class CreateDatabaseWithVersionRetentionPeriodSample {
@@ -38,39 +38,25 @@ static void createDatabaseWithVersionRetentionPeriod() {
String databaseId = "my-database";
String versionRetentionPeriod = "7d";
- try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
- createDatabaseWithVersionRetentionPeriod(adminClient, instanceId, databaseId,
- versionRetentionPeriod);
- }
+ createDatabaseWithVersionRetentionPeriod(projectId, instanceId, databaseId,
+ versionRetentionPeriod);
}
- static void createDatabaseWithVersionRetentionPeriod(DatabaseAdminClient adminClient,
+ static void createDatabaseWithVersionRetentionPeriod(String projectId,
String instanceId, String databaseId, String versionRetentionPeriod) {
- OperationFuture op =
- adminClient.createDatabase(
- instanceId,
- databaseId,
- Arrays.asList(
- "CREATE TABLE Singers ("
- + " SingerId INT64 NOT NULL,"
- + " FirstName STRING(1024),"
- + " LastName STRING(1024),"
- + " SingerInfo BYTES(MAX)"
- + ") PRIMARY KEY (SingerId)",
- "CREATE TABLE Albums ("
- + " SingerId INT64 NOT NULL,"
- + " AlbumId INT64 NOT NULL,"
- + " AlbumTitle STRING(MAX)"
- + ") PRIMARY KEY (SingerId, AlbumId),"
- + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE",
- "ALTER DATABASE " + "`" + databaseId + "`"
- + " SET OPTIONS ( version_retention_period = '" + versionRetentionPeriod + "' )"
- ));
- try {
- Database database = op.get();
- System.out.println("Created database [" + database.getId() + "]");
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ CreateDatabaseRequest request =
+ CreateDatabaseRequest.newBuilder()
+ .setParent(InstanceName.of(projectId, instanceId).toString())
+ .setCreateStatement("CREATE DATABASE `" + databaseId + "`")
+ .addAllExtraStatements(Lists.newArrayList("ALTER DATABASE " + "`" + databaseId + "`"
+ + " SET OPTIONS ( version_retention_period = '" + versionRetentionPeriod + "' )"))
+ .build();
+ Database database =
+ databaseAdminClient.createDatabaseAsync(request).get();
+ System.out.println("Created database [" + database.getName() + "]");
System.out.println("\tVersion retention period: " + database.getVersionRetentionPeriod());
System.out.println("\tEarliest version time: " + database.getEarliestVersionTime());
} catch (ExecutionException e) {
diff --git a/samples/snippets/src/main/java/com/example/spanner/CreateInstanceConfigSample.java b/samples/snippets/src/main/java/com/example/spanner/CreateInstanceConfigSample.java
index 379e0e2617..426d7c0484 100644
--- a/samples/snippets/src/main/java/com/example/spanner/CreateInstanceConfigSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/CreateInstanceConfigSample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,53 +17,73 @@
package com.example.spanner;
// [START spanner_create_instance_config]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.InstanceAdminClient;
-import com.google.cloud.spanner.InstanceConfig;
-import com.google.cloud.spanner.InstanceConfigId;
-import com.google.cloud.spanner.InstanceConfigInfo;
-import com.google.cloud.spanner.ReplicaInfo;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
-import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.instance.v1.CreateInstanceConfigMetadata;
+import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
+import com.google.spanner.admin.instance.v1.CreateInstanceConfigRequest;
+import com.google.spanner.admin.instance.v1.InstanceConfig;
+import com.google.spanner.admin.instance.v1.InstanceConfigName;
+import com.google.spanner.admin.instance.v1.ProjectName;
+import com.google.spanner.admin.instance.v1.ReplicaInfo;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
class CreateInstanceConfigSample {
+
static void createInstanceConfig() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
- String baseInstanceConfig = "my-base-instance-config";
+ String baseInstanceConfigId = "nam11";
String instanceConfigId = "custom-instance-config4";
- createInstanceConfig(projectId, baseInstanceConfig, instanceConfigId);
+
+ createInstanceConfig(projectId, baseInstanceConfigId, instanceConfigId);
}
static void createInstanceConfig(
- String projectId, String baseInstanceConfig, String instanceConfigId) {
+ String projectId, String baseInstanceConfigId, String instanceConfigId) {
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- final InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
- final InstanceConfig baseConfig = instanceAdminClient.getInstanceConfig(baseInstanceConfig);
- List readOnlyReplicas =
- ImmutableList.of(baseConfig.getOptionalReplicas().get(0));
- InstanceConfigInfo instanceConfigInfo =
- InstanceConfig.newBuilder(InstanceConfigId.of(projectId, instanceConfigId), baseConfig)
- .setDisplayName(instanceConfigId)
- .addReadOnlyReplicas(readOnlyReplicas)
- .build();
- final OperationFuture operation =
- instanceAdminClient.createInstanceConfig(instanceConfigInfo);
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ InstanceAdminClient instanceAdminClient = spanner.createInstanceAdminClient()) {
+ final InstanceConfigName baseInstanceConfigName = InstanceConfigName.of(projectId,
+ baseInstanceConfigId);
+ final InstanceConfig baseConfig =
+ instanceAdminClient.getInstanceConfig(baseInstanceConfigName.toString());
+ final InstanceConfigName instanceConfigName = InstanceConfigName.of(projectId,
+ instanceConfigId);
+ /**
+ * The replicas for the custom instance configuration must include all the replicas of the
+ * base configuration, in addition to at least one from the list of optional replicas of the
+ * base configuration.
+ */
+ final List replicas =
+ Stream.concat(baseConfig.getReplicasList().stream(),
+ baseConfig.getOptionalReplicasList().stream().limit(1)).collect(Collectors.toList());
+ final InstanceConfig instanceConfig =
+ InstanceConfig.newBuilder().setName(instanceConfigName.toString())
+ .setBaseConfig(baseInstanceConfigName.toString())
+ .setDisplayName("Instance Configuration").addAllReplicas(replicas).build();
+ final CreateInstanceConfigRequest createInstanceConfigRequest =
+ CreateInstanceConfigRequest.newBuilder().setParent(ProjectName.of(projectId).toString())
+ .setInstanceConfigId(instanceConfigId).setInstanceConfig(instanceConfig).build();
try {
- System.out.printf("Waiting for create operation for %s to complete...\n", instanceConfigId);
- InstanceConfig instanceConfig = operation.get(5, TimeUnit.MINUTES);
- System.out.printf("Created instance configuration %s\n", instanceConfig.getId());
+ System.out.printf("Waiting for create operation for %s to complete...\n",
+ instanceConfigName);
+ InstanceConfig instanceConfigResult =
+ instanceAdminClient.createInstanceConfigAsync(
+ createInstanceConfigRequest).get(5, TimeUnit.MINUTES);
+ System.out.printf("Created instance configuration %s\n", instanceConfigResult.getName());
} catch (ExecutionException | TimeoutException e) {
System.out.printf(
"Error: Creating instance configuration %s failed with error message %s\n",
- instanceConfigInfo.getId(), e.getMessage());
+ instanceConfig.getName(), e.getMessage());
} catch (InterruptedException e) {
System.out.println(
"Error: Waiting for createInstanceConfig operation to finish was interrupted");
diff --git a/samples/snippets/src/main/java/com/example/spanner/CreateInstanceExample.java b/samples/snippets/src/main/java/com/example/spanner/CreateInstanceExample.java
index 44e36a8b27..b53727ba6d 100644
--- a/samples/snippets/src/main/java/com/example/spanner/CreateInstanceExample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/CreateInstanceExample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Google LLC
+ * Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,15 +17,14 @@
package com.example.spanner;
//[START spanner_create_instance]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.Instance;
-import com.google.cloud.spanner.InstanceAdminClient;
-import com.google.cloud.spanner.InstanceConfigId;
-import com.google.cloud.spanner.InstanceId;
-import com.google.cloud.spanner.InstanceInfo;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
-import com.google.spanner.admin.instance.v1.CreateInstanceMetadata;
+import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
+import com.google.spanner.admin.instance.v1.CreateInstanceRequest;
+import com.google.spanner.admin.instance.v1.Instance;
+import com.google.spanner.admin.instance.v1.InstanceConfigName;
+import com.google.spanner.admin.instance.v1.ProjectName;
import java.util.concurrent.ExecutionException;
class CreateInstanceExample {
@@ -38,36 +37,41 @@ static void createInstance() {
}
static void createInstance(String projectId, String instanceId) {
- Spanner spanner = SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
- InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
-
// Set Instance configuration.
- String configId = "regional-us-central1";
int nodeCount = 2;
String displayName = "Descriptive name";
- // Create an InstanceInfo object that will be used to create the instance.
- InstanceInfo instanceInfo =
- InstanceInfo.newBuilder(InstanceId.of(projectId, instanceId))
- .setInstanceConfigId(InstanceConfigId.of(projectId, configId))
- .setNodeCount(nodeCount)
+ // Create an Instance object that will be used to create the instance.
+ Instance instance =
+ Instance.newBuilder()
.setDisplayName(displayName)
+ .setNodeCount(nodeCount)
+ .setConfig(
+ InstanceConfigName.of(projectId, "regional-us-central1").toString())
.build();
- OperationFuture operation =
- instanceAdminClient.createInstance(instanceInfo);
- try {
+
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ InstanceAdminClient instanceAdminClient = spanner.createInstanceAdminClient()) {
+
// Wait for the createInstance operation to finish.
- Instance instance = operation.get();
- System.out.printf("Instance %s was successfully created%n", instance.getId());
+ Instance createdInstance = instanceAdminClient.createInstanceAsync(
+ CreateInstanceRequest.newBuilder()
+ .setParent(ProjectName.of(projectId).toString())
+ .setInstanceId(instanceId)
+ .setInstance(instance)
+ .build()).get();
+ System.out.printf("Instance %s was successfully created%n", createdInstance.getName());
} catch (ExecutionException e) {
System.out.printf(
"Error: Creating instance %s failed with error message %s%n",
- instanceInfo.getId(), e.getMessage());
+ instance.getName(), e.getMessage());
} catch (InterruptedException e) {
System.out.println("Error: Waiting for createInstance operation to finish was interrupted");
- } finally {
- spanner.close();
}
}
}
-//[END spanner_create_instance]
+//[END spanner_create_instance]
\ No newline at end of file
diff --git a/samples/snippets/src/main/java/com/example/spanner/CreateInstanceWithAutoscalingConfigExample.java b/samples/snippets/src/main/java/com/example/spanner/CreateInstanceWithAutoscalingConfigExample.java
index 0719857411..dc62dd7a68 100644
--- a/samples/snippets/src/main/java/com/example/spanner/CreateInstanceWithAutoscalingConfigExample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/CreateInstanceWithAutoscalingConfigExample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,16 +18,14 @@
// [START spanner_create_instance_with_autoscaling_config]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.Instance;
-import com.google.cloud.spanner.InstanceAdminClient;
-import com.google.cloud.spanner.InstanceConfigId;
-import com.google.cloud.spanner.InstanceId;
-import com.google.cloud.spanner.InstanceInfo;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
import com.google.spanner.admin.instance.v1.AutoscalingConfig;
-import com.google.spanner.admin.instance.v1.CreateInstanceMetadata;
+import com.google.spanner.admin.instance.v1.CreateInstanceRequest;
+import com.google.spanner.admin.instance.v1.Instance;
+import com.google.spanner.admin.instance.v1.InstanceConfigName;
+import com.google.spanner.admin.instance.v1.ProjectName;
import java.util.concurrent.ExecutionException;
class CreateInstanceWithAutoscalingConfigExample {
@@ -40,44 +38,55 @@ static void createInstance() {
}
static void createInstance(String projectId, String instanceId) {
- Spanner spanner = SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
- InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ InstanceAdminClient instanceAdminClient = spanner.createInstanceAdminClient()) {
+ // Set Instance configuration.
+ String configId = "regional-us-central1";
+ String displayName = "Descriptive name";
- // Set Instance configuration.
- String configId = "regional-us-central1";
- // Create an autoscaling config.
- AutoscalingConfig autoscalingConfig =
- AutoscalingConfig.newBuilder()
- .setAutoscalingLimits(
- AutoscalingConfig.AutoscalingLimits.newBuilder().setMinNodes(1).setMaxNodes(2))
- .setAutoscalingTargets(
- AutoscalingConfig.AutoscalingTargets.newBuilder()
- .setHighPriorityCpuUtilizationPercent(65)
- .setStorageUtilizationPercent(95))
- .build();
+ // Create an autoscaling config.
+ // When autoscaling_config is enabled, node_count and processing_units fields
+ // need not be specified.
+ AutoscalingConfig autoscalingConfig =
+ AutoscalingConfig.newBuilder()
+ .setAutoscalingLimits(
+ AutoscalingConfig.AutoscalingLimits.newBuilder().setMinNodes(1).setMaxNodes(2))
+ .setAutoscalingTargets(
+ AutoscalingConfig.AutoscalingTargets.newBuilder()
+ .setHighPriorityCpuUtilizationPercent(65)
+ .setStorageUtilizationPercent(95))
+ .build();
+ Instance instance =
+ Instance.newBuilder()
+ .setAutoscalingConfig(autoscalingConfig)
+ .setDisplayName(displayName)
+ .setConfig(
+ InstanceConfigName.of(projectId, configId).toString())
+ .build();
- // Create an InstanceInfo object that will be used to create the instance.
- InstanceInfo instanceInfo =
- InstanceInfo.newBuilder(InstanceId.of(projectId, instanceId))
- .setInstanceConfigId(InstanceConfigId.of(projectId, configId))
- .setAutoscalingConfig(autoscalingConfig)
- .setDisplayName("Descriptive name")
- .build();
- OperationFuture operation =
- instanceAdminClient.createInstance(instanceInfo);
-
- try {
- // Wait for the createInstance operation to finish.
- Instance instance = operation.get();
- System.out.printf("Autoscaler instance %s was successfully created%n", instance.getId());
- } catch (ExecutionException e) {
- System.out.printf(
- "Error: Creating instance %s failed with error message %s%n",
- instanceInfo.getId(), e.getMessage());
- } catch (InterruptedException e) {
- System.out.println("Error: Waiting for createInstance operation to finish was interrupted");
- } finally {
- spanner.close();
+ // Creates a new instance
+ System.out.printf("Creating instance %s.%n", instanceId);
+ try {
+ // Wait for the createInstance operation to finish.
+ Instance instanceResult = instanceAdminClient.createInstanceAsync(
+ CreateInstanceRequest.newBuilder()
+ .setParent(ProjectName.of(projectId).toString())
+ .setInstanceId(instanceId)
+ .setInstance(instance)
+ .build()).get();
+ System.out.printf("Autoscaler instance %s was successfully created%n",
+ instanceResult.getName());
+ } catch (ExecutionException e) {
+ System.out.printf(
+ "Error: Creating instance %s failed with error message %s%n",
+ instance.getName(), e.getMessage());
+ } catch (InterruptedException e) {
+ System.out.println("Error: Waiting for createInstance operation to finish was interrupted");
+ }
}
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/CreateInstanceWithProcessingUnitsExample.java b/samples/snippets/src/main/java/com/example/spanner/CreateInstanceWithProcessingUnitsExample.java
index 1bfc66d3fd..293c10249c 100644
--- a/samples/snippets/src/main/java/com/example/spanner/CreateInstanceWithProcessingUnitsExample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/CreateInstanceWithProcessingUnitsExample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,15 +18,13 @@
//[START spanner_create_instance_with_processing_units]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.Instance;
-import com.google.cloud.spanner.InstanceAdminClient;
-import com.google.cloud.spanner.InstanceConfigId;
-import com.google.cloud.spanner.InstanceId;
-import com.google.cloud.spanner.InstanceInfo;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
-import com.google.spanner.admin.instance.v1.CreateInstanceMetadata;
+import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
+import com.google.spanner.admin.instance.v1.CreateInstanceRequest;
+import com.google.spanner.admin.instance.v1.Instance;
+import com.google.spanner.admin.instance.v1.InstanceConfigName;
+import com.google.spanner.admin.instance.v1.ProjectName;
class CreateInstanceWithProcessingUnitsExample {
@@ -38,39 +36,45 @@ static void createInstance() {
}
static void createInstance(String projectId, String instanceId) {
- Spanner spanner = SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
- InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ InstanceAdminClient instanceAdminClient = spanner.createInstanceAdminClient()) {
- // Set Instance configuration.
- String configId = "regional-us-central1";
- // This will create an instance with the processing power of 0.2 nodes.
- int processingUnits = 500;
- String displayName = "Descriptive name";
+ // Set Instance configuration.
+ String configId = "regional-us-central1";
+ // This will create an instance with the processing power of 0.2 nodes.
+ int processingUnits = 500;
+ String displayName = "Descriptive name";
- try {
- // Creates a new instance
- System.out.printf("Creating instance %s.%n", instanceId);
- OperationFuture operation =
- instanceAdminClient.createInstance(InstanceInfo
- .newBuilder(InstanceId.of(projectId, instanceId))
- .setInstanceConfigId(InstanceConfigId.of(projectId, configId))
- .setProcessingUnits(processingUnits)
- .setDisplayName(displayName)
- .build());
+ try {
+ // Creates a new instance
+ System.out.printf("Creating instance %s.%n", instanceId);
+ Instance instance =
+ Instance.newBuilder()
+ .setDisplayName(displayName)
+ .setProcessingUnits(processingUnits)
+ .setConfig(
+ InstanceConfigName.of(projectId, configId).toString())
+ .build();
+ // Wait for the createInstance operation to finish.
+ System.out.printf("Waiting for operation on %s to complete...%n", instanceId);
+ Instance createdInstance = instanceAdminClient.createInstanceAsync(
+ CreateInstanceRequest.newBuilder()
+ .setParent(ProjectName.of(projectId).toString())
+ .setInstanceId(instanceId)
+ .setInstance(instance)
+ .build()).get();
- // Wait for the createInstance operation to finish.
- System.out.printf("Waiting for operation on %s to complete...%n", instanceId);
- Instance createdInstance = operation.get();
-
- System.out.printf("Created instance %s.%n", createdInstance.getId().getInstance());
-
- Instance instance = instanceAdminClient.getInstance(instanceId);
- System.out.printf("Instance %s has %d processing units.%n", instance.getId().getInstance(),
- instance.getProcessingUnits());
- } catch (Exception e) {
- System.out.printf("Error: %s.%n", e.getMessage());
+ System.out.printf("Created instance %s.%n", createdInstance.getName());
+ System.out.printf("Instance %s has %d processing units.%n", createdInstance.getName(),
+ createdInstance.getProcessingUnits());
+ } catch (Exception e) {
+ System.out.printf("Error: %s.%n", e.getMessage());
+ }
}
- spanner.close();
}
}
//[END spanner_create_instance_with_processing_units]
diff --git a/samples/snippets/src/main/java/com/example/spanner/CreateSequenceSample.java b/samples/snippets/src/main/java/com/example/spanner/CreateSequenceSample.java
index 964b245ed8..757921080d 100644
--- a/samples/snippets/src/main/java/com/example/spanner/CreateSequenceSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/CreateSequenceSample.java
@@ -17,7 +17,7 @@
package com.example.spanner;
// [START spanner_create_sequence]
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.ResultSet;
@@ -25,13 +25,16 @@
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class CreateSequenceSample {
+
static void createSequence() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
@@ -41,20 +44,18 @@ static void createSequence() {
}
static void createSequence(String projectId, String instanceId, String databaseId) {
- try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- final DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
- dbAdminClient
- .updateDatabaseDdl(
- instanceId,
- databaseId,
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ databaseAdminClient
+ .updateDatabaseDdlAsync(
+ DatabaseName.of(projectId, instanceId, databaseId),
ImmutableList.of(
"CREATE SEQUENCE Seq OPTIONS (sequence_kind = 'bit_reversed_positive')",
"CREATE TABLE Customers (CustomerId INT64 DEFAULT "
+ "(GET_NEXT_SEQUENCE_VALUE(SEQUENCE Seq)), CustomerName STRING(1024)) "
- + "PRIMARY KEY (CustomerId)"),
- null)
+ + "PRIMARY KEY (CustomerId)"))
.get(5, TimeUnit.MINUTES);
System.out.println(
diff --git a/samples/snippets/src/main/java/com/example/spanner/CreateTableWithForeignKeyDeleteCascadeSample.java b/samples/snippets/src/main/java/com/example/spanner/CreateTableWithForeignKeyDeleteCascadeSample.java
index dda09591ee..c9484916a4 100644
--- a/samples/snippets/src/main/java/com/example/spanner/CreateTableWithForeignKeyDeleteCascadeSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/CreateTableWithForeignKeyDeleteCascadeSample.java
@@ -17,10 +17,12 @@
package com.example.spanner;
// [START spanner_create_table_with_foreign_key_delete_cascade]
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.database.v1.DatabaseName;
class CreateTableWithForeignKeyDeleteCascadeSample {
@@ -30,37 +32,35 @@ static void createForeignKeyDeleteCascadeConstraint() {
String instanceId = "my-instance";
String databaseId = "my-database";
- try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
- createForeignKeyDeleteCascadeConstraint(adminClient, instanceId, databaseId);
- }
+ createForeignKeyDeleteCascadeConstraint(projectId, instanceId, databaseId);
}
static void createForeignKeyDeleteCascadeConstraint(
- DatabaseAdminClient adminClient, String instanceId, String databaseId) {
- adminClient.updateDatabaseDdl(
- instanceId,
- databaseId,
- ImmutableList.of(
- "CREATE TABLE Customers (\n"
- + " CustomerId INT64 NOT NULL,\n"
- + " CustomerName STRING(62) NOT NULL,\n"
- + " ) PRIMARY KEY (CustomerId)",
- "CREATE TABLE ShoppingCarts (\n"
- + " CartId INT64 NOT NULL,\n"
- + " CustomerId INT64 NOT NULL,\n"
- + " CustomerName STRING(62) NOT NULL,\n"
- + " CONSTRAINT FKShoppingCartsCustomerId FOREIGN KEY (CustomerId)\n"
- + " REFERENCES Customers (CustomerId) ON DELETE CASCADE\n"
- + " ) PRIMARY KEY (CartId)\n"),
- null);
+ String projectId, String instanceId, String databaseId) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ databaseAdminClient.updateDatabaseDdlAsync(
+ DatabaseName.of(projectId, instanceId, databaseId),
+ ImmutableList.of(
+ "CREATE TABLE Customers (\n"
+ + " CustomerId INT64 NOT NULL,\n"
+ + " CustomerName STRING(62) NOT NULL,\n"
+ + " ) PRIMARY KEY (CustomerId)",
+ "CREATE TABLE ShoppingCarts (\n"
+ + " CartId INT64 NOT NULL,\n"
+ + " CustomerId INT64 NOT NULL,\n"
+ + " CustomerName STRING(62) NOT NULL,\n"
+ + " CONSTRAINT FKShoppingCartsCustomerId FOREIGN KEY (CustomerId)\n"
+ + " REFERENCES Customers (CustomerId) ON DELETE CASCADE\n"
+ + " ) PRIMARY KEY (CartId)\n"));
- System.out.printf(
- String.format(
- "Created Customers and ShoppingCarts table with FKShoppingCartsCustomerId\n"
- + "foreign key constraint on database %s on instance %s\n",
- databaseId, instanceId));
+ System.out.printf(
+ String.format(
+ "Created Customers and ShoppingCarts table with FKShoppingCartsCustomerId\n"
+ + "foreign key constraint on database %s on instance %s\n",
+ databaseId, instanceId));
+ }
}
}
// [END spanner_create_table_with_foreign_key_delete_cascade]
diff --git a/samples/snippets/src/main/java/com/example/spanner/DeleteInstanceConfigSample.java b/samples/snippets/src/main/java/com/example/spanner/DeleteInstanceConfigSample.java
index de76673ca7..c2da7b3000 100644
--- a/samples/snippets/src/main/java/com/example/spanner/DeleteInstanceConfigSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/DeleteInstanceConfigSample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,12 +17,16 @@
package com.example.spanner;
// [START spanner_delete_instance_config]
-import com.google.cloud.spanner.InstanceAdminClient;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
+import com.google.spanner.admin.instance.v1.DeleteInstanceConfigRequest;
+import com.google.spanner.admin.instance.v1.InstanceConfigName;
class DeleteInstanceConfigSample {
+
static void deleteInstanceConfig() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
@@ -32,16 +36,24 @@ static void deleteInstanceConfig() {
static void deleteInstanceConfig(String projectId, String instanceConfigId) {
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- final InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ InstanceAdminClient instanceAdminClient = spanner.createInstanceAdminClient()) {
+ final InstanceConfigName instanceConfigName = InstanceConfigName.of(projectId,
+ instanceConfigId);
+ final DeleteInstanceConfigRequest request =
+ DeleteInstanceConfigRequest.newBuilder().setName(instanceConfigName.toString()).build();
+
try {
- System.out.printf("Deleting %s...\n", instanceConfigId);
- instanceAdminClient.deleteInstanceConfig(instanceConfigId);
- System.out.printf("Deleted instance configuration %s\n", instanceConfigId);
+ System.out.printf("Deleting %s...\n", instanceConfigName);
+ instanceAdminClient.deleteInstanceConfig(request);
+ System.out.printf("Deleted instance configuration %s\n", instanceConfigName);
} catch (SpannerException e) {
System.out.printf(
"Error: Deleting instance configuration %s failed with error message: %s\n",
- instanceConfigId, e.getMessage());
+ instanceConfigName, e.getMessage());
}
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/DropForeignKeyConstraintDeleteCascadeSample.java b/samples/snippets/src/main/java/com/example/spanner/DropForeignKeyConstraintDeleteCascadeSample.java
index 13f39d129f..7c35b9f621 100644
--- a/samples/snippets/src/main/java/com/example/spanner/DropForeignKeyConstraintDeleteCascadeSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/DropForeignKeyConstraintDeleteCascadeSample.java
@@ -17,10 +17,12 @@
package com.example.spanner;
// [START spanner_drop_foreign_key_constraint_delete_cascade]
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.database.v1.DatabaseName;
class DropForeignKeyConstraintDeleteCascadeSample {
@@ -30,28 +32,26 @@ static void deleteForeignKeyDeleteCascadeConstraint() {
String instanceId = "my-instance";
String databaseId = "my-database";
- try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
- deleteForeignKeyDeleteCascadeConstraint(adminClient, instanceId, databaseId);
- }
+ deleteForeignKeyDeleteCascadeConstraint(projectId, instanceId, databaseId);
}
static void deleteForeignKeyDeleteCascadeConstraint(
- DatabaseAdminClient adminClient, String instanceId, String databaseId) {
- adminClient.updateDatabaseDdl(
- instanceId,
- databaseId,
- ImmutableList.of(
- "ALTER TABLE ShoppingCarts\n"
- + " DROP CONSTRAINT FKShoppingCartsCustomerName\n"),
- null);
-
- System.out.printf(
- String.format(
- "Altered ShoppingCarts table to drop FKShoppingCartsCustomerName\n"
- + "foreign key constraint on database %s on instance %s\n",
- databaseId, instanceId));
+ String projectId, String instanceId, String databaseId) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ databaseAdminClient.updateDatabaseDdlAsync(
+ DatabaseName.of(projectId, instanceId, databaseId),
+ ImmutableList.of(
+ "ALTER TABLE ShoppingCarts\n"
+ + " DROP CONSTRAINT FKShoppingCartsCustomerName\n"));
+
+ System.out.printf(
+ String.format(
+ "Altered ShoppingCarts table to drop FKShoppingCartsCustomerName\n"
+ + "foreign key constraint on database %s on instance %s\n",
+ databaseId, instanceId));
+ }
}
}
// [END spanner_drop_foreign_key_constraint_delete_cascade]
diff --git a/samples/snippets/src/main/java/com/example/spanner/DropSequenceSample.java b/samples/snippets/src/main/java/com/example/spanner/DropSequenceSample.java
index 6d054eea4d..9f1b32caed 100644
--- a/samples/snippets/src/main/java/com/example/spanner/DropSequenceSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/DropSequenceSample.java
@@ -17,16 +17,19 @@
package com.example.spanner;
// [START spanner_drop_sequence]
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class DropSequenceSample {
+
static void dropSequence() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
@@ -37,19 +40,14 @@ static void dropSequence() {
static void dropSequence(String projectId, String instanceId, String databaseId) {
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- final DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
-
- dbAdminClient
- .updateDatabaseDdl(
- instanceId,
- databaseId,
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ databaseAdminClient
+ .updateDatabaseDdlAsync(DatabaseName.of(projectId, instanceId, databaseId),
ImmutableList.of(
"ALTER TABLE Customers ALTER COLUMN CustomerId DROP DEFAULT",
- "DROP SEQUENCE Seq"),
- null)
+ "DROP SEQUENCE Seq"))
.get(5, TimeUnit.MINUTES);
-
System.out.println(
"Altered Customers table to drop DEFAULT from CustomerId column "
+ "and dropped the Seq sequence");
diff --git a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java
index c4c17645b6..e4e35bd95a 100644
--- a/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java
+++ b/samples/snippets/src/main/java/com/example/spanner/EnableFineGrainedAccess.java
@@ -17,13 +17,18 @@
package com.example.spanner;
// [START spanner_enable_fine_grained_access]
-import com.google.cloud.Binding;
-import com.google.cloud.Condition;
-import com.google.cloud.Policy;
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
+import com.google.iam.v1.Binding;
+import com.google.iam.v1.GetIamPolicyRequest;
+import com.google.iam.v1.GetPolicyOptions;
+import com.google.iam.v1.Policy;
+import com.google.iam.v1.SetIamPolicyRequest;
+import com.google.spanner.admin.database.v1.DatabaseName;
+import com.google.type.Expr;
public class EnableFineGrainedAccess {
@@ -46,12 +51,15 @@ static void enableFineGrainedAccess(
String title,
String role) {
try (Spanner spanner =
- SpannerOptions.newBuilder()
- .setProjectId(projectId)
- .build()
- .getService()) {
- final DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
- Policy policy = adminClient.getDatabaseIAMPolicy(instanceId, databaseId, 3);
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ final GetPolicyOptions options =
+ GetPolicyOptions.newBuilder().setRequestedPolicyVersion(3).build();
+ final GetIamPolicyRequest getRequest =
+ GetIamPolicyRequest.newBuilder()
+ .setResource(DatabaseName.of(projectId, instanceId, databaseId).toString())
+ .setOptions(options).build();
+ final Policy policy = databaseAdminClient.getIamPolicy(getRequest);
int policyVersion = policy.getVersion();
// The policy in the response from getDatabaseIAMPolicy might use the policy version
// that you specified, or it might use a lower policy version. For example, if you
@@ -65,20 +73,17 @@ static void enableFineGrainedAccess(
Binding binding1 =
Binding.newBuilder()
.setRole("roles/spanner.fineGrainedAccessUser")
- .setMembers(ImmutableList.of(iamMember))
+ .addAllMembers(ImmutableList.of(iamMember))
.build();
Binding binding2 =
Binding.newBuilder()
.setRole("roles/spanner.databaseRoleUser")
.setCondition(
- Condition.newBuilder()
- .setDescription(title)
- .setExpression(
- String.format("resource.name.endsWith(\"/databaseRoles/%s\")", role))
- .setTitle(title)
- .build())
- .setMembers(ImmutableList.of(iamMember))
+ Expr.newBuilder().setDescription(title).setExpression(
+ String.format("resource.name.endsWith(\"/databaseRoles/%s\")", role)
+ ).setTitle(title).build())
+ .addAllMembers(ImmutableList.of(iamMember))
.build();
ImmutableList bindings =
ImmutableList.builder()
@@ -90,10 +95,13 @@ static void enableFineGrainedAccess(
Policy.newBuilder()
.setVersion(policyVersion)
.setEtag(policy.getEtag())
- .setBindings(bindings)
+ .addAllBindings(bindings)
.build();
- Policy response =
- adminClient.setDatabaseIAMPolicy(instanceId, databaseId, policyWithConditions);
+ final SetIamPolicyRequest setRequest =
+ SetIamPolicyRequest.newBuilder()
+ .setResource(DatabaseName.of(projectId, instanceId, databaseId).toString())
+ .setPolicy(policyWithConditions).build();
+ final Policy response = databaseAdminClient.setIamPolicy(setRequest);
System.out.printf(
"Enabled fine-grained access in IAM with version %d%n", response.getVersion());
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/GetDatabaseDdlSample.java b/samples/snippets/src/main/java/com/example/spanner/GetDatabaseDdlSample.java
index 93d32a5ec6..b84f1c0ccc 100644
--- a/samples/snippets/src/main/java/com/example/spanner/GetDatabaseDdlSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/GetDatabaseDdlSample.java
@@ -18,10 +18,11 @@
//[START spanner_get_database_ddl]
-import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
-import java.util.List;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.spanner.admin.database.v1.DatabaseName;
+import com.google.spanner.admin.database.v1.GetDatabaseDdlResponse;
public class GetDatabaseDdlSample {
@@ -35,15 +36,13 @@ static void getDatabaseDdl() {
static void getDatabaseDdl(
String projectId, String instanceId, String databaseId) {
- try (Spanner spanner = SpannerOptions
- .newBuilder()
- .setProjectId(projectId)
- .build()
- .getService()) {
- final DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
- final List ddls = databaseAdminClient.getDatabaseDdl(instanceId, databaseId);
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ final GetDatabaseDdlResponse response =
+ databaseAdminClient.getDatabaseDdl(DatabaseName.of(projectId, instanceId, databaseId));
System.out.println("Retrieved database DDL for " + databaseId);
- for (String ddl : ddls) {
+ for (String ddl : response.getStatementsList()) {
System.out.println(ddl);
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/GetInstanceConfigSample.java b/samples/snippets/src/main/java/com/example/spanner/GetInstanceConfigSample.java
index 46f38b84d1..9dd8690f75 100644
--- a/samples/snippets/src/main/java/com/example/spanner/GetInstanceConfigSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/GetInstanceConfigSample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,35 +18,38 @@
//[START spanner_get_instance_config]
-import com.google.cloud.spanner.InstanceAdminClient;
-import com.google.cloud.spanner.InstanceConfig;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
+import com.google.spanner.admin.instance.v1.InstanceConfig;
+import com.google.spanner.admin.instance.v1.InstanceConfigName;
public class GetInstanceConfigSample {
static void getInstanceConfig() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
- final String instanceConfigName = "nam6";
- getInstanceConfig(projectId, instanceConfigName);
+ final String instanceConfigId = "nam6";
+ getInstanceConfig(projectId, instanceConfigId);
}
- static void getInstanceConfig(String projectId, String instanceConfigName) {
- try (Spanner spanner = SpannerOptions
- .newBuilder()
- .setProjectId(projectId)
- .build()
- .getService()) {
- final InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
+ static void getInstanceConfig(String projectId, String instanceConfigId) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ InstanceAdminClient instanceAdminClient = spanner.createInstanceAdminClient()) {
+ final InstanceConfigName instanceConfigName = InstanceConfigName.of(projectId,
+ instanceConfigId);
- final InstanceConfig instanceConfig = instanceAdminClient
- .getInstanceConfig(instanceConfigName);
+ final InstanceConfig instanceConfig =
+ instanceAdminClient.getInstanceConfig(instanceConfigName.toString());
System.out.printf(
"Available leader options for instance config %s: %s%n",
- instanceConfig.getId(),
- instanceConfig.getLeaderOptions()
+ instanceConfig.getName(),
+ instanceConfig.getLeaderOptionsList()
);
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java b/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java
index 9292405054..e16a55cb7b 100644
--- a/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java
+++ b/samples/snippets/src/main/java/com/example/spanner/ListDatabaseRoles.java
@@ -17,16 +17,18 @@
package com.example.spanner;
// [START spanner_list_database_roles]
-import com.google.cloud.spanner.DatabaseAdminClient;
-import com.google.cloud.spanner.DatabaseId;
-import com.google.cloud.spanner.DatabaseRole;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
-import java.util.concurrent.ExecutionException;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient.ListDatabaseRolesPage;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient.ListDatabaseRolesPagedResponse;
+import com.google.spanner.admin.database.v1.DatabaseName;
+import com.google.spanner.admin.database.v1.DatabaseRole;
public class ListDatabaseRoles {
- static void listDatabaseRoles() throws InterruptedException, ExecutionException {
+ static void listDatabaseRoles() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
@@ -36,15 +38,16 @@ static void listDatabaseRoles() throws InterruptedException, ExecutionException
static void listDatabaseRoles(String projectId, String instanceId, String databaseId) {
try (Spanner spanner =
- SpannerOptions.newBuilder()
- .setProjectId(projectId)
- .build()
- .getService()) {
- final DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
- String databasePath = DatabaseId.of(projectId, instanceId, databaseId).getName();
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ DatabaseName databaseName = DatabaseName.of(projectId, instanceId, databaseId);
+ ListDatabaseRolesPagedResponse response
+ = databaseAdminClient.listDatabaseRoles(databaseName);
System.out.println("List of Database roles");
- for (DatabaseRole role : adminClient.listDatabaseRoles(instanceId, databaseId).iterateAll()) {
- System.out.printf("%s%n", role.getName());
+ for (ListDatabaseRolesPage page : response.iteratePages()) {
+ for (DatabaseRole role : page.iterateAll()) {
+ System.out.printf("Obtained role %s%n", role.getName());
+ }
}
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/ListDatabasesSample.java b/samples/snippets/src/main/java/com/example/spanner/ListDatabasesSample.java
index 6e6a246a30..631b72dc11 100644
--- a/samples/snippets/src/main/java/com/example/spanner/ListDatabasesSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/ListDatabasesSample.java
@@ -18,11 +18,13 @@
//[START spanner_list_databases]
-import com.google.api.gax.paging.Page;
-import com.google.cloud.spanner.Database;
-import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient.ListDatabasesPage;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient.ListDatabasesPagedResponse;
+import com.google.spanner.admin.database.v1.Database;
+import com.google.spanner.admin.database.v1.InstanceName;
public class ListDatabasesSample {
@@ -34,21 +36,20 @@ static void listDatabases() {
}
static void listDatabases(String projectId, String instanceId) {
- try (Spanner spanner = SpannerOptions
- .newBuilder()
- .setProjectId(projectId)
- .build()
- .getService()) {
- final DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
- Page page = databaseAdminClient.listDatabases(instanceId);
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ ListDatabasesPagedResponse response =
+ databaseAdminClient.listDatabases(InstanceName.of(projectId, instanceId));
+
System.out.println("Databases for projects/" + projectId + "/instances/" + instanceId);
- while (page != null) {
+
+ for (ListDatabasesPage page : response.iteratePages()) {
for (Database database : page.iterateAll()) {
final String defaultLeader = database.getDefaultLeader().equals("")
? "" : "(default leader = " + database.getDefaultLeader() + ")";
- System.out.println("\t" + database.getId() + " " + defaultLeader);
+ System.out.println("\t" + database.getName() + " " + defaultLeader);
}
- page = page.getNextPage();
}
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigOperationsSample.java b/samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigOperationsSample.java
index bcf68b7d58..b42c52126b 100644
--- a/samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigOperationsSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigOperationsSample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,15 +17,18 @@
package com.example.spanner;
// [START spanner_list_instance_config_operations]
-import com.google.cloud.spanner.InstanceAdminClient;
-import com.google.cloud.spanner.Options;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
import com.google.longrunning.Operation;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.spanner.admin.instance.v1.CreateInstanceConfigMetadata;
+import com.google.spanner.admin.instance.v1.ListInstanceConfigOperationsRequest;
+import com.google.spanner.admin.instance.v1.ProjectName;
public class ListInstanceConfigOperationsSample {
+
static void listInstanceConfigOperations() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
@@ -34,32 +37,36 @@ static void listInstanceConfigOperations() {
static void listInstanceConfigOperations(String projectId) {
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- final InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
-
- try {
- System.out.printf(
- "Getting list of instance config operations for project %s...\n",
- projectId);
- final Iterable instanceConfigOperations =
- instanceAdminClient
- .listInstanceConfigOperations(
- Options.filter(
- "(metadata.@type=type.googleapis.com/"
- + "google.spanner.admin.instance.v1.CreateInstanceConfigMetadata)"))
- .iterateAll();
- for (Operation operation : instanceConfigOperations) {
- CreateInstanceConfigMetadata metadata =
- operation.getMetadata().unpack(CreateInstanceConfigMetadata.class);
- System.out.printf(
- "Create instance config operation for %s is %d%% completed.\n",
- metadata.getInstanceConfig().getName(), metadata.getProgress().getProgressPercent());
- }
- } catch (InvalidProtocolBufferException e) {
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ InstanceAdminClient instanceAdminClient = spanner.createInstanceAdminClient()) {
+ final ProjectName projectName = ProjectName.of(projectId);
+ System.out.printf(
+ "Getting list of instance config operations for project %s...\n",
+ projectId);
+ final ListInstanceConfigOperationsRequest request =
+ ListInstanceConfigOperationsRequest.newBuilder()
+ .setParent(projectName.toString())
+ .setFilter("(metadata.@type=type.googleapis.com/"
+ + "google.spanner.admin.instance.v1.CreateInstanceConfigMetadata)").build();
+ final Iterable instanceConfigOperations =
+ instanceAdminClient.listInstanceConfigOperations(request).iterateAll();
+ for (Operation operation : instanceConfigOperations) {
+ CreateInstanceConfigMetadata metadata =
+ operation.getMetadata().unpack(CreateInstanceConfigMetadata.class);
System.out.printf(
- "Error: Listing instance config operations failed with error message %s\n",
- e.getMessage());
+ "Create instance config operation for %s is %d%% completed.\n",
+ metadata.getInstanceConfig().getName(), metadata.getProgress().getProgressPercent());
}
+ System.out.printf(
+ "Obtained list of instance config operations for project %s...\n",
+ projectName);
+ } catch (InvalidProtocolBufferException e) {
+ System.out.printf(
+ "Error: Listing instance config operations failed with error message %s\n",
+ e.getMessage());
}
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigsSample.java b/samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigsSample.java
index d0de12dfce..7c5391638b 100644
--- a/samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigsSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/ListInstanceConfigsSample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,32 +18,34 @@
//[START spanner_list_instance_configs]
-import com.google.cloud.spanner.InstanceAdminClient;
-import com.google.cloud.spanner.InstanceConfig;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
+import com.google.spanner.admin.instance.v1.InstanceConfig;
+import com.google.spanner.admin.instance.v1.ProjectName;
public class ListInstanceConfigsSample {
static void listInstanceConfigs() {
// TODO(developer): Replace these variables before running the sample.
- final String projectId = "my-project";
+ String projectId = "my-project";
listInstanceConfigs(projectId);
}
static void listInstanceConfigs(String projectId) {
- try (Spanner spanner = SpannerOptions
- .newBuilder()
- .setProjectId(projectId)
- .build()
- .getService()) {
- final InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
-
- for (InstanceConfig instanceConfig : instanceAdminClient.listInstanceConfigs().iterateAll()) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ InstanceAdminClient instanceAdminClient = spanner.createInstanceAdminClient()) {
+ final ProjectName projectName = ProjectName.of(projectId);
+ for (InstanceConfig instanceConfig :
+ instanceAdminClient.listInstanceConfigs(projectName).iterateAll()) {
System.out.printf(
"Available leader options for instance config %s: %s%n",
- instanceConfig.getId(),
- instanceConfig.getLeaderOptions()
+ instanceConfig.getName(),
+ instanceConfig.getLeaderOptionsList()
);
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/PgAlterSequenceSample.java b/samples/snippets/src/main/java/com/example/spanner/PgAlterSequenceSample.java
index e10c29807f..a3e4a9a677 100644
--- a/samples/snippets/src/main/java/com/example/spanner/PgAlterSequenceSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/PgAlterSequenceSample.java
@@ -17,7 +17,7 @@
package com.example.spanner;
// [START spanner_postgresql_alter_sequence]
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.ResultSet;
@@ -25,13 +25,16 @@
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class PgAlterSequenceSample {
+
static void pgAlterSequence() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
@@ -42,14 +45,13 @@ static void pgAlterSequence() {
static void pgAlterSequence(String projectId, String instanceId, String databaseId) {
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- final DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
- dbAdminClient
- .updateDatabaseDdl(
- instanceId,
- databaseId,
- ImmutableList.of("ALTER SEQUENCE Seq SKIP RANGE 1000 5000000"),
- null)
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+
+ databaseAdminClient
+ .updateDatabaseDdlAsync(
+ DatabaseName.of(projectId, instanceId, databaseId),
+ ImmutableList.of("ALTER SEQUENCE Seq SKIP RANGE 1000 5000000"))
.get(5, TimeUnit.MINUTES);
System.out.println(
"Altered Seq sequence to skip an inclusive range between 1000 and 5000000");
diff --git a/samples/snippets/src/main/java/com/example/spanner/PgCaseSensitivitySample.java b/samples/snippets/src/main/java/com/example/spanner/PgCaseSensitivitySample.java
index d76b26b178..abebdef39a 100644
--- a/samples/snippets/src/main/java/com/example/spanner/PgCaseSensitivitySample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/PgCaseSensitivitySample.java
@@ -18,8 +18,6 @@
// [START spanner_postgresql_identifier_case_sensitivity]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Mutation;
@@ -28,7 +26,9 @@
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
-import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.common.collect.Lists;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
@@ -43,34 +43,28 @@ static void pgCaseSensitivity() {
}
static void pgCaseSensitivity(String projectId, String instanceId, String databaseId) {
+
try (Spanner spanner =
- SpannerOptions.newBuilder()
- .setProjectId(projectId)
- .build()
- .getService()) {
- final DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
// Spanner PostgreSQL follows the case sensitivity rules of PostgreSQL. This means that:
// 1. Identifiers that are not double-quoted are folded to lower case.
// 2. Identifiers that are double-quoted retain their case and are case-sensitive.
// See https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
// for more information.
- final OperationFuture updateOperation =
- databaseAdminClient.updateDatabaseDdl(
- instanceId,
- databaseId,
- Collections.singleton(
- "CREATE TABLE Singers ("
- // SingerId will be folded to `singerid`.
- + " SingerId bigint NOT NULL PRIMARY KEY,"
- // FirstName and LastName are double-quoted and will therefore retain their
- // mixed case and are case-sensitive. This means that any statement that
- // references any of these columns must use double quotes.
- + " \"FirstName\" varchar(1024) NOT NULL,"
- + " \"LastName\" varchar(1024) NOT NULL"
- + ")"),
- null);
- updateOperation.get();
+ databaseAdminClient.updateDatabaseDdlAsync(
+ DatabaseName.of(projectId, instanceId, databaseId),
+ Lists.newArrayList(
+ "CREATE TABLE Singers ("
+ // SingerId will be folded to `singerid`.
+ + " SingerId bigint NOT NULL PRIMARY KEY,"
+ // FirstName and LastName are double-quoted and will therefore retain their
+ // mixed case and are case-sensitive. This means that any statement that
+ // references any of these columns must use double quotes.
+ + " \"FirstName\" varchar(1024) NOT NULL,"
+ + " \"LastName\" varchar(1024) NOT NULL"
+ + ")")).get();
DatabaseClient client =
spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId));
diff --git a/samples/snippets/src/main/java/com/example/spanner/PgCreateSequenceSample.java b/samples/snippets/src/main/java/com/example/spanner/PgCreateSequenceSample.java
index e6e23f49b8..79445aa272 100644
--- a/samples/snippets/src/main/java/com/example/spanner/PgCreateSequenceSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/PgCreateSequenceSample.java
@@ -17,7 +17,7 @@
package com.example.spanner;
// [START spanner_postgresql_create_sequence]
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.ResultSet;
@@ -25,13 +25,16 @@
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class PgCreateSequenceSample {
+
static void pgCreateSequence() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
@@ -42,22 +45,18 @@ static void pgCreateSequence() {
static void pgCreateSequence(String projectId, String instanceId, String databaseId) {
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- final DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
-
- dbAdminClient
- .updateDatabaseDdl(
- instanceId,
- databaseId,
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ databaseAdminClient
+ .updateDatabaseDdlAsync(DatabaseName.of(projectId, instanceId, databaseId).toString(),
ImmutableList.of(
"CREATE SEQUENCE Seq BIT_REVERSED_POSITIVE;",
"CREATE TABLE Customers (CustomerId BIGINT DEFAULT nextval('Seq'), "
- + "CustomerName character varying(1024), PRIMARY KEY (CustomerId))"),
- null)
+ + "CustomerName character varying(1024), PRIMARY KEY (CustomerId))"))
.get(5, TimeUnit.MINUTES);
System.out.println(
- "Created Seq sequence and Customers table, where its key column "
+ "Created Seq sequence and Customers table, where the key column "
+ "CustomerId uses the sequence as a default value");
final DatabaseClient dbClient =
diff --git a/samples/snippets/src/main/java/com/example/spanner/PgDropSequenceSample.java b/samples/snippets/src/main/java/com/example/spanner/PgDropSequenceSample.java
index c0990c1c4d..129009e9b2 100644
--- a/samples/snippets/src/main/java/com/example/spanner/PgDropSequenceSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/PgDropSequenceSample.java
@@ -17,16 +17,19 @@
package com.example.spanner;
// [START spanner_postgresql_drop_sequence]
-import com.google.cloud.spanner.DatabaseAdminClient;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class PgDropSequenceSample {
+
static void pgDropSequence() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
@@ -36,17 +39,16 @@ static void pgDropSequence() {
}
static void pgDropSequence(String projectId, String instanceId, String databaseId) {
+
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- final DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
- dbAdminClient
- .updateDatabaseDdl(
- instanceId,
- databaseId,
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ databaseAdminClient
+ .updateDatabaseDdlAsync(
+ DatabaseName.of(projectId, instanceId, databaseId),
ImmutableList.of(
"ALTER TABLE Customers ALTER COLUMN CustomerId DROP DEFAULT",
- "DROP SEQUENCE Seq"),
- null)
+ "DROP SEQUENCE Seq"))
.get(5, TimeUnit.MINUTES);
System.out.println(
"Altered Customers table to drop DEFAULT from "
diff --git a/samples/snippets/src/main/java/com/example/spanner/PgInterleavedTableSample.java b/samples/snippets/src/main/java/com/example/spanner/PgInterleavedTableSample.java
index d79ba7b58f..30ee48ed6d 100644
--- a/samples/snippets/src/main/java/com/example/spanner/PgInterleavedTableSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/PgInterleavedTableSample.java
@@ -18,12 +18,11 @@
// [START spanner_postgresql_interleaved_table]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
-import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.Arrays;
import java.util.concurrent.ExecutionException;
@@ -38,35 +37,29 @@ static void pgInterleavedTable() {
}
static void pgInterleavedTable(String projectId, String instanceId, String databaseId) {
- try (Spanner spanner =
- SpannerOptions.newBuilder()
- .setProjectId(projectId)
- .build()
- .getService()) {
- final DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
// The Spanner PostgreSQL dialect extends the PostgreSQL dialect with certain Spanner
// specific features, such as interleaved tables.
// See https://cloud.google.com/spanner/docs/postgresql/data-definition-language#create_table
// for the full CREATE TABLE syntax.
- final OperationFuture updateOperation =
- databaseAdminClient.updateDatabaseDdl(
+ databaseAdminClient.updateDatabaseDdlAsync(DatabaseName.of(projectId,
instanceId,
- databaseId,
- Arrays.asList(
- "CREATE TABLE Singers ("
- + " SingerId bigint NOT NULL PRIMARY KEY,"
- + " FirstName varchar(1024) NOT NULL,"
- + " LastName varchar(1024) NOT NULL"
- + ")",
- "CREATE TABLE Albums ("
- + " SingerId bigint NOT NULL,"
- + " AlbumId bigint NOT NULL,"
- + " Title varchar(1024) NOT NULL,"
- + " PRIMARY KEY (SingerId, AlbumId)"
- + ") INTERLEAVE IN PARENT Singers ON DELETE CASCADE"),
- null);
- updateOperation.get();
+ databaseId),
+ Arrays.asList(
+ "CREATE TABLE Singers ("
+ + " SingerId bigint NOT NULL PRIMARY KEY,"
+ + " FirstName varchar(1024) NOT NULL,"
+ + " LastName varchar(1024) NOT NULL"
+ + ")",
+ "CREATE TABLE Albums ("
+ + " SingerId bigint NOT NULL,"
+ + " AlbumId bigint NOT NULL,"
+ + " Title varchar(1024) NOT NULL,"
+ + " PRIMARY KEY (SingerId, AlbumId)"
+ + ") INTERLEAVE IN PARENT Singers ON DELETE CASCADE")).get();
System.out.println("Created interleaved table hierarchy using PostgreSQL dialect");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
diff --git a/samples/snippets/src/main/java/com/example/spanner/PgSpannerSample.java b/samples/snippets/src/main/java/com/example/spanner/PgSpannerSample.java
index 44b96d4a40..600206c148 100644
--- a/samples/snippets/src/main/java/com/example/spanner/PgSpannerSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/PgSpannerSample.java
@@ -16,24 +16,16 @@
package com.example.spanner;
-import com.google.api.gax.longrunning.OperationFuture;
import com.google.api.gax.paging.Page;
import com.google.cloud.ByteArray;
import com.google.cloud.Date;
import com.google.cloud.Timestamp;
-import com.google.cloud.spanner.Database;
-import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
-import com.google.cloud.spanner.Dialect;
-import com.google.cloud.spanner.Instance;
-import com.google.cloud.spanner.InstanceAdminClient;
-import com.google.cloud.spanner.InstanceId;
import com.google.cloud.spanner.Key;
import com.google.cloud.spanner.KeyRange;
import com.google.cloud.spanner.KeySet;
import com.google.cloud.spanner.Mutation;
-import com.google.cloud.spanner.Options;
import com.google.cloud.spanner.ReadOnlyTransaction;
import com.google.cloud.spanner.ResultSet;
import com.google.cloud.spanner.Spanner;
@@ -45,19 +37,27 @@
import com.google.cloud.spanner.Struct;
import com.google.cloud.spanner.TimestampBound;
import com.google.cloud.spanner.Value;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient.ListBackupOperationsPagedResponse;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient.ListDatabaseOperationsPagedResponse;
import com.google.common.io.BaseEncoding;
import com.google.longrunning.Operation;
import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.spanner.admin.database.v1.BackupName;
+import com.google.spanner.admin.database.v1.CopyBackupMetadata;
import com.google.spanner.admin.database.v1.CreateBackupMetadata;
-import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
+import com.google.spanner.admin.database.v1.CreateDatabaseRequest;
+import com.google.spanner.admin.database.v1.Database;
+import com.google.spanner.admin.database.v1.DatabaseDialect;
+import com.google.spanner.admin.database.v1.DatabaseName;
+import com.google.spanner.admin.database.v1.ListBackupOperationsRequest;
+import com.google.spanner.admin.database.v1.ListDatabaseOperationsRequest;
import com.google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata;
-import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.spanner.admin.instance.v1.InstanceName;
import com.google.spanner.v1.ExecuteSqlRequest;
import java.math.BigDecimal;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@@ -66,6 +66,7 @@
* Example code for using the Cloud Spanner PostgreSQL interface.
*/
public class PgSpannerSample {
+
// [START spanner_postgresql_insert_data]
static final List SINGERS =
Arrays.asList(
@@ -83,7 +84,9 @@ public class PgSpannerSample {
new Album(2, 3, "Terrified"));
// [END spanner_postgresql_insert_data]
- /** Class to contain performance sample data. */
+ /**
+ * Class to contain performance sample data.
+ */
static class Performance {
final long singerId;
@@ -159,7 +162,9 @@ static class Performance {
new BigDecimal("390650.99")));
// [END spanner_postgresql_insert_datatypes_data]
- /** Class to contain venue sample data. */
+ /**
+ * Class to contain venue sample data.
+ */
static class Venue {
final long venueId;
@@ -195,15 +200,18 @@ static class Venue {
}
// [START spanner_postgresql_create_database]
- static void createPostgreSqlDatabase(DatabaseAdminClient dbAdminClient, DatabaseId id) {
- OperationFuture op = dbAdminClient.createDatabase(
- dbAdminClient.newDatabaseBuilder(id).setDialect(Dialect.POSTGRESQL).build(),
- Collections.emptyList());
+ static void createPostgreSqlDatabase(
+ DatabaseAdminClient dbAdminClient, String projectId, String instanceId, String databaseId) {
+ final CreateDatabaseRequest request =
+ CreateDatabaseRequest.newBuilder()
+ .setCreateStatement("CREATE DATABASE \"" + databaseId + "\"")
+ .setParent(InstanceName.of(projectId, instanceId).toString())
+ .setDatabaseDialect(DatabaseDialect.POSTGRESQL).build();
+
try {
// Initiate the request which returns an OperationFuture.
- Database db = op.get();
- System.out.println("Created database [" + db.getId() + "]");
- createTableUsingDdl(dbAdminClient, id);
+ Database db = dbAdminClient.createDatabaseAsync(request).get();
+ System.out.println("Created database [" + db.getName() + "]");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
throw (SpannerException) e.getCause();
@@ -272,9 +280,9 @@ static void deleteExampleData(DatabaseClient dbClient) {
// [START spanner_postgresql_query_data]
static void query(DatabaseClient dbClient) {
try (ResultSet resultSet =
- dbClient
- .singleUse() // Execute a single read or query against Cloud Spanner.
- .executeQuery(Statement.of("SELECT SingerId, AlbumId, AlbumTitle FROM Albums"))) {
+ dbClient
+ .singleUse() // Execute a single read or query against Cloud Spanner.
+ .executeQuery(Statement.of("SELECT SingerId, AlbumId, AlbumTitle FROM Albums"))) {
while (resultSet.next()) {
System.out.printf(
"%d %d %s\n", resultSet.getLong(0), resultSet.getLong(1),
@@ -287,12 +295,12 @@ static void query(DatabaseClient dbClient) {
// [START spanner_postgresql_read_data]
static void read(DatabaseClient dbClient) {
try (ResultSet resultSet =
- dbClient
- .singleUse()
- .read(
- "Albums",
- KeySet.all(), // Read all rows in a table.
- Arrays.asList("SingerId", "AlbumId", "AlbumTitle"))) {
+ dbClient
+ .singleUse()
+ .read(
+ "Albums",
+ KeySet.all(), // Read all rows in a table.
+ Arrays.asList("SingerId", "AlbumId", "AlbumTitle"))) {
while (resultSet.next()) {
System.out.printf(
"%d %d %s\n", resultSet.getLong(0), resultSet.getLong(1),
@@ -303,15 +311,12 @@ static void read(DatabaseClient dbClient) {
// [END spanner_postgresql_read_data]
// [START spanner_postgresql_add_column]
- static void addMarketingBudget(DatabaseAdminClient adminClient, DatabaseId dbId) {
- OperationFuture op = adminClient.updateDatabaseDdl(
- dbId.getInstanceId().getInstance(),
- dbId.getDatabase(),
- Arrays.asList("ALTER TABLE Albums ADD COLUMN MarketingBudget bigint"),
- null);
+ static void addMarketingBudget(DatabaseAdminClient adminClient, DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
+ adminClient.updateDatabaseDdlAsync(
+ databaseName,
+ Arrays.asList("ALTER TABLE Albums ADD COLUMN MarketingBudget bigint")).get();
System.out.println("Added MarketingBudget column");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
@@ -404,11 +409,11 @@ static void queryMarketingBudget(DatabaseClient dbClient) {
// null. A try-with-resource block is used to automatically release resources held by
// ResultSet.
try (ResultSet resultSet =
- dbClient
- .singleUse()
- .executeQuery(Statement.of("SELECT singerid as \"SingerId\", "
- + "albumid as \"AlbumId\", marketingbudget as \"MarketingBudget\" "
- + "FROM Albums"))) {
+ dbClient
+ .singleUse()
+ .executeQuery(Statement.of("SELECT singerid as \"SingerId\", "
+ + "albumid as \"AlbumId\", marketingbudget as \"MarketingBudget\" "
+ + "FROM Albums"))) {
while (resultSet.next()) {
System.out.printf(
"%d %d %s\n",
@@ -424,16 +429,12 @@ static void queryMarketingBudget(DatabaseClient dbClient) {
// [END spanner_postgresql_query_data_with_new_column]
// [START spanner_postgresql_create_index]
- static void addIndex(DatabaseAdminClient adminClient, DatabaseId dbId) {
- OperationFuture op =
- adminClient.updateDatabaseDdl(
- dbId.getInstanceId().getInstance(),
- dbId.getDatabase(),
- Arrays.asList("CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)"),
- null);
+ static void addIndex(DatabaseAdminClient adminClient, DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
+ adminClient.updateDatabaseDdlAsync(
+ databaseName,
+ Arrays.asList("CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)")).get();
System.out.println("Added AlbumsByAlbumTitle index");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
@@ -449,13 +450,13 @@ static void addIndex(DatabaseAdminClient adminClient, DatabaseId dbId) {
// [START spanner_postgresql_read_data_with_index]
static void readUsingIndex(DatabaseClient dbClient) {
try (ResultSet resultSet =
- dbClient
- .singleUse()
- .readUsingIndex(
- "Albums",
- "AlbumsByAlbumTitle",
- KeySet.all(),
- Arrays.asList("AlbumId", "AlbumTitle"))) {
+ dbClient
+ .singleUse()
+ .readUsingIndex(
+ "Albums",
+ "AlbumsByAlbumTitle",
+ KeySet.all(),
+ Arrays.asList("AlbumId", "AlbumTitle"))) {
while (resultSet.next()) {
System.out.printf("%d %s\n", resultSet.getLong(0), resultSet.getString(1));
}
@@ -464,17 +465,14 @@ static void readUsingIndex(DatabaseClient dbClient) {
// [END spanner_postgresql_read_data_with_index]
// [START spanner_postgresql_create_storing_index]
- static void addStoringIndex(DatabaseAdminClient adminClient, DatabaseId dbId) {
- OperationFuture op = adminClient.updateDatabaseDdl(
- dbId.getInstanceId().getInstance(),
- dbId.getDatabase(),
- Arrays.asList(
- "CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) "
- + "INCLUDE (MarketingBudget)"),
- null);
+ static void addStoringIndex(DatabaseAdminClient adminClient, DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
+ adminClient.updateDatabaseDdlAsync(
+ databaseName,
+ Arrays.asList(
+ "CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) "
+ + "INCLUDE (MarketingBudget)")).get();
System.out.println("Added AlbumsByAlbumTitle2 index");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
@@ -493,13 +491,13 @@ static void addStoringIndex(DatabaseAdminClient adminClient, DatabaseId dbId) {
static void readStoringIndex(DatabaseClient dbClient) {
// We can read MarketingBudget also from the index since it stores a copy of MarketingBudget.
try (ResultSet resultSet =
- dbClient
- .singleUse()
- .readUsingIndex(
- "Albums",
- "AlbumsByAlbumTitle2",
- KeySet.all(),
- Arrays.asList("AlbumId", "AlbumTitle", "MarketingBudget"))) {
+ dbClient
+ .singleUse()
+ .readUsingIndex(
+ "Albums",
+ "AlbumsByAlbumTitle2",
+ KeySet.all(),
+ Arrays.asList("AlbumId", "AlbumTitle", "MarketingBudget"))) {
while (resultSet.next()) {
System.out.printf(
"%d %s %s\n",
@@ -526,8 +524,8 @@ static void readOnlyTransaction(DatabaseClient dbClient) {
queryResultSet.getString(2));
}
try (ResultSet readResultSet =
- transaction.read(
- "Albums", KeySet.all(), Arrays.asList("SingerId", "AlbumId", "AlbumTitle"))) {
+ transaction.read(
+ "Albums", KeySet.all(), Arrays.asList("SingerId", "AlbumId", "AlbumTitle"))) {
while (readResultSet.next()) {
System.out.printf(
"%d %d %s\n",
@@ -542,10 +540,10 @@ static void readOnlyTransaction(DatabaseClient dbClient) {
// [START spanner_postgresql_query_singers_table]
static void querySingersTable(DatabaseClient dbClient) {
try (ResultSet resultSet =
- dbClient
- .singleUse()
- .executeQuery(Statement.of("SELECT singerid as \"SingerId\", "
- + "firstname as \"FirstName\", lastname as \"LastName\" FROM Singers"))) {
+ dbClient
+ .singleUse()
+ .executeQuery(Statement.of("SELECT singerid as \"SingerId\", "
+ + "firstname as \"FirstName\", lastname as \"LastName\" FROM Singers"))) {
while (resultSet.next()) {
System.out.printf(
"%s %s %s\n",
@@ -656,35 +654,31 @@ static void writeWithTransactionUsingDml(DatabaseClient dbClient) {
// [START spanner_postgresql_create_table_using_ddl]
// [START spanner_postgresql_create_database]
- static void createTableUsingDdl(DatabaseAdminClient dbAdminClient, DatabaseId id) {
- OperationFuture op =
- dbAdminClient.updateDatabaseDdl(
- id.getInstanceId().getInstance(),
- id.getDatabase(),
- Arrays.asList(
- "CREATE TABLE Singers ("
- + " SingerId bigint NOT NULL,"
- + " FirstName character varying(1024),"
- + " LastName character varying(1024),"
- + " SingerInfo bytea,"
- + " FullName character varying(2048) GENERATED "
- + " ALWAYS AS (FirstName || ' ' || LastName) STORED,"
- + " PRIMARY KEY (SingerId)"
- + ")",
- "CREATE TABLE Albums ("
- + " SingerId bigint NOT NULL,"
- + " AlbumId bigint NOT NULL,"
- + " AlbumTitle character varying(1024),"
- + " PRIMARY KEY (SingerId, AlbumId)"
- + ") INTERLEAVE IN PARENT Singers ON DELETE CASCADE"),
- null);
+ static void createTableUsingDdl(DatabaseAdminClient dbAdminClient, DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
- System.out.println("Created Singers & Albums tables in database: [" + id + "]");
+ dbAdminClient.updateDatabaseDdlAsync(
+ databaseName,
+ Arrays.asList(
+ "CREATE TABLE Singers ("
+ + " SingerId bigint NOT NULL,"
+ + " FirstName character varying(1024),"
+ + " LastName character varying(1024),"
+ + " SingerInfo bytea,"
+ + " FullName character varying(2048) GENERATED "
+ + " ALWAYS AS (FirstName || ' ' || LastName) STORED,"
+ + " PRIMARY KEY (SingerId)"
+ + ")",
+ "CREATE TABLE Albums ("
+ + " SingerId bigint NOT NULL,"
+ + " AlbumId bigint NOT NULL,"
+ + " AlbumTitle character varying(1024),"
+ + " PRIMARY KEY (SingerId, AlbumId)"
+ + ") INTERLEAVE IN PARENT Singers ON DELETE CASCADE")).get();
+ System.out.println("Created Singers & Albums tables in database: [" + databaseName + "]");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
- throw (SpannerException) e.getCause();
+ throw SpannerExceptionFactory.asSpannerException(e);
} catch (InterruptedException e) {
// Throw when a thread is waiting, sleeping, or otherwise occupied,
// and the thread is interrupted, either before or during the activity.
@@ -697,11 +691,11 @@ static void createTableUsingDdl(DatabaseAdminClient dbAdminClient, DatabaseId id
// [START spanner_postgresql_read_stale_data]
static void readStaleData(DatabaseClient dbClient) {
try (ResultSet resultSet =
- dbClient
- .singleUse(TimestampBound.ofExactStaleness(15, TimeUnit.SECONDS))
- .read(
- "Albums", KeySet.all(),
- Arrays.asList("SingerId", "AlbumId", "MarketingBudget"))) {
+ dbClient
+ .singleUse(TimestampBound.ofExactStaleness(15, TimeUnit.SECONDS))
+ .read(
+ "Albums", KeySet.all(),
+ Arrays.asList("SingerId", "AlbumId", "MarketingBudget"))) {
while (resultSet.next()) {
System.out.printf(
"%d %d %s\n",
@@ -749,17 +743,14 @@ static void updateWithTimestamp(DatabaseClient dbClient) {
// [END spanner_postgresql_update_data_with_timestamp_column]
// [START spanner_postgresql_add_timestamp_column]
- static void addLastUpdateTimestampColumn(DatabaseAdminClient adminClient, DatabaseId dbId) {
- OperationFuture op =
- adminClient.updateDatabaseDdl(
- dbId.getInstanceId().getInstance(),
- dbId.getDatabase(),
- Arrays.asList(
- "ALTER TABLE Albums ADD COLUMN LastUpdateTime spanner.commit_timestamp"),
- null);
+ static void addLastUpdateTimestampColumn(
+ DatabaseAdminClient adminClient, DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
+ adminClient.updateDatabaseDdlAsync(
+ databaseName,
+ Arrays.asList(
+ "ALTER TABLE Albums ADD COLUMN LastUpdateTime spanner.commit_timestamp")).get();
System.out.println("Added LastUpdateTime as a timestamp column in Albums table.");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
@@ -778,14 +769,14 @@ static void queryMarketingBudgetWithTimestamp(DatabaseClient dbClient) {
// null. A try-with-resource block is used to automatically release resources held by
// ResultSet.
try (ResultSet resultSet =
- dbClient
- .singleUse()
- .executeQuery(
- Statement.of(
- "SELECT singerid as \"SingerId\", albumid as \"AlbumId\", "
- + "marketingbudget as \"MarketingBudget\","
- + "lastupdatetime as \"LastUpdateTime\" FROM Albums"
- + " ORDER BY LastUpdateTime DESC"))) {
+ dbClient
+ .singleUse()
+ .executeQuery(
+ Statement.of(
+ "SELECT singerid as \"SingerId\", albumid as \"AlbumId\", "
+ + "marketingbudget as \"MarketingBudget\","
+ + "lastupdatetime as \"LastUpdateTime\" FROM Albums"
+ + " ORDER BY LastUpdateTime DESC"))) {
while (resultSet.next()) {
System.out.printf(
"%d %d %s %s\n",
@@ -801,24 +792,20 @@ static void queryMarketingBudgetWithTimestamp(DatabaseClient dbClient) {
// [END spanner_postgresql_query_data_with_timestamp_column]
// [START spanner_postgresql_create_table_with_timestamp_column]
- static void createTableWithTimestamp(DatabaseAdminClient dbAdminClient, DatabaseId id) {
- OperationFuture op =
- dbAdminClient.updateDatabaseDdl(
- id.getInstanceId().getInstance(),
- id.getDatabase(),
- Arrays.asList(
- "CREATE TABLE Performances ("
- + " SingerId BIGINT NOT NULL,"
- + " VenueId BIGINT NOT NULL,"
- + " Revenue BIGINT,"
- + " LastUpdateTime SPANNER.COMMIT_TIMESTAMP NOT NULL,"
- + " PRIMARY KEY (SingerId, VenueId))"
- + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE"),
- null);
+ static void createTableWithTimestamp(DatabaseAdminClient dbAdminClient,
+ DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
- System.out.println("Created Performances table in database: [" + id + "]");
+ dbAdminClient.updateDatabaseDdlAsync(databaseName,
+ Arrays.asList(
+ "CREATE TABLE Performances ("
+ + " SingerId BIGINT NOT NULL,"
+ + " VenueId BIGINT NOT NULL,"
+ + " Revenue BIGINT,"
+ + " LastUpdateTime SPANNER.COMMIT_TIMESTAMP NOT NULL,"
+ + " PRIMARY KEY (SingerId, VenueId))"
+ + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE")).get();
+ System.out.println("Created Performances table in database: [" + databaseName + "]");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
throw (SpannerException) e.getCause();
@@ -855,13 +842,13 @@ static void queryPerformancesTable(DatabaseClient dbClient) {
// null. A try-with-resource block is used to automatically release resources held by
// ResultSet.
try (ResultSet resultSet =
- dbClient
- .singleUse()
- .executeQuery(
- Statement.of(
- "SELECT singerid as \"SingerId\", venueid as \"VenueId\", "
- + "revenue as \"Revenue\", lastupdatetime as \"LastUpdateTime\" "
- + "FROM Performances ORDER BY LastUpdateTime DESC"))) {
+ dbClient
+ .singleUse()
+ .executeQuery(
+ Statement.of(
+ "SELECT singerid as \"SingerId\", venueid as \"VenueId\", "
+ + "revenue as \"Revenue\", lastupdatetime as \"LastUpdateTime\" "
+ + "FROM Performances ORDER BY LastUpdateTime DESC"))) {
while (resultSet.next()) {
System.out.printf(
"%d %d %s %s\n",
@@ -994,27 +981,24 @@ static void updateUsingBatchDml(DatabaseClient dbClient) {
// [END spanner_postgresql_dml_batch_update]
// [START spanner_postgresql_create_table_with_datatypes]
- static void createTableWithDatatypes(DatabaseAdminClient dbAdminClient, DatabaseId id) {
- OperationFuture op =
- dbAdminClient.updateDatabaseDdl(
- id.getInstanceId().getInstance(),
- id.getDatabase(),
- Arrays.asList(
- "CREATE TABLE Venues ("
- + " VenueId BIGINT NOT NULL,"
- + " VenueName character varying(100),"
- + " VenueInfo bytea,"
- + " Capacity BIGINT,"
- + " OutdoorVenue BOOL, "
- + " PopularityScore FLOAT8, "
- + " Revenue NUMERIC, "
- + " LastUpdateTime SPANNER.COMMIT_TIMESTAMP NOT NULL,"
- + " PRIMARY KEY (VenueId))"),
- null);
+ static void createTableWithDatatypes(DatabaseAdminClient dbAdminClient,
+ DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
- System.out.println("Created Venues table in database: [" + id + "]");
+ dbAdminClient.updateDatabaseDdlAsync(
+ databaseName,
+ Arrays.asList(
+ "CREATE TABLE Venues ("
+ + " VenueId BIGINT NOT NULL,"
+ + " VenueName character varying(100),"
+ + " VenueInfo bytea,"
+ + " Capacity BIGINT,"
+ + " OutdoorVenue BOOL, "
+ + " PopularityScore FLOAT8, "
+ + " Revenue NUMERIC, "
+ + " LastUpdateTime SPANNER.COMMIT_TIMESTAMP NOT NULL,"
+ + " PRIMARY KEY (VenueId))")).get();
+ System.out.println("Created Venues table in database: [" + databaseName + "]");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
throw (SpannerException) e.getCause();
@@ -1222,9 +1206,9 @@ static void clientWithQueryOptions(DatabaseId db) {
Spanner spanner = options.getService();
DatabaseClient dbClient = spanner.getDatabaseClient(db);
try (ResultSet resultSet =
- dbClient
- .singleUse()
- .executeQuery(Statement.of("SELECT SingerId, AlbumId, AlbumTitle FROM Albums"))) {
+ dbClient
+ .singleUse()
+ .executeQuery(Statement.of("SELECT SingerId, AlbumId, AlbumTitle FROM Albums"))) {
while (resultSet.next()) {
System.out.printf(
"%d %d %s\n", resultSet.getLong(0), resultSet.getLong(1), resultSet.getString(2));
@@ -1236,19 +1220,19 @@ static void clientWithQueryOptions(DatabaseId db) {
// [START spanner_postgresql_query_with_query_options]
static void queryWithQueryOptions(DatabaseClient dbClient) {
try (ResultSet resultSet =
- dbClient
- .singleUse()
- .executeQuery(
- Statement
- .newBuilder("SELECT SingerId, AlbumId, AlbumTitle FROM Albums")
- .withQueryOptions(ExecuteSqlRequest.QueryOptions
- .newBuilder()
- .setOptimizerVersion("1")
- // The list of available statistics packages can be found by querying
- // the "INFORMATION_SCHEMA.spanner_postgresql_STATISTICS" table.
- .setOptimizerStatisticsPackage("latest")
- .build())
- .build())) {
+ dbClient
+ .singleUse()
+ .executeQuery(
+ Statement
+ .newBuilder("SELECT SingerId, AlbumId, AlbumTitle FROM Albums")
+ .withQueryOptions(ExecuteSqlRequest.QueryOptions
+ .newBuilder()
+ .setOptimizerVersion("1")
+ // The list of available statistics packages can be found by querying
+ // the "INFORMATION_SCHEMA.spanner_postgresql_STATISTICS" table.
+ .setOptimizerStatisticsPackage("latest")
+ .build())
+ .build())) {
while (resultSet.next()) {
System.out.printf(
"%d %d %s\n", resultSet.getLong(0), resultSet.getLong(1), resultSet.getString(2));
@@ -1258,22 +1242,26 @@ static void queryWithQueryOptions(DatabaseClient dbClient) {
// [END spanner_postgresql_query_with_query_options]
// [START spanner_postgresql_list_backup_operations]
- static void listBackupOperations(InstanceAdminClient instanceAdminClient, DatabaseId databaseId) {
- Instance instance = instanceAdminClient.getInstance(databaseId.getInstanceId().getInstance());
- // Get create backup operations for the sample database.
- Timestamp last24Hours = Timestamp.ofTimeSecondsAndNanos(TimeUnit.SECONDS.convert(
- TimeUnit.HOURS.convert(Timestamp.now().getSeconds(), TimeUnit.SECONDS) - 24,
- TimeUnit.HOURS), 0);
+ static void listBackupOperations(
+ DatabaseAdminClient databaseAdminClient,
+ String projectId, String instanceId,
+ String databaseId, String backupId) {
+ com.google.spanner.admin.database.v1.InstanceName instanceName =
+ com.google.spanner.admin.database.v1.InstanceName.of(projectId, instanceId);
+ // Get 'CreateBackup' operations for the sample database.
String filter =
String.format(
- "(metadata.database:%s) AND "
- + "(metadata.@type:type.googleapis.com/"
- + "google.spanner.admin.database.v1.CreateBackupMetadata) AND "
- + "(metadata.progress.start_time > \"%s\")",
- databaseId.getName(), last24Hours);
- Page operations = instance
- .listBackupOperations(Options.filter(filter));
- for (com.google.longrunning.Operation op : operations.iterateAll()) {
+ "(metadata.@type:type.googleapis.com/"
+ + "google.spanner.admin.database.v1.CreateBackupMetadata) "
+ + "AND (metadata.database:%s)",
+ DatabaseName.of(projectId, instanceId, databaseId).toString());
+ ListBackupOperationsRequest listBackupOperationsRequest =
+ ListBackupOperationsRequest.newBuilder()
+ .setParent(instanceName.toString()).setFilter(filter).build();
+ ListBackupOperationsPagedResponse createBackupOperations
+ = databaseAdminClient.listBackupOperations(listBackupOperationsRequest);
+ System.out.println("Create Backup Operations:");
+ for (Operation op : createBackupOperations.iterateAll()) {
try {
CreateBackupMetadata metadata = op.getMetadata().unpack(CreateBackupMetadata.class);
System.out.println(
@@ -1287,23 +1275,55 @@ static void listBackupOperations(InstanceAdminClient instanceAdminClient, Databa
System.err.println(e.getMessage());
}
}
+ // Get copy backup operations for the sample database.
+ filter = String.format(
+ "(metadata.@type:type.googleapis.com/"
+ + "google.spanner.admin.database.v1.CopyBackupMetadata) "
+ + "AND (metadata.source_backup:%s)",
+ BackupName.of(projectId, instanceId, backupId).toString());
+ listBackupOperationsRequest =
+ ListBackupOperationsRequest.newBuilder()
+ .setParent(instanceName.toString()).setFilter(filter).build();
+ ListBackupOperationsPagedResponse copyBackupOperations =
+ databaseAdminClient.listBackupOperations(listBackupOperationsRequest);
+ System.out.println("Copy Backup Operations:");
+ for (Operation op : copyBackupOperations.iterateAll()) {
+ try {
+ CopyBackupMetadata copyBackupMetadata =
+ op.getMetadata().unpack(CopyBackupMetadata.class);
+ System.out.println(
+ String.format(
+ "Copy Backup %s on backup %s pending: %d%% complete",
+ copyBackupMetadata.getName(),
+ copyBackupMetadata.getSourceBackup(),
+ copyBackupMetadata.getProgress().getProgressPercent()));
+ } catch (InvalidProtocolBufferException e) {
+ // The returned operation does not contain CopyBackupMetadata.
+ System.err.println(e.getMessage());
+ }
+ }
}
// [END spanner_postgresql_list_backup_operations]
// [START spanner_postgresql_list_database_operations]
static void listDatabaseOperations(
- InstanceAdminClient instanceAdminClient,
- DatabaseAdminClient dbAdminClient,
- InstanceId instanceId) {
- Instance instance = instanceAdminClient.getInstance(instanceId.getInstance());
+ DatabaseAdminClient dbAdminClient, String projectId, String instanceId) {
// Get optimize restored database operations.
- Timestamp last24Hours = Timestamp.ofTimeSecondsAndNanos(TimeUnit.SECONDS.convert(
- TimeUnit.HOURS.convert(Timestamp.now().getSeconds(), TimeUnit.SECONDS) - 24,
- TimeUnit.HOURS), 0);
+ com.google.cloud.Timestamp last24Hours = com.google.cloud.Timestamp.ofTimeSecondsAndNanos(
+ TimeUnit.SECONDS.convert(
+ TimeUnit.HOURS.convert(com.google.cloud.Timestamp.now().getSeconds(), TimeUnit.SECONDS)
+ - 24,
+ TimeUnit.HOURS), 0);
String filter = String.format("(metadata.@type:type.googleapis.com/"
+ "google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata) AND "
+ "(metadata.progress.start_time > \"%s\")", last24Hours);
- for (Operation op : instance.listDatabaseOperations(Options.filter(filter)).iterateAll()) {
+ ListDatabaseOperationsRequest listDatabaseOperationsRequest =
+ ListDatabaseOperationsRequest.newBuilder()
+ .setParent(com.google.spanner.admin.instance.v1.InstanceName.of(
+ projectId, instanceId).toString()).setFilter(filter).build();
+ ListDatabaseOperationsPagedResponse pagedResponse
+ = dbAdminClient.listDatabaseOperations(listDatabaseOperationsRequest);
+ for (Operation op : pagedResponse.iterateAll()) {
try {
OptimizeRestoredDatabaseMetadata metadata =
op.getMetadata().unpack(OptimizeRestoredDatabaseMetadata.class);
@@ -1322,12 +1342,15 @@ static void listDatabaseOperations(
static void run(
DatabaseClient dbClient,
DatabaseAdminClient dbAdminClient,
- InstanceAdminClient instanceAdminClient,
String command,
- DatabaseId database) {
+ DatabaseId database,
+ String backupId) {
+ DatabaseName databaseName = DatabaseName.of(database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase());
switch (command) {
- case "createdatabase":
- createPostgreSqlDatabase(dbAdminClient, database);
+ case "createpgdatabase":
+ createPostgreSqlDatabase(dbAdminClient, database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase());
break;
case "write":
writeExampleData(dbClient);
@@ -1342,7 +1365,7 @@ static void run(
read(dbClient);
break;
case "addmarketingbudget":
- addMarketingBudget(dbAdminClient, database);
+ addMarketingBudget(dbAdminClient, databaseName);
break;
case "update":
update(dbClient);
@@ -1354,13 +1377,13 @@ static void run(
queryMarketingBudget(dbClient);
break;
case "addindex":
- addIndex(dbAdminClient, database);
+ addIndex(dbAdminClient, databaseName);
break;
case "readindex":
readUsingIndex(dbClient);
break;
case "addstoringindex":
- addStoringIndex(dbAdminClient, database);
+ addStoringIndex(dbAdminClient, databaseName);
break;
case "readstoringindex":
readStoringIndex(dbClient);
@@ -1381,13 +1404,13 @@ static void run(
writeWithTransactionUsingDml(dbClient);
break;
case "createtableusingddl":
- createTableUsingDdl(dbAdminClient, database);
+ createTableUsingDdl(dbAdminClient, databaseName);
break;
case "readstaledata":
readStaleData(dbClient);
break;
case "addlastupdatetimestampcolumn":
- addLastUpdateTimestampColumn(dbAdminClient, database);
+ addLastUpdateTimestampColumn(dbAdminClient, databaseName);
break;
case "updatewithtimestamp":
updateWithTimestamp(dbClient);
@@ -1396,7 +1419,7 @@ static void run(
queryMarketingBudgetWithTimestamp(dbClient);
break;
case "createtablewithtimestamp":
- createTableWithTimestamp(dbAdminClient, database);
+ createTableWithTimestamp(dbAdminClient, databaseName);
break;
case "writewithtimestamp":
writeExampleDataWithTimestamp(dbClient);
@@ -1426,7 +1449,7 @@ static void run(
updateUsingBatchDml(dbClient);
break;
case "createtablewithdatatypes":
- createTableWithDatatypes(dbAdminClient, database);
+ createTableWithDatatypes(dbAdminClient, databaseName);
break;
case "writedatatypesdata":
writeDatatypesData(dbClient);
@@ -1459,10 +1482,12 @@ static void run(
queryWithQueryOptions(dbClient);
break;
case "listbackupoperations":
- listBackupOperations(instanceAdminClient, database);
+ listBackupOperations(dbAdminClient, database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase(), backupId);
break;
case "listdatabaseoperations":
- listDatabaseOperations(instanceAdminClient, dbAdminClient, database.getInstanceId());
+ listDatabaseOperations(dbAdminClient, database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance());
break;
default:
printUsageAndExit();
@@ -1525,9 +1550,10 @@ public static void main(String[] args) {
// [START spanner_init_client]
SpannerOptions options = SpannerOptions.newBuilder().build();
Spanner spanner = options.getService();
+ DatabaseAdminClient dbAdminClient = null;
try {
// [END spanner_init_client]
- String command = args[0];
+ final String command = args[0];
DatabaseId db = DatabaseId.of(options.getProjectId(), args[1], args[2]);
// This will return the default project id based on the environment.
@@ -1539,23 +1565,35 @@ public static void main(String[] args) {
+ clientProject);
printUsageAndExit();
}
+ // Generate a backup id for the sample database.
+ String backupId = null;
+ if (args.length == 4) {
+ backupId = args[3];
+ }
+
// [START spanner_init_client]
DatabaseClient dbClient = spanner.getDatabaseClient(db);
- DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
- InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
+ dbAdminClient = spanner.createDatabaseAdminClient();
// [END spanner_init_client]
// Use client here...
- run(dbClient, dbAdminClient, instanceAdminClient, command, db);
+ run(dbClient, dbAdminClient, command, db, backupId);
// [START spanner_init_client]
} finally {
+ if (dbAdminClient != null) {
+ if (!dbAdminClient.isShutdown() || !dbAdminClient.isTerminated()) {
+ dbAdminClient.close();
+ }
+ }
spanner.close();
}
// [END spanner_init_client]
System.out.println("Closed client");
}
- /** Class to contain singer sample data. */
+ /**
+ * Class to contain singer sample data.
+ */
static class Singer {
final long singerId;
@@ -1569,7 +1607,9 @@ static class Singer {
}
}
- /** Class to contain album sample data. */
+ /**
+ * Class to contain album sample data.
+ */
static class Album {
final long singerId;
diff --git a/samples/snippets/src/main/java/com/example/spanner/RestoreBackupWithEncryptionKey.java b/samples/snippets/src/main/java/com/example/spanner/RestoreBackupWithEncryptionKey.java
index fa87d98151..af101f96cc 100644
--- a/samples/snippets/src/main/java/com/example/spanner/RestoreBackupWithEncryptionKey.java
+++ b/samples/snippets/src/main/java/com/example/spanner/RestoreBackupWithEncryptionKey.java
@@ -18,17 +18,17 @@
// [START spanner_restore_backup_with_encryption_key]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.BackupId;
-import com.google.cloud.spanner.Database;
-import com.google.cloud.spanner.DatabaseAdminClient;
-import com.google.cloud.spanner.DatabaseId;
-import com.google.cloud.spanner.Restore;
+import static com.google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
-import com.google.cloud.spanner.encryption.EncryptionConfigs;
-import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.spanner.admin.database.v1.BackupName;
+import com.google.spanner.admin.database.v1.Database;
+import com.google.spanner.admin.database.v1.InstanceName;
+import com.google.spanner.admin.database.v1.RestoreDatabaseEncryptionConfig;
+import com.google.spanner.admin.database.v1.RestoreDatabaseRequest;
import java.util.concurrent.ExecutionException;
public class RestoreBackupWithEncryptionKey {
@@ -43,8 +43,8 @@ static void restoreBackupWithEncryptionKey() {
"projects/" + projectId + "/locations//keyRings//cryptoKeys/";
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient adminClient = spanner.createDatabaseAdminClient()) {
restoreBackupWithEncryptionKey(
adminClient,
projectId,
@@ -57,19 +57,18 @@ static void restoreBackupWithEncryptionKey() {
static Void restoreBackupWithEncryptionKey(DatabaseAdminClient adminClient,
String projectId, String instanceId, String backupId, String restoreId, String kmsKeyName) {
- final Restore restore = adminClient
- .newRestoreBuilder(
- BackupId.of(projectId, instanceId, backupId),
- DatabaseId.of(projectId, instanceId, restoreId))
- .setEncryptionConfig(EncryptionConfigs.customerManagedEncryption(kmsKeyName))
- .build();
- final OperationFuture operation = adminClient
- .restoreDatabase(restore);
-
+ RestoreDatabaseRequest request =
+ RestoreDatabaseRequest.newBuilder()
+ .setParent(InstanceName.of(projectId, instanceId).toString())
+ .setDatabaseId(restoreId)
+ .setBackup(BackupName.of(projectId, instanceId, backupId).toString())
+ .setEncryptionConfig(RestoreDatabaseEncryptionConfig.newBuilder()
+ .setEncryptionType(CUSTOMER_MANAGED_ENCRYPTION).setKmsKeyName(kmsKeyName)).build();
Database database;
try {
System.out.println("Waiting for operation to complete...");
- database = operation.get();
+ database = adminClient.restoreDatabaseAsync(request).get();
+ ;
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
throw SpannerExceptionFactory.asSpannerException(e.getCause());
@@ -81,9 +80,9 @@ static Void restoreBackupWithEncryptionKey(DatabaseAdminClient adminClient,
System.out.printf(
"Database %s restored to %s from backup %s using encryption key %s%n",
- database.getRestoreInfo().getSourceDatabase(),
- database.getId(),
- database.getRestoreInfo().getBackup(),
+ database.getRestoreInfo().getBackupInfo().getSourceDatabase(),
+ database.getName(),
+ database.getRestoreInfo().getBackupInfo().getBackup(),
database.getEncryptionConfig().getKmsKeyName()
);
return null;
diff --git a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java
index 43c04aaa8d..d406225c28 100644
--- a/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java
@@ -20,28 +20,19 @@
import com.google.api.gax.longrunning.OperationFuture;
import com.google.api.gax.longrunning.OperationSnapshot;
-import com.google.api.gax.paging.Page;
import com.google.api.gax.retrying.RetryingFuture;
+import com.google.api.gax.rpc.NotFoundException;
import com.google.api.gax.rpc.StatusCode;
+import com.google.api.gax.rpc.StatusCode.Code;
import com.google.cloud.ByteArray;
import com.google.cloud.Date;
-import com.google.cloud.Timestamp;
-import com.google.cloud.spanner.Backup;
-import com.google.cloud.spanner.BackupId;
-import com.google.cloud.spanner.Database;
-import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
-import com.google.cloud.spanner.Instance;
-import com.google.cloud.spanner.InstanceAdminClient;
-import com.google.cloud.spanner.InstanceId;
import com.google.cloud.spanner.Key;
import com.google.cloud.spanner.KeyRange;
import com.google.cloud.spanner.KeySet;
import com.google.cloud.spanner.Mutation;
-import com.google.cloud.spanner.Options;
import com.google.cloud.spanner.ReadOnlyTransaction;
-import com.google.cloud.spanner.RestoreInfo;
import com.google.cloud.spanner.ResultSet;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerBatchUpdateException;
@@ -53,27 +44,41 @@
import com.google.cloud.spanner.TimestampBound;
import com.google.cloud.spanner.Type;
import com.google.cloud.spanner.Value;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient.ListBackupOperationsPagedResponse;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient.ListBackupsPagedResponse;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient.ListDatabaseOperationsPagedResponse;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
import com.google.common.io.BaseEncoding;
import com.google.longrunning.Operation;
+import com.google.protobuf.FieldMask;
import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.Timestamp;
+import com.google.spanner.admin.database.v1.Backup;
+import com.google.spanner.admin.database.v1.BackupInfo;
+import com.google.spanner.admin.database.v1.BackupName;
import com.google.spanner.admin.database.v1.CopyBackupMetadata;
import com.google.spanner.admin.database.v1.CreateBackupMetadata;
-import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
+import com.google.spanner.admin.database.v1.CreateDatabaseRequest;
+import com.google.spanner.admin.database.v1.DatabaseName;
+import com.google.spanner.admin.database.v1.InstanceName;
+import com.google.spanner.admin.database.v1.ListBackupOperationsRequest;
+import com.google.spanner.admin.database.v1.ListBackupsRequest;
+import com.google.spanner.admin.database.v1.ListDatabaseOperationsRequest;
import com.google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata;
import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata;
-import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.spanner.admin.database.v1.RestoreDatabaseRequest;
+import com.google.spanner.admin.database.v1.RestoreInfo;
import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
import java.math.BigDecimal;
import java.time.Instant;
+import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
-import org.threeten.bp.LocalDate;
-import org.threeten.bp.LocalDateTime;
-import org.threeten.bp.OffsetDateTime;
-import org.threeten.bp.temporal.ChronoField;
/**
* Example code for using the Cloud Spanner API. This example demonstrates all the common operations
@@ -93,7 +98,9 @@
*/
public class SpannerSample {
- /** Class to contain singer sample data. */
+ /**
+ * Class to contain singer sample data.
+ */
static class Singer {
final long singerId;
@@ -107,7 +114,9 @@ static class Singer {
}
}
- /** Class to contain album sample data. */
+ /**
+ * Class to contain album sample data.
+ */
static class Album {
final long singerId;
@@ -121,7 +130,9 @@ static class Album {
}
}
- /** Class to contain performance sample data. */
+ /**
+ * Class to contain performance sample data.
+ */
static class Performance {
final long singerId;
@@ -137,7 +148,9 @@ static class Performance {
}
}
- /** Class to contain venue sample data. */
+ /**
+ * Class to contain venue sample data.
+ */
static class Venue {
final long venueId;
@@ -175,17 +188,6 @@ static class Venue {
}
}
- /** Get a database id to restore a backup to from the sample database id. */
- static String createRestoredSampleDbId(DatabaseId database) {
- int index = database.getDatabase().indexOf('-');
- String prefix = database.getDatabase().substring(0, index);
- String restoredDbId = database.getDatabase().replace(prefix, "restored");
- if (restoredDbId.length() > 30) {
- restoredDbId = restoredDbId.substring(0, 30);
- }
- return restoredDbId;
- }
-
// [START spanner_insert_data]
static final List SINGERS =
Arrays.asList(
@@ -272,12 +274,13 @@ static String createRestoredSampleDbId(DatabaseId database) {
// [END spanner_insert_datatypes_data]
// [START spanner_create_database]
- static void createDatabase(DatabaseAdminClient dbAdminClient, DatabaseId id) {
- OperationFuture op =
- dbAdminClient.createDatabase(
- id.getInstanceId().getInstance(),
- id.getDatabase(),
- Arrays.asList(
+ static void createDatabase(DatabaseAdminClient dbAdminClient,
+ InstanceName instanceName, String databaseId) {
+ CreateDatabaseRequest createDatabaseRequest =
+ CreateDatabaseRequest.newBuilder()
+ .setCreateStatement("CREATE DATABASE `" + databaseId + "`")
+ .setParent(instanceName.toString())
+ .addAllExtraStatements(Arrays.asList(
"CREATE TABLE Singers ("
+ " SingerId INT64 NOT NULL,"
+ " FirstName STRING(1024),"
@@ -291,11 +294,12 @@ static void createDatabase(DatabaseAdminClient dbAdminClient, DatabaseId id) {
+ " AlbumId INT64 NOT NULL,"
+ " AlbumTitle STRING(MAX)"
+ ") PRIMARY KEY (SingerId, AlbumId),"
- + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE"));
+ + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE")).build();
try {
// Initiate the request which returns an OperationFuture.
- Database db = op.get();
- System.out.println("Created database [" + db.getId() + "]");
+ com.google.spanner.admin.database.v1.Database db =
+ dbAdminClient.createDatabaseAsync(createDatabaseRequest).get();
+ System.out.println("Created database [" + db.getName() + "]");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
throw (SpannerException) e.getCause();
@@ -308,25 +312,23 @@ static void createDatabase(DatabaseAdminClient dbAdminClient, DatabaseId id) {
// [END spanner_create_database]
// [START spanner_create_table_with_timestamp_column]
- static void createTableWithTimestamp(DatabaseAdminClient dbAdminClient, DatabaseId id) {
- OperationFuture op =
- dbAdminClient.updateDatabaseDdl(
- id.getInstanceId().getInstance(),
- id.getDatabase(),
- Arrays.asList(
- "CREATE TABLE Performances ("
- + " SingerId INT64 NOT NULL,"
- + " VenueId INT64 NOT NULL,"
- + " EventDate Date,"
- + " Revenue INT64, "
- + " LastUpdateTime TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)"
- + ") PRIMARY KEY (SingerId, VenueId, EventDate),"
- + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE"),
- null);
+ static void createTableWithTimestamp(DatabaseAdminClient dbAdminClient,
+ DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
- System.out.println("Created Performances table in database: [" + id + "]");
+ dbAdminClient.updateDatabaseDdlAsync(
+ databaseName,
+ Arrays.asList(
+ "CREATE TABLE Performances ("
+ + " SingerId INT64 NOT NULL,"
+ + " VenueId INT64 NOT NULL,"
+ + " EventDate Date,"
+ + " Revenue INT64, "
+ + " LastUpdateTime TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)"
+ + ") PRIMARY KEY (SingerId, VenueId, EventDate),"
+ + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE")).get();
+ System.out.println(
+ "Created Performances table in database: [" + databaseName.toString() + "]");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
throw (SpannerException) e.getCause();
@@ -446,16 +448,12 @@ static void read(DatabaseClient dbClient) {
// [END spanner_read_data]
// [START spanner_add_column]
- static void addMarketingBudget(DatabaseAdminClient adminClient, DatabaseId dbId) {
- OperationFuture op =
- adminClient.updateDatabaseDdl(
- dbId.getInstanceId().getInstance(),
- dbId.getDatabase(),
- Arrays.asList("ALTER TABLE Albums ADD COLUMN MarketingBudget INT64"),
- null);
+ static void addMarketingBudget(DatabaseAdminClient adminClient, DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
+ adminClient.updateDatabaseDdlAsync(
+ databaseName,
+ Arrays.asList("ALTER TABLE Albums ADD COLUMN MarketingBudget INT64")).get();
System.out.println("Added MarketingBudget column");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
@@ -565,16 +563,12 @@ static void queryMarketingBudget(DatabaseClient dbClient) {
// [END spanner_query_data_with_new_column]
// [START spanner_create_index]
- static void addIndex(DatabaseAdminClient adminClient, DatabaseId dbId) {
- OperationFuture op =
- adminClient.updateDatabaseDdl(
- dbId.getInstanceId().getInstance(),
- dbId.getDatabase(),
- Arrays.asList("CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)"),
- null);
+ static void addIndex(DatabaseAdminClient adminClient, DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
+ adminClient.updateDatabaseDdlAsync(
+ databaseName,
+ Arrays.asList("CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)")).get();
System.out.println("Added AlbumsByAlbumTitle index");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
@@ -636,18 +630,14 @@ static void readUsingIndex(DatabaseClient dbClient) {
// [END spanner_read_data_with_index]
// [START spanner_create_storing_index]
- static void addStoringIndex(DatabaseAdminClient adminClient, DatabaseId dbId) {
- OperationFuture op =
- adminClient.updateDatabaseDdl(
- dbId.getInstanceId().getInstance(),
- dbId.getDatabase(),
- Arrays.asList(
- "CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) "
- + "STORING (MarketingBudget)"),
- null);
+ static void addStoringIndex(DatabaseAdminClient adminClient, DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
+ adminClient.updateDatabaseDdlAsync(
+ databaseName,
+ Arrays.asList(
+ "CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) "
+ + "STORING (MarketingBudget)")).get();
System.out.println("Added AlbumsByAlbumTitle2 index");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
@@ -729,18 +719,14 @@ static void readStaleData(DatabaseClient dbClient) {
// [END spanner_read_stale_data]
// [START spanner_add_timestamp_column]
- static void addCommitTimestamp(DatabaseAdminClient adminClient, DatabaseId dbId) {
- OperationFuture op =
- adminClient.updateDatabaseDdl(
- dbId.getInstanceId().getInstance(),
- dbId.getDatabase(),
- Arrays.asList(
- "ALTER TABLE Albums ADD COLUMN LastUpdateTime TIMESTAMP "
- + "OPTIONS (allow_commit_timestamp=true)"),
- null);
+ static void addCommitTimestamp(DatabaseAdminClient adminClient, DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
+ adminClient.updateDatabaseDdlAsync(
+ databaseName,
+ Arrays.asList(
+ "ALTER TABLE Albums ADD COLUMN LastUpdateTime TIMESTAMP "
+ + "OPTIONS (allow_commit_timestamp=true)")).get();
System.out.println("Added LastUpdateTime as a commit timestamp column in Albums table.");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
@@ -1186,18 +1172,18 @@ static void writeWithTransactionUsingDml(DatabaseClient dbClient) {
album2Budget -= transfer;
Statement updateStatement =
Statement.newBuilder(
- "UPDATE Albums "
- + "SET MarketingBudget = @AlbumBudget "
- + "WHERE SingerId = 1 and AlbumId = 1")
+ "UPDATE Albums "
+ + "SET MarketingBudget = @AlbumBudget "
+ + "WHERE SingerId = 1 and AlbumId = 1")
.bind("AlbumBudget")
.to(album1Budget)
.build();
transaction.executeUpdate(updateStatement);
Statement updateStatement2 =
Statement.newBuilder(
- "UPDATE Albums "
- + "SET MarketingBudget = @AlbumBudget "
- + "WHERE SingerId = 2 and AlbumId = 2")
+ "UPDATE Albums "
+ + "SET MarketingBudget = @AlbumBudget "
+ + "WHERE SingerId = 2 and AlbumId = 2")
.bind("AlbumBudget")
.to(album2Budget)
.build();
@@ -1255,30 +1241,26 @@ static void updateUsingBatchDml(DatabaseClient dbClient) {
// [END spanner_dml_batch_update]
// [START spanner_create_table_with_datatypes]
- static void createTableWithDatatypes(DatabaseAdminClient dbAdminClient, DatabaseId id) {
- OperationFuture op =
- dbAdminClient.updateDatabaseDdl(
- id.getInstanceId().getInstance(),
- id.getDatabase(),
- Arrays.asList(
- "CREATE TABLE Venues ("
- + " VenueId INT64 NOT NULL,"
- + " VenueName STRING(100),"
- + " VenueInfo BYTES(MAX),"
- + " Capacity INT64,"
- + " AvailableDates ARRAY,"
- + " LastContactDate DATE,"
- + " OutdoorVenue BOOL, "
- + " PopularityScore FLOAT64, "
- + " Revenue NUMERIC, "
- + " VenueDetails JSON, "
- + " LastUpdateTime TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)"
- + ") PRIMARY KEY (VenueId)"),
- null);
+ static void createTableWithDatatypes(DatabaseAdminClient dbAdminClient,
+ DatabaseName databaseName) {
try {
// Initiate the request which returns an OperationFuture.
- op.get();
- System.out.println("Created Venues table in database: [" + id + "]");
+ dbAdminClient.updateDatabaseDdlAsync(databaseName,
+ Arrays.asList(
+ "CREATE TABLE Venues ("
+ + " VenueId INT64 NOT NULL,"
+ + " VenueName STRING(100),"
+ + " VenueInfo BYTES(MAX),"
+ + " Capacity INT64,"
+ + " AvailableDates ARRAY,"
+ + " LastContactDate DATE,"
+ + " OutdoorVenue BOOL, "
+ + " PopularityScore FLOAT64, "
+ + " Revenue NUMERIC, "
+ + " VenueDetails JSON, "
+ + " LastUpdateTime TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)"
+ + ") PRIMARY KEY (VenueId)")).get();
+ System.out.println("Created Venues table in database: [" + databaseName.toString() + "]");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
throw (SpannerException) e.getCause();
@@ -1570,74 +1552,76 @@ static void queryWithQueryOptions(DatabaseClient dbClient) {
// [END spanner_query_with_query_options]
// [START spanner_create_backup]
- static void createBackup(DatabaseAdminClient dbAdminClient, DatabaseId databaseId,
- BackupId backupId, Timestamp versionTime) {
+ static void createBackup(DatabaseAdminClient dbAdminClient, String projectId, String instanceId,
+ String databaseId, String backupId, Timestamp versionTime) {
// Set expire time to 14 days from now.
- Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert(
- System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS));
- Backup backup =
- dbAdminClient
- .newBackupBuilder(backupId)
- .setDatabase(databaseId)
- .setExpireTime(expireTime)
- .setVersionTime(versionTime)
- .build();
+ Timestamp expireTime =
+ Timestamp.newBuilder().setSeconds(TimeUnit.MILLISECONDS.toSeconds((
+ System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14)))).build();
+ BackupName backupName = BackupName.of(projectId, instanceId, backupId);
+ Backup backup = Backup.newBuilder()
+ .setName(backupName.toString())
+ .setDatabase(DatabaseName.of(projectId, instanceId, databaseId).toString())
+ .setExpireTime(expireTime).setVersionTime(versionTime).build();
+
// Initiate the request which returns an OperationFuture.
- System.out.println("Creating backup [" + backup.getId() + "]...");
- OperationFuture op = backup.create();
+ System.out.println("Creating backup [" + backupId + "]...");
try {
// Wait for the backup operation to complete.
- backup = op.get();
- System.out.println("Created backup [" + backup.getId() + "]");
+ backup = dbAdminClient.createBackupAsync(
+ InstanceName.of(projectId, instanceId), backup, backupId).get();
+ System.out.println("Created backup [" + backup.getName() + "]");
} catch (ExecutionException e) {
- throw (SpannerException) e.getCause();
+ throw SpannerExceptionFactory.asSpannerException(e);
} catch (InterruptedException e) {
throw SpannerExceptionFactory.propagateInterrupt(e);
}
// Reload the metadata of the backup from the server.
- backup = backup.reload();
+ backup = dbAdminClient.getBackup(backup.getName());
System.out.println(
String.format(
"Backup %s of size %d bytes was created at %s for version of database at %s",
- backup.getId().getName(),
- backup.getSize(),
- LocalDateTime.ofEpochSecond(
- backup.getProto().getCreateTime().getSeconds(),
- backup.getProto().getCreateTime().getNanos(),
- OffsetDateTime.now().getOffset()),
- LocalDateTime.ofEpochSecond(
- backup.getProto().getVersionTime().getSeconds(),
- backup.getProto().getVersionTime().getNanos(),
- OffsetDateTime.now().getOffset())
- ));
+ backup.getName(),
+ backup.getSizeBytes(),
+ java.time.OffsetDateTime.ofInstant(
+ Instant.ofEpochSecond(backup.getCreateTime().getSeconds(),
+ backup.getCreateTime().getNanos()), ZoneId.systemDefault()),
+ java.time.OffsetDateTime.ofInstant(
+ Instant.ofEpochSecond(backup.getVersionTime().getSeconds(),
+ backup.getVersionTime().getNanos()), ZoneId.systemDefault()))
+ );
}
// [END spanner_create_backup]
// [START spanner_cancel_backup_create]
static void cancelCreateBackup(
- DatabaseAdminClient dbAdminClient, DatabaseId databaseId, BackupId backupId) {
+ DatabaseAdminClient dbAdminClient, String projectId, String instanceId,
+ String databaseId, String backupId) {
// Set expire time to 14 days from now.
- Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert(
- System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS));
-
- // Create a backup instance.
- Backup backup =
- dbAdminClient
- .newBackupBuilder(backupId)
- .setDatabase(databaseId)
- .setExpireTime(expireTime)
- .build();
- // Start the creation of a backup.
- System.out.println("Creating backup [" + backup.getId() + "]...");
- OperationFuture op = backup.create();
+ Timestamp expireTime =
+ Timestamp.newBuilder().setSeconds(TimeUnit.MILLISECONDS.toSeconds((
+ System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14)))).build();
+ BackupName backupName = BackupName.of(projectId, instanceId, backupId);
+ Backup backup = Backup.newBuilder()
+ .setName(backupName.toString())
+ .setDatabase(DatabaseName.of(projectId, instanceId, databaseId).toString())
+ .setExpireTime(expireTime).build();
+
try {
+ // Start the creation of a backup.
+ System.out.println("Creating backup [" + backupId + "]...");
+ OperationFuture op = dbAdminClient.createBackupAsync(
+ InstanceName.of(projectId, instanceId), backup, backupId);
+
// Try to cancel the backup operation.
- System.out.println("Cancelling create backup operation for [" + backup.getId() + "]...");
- dbAdminClient.cancelOperation(op.getName());
+ System.out.println("Cancelling create backup operation for [" + backupId + "]...");
+ dbAdminClient.getOperationsClient().cancelOperation(op.getName());
+
// Get a polling future for the running operation. This future will regularly poll the server
// for the current status of the backup operation.
RetryingFuture pollingFuture = op.getPollingFuture();
+
// Wait for the operation to finish.
// isDone will return true when the operation is complete, regardless of whether it was
// successful or not.
@@ -1647,11 +1631,11 @@ static void cancelCreateBackup(
}
if (pollingFuture.get().getErrorCode() == null) {
// Backup was created before it could be cancelled. Delete the backup.
- backup.delete();
- System.out.println("Backup operation for [" + backup.getId()
+ dbAdminClient.deleteBackup(backupName);
+ System.out.println("Backup operation for [" + backupId
+ "] successfully finished before it could be cancelled");
} else if (pollingFuture.get().getErrorCode().getCode() == StatusCode.Code.CANCELLED) {
- System.out.println("Backup operation for [" + backup.getId() + "] successfully cancelled");
+ System.out.println("Backup operation for [" + backupId + "] successfully cancelled");
}
} catch (ExecutionException e) {
throw SpannerExceptionFactory.newSpannerException(e.getCause());
@@ -1663,20 +1647,22 @@ static void cancelCreateBackup(
// [START spanner_list_backup_operations]
static void listBackupOperations(
- InstanceAdminClient instanceAdminClient, DatabaseId databaseId, BackupId backupId) {
- Instance instance = instanceAdminClient.getInstance(databaseId.getInstanceId().getInstance());
- // Get create backup operations for the sample database.
- Timestamp last24Hours = Timestamp.ofTimeSecondsAndNanos(TimeUnit.SECONDS.convert(
- TimeUnit.HOURS.convert(Timestamp.now().getSeconds(), TimeUnit.SECONDS) - 24,
- TimeUnit.HOURS), 0);
+ DatabaseAdminClient databaseAdminClient,
+ String projectId, String instanceId,
+ String databaseId, String backupId) {
+ InstanceName instanceName = InstanceName.of(projectId, instanceId);
+ // Get 'CreateBackup' operations for the sample database.
String filter =
String.format(
- "(metadata.@type:type.googleapis.com/"
- + "google.spanner.admin.database.v1.CreateBackupMetadata) "
- + "AND (metadata.database:%s)",
- databaseId.getName());
- Page createBackupOperations = instance.listBackupOperations(
- Options.filter(filter));
+ "(metadata.@type:type.googleapis.com/"
+ + "google.spanner.admin.database.v1.CreateBackupMetadata) "
+ + "AND (metadata.database:%s)",
+ DatabaseName.of(projectId, instanceId, databaseId).toString());
+ ListBackupOperationsRequest listBackupOperationsRequest =
+ ListBackupOperationsRequest.newBuilder()
+ .setParent(instanceName.toString()).setFilter(filter).build();
+ ListBackupOperationsPagedResponse createBackupOperations
+ = databaseAdminClient.listBackupOperations(listBackupOperationsRequest);
System.out.println("Create Backup Operations:");
for (Operation op : createBackupOperations.iterateAll()) {
try {
@@ -1693,24 +1679,27 @@ static void listBackupOperations(
}
}
// Get copy backup operations for the sample database.
- filter =
- String.format(
- "(metadata.@type:type.googleapis.com/"
- + "google.spanner.admin.database.v1.CopyBackupMetadata) "
- + "AND (metadata.source_backup:%s)",
- backupId.getName());
- Page copyBackupOperations = instance.listBackupOperations(Options.filter(filter));
+ filter = String.format(
+ "(metadata.@type:type.googleapis.com/"
+ + "google.spanner.admin.database.v1.CopyBackupMetadata) "
+ + "AND (metadata.source_backup:%s)",
+ BackupName.of(projectId, instanceId, backupId).toString());
+ listBackupOperationsRequest =
+ ListBackupOperationsRequest.newBuilder()
+ .setParent(instanceName.toString()).setFilter(filter).build();
+ ListBackupOperationsPagedResponse copyBackupOperations =
+ databaseAdminClient.listBackupOperations(listBackupOperationsRequest);
System.out.println("Copy Backup Operations:");
for (Operation op : copyBackupOperations.iterateAll()) {
try {
CopyBackupMetadata copyBackupMetadata =
- op.getMetadata().unpack(CopyBackupMetadata.class);
+ op.getMetadata().unpack(CopyBackupMetadata.class);
System.out.println(
- String.format(
- "Copy Backup %s on backup %s pending: %d%% complete",
- copyBackupMetadata.getName(),
- copyBackupMetadata.getSourceBackup(),
- copyBackupMetadata.getProgress().getProgressPercent()));
+ String.format(
+ "Copy Backup %s on backup %s pending: %d%% complete",
+ copyBackupMetadata.getName(),
+ copyBackupMetadata.getSourceBackup(),
+ copyBackupMetadata.getProgress().getProgressPercent()));
} catch (InvalidProtocolBufferException e) {
// The returned operation does not contain CopyBackupMetadata.
System.err.println(e.getMessage());
@@ -1721,18 +1710,23 @@ static void listBackupOperations(
// [START spanner_list_database_operations]
static void listDatabaseOperations(
- InstanceAdminClient instanceAdminClient,
- DatabaseAdminClient dbAdminClient,
- InstanceId instanceId) {
- Instance instance = instanceAdminClient.getInstance(instanceId.getInstance());
+ DatabaseAdminClient dbAdminClient, String projectId, String instanceId) {
// Get optimize restored database operations.
- Timestamp last24Hours = Timestamp.ofTimeSecondsAndNanos(TimeUnit.SECONDS.convert(
- TimeUnit.HOURS.convert(Timestamp.now().getSeconds(), TimeUnit.SECONDS) - 24,
- TimeUnit.HOURS), 0);
+ com.google.cloud.Timestamp last24Hours = com.google.cloud.Timestamp.ofTimeSecondsAndNanos(
+ TimeUnit.SECONDS.convert(
+ TimeUnit.HOURS.convert(com.google.cloud.Timestamp.now().getSeconds(), TimeUnit.SECONDS)
+ - 24,
+ TimeUnit.HOURS), 0);
String filter = String.format("(metadata.@type:type.googleapis.com/"
- + "google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata) AND "
- + "(metadata.progress.start_time > \"%s\")", last24Hours);
- for (Operation op : instance.listDatabaseOperations(Options.filter(filter)).iterateAll()) {
+ + "google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata) AND "
+ + "(metadata.progress.start_time > \"%s\")", last24Hours);
+ ListDatabaseOperationsRequest listDatabaseOperationsRequest =
+ ListDatabaseOperationsRequest.newBuilder()
+ .setParent(com.google.spanner.admin.instance.v1.InstanceName.of(
+ projectId, instanceId).toString()).setFilter(filter).build();
+ ListDatabaseOperationsPagedResponse pagedResponse
+ = dbAdminClient.listDatabaseOperations(listDatabaseOperationsRequest);
+ for (Operation op : pagedResponse.iterateAll()) {
try {
OptimizeRestoredDatabaseMetadata metadata =
op.getMetadata().unpack(OptimizeRestoredDatabaseMetadata.class);
@@ -1750,74 +1744,92 @@ static void listDatabaseOperations(
// [START spanner_list_backups]
static void listBackups(
- InstanceAdminClient instanceAdminClient, DatabaseId databaseId, BackupId backupId) {
- Instance instance = instanceAdminClient.getInstance(databaseId.getInstanceId().getInstance());
+ DatabaseAdminClient dbAdminClient, String projectId,
+ String instanceId, String databaseId, String backupId) {
+ InstanceName instanceName = InstanceName.of(projectId, instanceId);
// List all backups.
System.out.println("All backups:");
- for (Backup backup : instance.listBackups().iterateAll()) {
+ for (Backup backup : dbAdminClient.listBackups(
+ instanceName.toString()).iterateAll()) {
System.out.println(backup);
}
// List all backups with a specific name.
System.out.println(
- String.format("All backups with backup name containing \"%s\":", backupId.getBackup()));
- for (Backup backup : instance.listBackups(
- Options.filter(String.format("name:%s", backupId.getBackup()))).iterateAll()) {
+ String.format("All backups with backup name containing \"%s\":", backupId));
+ ListBackupsRequest listBackupsRequest =
+ ListBackupsRequest.newBuilder().setParent(instanceName.toString())
+ .setFilter(String.format("name:%s", backupId)).build();
+ for (Backup backup : dbAdminClient.listBackups(listBackupsRequest).iterateAll()) {
System.out.println(backup);
}
// List all backups for databases whose name contains a certain text.
System.out.println(
String.format(
- "All backups for databases with a name containing \"%s\":",
- databaseId.getDatabase()));
- for (Backup backup : instance.listBackups(
- Options.filter(String.format("database:%s", databaseId.getDatabase()))).iterateAll()) {
+ "All backups for databases with a name containing \"%s\":", databaseId));
+ listBackupsRequest =
+ ListBackupsRequest.newBuilder().setParent(instanceName.toString())
+ .setFilter(String.format("database:%s", databaseId)).build();
+ for (Backup backup : dbAdminClient.listBackups(listBackupsRequest).iterateAll()) {
System.out.println(backup);
}
// List all backups that expire before a certain time.
- Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert(
- System.currentTimeMillis() + TimeUnit.DAYS.toMillis(30), TimeUnit.MILLISECONDS));
- System.out.println(String.format("All backups that expire before %s:", expireTime.toString()));
- for (Backup backup :
- instance.listBackups(
- Options.filter(String.format("expire_time < \"%s\"", expireTime.toString())))
- .iterateAll()) {
+ com.google.cloud.Timestamp expireTime = com.google.cloud.Timestamp.ofTimeMicroseconds(
+ TimeUnit.MICROSECONDS.convert(
+ System.currentTimeMillis() + TimeUnit.DAYS.toMillis(30), TimeUnit.MILLISECONDS));
+
+ System.out.println(String.format("All backups that expire before %s:", expireTime));
+ listBackupsRequest =
+ ListBackupsRequest.newBuilder().setParent(instanceName.toString())
+ .setFilter(String.format("expire_time < \"%s\"", expireTime)).build();
+
+ for (Backup backup : dbAdminClient.listBackups(listBackupsRequest).iterateAll()) {
System.out.println(backup);
}
// List all backups with size greater than a certain number of bytes.
+ listBackupsRequest =
+ ListBackupsRequest.newBuilder().setParent(instanceName.toString())
+ .setFilter("size_bytes > 100").build();
+
System.out.println("All backups with size greater than 100 bytes:");
- for (Backup backup : instance.listBackups(Options.filter("size_bytes > 100")).iterateAll()) {
+ for (Backup backup : dbAdminClient.listBackups(listBackupsRequest).iterateAll()) {
System.out.println(backup);
}
// List all backups with a create time after a certain timestamp and that are also ready.
- Timestamp createTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert(
- System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1), TimeUnit.MILLISECONDS));
+ com.google.cloud.Timestamp createTime = com.google.cloud.Timestamp.ofTimeMicroseconds(
+ TimeUnit.MICROSECONDS.convert(
+ System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1), TimeUnit.MILLISECONDS));
+
System.out.println(
String.format(
"All databases created after %s and that are ready:", createTime.toString()));
- for (Backup backup :
- instance
- .listBackups(Options.filter(
- String.format("create_time >= \"%s\" AND state:READY", createTime.toString())))
- .iterateAll()) {
+ listBackupsRequest =
+ ListBackupsRequest.newBuilder().setParent(instanceName.toString())
+ .setFilter(String.format(
+ "create_time >= \"%s\" AND state:READY", createTime.toString())).build();
+ for (Backup backup : dbAdminClient.listBackups(listBackupsRequest).iterateAll()) {
System.out.println(backup);
}
// List backups using pagination.
System.out.println("All backups, listed using pagination:");
- Page page = instance.listBackups(Options.pageSize(10));
+ listBackupsRequest =
+ ListBackupsRequest.newBuilder().setParent(instanceName.toString()).setPageSize(10).build();
while (true) {
- for (Backup backup : page.getValues()) {
+ ListBackupsPagedResponse response = dbAdminClient.listBackups(listBackupsRequest);
+ for (Backup backup : response.getPage().iterateAll()) {
System.out.println(backup);
}
- if (!page.hasNextPage()) {
+ String nextPageToken = response.getNextPageToken();
+ if (!Strings.isNullOrEmpty(nextPageToken)) {
+ listBackupsRequest = listBackupsRequest.toBuilder().setPageToken(nextPageToken).build();
+ } else {
break;
}
- page = page.getNextPage();
}
}
// [END spanner_list_backups]
@@ -1825,31 +1837,35 @@ static void listBackups(
// [START spanner_restore_backup]
static void restoreBackup(
DatabaseAdminClient dbAdminClient,
- BackupId backupId,
- DatabaseId sourceDatabaseId,
- DatabaseId restoreToDatabase) {
- Backup backup = dbAdminClient.newBackupBuilder(backupId).build();
+ String projectId,
+ String instanceId,
+ String backupId,
+ String restoreToDatabaseId) {
+ BackupName backupName = BackupName.of(projectId, instanceId, backupId);
+ Backup backup = dbAdminClient.getBackup(backupName);
// Initiate the request which returns an OperationFuture.
System.out.println(String.format(
- "Restoring backup [%s] to database [%s]...",
- backup.getId().toString(),
- restoreToDatabase.toString()));
+ "Restoring backup [%s] to database [%s]...", backup.getName(), restoreToDatabaseId));
try {
- OperationFuture op = backup.restore(restoreToDatabase);
+ RestoreDatabaseRequest request =
+ RestoreDatabaseRequest.newBuilder()
+ .setParent(InstanceName.of(projectId, instanceId).toString())
+ .setDatabaseId(restoreToDatabaseId)
+ .setBackup(backupName.toString()).build();
+ OperationFuture op =
+ dbAdminClient.restoreDatabaseAsync(request);
// Wait until the database has been restored.
- Database db = op.get();
- // Refresh database metadata and get the restore info.
- RestoreInfo restore = db.reload().getRestoreInfo();
- Timestamp versionTime = Timestamp.fromProto(restore
- .getProto()
- .getBackupInfo()
- .getVersionTime());
+ com.google.spanner.admin.database.v1.Database db = op.get();
+ // Get the restore info.
+ RestoreInfo restoreInfo = db.getRestoreInfo();
+ BackupInfo backupInfo = restoreInfo.getBackupInfo();
+
System.out.println(
"Restored database ["
- + restore.getSourceDatabase().getName()
+ + db.getName()
+ "] from ["
- + restore.getBackup().getName()
- + "] with version time [" + versionTime + "]");
+ + restoreInfo.getBackupInfo().getBackup()
+ + "] with version time [" + backupInfo.getVersionTime() + "]");
} catch (ExecutionException e) {
throw SpannerExceptionFactory.newSpannerException(e.getCause());
} catch (InterruptedException e) {
@@ -1859,49 +1875,59 @@ static void restoreBackup(
// [END spanner_restore_backup]
// [START spanner_update_backup]
- static void updateBackup(DatabaseAdminClient dbAdminClient, BackupId backupId) {
+ static void updateBackup(DatabaseAdminClient dbAdminClient, String projectId,
+ String instanceId, String backupId) {
+ BackupName backupName = BackupName.of(projectId, instanceId, backupId);
+
// Get current backup metadata.
- Backup backup = dbAdminClient.newBackupBuilder(backupId).build().reload();
+ Backup backup = dbAdminClient.getBackup(backupName);
// Add 30 days to the expire time.
// Expire time must be within 366 days of the create time of the backup.
- Timestamp expireTime =
- Timestamp.ofTimeMicroseconds(
- TimeUnit.SECONDS.toMicros(backup.getExpireTime().getSeconds())
- + TimeUnit.NANOSECONDS.toMicros(backup.getExpireTime().getNanos())
+ Timestamp currentExpireTime = backup.getExpireTime();
+ com.google.cloud.Timestamp newExpireTime =
+ com.google.cloud.Timestamp.ofTimeMicroseconds(
+ TimeUnit.SECONDS.toMicros(currentExpireTime.getSeconds())
+ + TimeUnit.NANOSECONDS.toMicros(currentExpireTime.getNanos())
+ TimeUnit.DAYS.toMicros(30L));
+
// New Expire Time must be less than Max Expire Time
- expireTime = expireTime.compareTo(backup.getMaxExpireTime())
- < 0 ? expireTime : backup.getMaxExpireTime();
- int timeDiff = expireTime.compareTo(backup.getExpireTime());
- Timestamp newExpireTime = (timeDiff < 0) ? expireTime : backup.getExpireTime();
+ newExpireTime =
+ newExpireTime.compareTo(com.google.cloud.Timestamp.fromProto(backup.getMaxExpireTime()))
+ < 0 ? newExpireTime : com.google.cloud.Timestamp.fromProto(backup.getMaxExpireTime());
System.out.println(String.format(
"Updating expire time of backup [%s] to %s...",
backupId.toString(),
- LocalDateTime.ofEpochSecond(
- expireTime.getSeconds(),
- expireTime.getNanos(),
- OffsetDateTime.now().getOffset()).toString()));
+ java.time.OffsetDateTime.ofInstant(
+ Instant.ofEpochSecond(newExpireTime.getSeconds(),
+ newExpireTime.getNanos()), ZoneId.systemDefault())));
// Update expire time.
- backup = backup.toBuilder().setExpireTime(expireTime).build();
- backup.updateExpireTime();
+ backup = backup.toBuilder().setExpireTime(newExpireTime.toProto()).build();
+ dbAdminClient.updateBackup(backup,
+ FieldMask.newBuilder().addAllPaths(Lists.newArrayList("expire_time")).build());
System.out.println("Updated backup [" + backupId + "]");
}
// [END spanner_update_backup]
// [START spanner_delete_backup]
- static void deleteBackup(DatabaseAdminClient dbAdminClient, BackupId backupId) {
- Backup backup = dbAdminClient.newBackupBuilder(backupId).build();
+ static void deleteBackup(DatabaseAdminClient dbAdminClient,
+ String project, String instance, String backupId) {
+ BackupName backupName = BackupName.of(project, instance, backupId);
+
// Delete the backup.
System.out.println("Deleting backup [" + backupId + "]...");
- backup.delete();
+ dbAdminClient.deleteBackup(backupName);
// Verify that the backup is deleted.
- if (backup.exists()) {
- System.out.println("Delete backup [" + backupId + "] failed");
- throw new RuntimeException("Delete backup [" + backupId + "] failed");
- } else {
- System.out.println("Deleted backup [" + backupId + "]");
+ try {
+ dbAdminClient.getBackup(backupName);
+ } catch (NotFoundException e) {
+ if (e.getStatusCode().getCode() == Code.NOT_FOUND) {
+ System.out.println("Deleted backup [" + backupId + "]");
+ } else {
+ System.out.println("Delete backup [" + backupId + "] failed");
+ throw new RuntimeException("Delete backup [" + backupId + "] failed", e);
+ }
}
}
// [END spanner_delete_backup]
@@ -1909,13 +1935,13 @@ static void deleteBackup(DatabaseAdminClient dbAdminClient, BackupId backupId) {
static void run(
DatabaseClient dbClient,
DatabaseAdminClient dbAdminClient,
- InstanceAdminClient instanceAdminClient,
String command,
DatabaseId database,
- BackupId backup) {
+ String backupId) {
switch (command) {
case "createdatabase":
- createDatabase(dbAdminClient, database);
+ createDatabase(dbAdminClient, InstanceName.of(database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance()), database.getDatabase());
break;
case "write":
writeExampleData(dbClient);
@@ -1930,7 +1956,8 @@ static void run(
read(dbClient);
break;
case "addmarketingbudget":
- addMarketingBudget(dbAdminClient, database);
+ addMarketingBudget(dbAdminClient, DatabaseName.of(database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase()));
break;
case "update":
update(dbClient);
@@ -1942,7 +1969,8 @@ static void run(
queryMarketingBudget(dbClient);
break;
case "addindex":
- addIndex(dbAdminClient, database);
+ addIndex(dbAdminClient, DatabaseName.of(database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase()));
break;
case "readindex":
readUsingIndex(dbClient);
@@ -1951,7 +1979,8 @@ static void run(
queryUsingIndex(dbClient);
break;
case "addstoringindex":
- addStoringIndex(dbAdminClient, database);
+ addStoringIndex(dbAdminClient, DatabaseName.of(database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase()));
break;
case "readstoringindex":
readStoringIndex(dbClient);
@@ -1963,7 +1992,8 @@ static void run(
readStaleData(dbClient);
break;
case "addcommittimestamp":
- addCommitTimestamp(dbAdminClient, database);
+ addCommitTimestamp(dbAdminClient, DatabaseName.of(database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase()));
break;
case "updatewithtimestamp":
updateWithTimestamp(dbClient);
@@ -1972,7 +2002,9 @@ static void run(
queryMarketingBudgetWithTimestamp(dbClient);
break;
case "createtablewithtimestamp":
- createTableWithTimestamp(dbAdminClient, database);
+ createTableWithTimestamp(dbAdminClient,
+ DatabaseName.of(database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase()));
break;
case "writewithtimestamp":
writeExampleDataWithTimestamp(dbClient);
@@ -2035,7 +2067,9 @@ static void run(
updateUsingBatchDml(dbClient);
break;
case "createtablewithdatatypes":
- createTableWithDatatypes(dbAdminClient, database);
+ createTableWithDatatypes(dbAdminClient,
+ DatabaseName.of(database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase()));
break;
case "writedatatypesdata":
writeDatatypesData(dbClient);
@@ -2074,35 +2108,41 @@ static void run(
queryWithQueryOptions(dbClient);
break;
case "createbackup":
- createBackup(dbAdminClient, database, backup, getVersionTime(dbClient));
+ createBackup(dbAdminClient, database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase(),
+ backupId, getVersionTime(dbClient));
break;
case "cancelcreatebackup":
cancelCreateBackup(
dbAdminClient,
- database,
- BackupId.of(backup.getInstanceId(), backup.getBackup() + "_cancel"));
+ database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase(),
+ backupId + "_cancel");
break;
case "listbackupoperations":
- listBackupOperations(instanceAdminClient, database, backup);
+ listBackupOperations(dbAdminClient, database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase(), backupId);
break;
case "listdatabaseoperations":
- listDatabaseOperations(instanceAdminClient, dbAdminClient, database.getInstanceId());
+ listDatabaseOperations(dbAdminClient, database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance());
break;
case "listbackups":
- listBackups(instanceAdminClient, database, backup);
+ listBackups(dbAdminClient, database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), database.getDatabase(), backupId);
break;
case "restorebackup":
restoreBackup(
- dbAdminClient,
- backup,
- database,
- DatabaseId.of(database.getInstanceId(), createRestoredSampleDbId(database)));
+ dbAdminClient, database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), backupId, database.getDatabase());
break;
case "updatebackup":
- updateBackup(dbAdminClient, backup);
+ updateBackup(dbAdminClient, database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), backupId);
break;
case "deletebackup":
- deleteBackup(dbAdminClient, backup);
+ deleteBackup(dbAdminClient, database.getInstanceId().getProject(),
+ database.getInstanceId().getInstance(), backupId);
break;
default:
printUsageAndExit();
@@ -2111,13 +2151,13 @@ static void run(
static Timestamp getVersionTime(DatabaseClient dbClient) {
// Generates a version time for the backup
- Timestamp versionTime;
+ com.google.cloud.Timestamp versionTime;
try (ResultSet resultSet = dbClient.singleUse()
.executeQuery(Statement.of("SELECT CURRENT_TIMESTAMP()"))) {
resultSet.next();
versionTime = resultSet.getTimestamp(0);
}
- return versionTime;
+ return versionTime.toProto();
}
static void printUsageAndExit() {
@@ -2185,15 +2225,16 @@ static void printUsageAndExit() {
System.exit(1);
}
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
if (args.length != 3 && args.length != 4) {
printUsageAndExit();
}
// [START init_client]
SpannerOptions options = SpannerOptions.newBuilder().build();
Spanner spanner = options.getService();
+ DatabaseAdminClient dbAdminClient = null;
try {
- String command = args[0];
+ final String command = args[0];
DatabaseId db = DatabaseId.of(options.getProjectId(), args[1], args[2]);
// [END init_client]
// This will return the default project id based on the environment.
@@ -2206,25 +2247,26 @@ public static void main(String[] args) throws Exception {
printUsageAndExit();
}
// Generate a backup id for the sample database.
- String backupName =
- String.format(
- "%s_%02d",
- db.getDatabase(), LocalDate.now().get(ChronoField.ALIGNED_WEEK_OF_YEAR));
- BackupId backup = BackupId.of(db.getInstanceId(), backupName);
+ String backupId = null;
if (args.length == 4) {
- backupName = args[3];
+ backupId = args[3];
}
// [START init_client]
DatabaseClient dbClient = spanner.getDatabaseClient(db);
- DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
- InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
+ dbAdminClient = spanner.createDatabaseAdminClient();
+
// Use client here...
// [END init_client]
- run(dbClient, dbAdminClient, instanceAdminClient, command, db, backup);
+ run(dbClient, dbAdminClient, command, db, backupId);
// [START init_client]
} finally {
+ if (dbAdminClient != null) {
+ if (!dbAdminClient.isShutdown() || !dbAdminClient.isTerminated()) {
+ dbAdminClient.close();
+ }
+ }
spanner.close();
}
// [END init_client]
diff --git a/samples/snippets/src/main/java/com/example/spanner/UpdateDatabaseSample.java b/samples/snippets/src/main/java/com/example/spanner/UpdateDatabaseSample.java
index c87c27690a..57bb8e9159 100644
--- a/samples/snippets/src/main/java/com/example/spanner/UpdateDatabaseSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/UpdateDatabaseSample.java
@@ -17,15 +17,18 @@
package com.example.spanner;
// [START spanner_update_database]
+
import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.Database;
-import com.google.cloud.spanner.DatabaseAdminClient;
-import com.google.cloud.spanner.DatabaseId;
-import com.google.cloud.spanner.DatabaseInfo.DatabaseField;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.common.collect.Lists;
+import com.google.protobuf.FieldMask;
+import com.google.spanner.admin.database.v1.Database;
+import com.google.spanner.admin.database.v1.DatabaseName;
import com.google.spanner.admin.database.v1.UpdateDatabaseMetadata;
+import com.google.spanner.admin.database.v1.UpdateDatabaseRequest;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -37,22 +40,31 @@ static void updateDatabase() {
final String projectId = "my-project";
final String instanceId = "my-instance";
final String databaseId = "my-database";
+
updateDatabase(projectId, instanceId, databaseId);
}
- static void updateDatabase(String projectId, String instanceId, String databaseId) {
+ static void updateDatabase(
+ String projectId, String instanceId, String databaseId) {
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- final DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
-
- DatabaseId dbId = DatabaseId.of(projectId, instanceId, databaseId);
- Database databaseToUpdate =
- databaseAdminClient.newDatabaseBuilder(dbId).enableDropProtection().build();
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ final Database database =
+ Database.newBuilder()
+ .setName(DatabaseName.of(projectId, instanceId, databaseId).toString())
+ .setEnableDropProtection(true).build();
+ final UpdateDatabaseRequest updateDatabaseRequest =
+ UpdateDatabaseRequest.newBuilder()
+ .setDatabase(database)
+ .setUpdateMask(
+ FieldMask.newBuilder().addAllPaths(
+ Lists.newArrayList("enable_drop_protection")).build())
+ .build();
OperationFuture operation =
- databaseAdminClient.updateDatabase(databaseToUpdate, DatabaseField.DROP_PROTECTION);
- System.out.printf("Waiting for update operation for %s to complete...\n", dbId);
+ databaseAdminClient.updateDatabaseAsync(updateDatabaseRequest);
+ System.out.printf("Waiting for update operation for %s to complete...\n", databaseId);
Database updatedDb = operation.get(5, TimeUnit.MINUTES);
- System.out.printf("Updated database %s.\n", updatedDb.getId().getName());
+ System.out.printf("Updated database %s.\n", updatedDb.getName());
} catch (ExecutionException | TimeoutException e) {
// If the operation failed during execution, expose the cause.
throw SpannerExceptionFactory.asSpannerException(e.getCause());
diff --git a/samples/snippets/src/main/java/com/example/spanner/UpdateDatabaseWithDefaultLeaderSample.java b/samples/snippets/src/main/java/com/example/spanner/UpdateDatabaseWithDefaultLeaderSample.java
index f3ce004a69..701240cb12 100644
--- a/samples/snippets/src/main/java/com/example/spanner/UpdateDatabaseWithDefaultLeaderSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/UpdateDatabaseWithDefaultLeaderSample.java
@@ -18,13 +18,12 @@
//[START spanner_update_database_with_default_leader]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
-import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.spanner.admin.database.v1.DatabaseName;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
@@ -41,26 +40,20 @@ static void updateDatabaseWithDefaultLeader() {
static void updateDatabaseWithDefaultLeader(
String projectId, String instanceId, String databaseId, String defaultLeader) {
- try (Spanner spanner = SpannerOptions
- .newBuilder()
- .setProjectId(projectId)
- .build()
- .getService()) {
- final DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
- final OperationFuture operation = databaseAdminClient
- .updateDatabaseDdl(
- instanceId,
- databaseId,
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
+ databaseAdminClient
+ .updateDatabaseDdlAsync(
+ DatabaseName.of(projectId, instanceId, databaseId),
Collections.singletonList(
String.format(
"ALTER DATABASE `%s` SET OPTIONS (default_leader = '%s')",
databaseId,
defaultLeader
)
- ),
- null
- );
- operation.get();
+ )
+ ).get();
System.out.println("Updated default leader to " + defaultLeader);
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
diff --git a/samples/snippets/src/main/java/com/example/spanner/UpdateInstanceConfigSample.java b/samples/snippets/src/main/java/com/example/spanner/UpdateInstanceConfigSample.java
index 6450f265e1..c10175abe1 100644
--- a/samples/snippets/src/main/java/com/example/spanner/UpdateInstanceConfigSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/UpdateInstanceConfigSample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Google LLC
+ * Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,21 +17,21 @@
package com.example.spanner;
// [START spanner_update_instance_config]
-import com.google.api.gax.longrunning.OperationFuture;
-import com.google.cloud.spanner.InstanceAdminClient;
-import com.google.cloud.spanner.InstanceConfig;
-import com.google.cloud.spanner.InstanceConfigId;
-import com.google.cloud.spanner.InstanceConfigInfo;
-import com.google.cloud.spanner.InstanceConfigInfo.InstanceConfigField;
+
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.instance.v1.UpdateInstanceConfigMetadata;
+import com.google.protobuf.FieldMask;
+import com.google.spanner.admin.instance.v1.InstanceConfig;
+import com.google.spanner.admin.instance.v1.InstanceConfigName;
+import com.google.spanner.admin.instance.v1.UpdateInstanceConfigRequest;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
class UpdateInstanceConfigSample {
+
static void updateInstanceConfig() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
@@ -41,27 +41,42 @@ static void updateInstanceConfig() {
static void updateInstanceConfig(String projectId, String instanceConfigId) {
try (Spanner spanner =
- SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- final InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
- InstanceConfigInfo instanceConfigInfo =
- InstanceConfig.newBuilder(InstanceConfigId.of(projectId, instanceConfigId))
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService();
+ InstanceAdminClient instanceAdminClient = spanner.createInstanceAdminClient()) {
+ final InstanceConfigName instanceConfigName =
+ InstanceConfigName.of(projectId, instanceConfigId);
+ final InstanceConfig instanceConfig =
+ InstanceConfig.newBuilder()
+ .setName(instanceConfigName.toString())
.setDisplayName("updated custom instance config")
- .addLabel("updated", "true")
- .build();
- final OperationFuture operation =
- instanceAdminClient.updateInstanceConfig(
- instanceConfigInfo,
- ImmutableList.of(InstanceConfigField.DISPLAY_NAME, InstanceConfigField.LABELS));
+ .putLabels("updated", "true").build();
+ /**
+ * The field mask must always be specified; this prevents any future
+ * fields in [InstanceConfig][google.spanner.admin.instance.v1.InstanceConfig]
+ * from being erased accidentally by clients that do not know about them.
+ */
+ final UpdateInstanceConfigRequest updateInstanceConfigRequest =
+ UpdateInstanceConfigRequest.newBuilder()
+ .setInstanceConfig(instanceConfig)
+ .setUpdateMask(
+ FieldMask.newBuilder().addAllPaths(ImmutableList.of("display_name", "labels"))
+ .build()).build();
try {
- System.out.printf("Waiting for update operation on %s to complete...\n", instanceConfigId);
- InstanceConfig instanceConfig = operation.get(5, TimeUnit.MINUTES);
+ System.out.printf("Waiting for update operation on %s to complete...\n",
+ instanceConfigName);
+ InstanceConfig instanceConfigResult =
+ instanceAdminClient.updateInstanceConfigAsync(
+ updateInstanceConfigRequest).get(5, TimeUnit.MINUTES);
System.out.printf(
"Updated instance configuration %s with new display name %s\n",
- instanceConfig.getId(), instanceConfig.getDisplayName());
+ instanceConfigResult.getName(), instanceConfig.getDisplayName());
} catch (ExecutionException | TimeoutException e) {
System.out.printf(
"Error: Updating instance config %s failed with error message %s\n",
- instanceConfigInfo.getId(), e.getMessage());
+ instanceConfig.getName(), e.getMessage());
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println(
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/.gitkeep b/samples/snippets/src/main/java/com/example/spanner/admin/archived/.gitkeep
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/AddAndDropDatabaseRole.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/AddAndDropDatabaseRole.java
new file mode 100644
index 0000000000..cce8543492
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/AddAndDropDatabaseRole.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2022 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+// [START spanner_add_and_drop_database_role]
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class AddAndDropDatabaseRole {
+
+ static void addAndDropDatabaseRole() {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = "my-project";
+ String instanceId = "my-instance";
+ String databaseId = "my-database";
+ String parentRole = "my-new-parent-role";
+ String childRole = "my-new-child-role";
+ addAndDropDatabaseRole(projectId, instanceId, databaseId, parentRole, childRole);
+ }
+
+ static void addAndDropDatabaseRole(
+ String projectId, String instanceId, String databaseId, String parentRole, String childRole) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService()) {
+ final DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ OperationFuture operation =
+ adminClient.updateDatabaseDdl(
+ instanceId,
+ databaseId,
+ ImmutableList.of(
+ "CREATE ROLE " + parentRole,
+ "GRANT SELECT ON TABLE Albums TO ROLE " + parentRole,
+ "CREATE ROLE " + childRole,
+ "GRANT ROLE " + parentRole + " TO ROLE " + childRole),
+ null);
+ try {
+ System.out.println("Waiting for role create operation to complete...");
+ operation.get(5, TimeUnit.MINUTES);
+ System.out.printf(
+ "Created roles %s and %s and granted privileges%n", parentRole, childRole);
+ // Delete role and membership.
+ operation =
+ adminClient.updateDatabaseDdl(
+ instanceId,
+ databaseId,
+ ImmutableList.of(
+ "REVOKE ROLE " + parentRole + " FROM ROLE " + childRole,
+ "DROP ROLE " + childRole),
+ null);
+ System.out.println("Waiting for role revoke & drop operation to complete...");
+ operation.get(5, TimeUnit.MINUTES);
+ System.out.printf("Revoked privileges and dropped role %s%n", childRole);
+ } catch (ExecutionException | TimeoutException e) {
+ System.out.printf(
+ "Error: AddAndDropDatabaseRole failed with error message %s\n", e.getMessage());
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ System.out.println(
+ "Error: Waiting for AddAndDropDatabaseRole operation to finish was interrupted");
+ }
+ }
+ }
+}
+// [END spanner_add_and_drop_database_role]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/AddJsonColumnSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/AddJsonColumnSample.java
similarity index 55%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/AddJsonColumnSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/AddJsonColumnSample.java
index 32d1daea2d..8be7d6bd58 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/AddJsonColumnSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/AddJsonColumnSample.java
@@ -14,35 +14,43 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_add_json_column]
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
+import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
import java.util.concurrent.ExecutionException;
class AddJsonColumnSample {
- static void addJsonColumn() throws InterruptedException, ExecutionException, IOException {
+ static void addJsonColumn() throws InterruptedException, ExecutionException {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
String databaseId = "my-database";
- addJsonColumn(projectId, instanceId, databaseId);
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ addJsonColumn(adminClient, instanceId, databaseId);
+ }
}
- static void addJsonColumn(String projectId, String instanceId, String databaseId)
- throws InterruptedException, ExecutionException, IOException {
- final DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
-
+ static void addJsonColumn(DatabaseAdminClient adminClient, String instanceId, String databaseId)
+ throws InterruptedException, ExecutionException {
+ OperationFuture operation =
+ adminClient.updateDatabaseDdl(
+ instanceId,
+ databaseId,
+ ImmutableList.of("ALTER TABLE Venues ADD COLUMN VenueDetails JSON"),
+ null);
// Wait for the operation to finish.
// This will throw an ExecutionException if the operation fails.
- databaseAdminClient.updateDatabaseDdlAsync(
- DatabaseName.of(projectId, instanceId, databaseId),
- ImmutableList.of("ALTER TABLE Venues ADD COLUMN VenueDetails JSON")).get();
+ operation.get();
System.out.printf("Successfully added column `VenueDetails`%n");
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/AddJsonbColumnSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/AddJsonbColumnSample.java
similarity index 55%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/AddJsonbColumnSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/AddJsonbColumnSample.java
index 800c2d3d65..102ea36b0e 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/AddJsonbColumnSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/AddJsonbColumnSample.java
@@ -14,36 +14,43 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_postgresql_jsonb_add_column]
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
+import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
import java.util.concurrent.ExecutionException;
class AddJsonbColumnSample {
- static void addJsonbColumn() throws InterruptedException, ExecutionException, IOException {
+ static void addJsonbColumn() throws InterruptedException, ExecutionException {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
String databaseId = "my-database";
- addJsonbColumn(projectId, instanceId, databaseId);
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ addJsonbColumn(adminClient, instanceId, databaseId);
+ }
}
- static void addJsonbColumn(String projectId, String instanceId, String databaseId)
- throws InterruptedException, ExecutionException, IOException {
- final DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
-
- // JSONB datatype is only supported with PostgreSQL-dialect databases.
+ static void addJsonbColumn(DatabaseAdminClient adminClient, String instanceId, String databaseId)
+ throws InterruptedException, ExecutionException {
+ OperationFuture operation =
+ adminClient.updateDatabaseDdl(
+ instanceId,
+ databaseId,
+ ImmutableList.of("ALTER TABLE Venues ADD COLUMN VenueDetails JSONB"),
+ null);
// Wait for the operation to finish.
// This will throw an ExecutionException if the operation fails.
- databaseAdminClient.updateDatabaseDdlAsync(
- DatabaseName.of(projectId, instanceId, databaseId),
- ImmutableList.of("ALTER TABLE Venues ADD COLUMN VenueDetails JSONB")).get();
+ operation.get();
System.out.printf("Successfully added column `VenueDetails`%n");
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/AddNumericColumnSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/AddNumericColumnSample.java
similarity index 54%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/AddNumericColumnSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/AddNumericColumnSample.java
index 191e0377b6..347aaf5a9e 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/AddNumericColumnSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/AddNumericColumnSample.java
@@ -14,36 +14,44 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_add_numeric_column]
-
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
+import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
import java.util.concurrent.ExecutionException;
class AddNumericColumnSample {
- static void addNumericColumn() throws InterruptedException, ExecutionException, IOException {
+ static void addNumericColumn() throws InterruptedException, ExecutionException {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
String databaseId = "my-database";
- addNumericColumn(projectId, instanceId, databaseId);
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ addNumericColumn(adminClient, instanceId, databaseId);
+ }
}
- static void addNumericColumn(String projectId, String instanceId, String databaseId)
- throws InterruptedException, ExecutionException, IOException {
- final DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
-
+ static void addNumericColumn(
+ DatabaseAdminClient adminClient, String instanceId, String databaseId)
+ throws InterruptedException, ExecutionException {
+ OperationFuture operation =
+ adminClient.updateDatabaseDdl(
+ instanceId,
+ databaseId,
+ ImmutableList.of("ALTER TABLE Venues ADD COLUMN Revenue NUMERIC"),
+ null);
// Wait for the operation to finish.
// This will throw an ExecutionException if the operation fails.
- databaseAdminClient.updateDatabaseDdlAsync(
- DatabaseName.of(projectId, instanceId, databaseId),
- ImmutableList.of("ALTER TABLE Venues ADD COLUMN Revenue NUMERIC")).get();
+ operation.get();
System.out.printf("Successfully added column `Revenue`%n");
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/AlterSequenceSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/AlterSequenceSample.java
similarity index 87%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/AlterSequenceSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/AlterSequenceSample.java
index 05ae63a7a5..294bfdf6e2 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/AlterSequenceSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/AlterSequenceSample.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_alter_sequence]
-
+import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.ResultSet;
@@ -25,18 +25,14 @@
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class AlterSequenceSample {
-
- static void alterSequence() throws IOException {
+ static void alterSequence() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
final String instanceId = "my-instance";
@@ -44,17 +40,19 @@ static void alterSequence() throws IOException {
alterSequence(projectId, instanceId, databaseId);
}
- static void alterSequence(String projectId, String instanceId, String databaseId)
- throws IOException {
- DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
+ static void alterSequence(String projectId, String instanceId, String databaseId) {
try (Spanner spanner =
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ final DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
- databaseAdminClient
- .updateDatabaseDdlAsync(DatabaseName.of(projectId, instanceId, databaseId),
+ dbAdminClient
+ .updateDatabaseDdl(
+ instanceId,
+ databaseId,
ImmutableList.of(
"ALTER SEQUENCE Seq SET OPTIONS "
- + "(skip_range_min = 1000, skip_range_max = 5000000)"))
+ + "(skip_range_min = 1000, skip_range_max = 5000000)"),
+ null)
.get(5, TimeUnit.MINUTES);
System.out.println(
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/AlterTableWithForeignKeyDeleteCascadeSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/AlterTableWithForeignKeyDeleteCascadeSample.java
similarity index 68%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/AlterTableWithForeignKeyDeleteCascadeSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/AlterTableWithForeignKeyDeleteCascadeSample.java
index 5784bfab0c..ebf8a3f053 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/AlterTableWithForeignKeyDeleteCascadeSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/AlterTableWithForeignKeyDeleteCascadeSample.java
@@ -14,38 +14,41 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_alter_table_with_foreign_key_delete_cascade]
-
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
class AlterTableWithForeignKeyDeleteCascadeSample {
- static void alterForeignKeyDeleteCascadeConstraint() throws IOException {
+ static void alterForeignKeyDeleteCascadeConstraint() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
String databaseId = "my-database";
- alterForeignKeyDeleteCascadeConstraint(projectId, instanceId, databaseId);
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ alterForeignKeyDeleteCascadeConstraint(adminClient, instanceId, databaseId);
+ }
}
static void alterForeignKeyDeleteCascadeConstraint(
- String projectId, String instanceId, String databaseId) throws IOException {
- DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
-
- databaseAdminClient.updateDatabaseDdlAsync(DatabaseName.of(projectId, instanceId,
- databaseId),
+ DatabaseAdminClient adminClient, String instanceId, String databaseId) {
+ adminClient.updateDatabaseDdl(
+ instanceId,
+ databaseId,
ImmutableList.of(
"ALTER TABLE ShoppingCarts\n"
+ " ADD CONSTRAINT FKShoppingCartsCustomerName\n"
+ " FOREIGN KEY (CustomerName)\n"
+ " REFERENCES Customers(CustomerName)\n"
- + " ON DELETE CASCADE\n"));
+ + " ON DELETE CASCADE\n"),
+ null);
System.out.printf(
String.format(
"Altered ShoppingCarts table with FKShoppingCartsCustomerName\n"
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/CopyBackupSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CopyBackupSample.java
new file mode 100644
index 0000000000..3b3c192a5a
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CopyBackupSample.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2022 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+// [START spanner_copy_backup]
+
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.Timestamp;
+import com.google.cloud.spanner.Backup;
+import com.google.cloud.spanner.BackupId;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerException;
+import com.google.cloud.spanner.SpannerExceptionFactory;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.spanner.admin.database.v1.CopyBackupMetadata;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+public class CopyBackupSample {
+ static void copyBackup() {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = "my-project";
+ String instanceId = "my-instance";
+ String sourceBackupId = "my-backup";
+ String destinationBackupId = "my-destination-backup";
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
+ copyBackup(databaseAdminClient, projectId, instanceId, sourceBackupId, destinationBackupId);
+ }
+ }
+
+ static void copyBackup(
+ DatabaseAdminClient databaseAdminClient,
+ String projectId,
+ String instanceId,
+ String sourceBackupId,
+ String destinationBackupId) {
+
+ Timestamp expireTime =
+ Timestamp.ofTimeMicroseconds(
+ TimeUnit.MICROSECONDS.convert(
+ System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14),
+ TimeUnit.MILLISECONDS));
+ // Creates a copy of an existing backup.
+ Backup destinationBackup =
+ databaseAdminClient
+ .newBackupBuilder(BackupId.of(projectId, instanceId, destinationBackupId))
+ .setExpireTime(expireTime)
+ .build();
+
+ // Initiate the request which returns an OperationFuture.
+ System.out.println("Copying backup [" + destinationBackup.getId() + "]...");
+ OperationFuture operation =
+ databaseAdminClient.copyBackup(
+ BackupId.of(projectId, instanceId, sourceBackupId), destinationBackup);
+ try {
+ // Wait for the backup operation to complete.
+ destinationBackup = operation.get();
+ System.out.println("Copied backup [" + destinationBackup.getId() + "]");
+ } catch (ExecutionException e) {
+ throw (SpannerException) e.getCause();
+ } catch (InterruptedException e) {
+ throw SpannerExceptionFactory.propagateInterrupt(e);
+ }
+ // Load the metadata of the new backup from the server.
+ destinationBackup = destinationBackup.reload();
+ System.out.println(
+ String.format(
+ "Backup %s of size %d bytes was copied at %s for version of database at %s",
+ destinationBackup.getId().getName(),
+ destinationBackup.getSize(),
+ LocalDateTime.ofEpochSecond(
+ destinationBackup.getProto().getCreateTime().getSeconds(),
+ destinationBackup.getProto().getCreateTime().getNanos(),
+ OffsetDateTime.now().getOffset()),
+ LocalDateTime.ofEpochSecond(
+ destinationBackup.getProto().getVersionTime().getSeconds(),
+ destinationBackup.getProto().getVersionTime().getNanos(),
+ OffsetDateTime.now().getOffset())));
+ return;
+ }
+}
+// [END spanner_copy_backup]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateBackupWithEncryptionKey.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateBackupWithEncryptionKey.java
new file mode 100644
index 0000000000..23ddd69917
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateBackupWithEncryptionKey.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+// [START spanner_create_backup_with_encryption_key]
+
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.Timestamp;
+import com.google.cloud.spanner.Backup;
+import com.google.cloud.spanner.BackupId;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.DatabaseId;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerExceptionFactory;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.encryption.EncryptionConfigs;
+import com.google.spanner.admin.database.v1.CreateBackupMetadata;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.threeten.bp.LocalDateTime;
+import org.threeten.bp.OffsetDateTime;
+
+public class CreateBackupWithEncryptionKey {
+
+ static void createBackupWithEncryptionKey() throws InterruptedException {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = "my-project";
+ String instanceId = "my-instance";
+ String databaseId = "my-database";
+ String backupId = "my-backup";
+ String kmsKeyName =
+ "projects/" + projectId + "/locations//keyRings//cryptoKeys/";
+
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ createBackupWithEncryptionKey(
+ adminClient,
+ projectId,
+ instanceId,
+ databaseId,
+ backupId,
+ kmsKeyName);
+ }
+ }
+
+ static Void createBackupWithEncryptionKey(DatabaseAdminClient adminClient,
+ String projectId, String instanceId, String databaseId, String backupId, String kmsKeyName)
+ throws InterruptedException {
+ // Set expire time to 14 days from now.
+ final Timestamp expireTime = Timestamp.ofTimeMicroseconds(TimeUnit.MICROSECONDS.convert(
+ System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14), TimeUnit.MILLISECONDS));
+ final Backup backupToCreate = adminClient
+ .newBackupBuilder(BackupId.of(projectId, instanceId, backupId))
+ .setDatabase(DatabaseId.of(projectId, instanceId, databaseId))
+ .setExpireTime(expireTime)
+ .setEncryptionConfig(EncryptionConfigs.customerManagedEncryption(kmsKeyName))
+ .build();
+ final OperationFuture operation = adminClient
+ .createBackup(backupToCreate);
+
+ Backup backup;
+ try {
+ System.out.println("Waiting for operation to complete...");
+ backup = operation.get(1200, TimeUnit.SECONDS);
+ } catch (ExecutionException e) {
+ // If the operation failed during execution, expose the cause.
+ throw SpannerExceptionFactory.asSpannerException(e.getCause());
+ } catch (InterruptedException e) {
+ // Throw when a thread is waiting, sleeping, or otherwise occupied,
+ // and the thread is interrupted, either before or during the activity.
+ throw SpannerExceptionFactory.propagateInterrupt(e);
+ } catch (TimeoutException e) {
+ // If the operation timed out propagates the timeout
+ throw SpannerExceptionFactory.propagateTimeout(e);
+ }
+
+ System.out.printf(
+ "Backup %s of size %d bytes was created at %s using encryption key %s%n",
+ backup.getId().getName(),
+ backup.getSize(),
+ LocalDateTime.ofEpochSecond(
+ backup.getProto().getCreateTime().getSeconds(),
+ backup.getProto().getCreateTime().getNanos(),
+ OffsetDateTime.now().getOffset()),
+ kmsKeyName
+ );
+
+ return null;
+ }
+}
+// [END spanner_create_backup_with_encryption_key]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateDatabaseWithDefaultLeaderSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateDatabaseWithDefaultLeaderSample.java
new file mode 100644
index 0000000000..8bfc6422cf
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateDatabaseWithDefaultLeaderSample.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+//[START spanner_create_database_with_default_leader]
+
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.Database;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerException;
+import com.google.cloud.spanner.SpannerExceptionFactory;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
+import java.util.Arrays;
+import java.util.concurrent.ExecutionException;
+
+public class CreateDatabaseWithDefaultLeaderSample {
+
+ static void createDatabaseWithDefaultLeader() {
+ // TODO(developer): Replace these variables before running the sample.
+ final String projectId = "my-project";
+ final String instanceId = "my-instance";
+ final String databaseId = "my-database";
+ final String defaultLeader = "my-default-leader";
+ createDatabaseWithDefaultLeader(projectId, instanceId, databaseId, defaultLeader);
+ }
+
+ static void createDatabaseWithDefaultLeader(
+ String projectId, String instanceId, String databaseId, String defaultLeader) {
+ try (Spanner spanner = SpannerOptions
+ .newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService()) {
+ final DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
+ final OperationFuture operation = databaseAdminClient
+ .createDatabase(
+ instanceId,
+ databaseId,
+ Arrays.asList(
+ "CREATE TABLE Singers ("
+ + " SingerId INT64 NOT NULL,"
+ + " FirstName STRING(1024),"
+ + " LastName STRING(1024),"
+ + " SingerInfo BYTES(MAX)"
+ + ") PRIMARY KEY (SingerId)",
+ "CREATE TABLE Albums ("
+ + " SingerId INT64 NOT NULL,"
+ + " AlbumId INT64 NOT NULL,"
+ + " AlbumTitle STRING(MAX)"
+ + ") PRIMARY KEY (SingerId, AlbumId),"
+ + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE",
+ "ALTER DATABASE " + "`" + databaseId + "`"
+ + " SET OPTIONS ( default_leader = '" + defaultLeader + "' )"
+ )
+ );
+ final Database database = operation.get();
+ System.out.println("Created database [" + database.getId() + "]");
+ System.out.println("\tDefault leader: " + database.getDefaultLeader());
+ } catch (ExecutionException e) {
+ // If the operation failed during execution, expose the cause.
+ throw (SpannerException) e.getCause();
+ } catch (InterruptedException e) {
+ // Throw when a thread is waiting, sleeping, or otherwise occupied,
+ // and the thread is interrupted, either before or during the activity.
+ throw SpannerExceptionFactory.propagateInterrupt(e);
+ }
+ }
+}
+//[END spanner_create_database_with_default_leader]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateDatabaseWithEncryptionKey.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateDatabaseWithEncryptionKey.java
new file mode 100644
index 0000000000..2064423547
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateDatabaseWithEncryptionKey.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+// [START spanner_create_database_with_encryption_key]
+
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.Database;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.DatabaseId;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerExceptionFactory;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.encryption.EncryptionConfigs;
+import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
+import java.util.Arrays;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class CreateDatabaseWithEncryptionKey {
+
+ static void createDatabaseWithEncryptionKey() {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = "my-project";
+ String instanceId = "my-instance";
+ String databaseId = "my-database";
+ String kmsKeyName =
+ "projects/" + projectId + "/locations//keyRings//cryptoKeys/";
+
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ createDatabaseWithEncryptionKey(
+ adminClient,
+ projectId,
+ instanceId,
+ databaseId,
+ kmsKeyName);
+ }
+ }
+
+ static void createDatabaseWithEncryptionKey(DatabaseAdminClient adminClient,
+ String projectId, String instanceId, String databaseId, String kmsKeyName) {
+ final Database databaseToCreate = adminClient
+ .newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId))
+ .setEncryptionConfig(EncryptionConfigs.customerManagedEncryption(kmsKeyName))
+ .build();
+ final OperationFuture operation = adminClient
+ .createDatabase(databaseToCreate, Arrays.asList(
+ "CREATE TABLE Singers ("
+ + " SingerId INT64 NOT NULL,"
+ + " FirstName STRING(1024),"
+ + " LastName STRING(1024),"
+ + " SingerInfo BYTES(MAX)"
+ + ") PRIMARY KEY (SingerId)",
+ "CREATE TABLE Albums ("
+ + " SingerId INT64 NOT NULL,"
+ + " AlbumId INT64 NOT NULL,"
+ + " AlbumTitle STRING(MAX)"
+ + ") PRIMARY KEY (SingerId, AlbumId),"
+ + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE"
+ ));
+ try {
+ System.out.println("Waiting for operation to complete...");
+ Database createdDatabase = operation.get(120, TimeUnit.SECONDS);
+
+ System.out.printf(
+ "Database %s created with encryption key %s%n",
+ createdDatabase.getId(),
+ createdDatabase.getEncryptionConfig().getKmsKeyName()
+ );
+ } catch (ExecutionException e) {
+ // If the operation failed during execution, expose the cause.
+ throw SpannerExceptionFactory.asSpannerException(e.getCause());
+ } catch (InterruptedException e) {
+ // Throw when a thread is waiting, sleeping, or otherwise occupied,
+ // and the thread is interrupted, either before or during the activity.
+ throw SpannerExceptionFactory.propagateInterrupt(e);
+ } catch (TimeoutException e) {
+ // If the operation timed out propagates the timeout
+ throw SpannerExceptionFactory.propagateTimeout(e);
+ }
+ }
+}
+// [END spanner_create_database_with_encryption_key]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateDatabaseWithVersionRetentionPeriodSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateDatabaseWithVersionRetentionPeriodSample.java
new file mode 100644
index 0000000000..1dea5af204
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateDatabaseWithVersionRetentionPeriodSample.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+// [START spanner_create_database_with_version_retention_period]
+
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.Database;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerException;
+import com.google.cloud.spanner.SpannerExceptionFactory;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
+import java.util.Arrays;
+import java.util.concurrent.ExecutionException;
+
+public class CreateDatabaseWithVersionRetentionPeriodSample {
+
+ static void createDatabaseWithVersionRetentionPeriod() {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = "my-project";
+ String instanceId = "my-instance";
+ String databaseId = "my-database";
+ String versionRetentionPeriod = "7d";
+
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ createDatabaseWithVersionRetentionPeriod(adminClient, instanceId, databaseId,
+ versionRetentionPeriod);
+ }
+ }
+
+ static void createDatabaseWithVersionRetentionPeriod(DatabaseAdminClient adminClient,
+ String instanceId, String databaseId, String versionRetentionPeriod) {
+ OperationFuture op =
+ adminClient.createDatabase(
+ instanceId,
+ databaseId,
+ Arrays.asList(
+ "CREATE TABLE Singers ("
+ + " SingerId INT64 NOT NULL,"
+ + " FirstName STRING(1024),"
+ + " LastName STRING(1024),"
+ + " SingerInfo BYTES(MAX)"
+ + ") PRIMARY KEY (SingerId)",
+ "CREATE TABLE Albums ("
+ + " SingerId INT64 NOT NULL,"
+ + " AlbumId INT64 NOT NULL,"
+ + " AlbumTitle STRING(MAX)"
+ + ") PRIMARY KEY (SingerId, AlbumId),"
+ + " INTERLEAVE IN PARENT Singers ON DELETE CASCADE",
+ "ALTER DATABASE " + "`" + databaseId + "`"
+ + " SET OPTIONS ( version_retention_period = '" + versionRetentionPeriod + "' )"
+ ));
+ try {
+ Database database = op.get();
+ System.out.println("Created database [" + database.getId() + "]");
+ System.out.println("\tVersion retention period: " + database.getVersionRetentionPeriod());
+ System.out.println("\tEarliest version time: " + database.getEarliestVersionTime());
+ } catch (ExecutionException e) {
+ // If the operation failed during execution, expose the cause.
+ throw (SpannerException) e.getCause();
+ } catch (InterruptedException e) {
+ // Throw when a thread is waiting, sleeping, or otherwise occupied,
+ // and the thread is interrupted, either before or during the activity.
+ throw SpannerExceptionFactory.propagateInterrupt(e);
+ }
+ }
+}
+// [END spanner_create_database_with_version_retention_period]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateInstanceConfigSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateInstanceConfigSample.java
new file mode 100644
index 0000000000..3b9e49bf0e
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateInstanceConfigSample.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+// [START spanner_create_instance_config]
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.InstanceAdminClient;
+import com.google.cloud.spanner.InstanceConfig;
+import com.google.cloud.spanner.InstanceConfigId;
+import com.google.cloud.spanner.InstanceConfigInfo;
+import com.google.cloud.spanner.ReplicaInfo;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.common.collect.ImmutableList;
+import com.google.spanner.admin.instance.v1.CreateInstanceConfigMetadata;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+class CreateInstanceConfigSample {
+ static void createInstanceConfig() {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = "my-project";
+ String baseInstanceConfig = "my-base-instance-config";
+ String instanceConfigId = "custom-instance-config4";
+ createInstanceConfig(projectId, baseInstanceConfig, instanceConfigId);
+ }
+
+ static void createInstanceConfig(
+ String projectId, String baseInstanceConfig, String instanceConfigId) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ final InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
+ final InstanceConfig baseConfig = instanceAdminClient.getInstanceConfig(baseInstanceConfig);
+ List readOnlyReplicas =
+ ImmutableList.of(baseConfig.getOptionalReplicas().get(0));
+ InstanceConfigInfo instanceConfigInfo =
+ InstanceConfig.newBuilder(InstanceConfigId.of(projectId, instanceConfigId), baseConfig)
+ .setDisplayName(instanceConfigId)
+ .addReadOnlyReplicas(readOnlyReplicas)
+ .build();
+ final OperationFuture operation =
+ instanceAdminClient.createInstanceConfig(instanceConfigInfo);
+ try {
+ System.out.printf("Waiting for create operation for %s to complete...\n", instanceConfigId);
+ InstanceConfig instanceConfig = operation.get(5, TimeUnit.MINUTES);
+ System.out.printf("Created instance configuration %s\n", instanceConfig.getId());
+ } catch (ExecutionException | TimeoutException e) {
+ System.out.printf(
+ "Error: Creating instance configuration %s failed with error message %s\n",
+ instanceConfigInfo.getId(), e.getMessage());
+ } catch (InterruptedException e) {
+ System.out.println(
+ "Error: Waiting for createInstanceConfig operation to finish was interrupted");
+ }
+ }
+ }
+}
+// [END spanner_create_instance_config]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/CreateInstanceExample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateInstanceExample.java
similarity index 53%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/CreateInstanceExample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateInstanceExample.java
index 925b098499..15b33ae892 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/CreateInstanceExample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateInstanceExample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 Google LLC
+ * Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,58 +14,60 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
//[START spanner_create_instance]
-
-import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
-import com.google.spanner.admin.instance.v1.CreateInstanceRequest;
-import com.google.spanner.admin.instance.v1.Instance;
-import com.google.spanner.admin.instance.v1.InstanceConfigName;
-import com.google.spanner.admin.instance.v1.ProjectName;
-import java.io.IOException;
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.Instance;
+import com.google.cloud.spanner.InstanceAdminClient;
+import com.google.cloud.spanner.InstanceConfigId;
+import com.google.cloud.spanner.InstanceId;
+import com.google.cloud.spanner.InstanceInfo;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.spanner.admin.instance.v1.CreateInstanceMetadata;
import java.util.concurrent.ExecutionException;
class CreateInstanceExample {
- static void createInstance() throws IOException {
+ static void createInstance() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
createInstance(projectId, instanceId);
}
- static void createInstance(String projectId, String instanceId) throws IOException {
- InstanceAdminClient instanceAdminClient = InstanceAdminClient.create();
+ static void createInstance(String projectId, String instanceId) {
+ Spanner spanner = SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
// Set Instance configuration.
+ String configId = "regional-us-central1";
int nodeCount = 2;
String displayName = "Descriptive name";
- // Create an Instance object that will be used to create the instance.
- Instance instance =
- Instance.newBuilder()
- .setDisplayName(displayName)
+ // Create an InstanceInfo object that will be used to create the instance.
+ InstanceInfo instanceInfo =
+ InstanceInfo.newBuilder(InstanceId.of(projectId, instanceId))
+ .setInstanceConfigId(InstanceConfigId.of(projectId, configId))
.setNodeCount(nodeCount)
- .setConfig(
- InstanceConfigName.of(projectId, "regional-us-central1").toString())
+ .setDisplayName(displayName)
.build();
+ OperationFuture operation =
+ instanceAdminClient.createInstance(instanceInfo);
try {
// Wait for the createInstance operation to finish.
- Instance createdInstance = instanceAdminClient.createInstanceAsync(
- CreateInstanceRequest.newBuilder()
- .setParent(ProjectName.of(projectId).toString())
- .setInstanceId(instanceId)
- .setInstance(instance)
- .build()).get();
- System.out.printf("Instance %s was successfully created%n", createdInstance.getName());
+ Instance instance = operation.get();
+ System.out.printf("Instance %s was successfully created%n", instance.getId());
} catch (ExecutionException e) {
System.out.printf(
"Error: Creating instance %s failed with error message %s%n",
- instance.getName(), e.getMessage());
+ instanceInfo.getId(), e.getMessage());
} catch (InterruptedException e) {
System.out.println("Error: Waiting for createInstance operation to finish was interrupted");
+ } finally {
+ spanner.close();
}
}
}
-//[END spanner_create_instance]
\ No newline at end of file
+//[END spanner_create_instance]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateInstanceWithAutoscalingConfigExample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateInstanceWithAutoscalingConfigExample.java
new file mode 100644
index 0000000000..3fe60c554b
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateInstanceWithAutoscalingConfigExample.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+// [START spanner_create_instance_with_autoscaling_config]
+
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.Instance;
+import com.google.cloud.spanner.InstanceAdminClient;
+import com.google.cloud.spanner.InstanceConfigId;
+import com.google.cloud.spanner.InstanceId;
+import com.google.cloud.spanner.InstanceInfo;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.spanner.admin.instance.v1.AutoscalingConfig;
+import com.google.spanner.admin.instance.v1.CreateInstanceMetadata;
+import java.util.concurrent.ExecutionException;
+
+class CreateInstanceWithAutoscalingConfigExample {
+
+ static void createInstance() {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = "my-project";
+ String instanceId = "my-instance";
+ createInstance(projectId, instanceId);
+ }
+
+ static void createInstance(String projectId, String instanceId) {
+ Spanner spanner = SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
+
+ // Set Instance configuration.
+ String configId = "regional-us-central1";
+ // Create an autoscaling config.
+ AutoscalingConfig autoscalingConfig =
+ AutoscalingConfig.newBuilder()
+ .setAutoscalingLimits(
+ AutoscalingConfig.AutoscalingLimits.newBuilder().setMinNodes(1).setMaxNodes(2))
+ .setAutoscalingTargets(
+ AutoscalingConfig.AutoscalingTargets.newBuilder()
+ .setHighPriorityCpuUtilizationPercent(65)
+ .setStorageUtilizationPercent(95))
+ .build();
+
+ // Create an InstanceInfo object that will be used to create the instance.
+ InstanceInfo instanceInfo =
+ InstanceInfo.newBuilder(InstanceId.of(projectId, instanceId))
+ .setInstanceConfigId(InstanceConfigId.of(projectId, configId))
+ .setAutoscalingConfig(autoscalingConfig)
+ .setDisplayName("Descriptive name")
+ .build();
+ OperationFuture operation =
+ instanceAdminClient.createInstance(instanceInfo);
+
+ try {
+ // Wait for the createInstance operation to finish.
+ Instance instance = operation.get();
+ System.out.printf("Autoscaler instance %s was successfully created%n", instance.getId());
+ } catch (ExecutionException e) {
+ System.out.printf(
+ "Error: Creating instance %s failed with error message %s%n",
+ instanceInfo.getId(), e.getMessage());
+ } catch (InterruptedException e) {
+ System.out.println("Error: Waiting for createInstance operation to finish was interrupted");
+ } finally {
+ spanner.close();
+ }
+ }
+}
+// [END spanner_create_instance_with_autoscaling_config]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateInstanceWithProcessingUnitsExample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateInstanceWithProcessingUnitsExample.java
new file mode 100644
index 0000000000..f688b4cdbf
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateInstanceWithProcessingUnitsExample.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+//[START spanner_create_instance_with_processing_units]
+
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.Instance;
+import com.google.cloud.spanner.InstanceAdminClient;
+import com.google.cloud.spanner.InstanceConfigId;
+import com.google.cloud.spanner.InstanceId;
+import com.google.cloud.spanner.InstanceInfo;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.spanner.admin.instance.v1.CreateInstanceMetadata;
+
+class CreateInstanceWithProcessingUnitsExample {
+
+ static void createInstance() {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = "my-project";
+ String instanceId = "my-instance";
+ createInstance(projectId, instanceId);
+ }
+
+ static void createInstance(String projectId, String instanceId) {
+ Spanner spanner = SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
+ InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
+
+ // Set Instance configuration.
+ String configId = "regional-us-central1";
+ // This will create an instance with the processing power of 0.2 nodes.
+ int processingUnits = 500;
+ String displayName = "Descriptive name";
+
+ try {
+ // Creates a new instance
+ System.out.printf("Creating instance %s.%n", instanceId);
+ OperationFuture operation =
+ instanceAdminClient.createInstance(InstanceInfo
+ .newBuilder(InstanceId.of(projectId, instanceId))
+ .setInstanceConfigId(InstanceConfigId.of(projectId, configId))
+ .setProcessingUnits(processingUnits)
+ .setDisplayName(displayName)
+ .build());
+
+ // Wait for the createInstance operation to finish.
+ System.out.printf("Waiting for operation on %s to complete...%n", instanceId);
+ Instance createdInstance = operation.get();
+
+ System.out.printf("Created instance %s.%n", createdInstance.getId().getInstance());
+
+ Instance instance = instanceAdminClient.getInstance(instanceId);
+ System.out.printf("Instance %s has %d processing units.%n", instance.getId().getInstance(),
+ instance.getProcessingUnits());
+ } catch (Exception e) {
+ System.out.printf("Error: %s.%n", e.getMessage());
+ }
+ spanner.close();
+ }
+}
+//[END spanner_create_instance_with_processing_units]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/CreateSequenceSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateSequenceSample.java
similarity index 87%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/CreateSequenceSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateSequenceSample.java
index 6614d988b7..637bd39d9a 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/CreateSequenceSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateSequenceSample.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_create_sequence]
-
+import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.ResultSet;
@@ -25,18 +25,14 @@
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class CreateSequenceSample {
-
- static void createSequence() throws IOException {
+ static void createSequence() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
final String instanceId = "my-instance";
@@ -44,21 +40,21 @@ static void createSequence() throws IOException {
createSequence(projectId, instanceId, databaseId);
}
- static void createSequence(String projectId, String instanceId, String databaseId)
- throws IOException {
- DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
-
+ static void createSequence(String projectId, String instanceId, String databaseId) {
try (Spanner spanner =
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ final DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
- databaseAdminClient
- .updateDatabaseDdlAsync(
- DatabaseName.of(projectId, instanceId, databaseId),
+ dbAdminClient
+ .updateDatabaseDdl(
+ instanceId,
+ databaseId,
ImmutableList.of(
"CREATE SEQUENCE Seq OPTIONS (sequence_kind = 'bit_reversed_positive')",
"CREATE TABLE Customers (CustomerId INT64 DEFAULT "
+ "(GET_NEXT_SEQUENCE_VALUE(SEQUENCE Seq)), CustomerName STRING(1024)) "
- + "PRIMARY KEY (CustomerId)"))
+ + "PRIMARY KEY (CustomerId)"),
+ null)
.get(5, TimeUnit.MINUTES);
System.out.println(
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/CreateTableWithForeignKeyDeleteCascadeSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateTableWithForeignKeyDeleteCascadeSample.java
similarity index 72%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/CreateTableWithForeignKeyDeleteCascadeSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateTableWithForeignKeyDeleteCascadeSample.java
index cc46f1e214..a5cc4668d5 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/CreateTableWithForeignKeyDeleteCascadeSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/CreateTableWithForeignKeyDeleteCascadeSample.java
@@ -14,32 +14,34 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_create_table_with_foreign_key_delete_cascade]
-
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.CreateDatabaseRequest;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
class CreateTableWithForeignKeyDeleteCascadeSample {
- static void createForeignKeyDeleteCascadeConstraint() throws IOException {
+ static void createForeignKeyDeleteCascadeConstraint() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
String databaseId = "my-database";
- createForeignKeyDeleteCascadeConstraint(projectId, instanceId, databaseId);
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ createForeignKeyDeleteCascadeConstraint(adminClient, instanceId, databaseId);
+ }
}
static void createForeignKeyDeleteCascadeConstraint(
- String projectId, String instanceId, String databaseId) throws IOException {
- DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
- databaseAdminClient.updateDatabaseDdlAsync(
- DatabaseName.of(projectId, instanceId, databaseId),
+ DatabaseAdminClient adminClient, String instanceId, String databaseId) {
+ adminClient.updateDatabaseDdl(
+ instanceId,
+ databaseId,
ImmutableList.of(
"CREATE TABLE Customers (\n"
+ " CustomerId INT64 NOT NULL,\n"
@@ -51,7 +53,8 @@ static void createForeignKeyDeleteCascadeConstraint(
+ " CustomerName STRING(62) NOT NULL,\n"
+ " CONSTRAINT FKShoppingCartsCustomerId FOREIGN KEY (CustomerId)\n"
+ " REFERENCES Customers (CustomerId) ON DELETE CASCADE\n"
- + " ) PRIMARY KEY (CartId)\n"));
+ + " ) PRIMARY KEY (CartId)\n"),
+ null);
System.out.printf(
String.format(
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/DeleteInstanceConfigSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/DeleteInstanceConfigSample.java
similarity index 57%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/DeleteInstanceConfigSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/DeleteInstanceConfigSample.java
index 1fa9aee586..b1013cd4b0 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/DeleteInstanceConfigSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/DeleteInstanceConfigSample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,40 +14,34 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_delete_instance_config]
-
+import com.google.cloud.spanner.InstanceAdminClient;
+import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
-import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
-import com.google.spanner.admin.instance.v1.DeleteInstanceConfigRequest;
-import com.google.spanner.admin.instance.v1.InstanceConfigName;
-import java.io.IOException;
+import com.google.cloud.spanner.SpannerOptions;
class DeleteInstanceConfigSample {
-
- static void deleteInstanceConfig() throws IOException {
+ static void deleteInstanceConfig() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceConfigId = "custom-user-config";
deleteInstanceConfig(projectId, instanceConfigId);
}
- static void deleteInstanceConfig(String projectId, String instanceConfigId) throws IOException {
- try (final InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
- final InstanceConfigName instanceConfigName = InstanceConfigName.of(projectId,
- instanceConfigId);
- final DeleteInstanceConfigRequest request =
- DeleteInstanceConfigRequest.newBuilder().setName(instanceConfigName.toString()).build();
-
+ static void deleteInstanceConfig(String projectId, String instanceConfigId) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ final InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
try {
- System.out.printf("Deleting %s...\n", instanceConfigName);
- instanceAdminClient.deleteInstanceConfig(request);
- System.out.printf("Deleted instance configuration %s\n", instanceConfigName);
+ System.out.printf("Deleting %s...\n", instanceConfigId);
+ instanceAdminClient.deleteInstanceConfig(instanceConfigId);
+ System.out.printf("Deleted instance configuration %s\n", instanceConfigId);
} catch (SpannerException e) {
System.out.printf(
"Error: Deleting instance configuration %s failed with error message: %s\n",
- instanceConfigName, e.getMessage());
+ instanceConfigId, e.getMessage());
}
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/DropForeignKeyConstraintDeleteCascadeSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/DropForeignKeyConstraintDeleteCascadeSample.java
similarity index 67%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/DropForeignKeyConstraintDeleteCascadeSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/DropForeignKeyConstraintDeleteCascadeSample.java
index 7d569acea8..bf03542f91 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/DropForeignKeyConstraintDeleteCascadeSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/DropForeignKeyConstraintDeleteCascadeSample.java
@@ -14,34 +14,38 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_drop_foreign_key_constraint_delete_cascade]
-
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
class DropForeignKeyConstraintDeleteCascadeSample {
- static void deleteForeignKeyDeleteCascadeConstraint() throws IOException {
+ static void deleteForeignKeyDeleteCascadeConstraint() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
String databaseId = "my-database";
- deleteForeignKeyDeleteCascadeConstraint(projectId, instanceId, databaseId);
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ deleteForeignKeyDeleteCascadeConstraint(adminClient, instanceId, databaseId);
+ }
}
static void deleteForeignKeyDeleteCascadeConstraint(
- String projectId, String instanceId, String databaseId) throws IOException {
- DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
- databaseAdminClient.updateDatabaseDdlAsync(
- DatabaseName.of(projectId, instanceId, databaseId),
+ DatabaseAdminClient adminClient, String instanceId, String databaseId) {
+ adminClient.updateDatabaseDdl(
+ instanceId,
+ databaseId,
ImmutableList.of(
"ALTER TABLE ShoppingCarts\n"
- + " DROP CONSTRAINT FKShoppingCartsCustomerName\n"));
+ + " DROP CONSTRAINT FKShoppingCartsCustomerName\n"),
+ null);
System.out.printf(
String.format(
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/DropSequenceSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/DropSequenceSample.java
similarity index 78%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/DropSequenceSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/DropSequenceSample.java
index f9917677de..3e8f2bb414 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/DropSequenceSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/DropSequenceSample.java
@@ -14,22 +14,20 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_drop_sequence]
-
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
+import com.google.cloud.spanner.SpannerOptions;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class DropSequenceSample {
-
- static void dropSequence() throws IOException {
+ static void dropSequence() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
final String instanceId = "my-instance";
@@ -37,16 +35,21 @@ static void dropSequence() throws IOException {
dropSequence(projectId, instanceId, databaseId);
}
- static void dropSequence(String projectId, String instanceId, String databaseId)
- throws IOException {
- DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
- try {
- databaseAdminClient
- .updateDatabaseDdlAsync(DatabaseName.of(projectId, instanceId, databaseId),
+ static void dropSequence(String projectId, String instanceId, String databaseId) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ final DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
+
+ dbAdminClient
+ .updateDatabaseDdl(
+ instanceId,
+ databaseId,
ImmutableList.of(
"ALTER TABLE Customers ALTER COLUMN CustomerId DROP DEFAULT",
- "DROP SEQUENCE Seq"))
+ "DROP SEQUENCE Seq"),
+ null)
.get(5, TimeUnit.MINUTES);
+
System.out.println(
"Altered Customers table to drop DEFAULT from CustomerId column "
+ "and dropped the Seq sequence");
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/EnableFineGrainedAccess.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/EnableFineGrainedAccess.java
new file mode 100644
index 0000000000..cc373f50f6
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/EnableFineGrainedAccess.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2022 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+// [START spanner_enable_fine_grained_access]
+import com.google.cloud.Binding;
+import com.google.cloud.Condition;
+import com.google.cloud.Policy;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.common.collect.ImmutableList;
+
+public class EnableFineGrainedAccess {
+
+ static void enableFineGrainedAccess() {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = "my-project";
+ String instanceId = "my-instance";
+ String databaseId = "my-database";
+ String iamMember = "user:alice@example.com";
+ String role = "my-role";
+ String title = "my-condition-title";
+ enableFineGrainedAccess(projectId, instanceId, databaseId, iamMember, title, role);
+ }
+
+ static void enableFineGrainedAccess(
+ String projectId,
+ String instanceId,
+ String databaseId,
+ String iamMember,
+ String title,
+ String role) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService()) {
+ final DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ Policy policy = adminClient.getDatabaseIAMPolicy(instanceId, databaseId, 3);
+ int policyVersion = policy.getVersion();
+ // The policy in the response from getDatabaseIAMPolicy might use the policy version
+ // that you specified, or it might use a lower policy version. For example, if you
+ // specify version 3, but the policy has no conditional role bindings, the response
+ // uses version 1. Valid values are 0, 1, and 3.
+ if (policy.getVersion() < 3) {
+ // conditional role bindings work with policy version 3
+ policyVersion = 3;
+ }
+
+ Binding binding1 =
+ Binding.newBuilder()
+ .setRole("roles/spanner.fineGrainedAccessUser")
+ .setMembers(ImmutableList.of(iamMember))
+ .build();
+
+ Binding binding2 =
+ Binding.newBuilder()
+ .setRole("roles/spanner.databaseRoleUser")
+ .setCondition(
+ Condition.newBuilder()
+ .setDescription(title)
+ .setExpression(
+ String.format("resource.name.endsWith(\"/databaseRoles/%s\")", role))
+ .setTitle(title)
+ .build())
+ .setMembers(ImmutableList.of(iamMember))
+ .build();
+ ImmutableList bindings =
+ ImmutableList.builder()
+ .addAll(policy.getBindingsList())
+ .add(binding1)
+ .add(binding2)
+ .build();
+ Policy policyWithConditions =
+ Policy.newBuilder()
+ .setVersion(policyVersion)
+ .setEtag(policy.getEtag())
+ .setBindings(bindings)
+ .build();
+ Policy response =
+ adminClient.setDatabaseIAMPolicy(instanceId, databaseId, policyWithConditions);
+ System.out.printf(
+ "Enabled fine-grained access in IAM with version %d%n", response.getVersion());
+ }
+ }
+}
+// [END spanner_enable_fine_grained_access]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/GetDatabaseDdlSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/GetDatabaseDdlSample.java
similarity index 56%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/GetDatabaseDdlSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/GetDatabaseDdlSample.java
index 250136c1fb..c7f56f4969 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/GetDatabaseDdlSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/GetDatabaseDdlSample.java
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
//[START spanner_get_database_ddl]
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import com.google.spanner.admin.database.v1.GetDatabaseDdlResponse;
-import java.io.IOException;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
+import java.util.List;
public class GetDatabaseDdlSample {
- static void getDatabaseDdl() throws IOException {
+ static void getDatabaseDdl() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
final String instanceId = "my-instance";
@@ -34,15 +34,18 @@ static void getDatabaseDdl() throws IOException {
}
static void getDatabaseDdl(
- String projectId, String instanceId, String databaseId) throws IOException {
-
- final DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
-
- final GetDatabaseDdlResponse response =
- databaseAdminClient.getDatabaseDdl(DatabaseName.of(projectId, instanceId, databaseId));
- System.out.println("Retrieved database DDL for " + databaseId);
- for (String ddl : response.getStatementsList()) {
- System.out.println(ddl);
+ String projectId, String instanceId, String databaseId) {
+ try (Spanner spanner = SpannerOptions
+ .newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService()) {
+ final DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
+ final List ddls = databaseAdminClient.getDatabaseDdl(instanceId, databaseId);
+ System.out.println("Retrieved database DDL for " + databaseId);
+ for (String ddl : ddls) {
+ System.out.println(ddl);
+ }
}
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/GetInstanceConfigSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/GetInstanceConfigSample.java
similarity index 52%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/GetInstanceConfigSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/GetInstanceConfigSample.java
index 5fc1b90747..38b6230b97 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/GetInstanceConfigSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/GetInstanceConfigSample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,36 +14,39 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
//[START spanner_get_instance_config]
-import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
-import com.google.spanner.admin.instance.v1.InstanceConfig;
-import com.google.spanner.admin.instance.v1.InstanceConfigName;
-import java.io.IOException;
+import com.google.cloud.spanner.InstanceAdminClient;
+import com.google.cloud.spanner.InstanceConfig;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
public class GetInstanceConfigSample {
- static void getInstanceConfig() throws IOException {
+ static void getInstanceConfig() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
- final String instanceConfigId = "nam6";
- getInstanceConfig(projectId, instanceConfigId);
+ final String instanceConfigName = "nam6";
+ getInstanceConfig(projectId, instanceConfigName);
}
- static void getInstanceConfig(String projectId, String instanceConfigId) throws IOException {
- try (final InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
- final InstanceConfigName instanceConfigName = InstanceConfigName.of(projectId,
- instanceConfigId);
+ static void getInstanceConfig(String projectId, String instanceConfigName) {
+ try (Spanner spanner = SpannerOptions
+ .newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService()) {
+ final InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
- final InstanceConfig instanceConfig =
- instanceAdminClient.getInstanceConfig(instanceConfigName.toString());
+ final InstanceConfig instanceConfig = instanceAdminClient
+ .getInstanceConfig(instanceConfigName);
System.out.printf(
"Available leader options for instance config %s: %s%n",
- instanceConfig.getName(),
- instanceConfig.getLeaderOptionsList()
+ instanceConfig.getId(),
+ instanceConfig.getLeaderOptions()
);
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/ListDatabaseRoles.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/ListDatabaseRoles.java
new file mode 100644
index 0000000000..ee31d874ec
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/ListDatabaseRoles.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2022 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+// [START spanner_list_database_roles]
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.DatabaseId;
+import com.google.cloud.spanner.DatabaseRole;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
+import java.util.concurrent.ExecutionException;
+
+public class ListDatabaseRoles {
+
+ static void listDatabaseRoles() throws InterruptedException, ExecutionException {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = "my-project";
+ String instanceId = "my-instance";
+ String databaseId = "my-database";
+ listDatabaseRoles(projectId, instanceId, databaseId);
+ }
+
+ static void listDatabaseRoles(String projectId, String instanceId, String databaseId) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService()) {
+ final DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
+ String databasePath = DatabaseId.of(projectId, instanceId, databaseId).getName();
+ System.out.println("List of Database roles");
+ for (DatabaseRole role : adminClient.listDatabaseRoles(instanceId, databaseId).iterateAll()) {
+ System.out.printf("%s%n", role.getName());
+ }
+ }
+ }
+}
+// [END spanner_list_database_roles]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/ListDatabasesSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/ListDatabasesSample.java
new file mode 100644
index 0000000000..4abd2c6f25
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/ListDatabasesSample.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+//[START spanner_list_databases]
+
+import com.google.api.gax.paging.Page;
+import com.google.cloud.spanner.Database;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
+
+public class ListDatabasesSample {
+
+ static void listDatabases() {
+ // TODO(developer): Replace these variables before running the sample.
+ final String projectId = "my-project";
+ final String instanceId = "my-instance";
+ listDatabases(projectId, instanceId);
+ }
+
+ static void listDatabases(String projectId, String instanceId) {
+ try (Spanner spanner = SpannerOptions
+ .newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService()) {
+ final DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
+ Page page = databaseAdminClient.listDatabases(instanceId);
+ System.out.println("Databases for projects/" + projectId + "/instances/" + instanceId);
+ while (page != null) {
+ for (Database database : page.iterateAll()) {
+ final String defaultLeader = database.getDefaultLeader().equals("")
+ ? "" : "(default leader = " + database.getDefaultLeader() + ")";
+ System.out.println("\t" + database.getId() + " " + defaultLeader);
+ }
+ page = page.getNextPage();
+ }
+ }
+ }
+}
+//[END spanner_list_databases]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/ListInstanceConfigOperationsSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/ListInstanceConfigOperationsSample.java
new file mode 100644
index 0000000000..2cf683b4c9
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/ListInstanceConfigOperationsSample.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+// [START spanner_list_instance_config_operations]
+import com.google.cloud.spanner.InstanceAdminClient;
+import com.google.cloud.spanner.Options;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.longrunning.Operation;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.spanner.admin.instance.v1.CreateInstanceConfigMetadata;
+
+public class ListInstanceConfigOperationsSample {
+ static void listInstanceConfigOperations() {
+ // TODO(developer): Replace these variables before running the sample.
+ String projectId = "my-project";
+ listInstanceConfigOperations(projectId);
+ }
+
+ static void listInstanceConfigOperations(String projectId) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
+ final InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
+
+ try {
+ System.out.printf(
+ "Getting list of instance config operations for project %s...\n",
+ projectId);
+ final Iterable instanceConfigOperations =
+ instanceAdminClient
+ .listInstanceConfigOperations(
+ Options.filter(
+ "(metadata.@type=type.googleapis.com/"
+ + "google.spanner.admin.instance.v1.CreateInstanceConfigMetadata)"))
+ .iterateAll();
+ for (Operation operation : instanceConfigOperations) {
+ CreateInstanceConfigMetadata metadata =
+ operation.getMetadata().unpack(CreateInstanceConfigMetadata.class);
+ System.out.printf(
+ "Create instance config operation for %s is %d%% completed.\n",
+ metadata.getInstanceConfig().getName(), metadata.getProgress().getProgressPercent());
+ }
+ } catch (InvalidProtocolBufferException e) {
+ System.out.printf(
+ "Error: Listing instance config operations failed with error message %s\n",
+ e.getMessage());
+ }
+ }
+ }
+}
+// [END spanner_list_instance_config_operations]
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/ListInstanceConfigsSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/ListInstanceConfigsSample.java
similarity index 53%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/ListInstanceConfigsSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/ListInstanceConfigsSample.java
index 92a0c7014e..b7753502ba 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/ListInstanceConfigsSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/ListInstanceConfigsSample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Google LLC
+ * Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,32 +14,36 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
//[START spanner_list_instance_configs]
-import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
-import com.google.spanner.admin.instance.v1.InstanceConfig;
-import com.google.spanner.admin.instance.v1.ProjectName;
-import java.io.IOException;
+import com.google.cloud.spanner.InstanceAdminClient;
+import com.google.cloud.spanner.InstanceConfig;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
public class ListInstanceConfigsSample {
- static void listInstanceConfigs() throws IOException {
+ static void listInstanceConfigs() {
// TODO(developer): Replace these variables before running the sample.
- String projectId = "my-project";
+ final String projectId = "my-project";
listInstanceConfigs(projectId);
}
- static void listInstanceConfigs(String projectId) throws IOException {
- try (final InstanceAdminClient instanceAdminClient = InstanceAdminClient.create()) {
- final ProjectName projectName = ProjectName.of(projectId);
- for (InstanceConfig instanceConfig :
- instanceAdminClient.listInstanceConfigs(projectName).iterateAll()) {
+ static void listInstanceConfigs(String projectId) {
+ try (Spanner spanner = SpannerOptions
+ .newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService()) {
+ final InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
+
+ for (InstanceConfig instanceConfig : instanceAdminClient.listInstanceConfigs().iterateAll()) {
System.out.printf(
"Available leader options for instance config %s: %s%n",
- instanceConfig.getName(),
- instanceConfig.getLeaderOptionsList()
+ instanceConfig.getId(),
+ instanceConfig.getLeaderOptions()
);
}
}
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/PgAlterSequenceSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgAlterSequenceSample.java
similarity index 86%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/PgAlterSequenceSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/PgAlterSequenceSample.java
index 39a4cd543a..10bccc2cb4 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/PgAlterSequenceSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgAlterSequenceSample.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_postgresql_alter_sequence]
-
+import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.ResultSet;
@@ -25,18 +25,14 @@
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class PgAlterSequenceSample {
-
- static void pgAlterSequence() throws IOException {
+ static void pgAlterSequence() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
final String instanceId = "my-instance";
@@ -44,15 +40,16 @@ static void pgAlterSequence() throws IOException {
pgAlterSequence(projectId, instanceId, databaseId);
}
- static void pgAlterSequence(String projectId, String instanceId, String databaseId)
- throws IOException {
+ static void pgAlterSequence(String projectId, String instanceId, String databaseId) {
try (Spanner spanner =
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- final DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
- databaseAdminClient
- .updateDatabaseDdlAsync(
- DatabaseName.of(projectId, instanceId, databaseId),
- ImmutableList.of("ALTER SEQUENCE Seq SKIP RANGE 1000 5000000"))
+ final DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
+ dbAdminClient
+ .updateDatabaseDdl(
+ instanceId,
+ databaseId,
+ ImmutableList.of("ALTER SEQUENCE Seq SKIP RANGE 1000 5000000"),
+ null)
.get(5, TimeUnit.MINUTES);
System.out.println(
"Altered Seq sequence to skip an inclusive range between 1000 and 5000000");
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/PgCaseSensitivitySample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgCaseSensitivitySample.java
similarity index 80%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/PgCaseSensitivitySample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/PgCaseSensitivitySample.java
index 951b46446f..a9096c0c2e 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/PgCaseSensitivitySample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgCaseSensitivitySample.java
@@ -14,10 +14,12 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_postgresql_identifier_case_sensitivity]
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Mutation;
@@ -26,16 +28,13 @@
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
-import com.google.common.collect.Lists;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
+import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
public class PgCaseSensitivitySample {
- static void pgCaseSensitivity() throws IOException {
+ static void pgCaseSensitivity() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
final String instanceId = "my-instance";
@@ -43,33 +42,35 @@ static void pgCaseSensitivity() throws IOException {
pgCaseSensitivity(projectId, instanceId, databaseId);
}
- static void pgCaseSensitivity(String projectId, String instanceId, String databaseId)
- throws IOException {
- DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
-
+ static void pgCaseSensitivity(String projectId, String instanceId, String databaseId) {
try (Spanner spanner =
SpannerOptions.newBuilder()
.setProjectId(projectId)
.build()
.getService()) {
+ final DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
// Spanner PostgreSQL follows the case sensitivity rules of PostgreSQL. This means that:
// 1. Identifiers that are not double-quoted are folded to lower case.
// 2. Identifiers that are double-quoted retain their case and are case-sensitive.
// See https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
// for more information.
- databaseAdminClient.updateDatabaseDdlAsync(
- DatabaseName.of(projectId, instanceId, databaseId),
- Lists.newArrayList(
- "CREATE TABLE Singers ("
- // SingerId will be folded to `singerid`.
- + " SingerId bigint NOT NULL PRIMARY KEY,"
- // FirstName and LastName are double-quoted and will therefore retain their
- // mixed case and are case-sensitive. This means that any statement that
- // references any of these columns must use double quotes.
- + " \"FirstName\" varchar(1024) NOT NULL,"
- + " \"LastName\" varchar(1024) NOT NULL"
- + ")")).get();
+ final OperationFuture updateOperation =
+ databaseAdminClient.updateDatabaseDdl(
+ instanceId,
+ databaseId,
+ Collections.singleton(
+ "CREATE TABLE Singers ("
+ // SingerId will be folded to `singerid`.
+ + " SingerId bigint NOT NULL PRIMARY KEY,"
+ // FirstName and LastName are double-quoted and will therefore retain their
+ // mixed case and are case-sensitive. This means that any statement that
+ // references any of these columns must use double quotes.
+ + " \"FirstName\" varchar(1024) NOT NULL,"
+ + " \"LastName\" varchar(1024) NOT NULL"
+ + ")"),
+ null);
+ updateOperation.get();
DatabaseClient client =
spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId));
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/PgCreateSequenceSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgCreateSequenceSample.java
similarity index 85%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/PgCreateSequenceSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/PgCreateSequenceSample.java
index 6e7d9c34c5..070f62f70f 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/PgCreateSequenceSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgCreateSequenceSample.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_postgresql_create_sequence]
-
+import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.ResultSet;
@@ -25,18 +25,14 @@
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class PgCreateSequenceSample {
-
- static void pgCreateSequence() throws IOException {
+ static void pgCreateSequence() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
final String instanceId = "my-instance";
@@ -44,22 +40,24 @@ static void pgCreateSequence() throws IOException {
pgCreateSequence(projectId, instanceId, databaseId);
}
- static void pgCreateSequence(String projectId, String instanceId, String databaseId)
- throws IOException {
- DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
-
+ static void pgCreateSequence(String projectId, String instanceId, String databaseId) {
try (Spanner spanner =
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- databaseAdminClient
- .updateDatabaseDdlAsync(DatabaseName.of(projectId, instanceId, databaseId).toString(),
+ final DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
+
+ dbAdminClient
+ .updateDatabaseDdl(
+ instanceId,
+ databaseId,
ImmutableList.of(
"CREATE SEQUENCE Seq BIT_REVERSED_POSITIVE;",
"CREATE TABLE Customers (CustomerId BIGINT DEFAULT nextval('Seq'), "
- + "CustomerName character varying(1024), PRIMARY KEY (CustomerId))"))
+ + "CustomerName character varying(1024), PRIMARY KEY (CustomerId))"),
+ null)
.get(5, TimeUnit.MINUTES);
System.out.println(
- "Created Seq sequence and Customers table, where the key column "
+ "Created Seq sequence and Customers table, where its key column "
+ "CustomerId uses the sequence as a default value");
final DatabaseClient dbClient =
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/PgDropSequenceSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgDropSequenceSample.java
similarity index 81%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/PgDropSequenceSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/PgDropSequenceSample.java
index dec927d20a..26e8eb74bb 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/PgDropSequenceSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgDropSequenceSample.java
@@ -14,24 +14,20 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_postgresql_drop_sequence]
-
+import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class PgDropSequenceSample {
-
- static void pgDropSequence() throws IOException {
+ static void pgDropSequence() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
final String instanceId = "my-instance";
@@ -39,18 +35,18 @@ static void pgDropSequence() throws IOException {
pgDropSequence(projectId, instanceId, databaseId);
}
- static void pgDropSequence(String projectId, String instanceId, String databaseId)
- throws IOException {
- DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
-
+ static void pgDropSequence(String projectId, String instanceId, String databaseId) {
try (Spanner spanner =
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
- databaseAdminClient
- .updateDatabaseDdlAsync(
- DatabaseName.of(projectId, instanceId, databaseId),
+ final DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
+ dbAdminClient
+ .updateDatabaseDdl(
+ instanceId,
+ databaseId,
ImmutableList.of(
"ALTER TABLE Customers ALTER COLUMN CustomerId DROP DEFAULT",
- "DROP SEQUENCE Seq"))
+ "DROP SEQUENCE Seq"),
+ null)
.get(5, TimeUnit.MINUTES);
System.out.println(
"Altered Customers table to drop DEFAULT from "
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/generated/PgInterleavedTableSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgInterleavedTableSample.java
similarity index 57%
rename from samples/snippets/src/main/java/com/example/spanner/admin/generated/PgInterleavedTableSample.java
rename to samples/snippets/src/main/java/com/example/spanner/admin/archived/PgInterleavedTableSample.java
index 14af53dc5a..007843a4a2 100644
--- a/samples/snippets/src/main/java/com/example/spanner/admin/generated/PgInterleavedTableSample.java
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgInterleavedTableSample.java
@@ -14,20 +14,22 @@
* limitations under the License.
*/
-package com.example.spanner.admin.generated;
+package com.example.spanner.admin.archived;
// [START spanner_postgresql_interleaved_table]
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
-import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
-import com.google.spanner.admin.database.v1.DatabaseName;
-import java.io.IOException;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
import java.util.Arrays;
import java.util.concurrent.ExecutionException;
public class PgInterleavedTableSample {
- static void pgInterleavedTable() throws IOException {
+ static void pgInterleavedTable() {
// TODO(developer): Replace these variables before running the sample.
final String projectId = "my-project";
final String instanceId = "my-instance";
@@ -35,29 +37,36 @@ static void pgInterleavedTable() throws IOException {
pgInterleavedTable(projectId, instanceId, databaseId);
}
- static void pgInterleavedTable(String projectId, String instanceId, String databaseId)
- throws IOException {
- DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create();
- try {
+ static void pgInterleavedTable(String projectId, String instanceId, String databaseId) {
+ try (Spanner spanner =
+ SpannerOptions.newBuilder()
+ .setProjectId(projectId)
+ .build()
+ .getService()) {
+ final DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
+
// The Spanner PostgreSQL dialect extends the PostgreSQL dialect with certain Spanner
// specific features, such as interleaved tables.
// See https://cloud.google.com/spanner/docs/postgresql/data-definition-language#create_table
// for the full CREATE TABLE syntax.
- databaseAdminClient.updateDatabaseDdlAsync(DatabaseName.of(projectId,
+ final OperationFuture updateOperation =
+ databaseAdminClient.updateDatabaseDdl(
instanceId,
- databaseId),
- Arrays.asList(
- "CREATE TABLE Singers ("
- + " SingerId bigint NOT NULL PRIMARY KEY,"
- + " FirstName varchar(1024) NOT NULL,"
- + " LastName varchar(1024) NOT NULL"
- + ")",
- "CREATE TABLE Albums ("
- + " SingerId bigint NOT NULL,"
- + " AlbumId bigint NOT NULL,"
- + " Title varchar(1024) NOT NULL,"
- + " PRIMARY KEY (SingerId, AlbumId)"
- + ") INTERLEAVE IN PARENT Singers ON DELETE CASCADE")).get();
+ databaseId,
+ Arrays.asList(
+ "CREATE TABLE Singers ("
+ + " SingerId bigint NOT NULL PRIMARY KEY,"
+ + " FirstName varchar(1024) NOT NULL,"
+ + " LastName varchar(1024) NOT NULL"
+ + ")",
+ "CREATE TABLE Albums ("
+ + " SingerId bigint NOT NULL,"
+ + " AlbumId bigint NOT NULL,"
+ + " Title varchar(1024) NOT NULL,"
+ + " PRIMARY KEY (SingerId, AlbumId)"
+ + ") INTERLEAVE IN PARENT Singers ON DELETE CASCADE"),
+ null);
+ updateOperation.get();
System.out.println("Created interleaved table hierarchy using PostgreSQL dialect");
} catch (ExecutionException e) {
// If the operation failed during execution, expose the cause.
diff --git a/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgSpannerSample.java b/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgSpannerSample.java
new file mode 100644
index 0000000000..8a95cebef0
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/spanner/admin/archived/PgSpannerSample.java
@@ -0,0 +1,1585 @@
+/*
+ * Copyright 2022 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.spanner.admin.archived;
+
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.api.gax.paging.Page;
+import com.google.cloud.ByteArray;
+import com.google.cloud.Date;
+import com.google.cloud.Timestamp;
+import com.google.cloud.spanner.Database;
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.DatabaseClient;
+import com.google.cloud.spanner.DatabaseId;
+import com.google.cloud.spanner.Dialect;
+import com.google.cloud.spanner.Instance;
+import com.google.cloud.spanner.InstanceAdminClient;
+import com.google.cloud.spanner.InstanceId;
+import com.google.cloud.spanner.Key;
+import com.google.cloud.spanner.KeyRange;
+import com.google.cloud.spanner.KeySet;
+import com.google.cloud.spanner.Mutation;
+import com.google.cloud.spanner.Options;
+import com.google.cloud.spanner.ReadOnlyTransaction;
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerBatchUpdateException;
+import com.google.cloud.spanner.SpannerException;
+import com.google.cloud.spanner.SpannerExceptionFactory;
+import com.google.cloud.spanner.SpannerOptions;
+import com.google.cloud.spanner.Statement;
+import com.google.cloud.spanner.Struct;
+import com.google.cloud.spanner.TimestampBound;
+import com.google.cloud.spanner.Value;
+import com.google.common.io.BaseEncoding;
+import com.google.longrunning.Operation;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.spanner.admin.database.v1.CreateBackupMetadata;
+import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
+import com.google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata;
+import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
+import com.google.spanner.v1.ExecuteSqlRequest;
+import java.math.BigDecimal;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Example code for using the Cloud Spanner PostgreSQL interface.
+ */
+public class PgSpannerSample {
+ // [START spanner_postgresql_insert_data]
+ static final List SINGERS =
+ Arrays.asList(
+ new Singer(1, "Marc", "Richards"),
+ new Singer(2, "Catalina", "Smith"),
+ new Singer(3, "Alice", "Trentor"),
+ new Singer(4, "Lea", "Martin"),
+ new Singer(5, "David", "Lomond"));
+ static final List ALBUMS =
+ Arrays.asList(
+ new Album(1, 1, "Total Junk"),
+ new Album(1, 2, "Go, Go, Go"),
+ new Album(2, 1, "Green"),
+ new Album(2, 2, "Forever Hold Your Peace"),
+ new Album(2, 3, "Terrified"));
+ // [END spanner_postgresql_insert_data]
+
+ /** Class to contain performance sample data. */
+ static class Performance {
+
+ final long singerId;
+ final long venueId;
+ final String eventDate;
+ final long revenue;
+
+ Performance(long singerId, long venueId, String eventDate, long revenue) {
+ this.singerId = singerId;
+ this.venueId = venueId;
+ this.eventDate = eventDate;
+ this.revenue = revenue;
+ }
+ }
+
+ // [START spanner_postgresql_insert_data_with_timestamp_column]
+ static final List PERFORMANCES =
+ Arrays.asList(
+ new Performance(1, 4, "2017-10-05", 11000),
+ new Performance(1, 19, "2017-11-02", 15000),
+ new Performance(2, 42, "2017-12-23", 7000));
+ // [START spanner_postgresql_insert_datatypes_data]
+
+ static Value availableDates1 =
+ Value.dateArray(
+ Arrays.asList(
+ Date.parseDate("2020-12-01"),
+ Date.parseDate("2020-12-02"),
+ Date.parseDate("2020-12-03")));
+ static Value availableDates2 =
+ Value.dateArray(
+ Arrays.asList(
+ Date.parseDate("2020-11-01"),
+ Date.parseDate("2020-11-05"),
+ Date.parseDate("2020-11-15")));
+ static Value availableDates3 =
+ Value.dateArray(Arrays.asList(Date.parseDate("2020-10-01"), Date.parseDate("2020-10-07")));
+ // [END spanner_postgresql_insert_data_with_timestamp_column]
+ static String exampleBytes1 = BaseEncoding.base64().encode("Hello World 1".getBytes());
+ static String exampleBytes2 = BaseEncoding.base64().encode("Hello World 2".getBytes());
+ static String exampleBytes3 = BaseEncoding.base64().encode("Hello World 3".getBytes());
+ static final List