Skip to content

Commit

Permalink
feat: PostgreSQL dialect databases (#1673)
Browse files Browse the repository at this point in the history
* feat: PostgreSQL dialect databases

* 🦉 Updates from OwlBot

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* fix: add clirr differences

* fix: do not join type names for every invocation

* 🦉 Updates from OwlBot

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* fix: revert to showing column index

* test: add parameterization for ITBatchReadTest

* test: parameterize BatchReadTest and skip unsupported tests

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
  • Loading branch information
olavloite and gcf-owl-bot[bot] authored Feb 10, 2022
1 parent 8ea2220 commit 5f156f2
Show file tree
Hide file tree
Showing 91 changed files with 11,073 additions and 6,824 deletions.
13 changes: 13 additions & 0 deletions google-cloud-spanner/clirr-ignored-differences.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- see http://www.mojohaus.org/clirr-maven-plugin/examples/ignored-differences.html -->
<differences>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/connection/Connection</className>
<method>com.google.cloud.spanner.Dialect getDialect()</method>
</difference>
<difference>
<differenceType>8001</differenceType>
<className>com/google/cloud/spanner/connection/StatementParser</className>
</difference>
</differences>
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,9 @@ private Object writeReplace() {
case NUMERIC:
builder.set(fieldName).to((BigDecimal) value);
break;
case PG_NUMERIC:
builder.set(fieldName).to((String) value);
break;
case STRING:
builder.set(fieldName).to((String) value);
break;
Expand All @@ -391,7 +394,8 @@ private Object writeReplace() {
builder.set(fieldName).to((Date) value);
break;
case ARRAY:
switch (fieldType.getArrayElementType().getCode()) {
final Type elementType = fieldType.getArrayElementType();
switch (elementType.getCode()) {
case BOOL:
builder.set(fieldName).toBoolArray((Iterable<Boolean>) value);
break;
Expand All @@ -404,6 +408,9 @@ private Object writeReplace() {
case NUMERIC:
builder.set(fieldName).toNumericArray((Iterable<BigDecimal>) value);
break;
case PG_NUMERIC:
builder.set(fieldName).toPgNumericArray((Iterable<String>) value);
break;
case STRING:
builder.set(fieldName).toStringArray((Iterable<String>) value);
break;
Expand All @@ -420,13 +427,10 @@ private Object writeReplace() {
builder.set(fieldName).toDateArray((Iterable<Date>) value);
break;
case STRUCT:
builder
.set(fieldName)
.toStructArray(fieldType.getArrayElementType(), (Iterable<Struct>) value);
builder.set(fieldName).toStructArray(elementType, (Iterable<Struct>) value);
break;
default:
throw new AssertionError(
"Unhandled array type code: " + fieldType.getArrayElementType());
throw new AssertionError("Unhandled array type code: " + elementType);
}
break;
case STRUCT:
Expand Down Expand Up @@ -484,7 +488,11 @@ private static Object decodeValue(Type fieldType, com.google.protobuf.Value prot
case FLOAT64:
return valueProtoToFloat64(proto);
case NUMERIC:
checkType(fieldType, proto, KindCase.STRING_VALUE);
return new BigDecimal(proto.getStringValue());
case PG_NUMERIC:
checkType(fieldType, proto, KindCase.STRING_VALUE);
return proto.getStringValue();
case STRING:
case JSON:
checkType(fieldType, proto, KindCase.STRING_VALUE);
Expand Down Expand Up @@ -549,6 +557,10 @@ static Object decodeArrayValue(Type elementType, ListValue listValue) {
}
return list;
}
case PG_NUMERIC:
return Lists.transform(
listValue.getValuesList(),
input -> input.getKindCase() == KindCase.NULL_VALUE ? null : input.getStringValue());
case STRING:
case JSON:
return Lists.transform(
Expand Down Expand Up @@ -695,6 +707,8 @@ protected Value getValueInternal(int columnIndex) {
return Value.int64(isNull ? null : getLongInternal(columnIndex));
case NUMERIC:
return Value.numeric(isNull ? null : getBigDecimalInternal(columnIndex));
case PG_NUMERIC:
return Value.pgNumeric(isNull ? null : getStringInternal(columnIndex));
case FLOAT64:
return Value.float64(isNull ? null : getDoubleInternal(columnIndex));
case STRING:
Expand All @@ -708,13 +722,16 @@ protected Value getValueInternal(int columnIndex) {
case STRUCT:
return Value.struct(isNull ? null : getStructInternal(columnIndex));
case ARRAY:
switch (columnType.getArrayElementType().getCode()) {
final Type elementType = columnType.getArrayElementType();
switch (elementType.getCode()) {
case BOOL:
return Value.boolArray(isNull ? null : getBooleanListInternal(columnIndex));
case INT64:
return Value.int64Array(isNull ? null : getLongListInternal(columnIndex));
case NUMERIC:
return Value.numericArray(isNull ? null : getBigDecimalListInternal(columnIndex));
case PG_NUMERIC:
return Value.pgNumericArray(isNull ? null : getStringListInternal(columnIndex));
case FLOAT64:
return Value.float64Array(isNull ? null : getDoubleListInternal(columnIndex));
case STRING:
Expand All @@ -727,8 +744,7 @@ protected Value getValueInternal(int columnIndex) {
return Value.dateArray(isNull ? null : getDateListInternal(columnIndex));
case STRUCT:
return Value.structArray(
columnType.getArrayElementType(),
isNull ? null : getStructListInternal(columnIndex));
elementType, isNull ? null : getStructListInternal(columnIndex));
default:
throw new IllegalArgumentException(
"Invalid array value type " + this.type.getArrayElementType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.google.cloud.Date;
import com.google.cloud.Timestamp;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

/**
Expand Down Expand Up @@ -159,14 +160,19 @@ public BigDecimal getBigDecimal(String columnName) {

@Override
public String getString(int columnIndex) {
checkNonNullOfType(columnIndex, Type.string(), columnIndex);
checkNonNullOfTypes(
columnIndex,
Arrays.asList(Type.string(), Type.pgNumeric()),
columnIndex,
"STRING, NUMERIC");
return getStringInternal(columnIndex);
}

@Override
public String getString(String columnName) {
int columnIndex = getColumnIndex(columnName);
checkNonNullOfType(columnIndex, Type.string(), columnName);
checkNonNullOfTypes(
columnIndex, Arrays.asList(Type.string(), Type.pgNumeric()), columnName, "STRING, NUMERIC");
return getStringInternal(columnIndex);
}

Expand Down Expand Up @@ -327,14 +333,22 @@ public List<BigDecimal> getBigDecimalList(String columnName) {

@Override
public List<String> getStringList(int columnIndex) {
checkNonNullOfType(columnIndex, Type.array(Type.string()), columnIndex);
checkNonNullOfTypes(
columnIndex,
Arrays.asList(Type.array(Type.string()), Type.array(Type.pgNumeric())),
columnIndex,
"ARRAY<STRING>, ARRAY<NUMERIC>");
return getStringListInternal(columnIndex);
}

@Override
public List<String> getStringList(String columnName) {
int columnIndex = getColumnIndex(columnName);
checkNonNullOfType(columnIndex, Type.array(Type.string()), columnName);
checkNonNullOfTypes(
columnIndex,
Arrays.asList(Type.array(Type.string()), Type.array(Type.pgNumeric())),
columnName,
"ARRAY<STRING>, ARRAY<NUMERIC>");
return getStringListInternal(columnIndex);
}

Expand Down Expand Up @@ -429,6 +443,21 @@ private void checkNonNullOfType(int columnIndex, Type expectedType, Object colum
checkNonNull(columnIndex, columnNameForError);
}

private void checkNonNullOfTypes(
int columnIndex,
List<Type> expectedTypes,
Object columnNameForError,
String expectedTypeNames) {
Type actualType = getColumnType(columnIndex);
checkState(
expectedTypes.contains(actualType),
"Column %s is not of correct type: expected one of [%s] but was %s",
columnNameForError,
expectedTypeNames,
actualType);
checkNonNull(columnIndex, columnNameForError);
}

private void checkNonNullArrayOfStruct(int columnIndex, Object columnNameForError) {
Type actualType = getColumnType(columnIndex);
checkState(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ static Database fromProto(
.setEarliestVersionTime(Timestamp.fromProto(proto.getEarliestVersionTime()))
.setEncryptionConfig(CustomerManagedEncryption.fromProtoOrNull(proto.getEncryptionConfig()))
.setDefaultLeader(proto.getDefaultLeader())
.setDialect(Dialect.fromProto(proto.getDatabaseDialect()))
.setProto(proto)
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.google.cloud.Policy;
import com.google.cloud.Policy.DefaultMarshaller;
import com.google.cloud.Timestamp;
import com.google.cloud.spanner.DatabaseInfo.State;
import com.google.cloud.spanner.Options.ListOption;
import com.google.cloud.spanner.SpannerImpl.PageFetcher;
import com.google.cloud.spanner.spi.v1.SpannerRpc;
Expand Down Expand Up @@ -281,14 +280,18 @@ public Backup fromProto(com.google.spanner.admin.database.v1.Backup proto) {
public OperationFuture<Database, CreateDatabaseMetadata> createDatabase(
String instanceId, String databaseId, Iterable<String> statements) throws SpannerException {
return createDatabase(
new Database(DatabaseId.of(projectId, instanceId, databaseId), State.UNSPECIFIED, this),
newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId))
.setDialect(Dialect.GOOGLE_STANDARD_SQL)
.build(),
statements);
}

@Override
public OperationFuture<Database, CreateDatabaseMetadata> createDatabase(
Database database, Iterable<String> statements) throws SpannerException {
String createStatement = "CREATE DATABASE `" + database.getId().getDatabase() + "`";
final Dialect dialect = Preconditions.checkNotNull(database.getDialect());
final String createStatement =
dialect.createDatabaseStatementFor(database.getId().getDatabase());
OperationFuture<com.google.spanner.admin.database.v1.Database, CreateDatabaseMetadata>
rawOperationFuture =
rpc.createDatabase(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ public Builder setDefaultLeader(String defaultLeader) {
throw new UnsupportedOperationException("Unimplemented");
}

public Builder setDialect(Dialect dialect) {
throw new UnsupportedOperationException("Unimplemented");
}

abstract Builder setProto(com.google.spanner.admin.database.v1.Database proto);

/** Builds the database from this builder. */
Expand All @@ -69,6 +73,7 @@ abstract static class BuilderImpl extends Builder {
private Timestamp earliestVersionTime;
private CustomerManagedEncryption encryptionConfig;
private String defaultLeader;
private Dialect dialect = Dialect.GOOGLE_STANDARD_SQL;
private com.google.spanner.admin.database.v1.Database proto;

BuilderImpl(DatabaseId id) {
Expand All @@ -84,6 +89,7 @@ abstract static class BuilderImpl extends Builder {
this.earliestVersionTime = other.earliestVersionTime;
this.encryptionConfig = other.encryptionConfig;
this.defaultLeader = other.defaultLeader;
this.dialect = other.dialect;
this.proto = other.proto;
}

Expand Down Expand Up @@ -129,6 +135,12 @@ public Builder setDefaultLeader(String defaultLeader) {
return this;
}

@Override
public Builder setDialect(Dialect dialect) {
this.dialect = dialect;
return this;
}

@Override
Builder setProto(@Nullable com.google.spanner.admin.database.v1.Database proto) {
this.proto = proto;
Expand Down Expand Up @@ -156,6 +168,7 @@ public enum State {
private final Timestamp earliestVersionTime;
private final CustomerManagedEncryption encryptionConfig;
private final String defaultLeader;
private final Dialect dialect;
private final com.google.spanner.admin.database.v1.Database proto;

public DatabaseInfo(DatabaseId id, State state) {
Expand All @@ -167,6 +180,7 @@ public DatabaseInfo(DatabaseId id, State state) {
this.earliestVersionTime = null;
this.encryptionConfig = null;
this.defaultLeader = null;
this.dialect = null;
this.proto = null;
}

Expand All @@ -179,6 +193,7 @@ public DatabaseInfo(DatabaseId id, State state) {
this.earliestVersionTime = builder.earliestVersionTime;
this.encryptionConfig = builder.encryptionConfig;
this.defaultLeader = builder.defaultLeader;
this.dialect = builder.dialect;
this.proto = builder.proto;
}

Expand Down Expand Up @@ -239,6 +254,14 @@ public Timestamp getEarliestVersionTime() {
return defaultLeader;
}

/**
* The dialect that is used by the database. It can be one of the values as specified in {@link
* Dialect#values()}.
*/
public @Nullable Dialect getDialect() {
return dialect;
}

/** Returns the raw proto instance that was used to construct this {@link Database}. */
public @Nullable com.google.spanner.admin.database.v1.Database getProto() {
return proto;
Expand All @@ -260,7 +283,8 @@ public boolean equals(Object o) {
&& Objects.equals(versionRetentionPeriod, that.versionRetentionPeriod)
&& Objects.equals(earliestVersionTime, that.earliestVersionTime)
&& Objects.equals(encryptionConfig, that.encryptionConfig)
&& Objects.equals(defaultLeader, that.defaultLeader);
&& Objects.equals(defaultLeader, that.defaultLeader)
&& Objects.equals(dialect, that.dialect);
}

@Override
Expand All @@ -273,20 +297,22 @@ public int hashCode() {
versionRetentionPeriod,
earliestVersionTime,
encryptionConfig,
defaultLeader);
defaultLeader,
dialect);
}

@Override
public String toString() {
return String.format(
"Database[%s, %s, %s, %s, %s, %s, %s, %s]",
"Database[%s, %s, %s, %s, %s, %s, %s, %s, %s]",
id.getName(),
state,
createTime,
restoreInfo,
versionRetentionPeriod,
earliestVersionTime,
encryptionConfig,
defaultLeader);
defaultLeader,
dialect);
}
}
Loading

0 comments on commit 5f156f2

Please sign in to comment.