From b95f57765975456a9590b1c595416e65632e94ae Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Fri, 27 Jan 2023 07:19:06 +0000 Subject: [PATCH 01/25] feat: add code changes and tests for Proto columns DDL support --- README.md | 6 +- google-cloud-spanner/pom.xml | 5 +- .../com/google/cloud/spanner/Database.java | 6 + .../cloud/spanner/DatabaseAdminClient.java | 14 +- .../spanner/DatabaseAdminClientImpl.java | 18 +- .../google/cloud/spanner/DatabaseInfo.java | 50 ++- .../java/com/google/cloud/spanner/Type.java | 43 +- .../database/v1/DatabaseAdminClient.java | 6 + .../database/v1/DatabaseAdminSettings.java | 5 +- .../v1/stub/DatabaseAdminStubSettings.java | 5 +- .../instance/v1/InstanceAdminSettings.java | 5 +- .../v1/stub/InstanceAdminStubSettings.java | 5 +- .../cloud/spanner/spi/v1/GapicSpannerRpc.java | 17 +- .../cloud/spanner/spi/v1/SpannerRpc.java | 7 +- .../cloud/spanner/v1/SpannerSettings.java | 5 +- .../spanner/v1/stub/SpannerStubSettings.java | 5 +- .../spanner/DatabaseAdminClientImplTest.java | 38 +- .../cloud/spanner/GceTestEnvConfig.java | 1 + .../v1/DatabaseAdminClientHttpJsonTest.java | 10 +- .../database/v1/DatabaseAdminClientTest.java | 10 +- .../spanner/it/ITCreateDatabaseProtos.java | 307 ++++++++++++++ .../cloud/spanner/it/ITProtoColumnTest.java | 102 ++++- .../v1/CreateDatabaseRequestOrBuilder.java | 27 ++ .../database/v1/GetDatabaseDdlResponse.java | 111 +++++ .../v1/GetDatabaseDdlResponseOrBuilder.java | 17 + .../v1/SpannerDatabaseAdminProto.java | 395 +++++++++--------- .../database/v1/UpdateDatabaseDdlRequest.java | 171 ++++++++ .../v1/UpdateDatabaseDdlRequestOrBuilder.java | 32 ++ .../database/v1/spanner_database_admin.proto | 46 ++ 29 files changed, 1214 insertions(+), 255 deletions(-) create mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java diff --git a/README.md b/README.md index baac29f6974..86dbd0f39c0 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ If you are using Maven without BOM, add this to your dependencies: If you are using Gradle 5.x or later, add this to your dependencies: ```Groovy -implementation platform('com.google.cloud:libraries-bom:26.2.0') +implementation platform('com.google.cloud:libraries-bom:26.3.0') implementation 'com.google.cloud:google-cloud-spanner' ``` @@ -261,6 +261,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/ | Create Backup With Encryption Key | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateBackupWithEncryptionKey.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/CreateBackupWithEncryptionKey.java) | | Create Database With Default Leader Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithDefaultLeaderSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithDefaultLeaderSample.java) | | Create Database With Encryption Key | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithEncryptionKey.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithEncryptionKey.java) | +| Create Database With Proto Descriptor | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithProtoDescriptor.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithProtoDescriptor.java) | | Create Database With Version Retention Period Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithVersionRetentionPeriodSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithVersionRetentionPeriodSample.java) | | Create Instance Config Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateInstanceConfigSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/CreateInstanceConfigSample.java) | | Create Instance Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateInstanceExample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/CreateInstanceExample.java) | @@ -290,12 +291,14 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/ | Pg Spanner Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/PgSpannerSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/PgSpannerSample.java) | | Pg Update Using Dml Returning Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/PgUpdateUsingDmlReturningSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/PgUpdateUsingDmlReturningSample.java) | | Query Information Schema Database Options Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/QueryInformationSchemaDatabaseOptionsSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/QueryInformationSchemaDatabaseOptionsSample.java) | +| Query Proto Column Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/QueryProtoColumnSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/QueryProtoColumnSample.java) | | Query With Json Parameter Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/QueryWithJsonParameterSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/QueryWithJsonParameterSample.java) | | Query With Jsonb Parameter Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/QueryWithJsonbParameterSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/QueryWithJsonbParameterSample.java) | | Query With Numeric Parameter Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/QueryWithNumericParameterSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/QueryWithNumericParameterSample.java) | | Quickstart Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/QuickstartSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/QuickstartSample.java) | | Read Data With Database Role | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/ReadDataWithDatabaseRole.java) | | Restore Backup With Encryption Key | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/RestoreBackupWithEncryptionKey.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/RestoreBackupWithEncryptionKey.java) | +| Singer Proto | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/SingerProto.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/SingerProto.java) | | Spanner Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/SpannerSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/SpannerSample.java) | | Statement Timeout Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/StatementTimeoutExample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/StatementTimeoutExample.java) | | Tag Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/TagSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/TagSample.java) | @@ -305,6 +308,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/ | Update Json Data Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/UpdateJsonDataSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/UpdateJsonDataSample.java) | | Update Jsonb Data Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/UpdateJsonbDataSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/UpdateJsonbDataSample.java) | | Update Numeric Data Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/UpdateNumericDataSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/UpdateNumericDataSample.java) | +| Update Proto Column Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/UpdateProtoColumnSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/UpdateProtoColumnSample.java) | | Update Using Dml Returning Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/UpdateUsingDmlReturningSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/UpdateUsingDmlReturningSample.java) | diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index c8246a4bd16..0ea72e5300b 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -18,8 +18,9 @@ 0.31.1 22.3.0 com.google.cloud.spanner.GceTestEnvConfig - projects/gcloud-devel/instances/spanner-testing-east1 - gcloud-devel + projects/span-cloud-testing/instances/harsha-test-gcloud + span-cloud-testing + https://staging-wrenchworks.sandbox.googleapis.com projects/gcloud-devel/locations/us-east1/keyRings/cmek-test-key-ring/cryptoKeys/cmek-test-key diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java index 94c30c9c702..89206119c79 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java @@ -25,6 +25,7 @@ import com.google.cloud.spanner.encryption.CustomerManagedEncryption; import com.google.common.base.Preconditions; import com.google.longrunning.Operation; +import com.google.protobuf.ByteString; import com.google.spanner.admin.database.v1.CreateBackupMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; @@ -88,6 +89,11 @@ public OperationFuture updateDdl( return dbClient.updateDatabaseDdl(instance(), database(), statements, operationId); } + public OperationFuture updateDdl( + Iterable statements, String operationId, byte[] protoDescriptors) throws SpannerException { + return dbClient.updateDatabaseDdl(instance(), database(), statements, operationId, protoDescriptors); + } + /** Drops this database. */ public void drop() throws SpannerException { dbClient.dropDatabase(instance(), database()); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java index 1363118e3aa..69e1c6187e3 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java @@ -22,10 +22,12 @@ import com.google.cloud.Timestamp; import com.google.cloud.spanner.Options.ListOption; import com.google.longrunning.Operation; +import com.google.protobuf.ByteString; 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.GetDatabaseDdlResponse; import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import java.util.List; @@ -383,7 +385,7 @@ OperationFuture restoreDatabase(Restore resto *

If an operation already exists with the given operation id, the operation will be resumed * and the returned future will complete when the original operation finishes. See more * information in {@link com.google.cloud.spanner.spi.v1.GapicSpannerRpc#updateDatabaseDdl(String, - * Iterable, String)} + * Iterable, String, ByteString)} * *

Example to update the database DDL. * @@ -407,6 +409,14 @@ OperationFuture updateDatabaseDdl( @Nullable String operationId) throws SpannerException; + OperationFuture updateDatabaseDdl( + String instanceId, + String databaseId, + Iterable statements, + @Nullable String operationId, + @Nullable byte[] protoDescriptors) + throws SpannerException; + /** * Drops a Cloud Spanner database. * @@ -434,6 +444,8 @@ OperationFuture updateDatabaseDdl( */ List getDatabaseDdl(String instanceId, String databaseId); + GetDatabaseDdlResponse getDatabaseDdlWithProtoDescriptors(String instanceId, String databaseId); + /** * Returns the list of Cloud Spanner database in the given instance. * diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java index 73ece214c3a..9f170096386 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java @@ -31,6 +31,7 @@ import com.google.common.base.Preconditions; import com.google.iam.v1.GetPolicyOptions; import com.google.longrunning.Operation; +import com.google.protobuf.ByteString; import com.google.protobuf.Empty; import com.google.protobuf.FieldMask; import com.google.spanner.admin.database.v1.*; @@ -415,17 +416,25 @@ public Database getDatabase(String instanceId, String databaseId) throws Spanner return Database.fromProto(rpc.getDatabase(dbName), DatabaseAdminClientImpl.this); } + @Override + public OperationFuture updateDatabaseDdl(String instanceId, + String databaseId, Iterable statements, @Nullable String operationId) + throws SpannerException { + return updateDatabaseDdl(instanceId, databaseId, statements, operationId, null); + } + @Override public OperationFuture updateDatabaseDdl( final String instanceId, final String databaseId, final Iterable statements, - @Nullable String operationId) + @Nullable String operationId, + @Nullable byte[] protoDescriptors) throws SpannerException { final String dbName = getDatabaseName(instanceId, databaseId); final String opId = operationId != null ? operationId : randomOperationId(); OperationFuture rawOperationFuture = - rpc.updateDatabaseDdl(dbName, statements, opId); + rpc.updateDatabaseDdl(dbName, statements, opId, ByteString.copyFrom(protoDescriptors)); return new OperationFutureImpl<>( rawOperationFuture.getPollingFuture(), rawOperationFuture.getInitialFuture(), @@ -447,6 +456,11 @@ public void dropDatabase(String instanceId, String databaseId) throws SpannerExc @Override public List getDatabaseDdl(String instanceId, String databaseId) { + return getDatabaseDdlWithProtoDescriptors(instanceId, databaseId).getStatementsList(); + } + + @Override + public GetDatabaseDdlResponse getDatabaseDdlWithProtoDescriptors(String instanceId, String databaseId) { String dbName = getDatabaseName(instanceId, databaseId); return rpc.getDatabaseDdl(dbName); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java index 565517e3419..d49c5279da3 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java @@ -19,7 +19,12 @@ import com.google.cloud.Timestamp; import com.google.cloud.spanner.encryption.CustomerManagedEncryption; import com.google.common.base.Preconditions; +import com.google.common.io.ByteStreams; +import com.google.protobuf.ByteString; +import java.io.FileInputStream; +import java.io.InputStream; import java.util.Objects; +import javax.annotation.Nonnull; import javax.annotation.Nullable; /** Represents a Cloud Spanner database. */ @@ -58,6 +63,12 @@ public Builder setDialect(Dialect dialect) { throw new UnsupportedOperationException("Unimplemented"); } + public abstract Builder setProtoDescriptors(byte[] protoDescriptors); + + public abstract Builder setProtoDescriptors(InputStream inputStream) throws Exception; + + public abstract Builder setProtoDescriptors(String filePath) throws Exception; + abstract Builder setProto(com.google.spanner.admin.database.v1.Database proto); /** Builds the database from this builder. */ @@ -74,6 +85,7 @@ abstract static class BuilderImpl extends Builder { private CustomerManagedEncryption encryptionConfig; private String defaultLeader; private Dialect dialect = Dialect.GOOGLE_STANDARD_SQL; + private ByteString protoDescriptors; private com.google.spanner.admin.database.v1.Database proto; BuilderImpl(DatabaseId id) { @@ -90,6 +102,7 @@ abstract static class BuilderImpl extends Builder { this.encryptionConfig = other.encryptionConfig; this.defaultLeader = other.defaultLeader; this.dialect = other.dialect; + this.protoDescriptors = other.protoDescriptors; this.proto = other.proto; } @@ -141,6 +154,25 @@ public Builder setDialect(Dialect dialect) { return this; } + @Override + public Builder setProtoDescriptors(@Nonnull byte[] protoDescriptors) { + this.protoDescriptors = ByteString.copyFrom(protoDescriptors); + return this; + } + + @Override + public Builder setProtoDescriptors(InputStream inputStream) throws Exception{ + byte[] byteArray = ByteStreams.toByteArray(inputStream); + this.protoDescriptors = byteArray != null ? ByteString.copyFrom(byteArray) : ByteString.EMPTY; + return this; + } + + @Override + public Builder setProtoDescriptors(String filePath) throws Exception{ + InputStream inputStream = new FileInputStream(filePath); + return setProtoDescriptors(inputStream); + } + @Override Builder setProto(@Nullable com.google.spanner.admin.database.v1.Database proto) { this.proto = proto; @@ -169,6 +201,7 @@ public enum State { private final CustomerManagedEncryption encryptionConfig; private final String defaultLeader; private final Dialect dialect; + private final ByteString protoDescriptors; private final com.google.spanner.admin.database.v1.Database proto; public DatabaseInfo(DatabaseId id, State state) { @@ -181,6 +214,7 @@ public DatabaseInfo(DatabaseId id, State state) { this.encryptionConfig = null; this.defaultLeader = null; this.dialect = null; + this.protoDescriptors = null; this.proto = null; } @@ -194,6 +228,7 @@ public DatabaseInfo(DatabaseId id, State state) { this.encryptionConfig = builder.encryptionConfig; this.defaultLeader = builder.defaultLeader; this.dialect = builder.dialect; + this.protoDescriptors = builder.protoDescriptors; this.proto = builder.proto; } @@ -262,6 +297,10 @@ public Timestamp getEarliestVersionTime() { return dialect; } + public ByteString getProtoDescriptors(){ + return protoDescriptors; + } + /** 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; @@ -284,7 +323,8 @@ public boolean equals(Object o) { && Objects.equals(earliestVersionTime, that.earliestVersionTime) && Objects.equals(encryptionConfig, that.encryptionConfig) && Objects.equals(defaultLeader, that.defaultLeader) - && Objects.equals(dialect, that.dialect); + && Objects.equals(dialect, that.dialect) + && Objects.equals(protoDescriptors, that.protoDescriptors); } @Override @@ -298,13 +338,14 @@ public int hashCode() { earliestVersionTime, encryptionConfig, defaultLeader, - dialect); + dialect, + protoDescriptors); } @Override public String toString() { return String.format( - "Database[%s, %s, %s, %s, %s, %s, %s, %s, %s]", + "Database[%s, %s, %s, %s, %s, %s, %s, %s, %s, %s]", id.getName(), state, createTime, @@ -313,6 +354,7 @@ public String toString() { earliestVersionTime, encryptionConfig, defaultLeader, - dialect); + dialect, + protoDescriptors); } } 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 e81f0c874ea..737b5828e99 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 @@ -46,6 +46,7 @@ */ @Immutable 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_FLOAT64 = new Type(Code.FLOAT64, null, null); @@ -72,7 +73,9 @@ public final class Type implements Serializable { private static final int AMBIGUOUS_FIELD = -1; private static final long serialVersionUID = -3076152125004114582L; - /** Returns the descriptor for the {@code BOOL type}. */ + /** + * Returns the descriptor for the {@code BOOL type}. + */ public static Type bool() { return TYPE_BOOL; } @@ -93,7 +96,9 @@ public static Type float64() { return TYPE_FLOAT64; } - /** Returns the descriptor for the {@code NUMERIC} type. */ + /** + * Returns the descriptor for the {@code NUMERIC} type. + */ public static Type numeric() { return TYPE_NUMERIC; } @@ -107,18 +112,23 @@ public static Type pgNumeric() { } /** - * Returns the descriptor for the {@code STRING} type: a variable-length Unicode character string. + * Returns the descriptor for the {@code STRING} type: a variable-length Unicode character + * string. */ public static Type string() { return TYPE_STRING; } - /** Returns the descriptor for the {@code JSON} type. */ + /** + * Returns the descriptor for the {@code JSON} type. + */ public static Type json() { return TYPE_JSON; } - /** Returns the descriptor for the {@code JSONB} type. */ + /** + * Returns the descriptor for the {@code JSONB} type. + */ public static Type pgJsonb() { return TYPE_PG_JSONB; } @@ -141,7 +151,9 @@ public static Type protoEnum(String protoTypeFqn) { return new Type(Code.ENUM, protoTypeFqn); } - /** Returns the descriptor for the {@code BYTES} type: a variable-length byte string. */ + /** + * Returns the descriptor for the {@code BYTES} type: a variable-length byte string. + */ public static Type bytes() { return TYPE_BYTES; } @@ -162,7 +174,9 @@ public static Type date() { return TYPE_DATE; } - /** Returns a descriptor for an array of {@code elementType}. */ + /** + * Returns a descriptor for an array of {@code elementType}. + */ public static Type array(Type elementType) { Preconditions.checkNotNull(elementType); switch (elementType.getCode()) { @@ -234,7 +248,9 @@ private Type(Code code, @Nonnull String protoTypeFqn) { this.protoTypeFqn = protoTypeFqn; } - /** Enumerates the categories of types. */ + /** + * Enumerates the categories of types. + */ public enum Code { BOOL(TypeCode.BOOL), INT64(TypeCode.INT64), @@ -299,8 +315,11 @@ public String toString() { } } - /** Describes an individual field in a {@code STRUCT type}. */ + /** + * Describes an individual field in a {@code STRUCT type}. + */ public static final class StructField implements Serializable { + private static final long serialVersionUID = 8640511292704408210L; private final String name; @@ -341,7 +360,9 @@ public int hashCode() { } } - /** Returns the type code corresponding to this type. */ + /** + * Returns the type code corresponding to this type. + */ public Code getCode() { return code; } @@ -382,7 +403,7 @@ public String getProtoTypeFqn() { * Returns the index of the field named {@code fieldName} in this {@code STRUCT} type. * * @throws IllegalArgumentException if there is not exactly one element of {@link - * #getStructFields()} with {@link StructField#getName()} equal to {@code fieldName} + * #getStructFields()} with {@link StructField#getName()} equal to {@code fieldName} * @throws IllegalStateException if {@code code() != Code.STRUCT} */ public int getFieldIndex(String fieldName) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClient.java index d625748b5e8..6325f020c89 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClient.java @@ -525,6 +525,7 @@ public final OperationFuture createDatabaseAsy * .addAllExtraStatements(new ArrayList()) * .setEncryptionConfig(EncryptionConfig.newBuilder().build()) * .setDatabaseDialect(DatabaseDialect.forNumber(0)) + * .setProtoDescriptors(ByteString.EMPTY) * .build(); * Database response = databaseAdminClient.createDatabaseAsync(request).get(); * } @@ -564,6 +565,7 @@ public final OperationFuture createDatabaseAsy * .addAllExtraStatements(new ArrayList()) * .setEncryptionConfig(EncryptionConfig.newBuilder().build()) * .setDatabaseDialect(DatabaseDialect.forNumber(0)) + * .setProtoDescriptors(ByteString.EMPTY) * .build(); * OperationFuture future = * databaseAdminClient.createDatabaseOperationCallable().futureCall(request); @@ -603,6 +605,7 @@ public final OperationFuture createDatabaseAsy * .addAllExtraStatements(new ArrayList()) * .setEncryptionConfig(EncryptionConfig.newBuilder().build()) * .setDatabaseDialect(DatabaseDialect.forNumber(0)) + * .setProtoDescriptors(ByteString.EMPTY) * .build(); * ApiFuture future = * databaseAdminClient.createDatabaseCallable().futureCall(request); @@ -827,6 +830,7 @@ public final OperationFuture updateDatabaseDdl * .setDatabase(DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]").toString()) * .addAllStatements(new ArrayList()) * .setOperationId("operationId129704162") + * .setProtoDescriptors(ByteString.EMPTY) * .build(); * databaseAdminClient.updateDatabaseDdlAsync(request).get(); * } @@ -864,6 +868,7 @@ public final OperationFuture updateDatabaseDdl * .setDatabase(DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]").toString()) * .addAllStatements(new ArrayList()) * .setOperationId("operationId129704162") + * .setProtoDescriptors(ByteString.EMPTY) * .build(); * OperationFuture future = * databaseAdminClient.updateDatabaseDdlOperationCallable().futureCall(request); @@ -901,6 +906,7 @@ public final OperationFuture updateDatabaseDdl * .setDatabase(DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]").toString()) * .addAllStatements(new ArrayList()) * .setOperationId("operationId129704162") + * .setProtoDescriptors(ByteString.EMPTY) * .build(); * ApiFuture future = * databaseAdminClient.updateDatabaseDdlCallable().futureCall(request); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java index 9a353025074..7f86f2a522a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java @@ -103,7 +103,10 @@ * databaseAdminSettingsBuilder * .getDatabaseSettings() * .setRetrySettings( - * databaseAdminSettingsBuilder.getDatabaseSettings().getRetrySettings().toBuilder() + * databaseAdminSettingsBuilder + * .getDatabaseSettings() + * .getRetrySettings() + * .toBuilder() * .setTotalTimeout(Duration.ofSeconds(30)) * .build()); * DatabaseAdminSettings databaseAdminSettings = databaseAdminSettingsBuilder.build(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStubSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStubSettings.java index 9c209ed0fef..f7836e028eb 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStubSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStubSettings.java @@ -125,7 +125,10 @@ * databaseAdminSettingsBuilder * .getDatabaseSettings() * .setRetrySettings( - * databaseAdminSettingsBuilder.getDatabaseSettings().getRetrySettings().toBuilder() + * databaseAdminSettingsBuilder + * .getDatabaseSettings() + * .getRetrySettings() + * .toBuilder() * .setTotalTimeout(Duration.ofSeconds(30)) * .build()); * DatabaseAdminStubSettings databaseAdminSettings = databaseAdminSettingsBuilder.build(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminSettings.java index bed7960d4f0..4409fa180e2 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminSettings.java @@ -92,7 +92,10 @@ * instanceAdminSettingsBuilder * .getInstanceConfigSettings() * .setRetrySettings( - * instanceAdminSettingsBuilder.getInstanceConfigSettings().getRetrySettings().toBuilder() + * instanceAdminSettingsBuilder + * .getInstanceConfigSettings() + * .getRetrySettings() + * .toBuilder() * .setTotalTimeout(Duration.ofSeconds(30)) * .build()); * InstanceAdminSettings instanceAdminSettings = instanceAdminSettingsBuilder.build(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStubSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStubSettings.java index 9a22ef3eddd..547107b4c98 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStubSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStubSettings.java @@ -113,7 +113,10 @@ * instanceAdminSettingsBuilder * .getInstanceConfigSettings() * .setRetrySettings( - * instanceAdminSettingsBuilder.getInstanceConfigSettings().getRetrySettings().toBuilder() + * instanceAdminSettingsBuilder + * .getInstanceConfigSettings() + * .getRetrySettings() + * .toBuilder() * .setTotalTimeout(Duration.ofSeconds(30)) * .build()); * InstanceAdminStubSettings instanceAdminSettings = instanceAdminSettingsBuilder.build(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 7f325665542..ebf4544ee1e 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -98,6 +98,7 @@ import com.google.longrunning.GetOperationRequest; import com.google.longrunning.Operation; import com.google.longrunning.OperationsGrpc; +import com.google.protobuf.ByteString; import com.google.protobuf.Empty; import com.google.protobuf.FieldMask; import com.google.protobuf.InvalidProtocolBufferException; @@ -117,6 +118,7 @@ import com.google.spanner.admin.database.v1.DropDatabaseRequest; import com.google.spanner.admin.database.v1.GetBackupRequest; import com.google.spanner.admin.database.v1.GetDatabaseDdlRequest; +import com.google.spanner.admin.database.v1.GetDatabaseDdlResponse; import com.google.spanner.admin.database.v1.GetDatabaseRequest; import com.google.spanner.admin.database.v1.ListBackupOperationsRequest; import com.google.spanner.admin.database.v1.ListBackupOperationsResponse; @@ -1190,8 +1192,12 @@ public OperationFuture createDatabase( if (databaseInfo.getDialect() != null) { requestBuilder.setDatabaseDialect(databaseInfo.getDialect().toProto()); } + if (databaseInfo.getProtoDescriptors() != null){ + requestBuilder.setProtoDescriptors(databaseInfo.getProtoDescriptors()); + } final CreateDatabaseRequest request = requestBuilder.build(); - + String req_string = request.toString(); + System.out.println(req_string); OperationFutureCallable callable = new OperationFutureCallable<>( databaseAdminStub.createDatabaseOperationCallable(), @@ -1248,7 +1254,8 @@ public OperationFuture createDatabase( public OperationFuture updateDatabaseDdl( final String databaseName, final Iterable updateDatabaseStatements, - @Nullable final String updateId) + @Nullable final String updateId, + @Nullable ByteString protoDescriptors) throws SpannerException { acquireAdministrativeRequestsRateLimiter(); final UpdateDatabaseDdlRequest request = @@ -1256,6 +1263,7 @@ public OperationFuture updateDatabaseDdl( .setDatabase(databaseName) .addAllStatements(updateDatabaseStatements) .setOperationId(MoreObjects.firstNonNull(updateId, "")) + .setProtoDescriptors(protoDescriptors) .build(); final GrpcCallContext context = newCallContext(null, databaseName, request, DatabaseAdminGrpc.getUpdateDatabaseDdlMethod()); @@ -1316,7 +1324,7 @@ public Database getDatabase(String databaseName) throws SpannerException { } @Override - public List getDatabaseDdl(String databaseName) throws SpannerException { + public GetDatabaseDdlResponse getDatabaseDdl(String databaseName) throws SpannerException { acquireAdministrativeRequestsRateLimiter(); final GetDatabaseDdlRequest request = GetDatabaseDdlRequest.newBuilder().setDatabase(databaseName).build(); @@ -1325,8 +1333,7 @@ public List getDatabaseDdl(String databaseName) throws SpannerException newCallContext(null, databaseName, request, DatabaseAdminGrpc.getGetDatabaseDdlMethod()); return runWithRetryOnAdministrativeRequestsExceeded( () -> - get(databaseAdminStub.getDatabaseDdlCallable().futureCall(request, context)) - .getStatementsList()); + get(databaseAdminStub.getDatabaseDdlCallable().futureCall(request, context))); } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java index 2f68b9c1df2..2c30e9a7d00 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java @@ -32,6 +32,7 @@ import com.google.iam.v1.Policy; import com.google.iam.v1.TestIamPermissionsResponse; import com.google.longrunning.Operation; +import com.google.protobuf.ByteString; import com.google.protobuf.Empty; import com.google.protobuf.FieldMask; import com.google.spanner.admin.database.v1.Backup; @@ -40,6 +41,7 @@ import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; import com.google.spanner.admin.database.v1.Database; import com.google.spanner.admin.database.v1.DatabaseRole; +import com.google.spanner.admin.database.v1.GetDatabaseDdlResponse; import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import com.google.spanner.admin.instance.v1.CreateInstanceConfigMetadata; @@ -225,14 +227,15 @@ OperationFuture createDatabase( throws SpannerException; OperationFuture updateDatabaseDdl( - String databaseName, Iterable updateDatabaseStatements, @Nullable String updateId) + String databaseName, Iterable updateDatabaseStatements, @Nullable String updateId, @Nullable + ByteString protoDescriptors) throws SpannerException; void dropDatabase(String databaseName) throws SpannerException; Database getDatabase(String databaseName) throws SpannerException; - List getDatabaseDdl(String databaseName) throws SpannerException; + GetDatabaseDdlResponse getDatabaseDdl(String databaseName) throws SpannerException; /** Lists the backups in the specified instance. */ Paginated listBackups( String instanceName, int pageSize, @Nullable String filter, @Nullable String pageToken) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/SpannerSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/SpannerSettings.java index dd3d71d6396..6cec68b9a21 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/SpannerSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/SpannerSettings.java @@ -86,7 +86,10 @@ * spannerSettingsBuilder * .createSessionSettings() * .setRetrySettings( - * spannerSettingsBuilder.createSessionSettings().getRetrySettings().toBuilder() + * spannerSettingsBuilder + * .createSessionSettings() + * .getRetrySettings() + * .toBuilder() * .setTotalTimeout(Duration.ofSeconds(30)) * .build()); * SpannerSettings spannerSettings = spannerSettingsBuilder.build(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/stub/SpannerStubSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/stub/SpannerStubSettings.java index f244ce87f87..ff5a6b9bb28 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/stub/SpannerStubSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/stub/SpannerStubSettings.java @@ -103,7 +103,10 @@ * spannerSettingsBuilder * .createSessionSettings() * .setRetrySettings( - * spannerSettingsBuilder.createSessionSettings().getRetrySettings().toBuilder() + * spannerSettingsBuilder + * .createSessionSettings() + * .getRetrySettings() + * .toBuilder() * .setTotalTimeout(Duration.ofSeconds(30)) * .build()); * SpannerStubSettings spannerSettings = spannerSettingsBuilder.build(); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java index 0255f6c1668..cd4d6480f57 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java @@ -51,6 +51,7 @@ import com.google.spanner.admin.database.v1.DatabaseDialect; import com.google.spanner.admin.database.v1.DatabaseRole; import com.google.spanner.admin.database.v1.EncryptionInfo; +import com.google.spanner.admin.database.v1.GetDatabaseDdlResponse; import com.google.spanner.admin.database.v1.RestoreDatabaseMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import java.util.ArrayList; @@ -67,6 +68,7 @@ @RunWith(JUnit4.class) public class DatabaseAdminClientImplTest { + private static final String PROJECT_ID = "my-project"; private static final String INSTANCE_ID = "my-instance"; private static final String INSTANCE_NAME = "projects/my-project/instances/my-instance"; @@ -87,7 +89,8 @@ public class DatabaseAdminClientImplTest { private static final String KMS_KEY_VERSION = "1"; private static final DatabaseDialect DIALECT = GOOGLE_STANDARD_SQL; - @Mock SpannerRpc rpc; + @Mock + SpannerRpc rpc; DatabaseAdminClientImpl client; @Before @@ -176,14 +179,14 @@ public void createDatabase() throws Exception { OperationFutureUtil.immediateOperationFuture( "createDatabase", getDatabaseProto(), CreateDatabaseMetadata.getDefaultInstance()); when(rpc.createDatabase( - INSTANCE_NAME, - "CREATE DATABASE `" + DB_ID + "`", - Collections.emptyList(), - client - .newDatabaseBuilder(DatabaseId.of(DB_NAME)) - .setState(State.UNSPECIFIED) - .setDialect(Dialect.GOOGLE_STANDARD_SQL) - .build())) + INSTANCE_NAME, + "CREATE DATABASE `" + DB_ID + "`", + Collections.emptyList(), + client + .newDatabaseBuilder(DatabaseId.of(DB_NAME)) + .setState(State.UNSPECIFIED) + .setDialect(Dialect.GOOGLE_STANDARD_SQL) + .build())) .thenReturn(rawOperationFuture); OperationFuture op = client.createDatabase(INSTANCE_ID, DB_ID, Collections.emptyList()); @@ -206,7 +209,7 @@ public void createEncryptedDatabase() throws Exception { getEncryptedDatabaseProto(), CreateDatabaseMetadata.getDefaultInstance()); when(rpc.createDatabase( - INSTANCE_NAME, "CREATE DATABASE `" + DB_ID + "`", Collections.emptyList(), database)) + INSTANCE_NAME, "CREATE DATABASE `" + DB_ID + "`", Collections.emptyList(), database)) .thenReturn(rawOperationFuture); OperationFuture op = client.createDatabase(database, Collections.emptyList()); @@ -222,7 +225,7 @@ public void updateDatabaseDdl() throws Exception { OperationFuture rawOperationFuture = OperationFutureUtil.immediateOperationFuture( opName, Empty.getDefaultInstance(), UpdateDatabaseDdlMetadata.getDefaultInstance()); - when(rpc.updateDatabaseDdl(DB_NAME, ddl, opId)).thenReturn(rawOperationFuture); + when(rpc.updateDatabaseDdl(DB_NAME, ddl, opId, null)).thenReturn(rawOperationFuture); OperationFuture op = client.updateDatabaseDdl(INSTANCE_ID, DB_ID, ddl, opId); assertThat(op.isDone()).isTrue(); @@ -240,7 +243,7 @@ public void updateDatabaseDdlOpAlreadyExists() throws Exception { UpdateDatabaseDdlMetadata.getDefaultInstance()); String newOpId = "newop"; - when(rpc.updateDatabaseDdl(DB_NAME, ddl, newOpId)).thenReturn(originalOp); + when(rpc.updateDatabaseDdl(DB_NAME, ddl, newOpId, null)).thenReturn(originalOp); OperationFuture op = client.updateDatabaseDdl(INSTANCE_ID, DB_ID, ddl, newOpId); assertThat(op.getName()).isEqualTo(originalOpName); @@ -255,7 +258,8 @@ public void dropDatabase() { @Test public void getDatabaseDdl() { List ddl = ImmutableList.of("CREATE TABLE mytable()"); - when(rpc.getDatabaseDdl(DB_NAME)).thenReturn(ddl); + when(rpc.getDatabaseDdl(DB_NAME)).thenReturn( + GetDatabaseDdlResponse.newBuilder().addAllStatements(ddl).build()); assertThat(client.getDatabaseDdl(INSTANCE_ID, DB_ID)).isEqualTo(ddl); } @@ -648,8 +652,8 @@ public void restoreDatabase() throws Exception { "restoreDatabase", getDatabaseProto(), RestoreDatabaseMetadata.getDefaultInstance()); final Restore restore = new Restore.Builder( - BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID), - DatabaseId.of(PROJECT_ID, INSTANCE_ID, DB_ID)) + BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID), + DatabaseId.of(PROJECT_ID, INSTANCE_ID, DB_ID)) .build(); when(rpc.restoreDatabase(restore)).thenReturn(rawOperationFuture); OperationFuture op = @@ -667,8 +671,8 @@ public void restoreEncryptedDatabase() throws Exception { RestoreDatabaseMetadata.getDefaultInstance()); final Restore restore = new Restore.Builder( - BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID), - DatabaseId.of(PROJECT_ID, INSTANCE_ID, DB_ID)) + BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID), + DatabaseId.of(PROJECT_ID, INSTANCE_ID, DB_ID)) .build(); when(rpc.restoreDatabase(restore)).thenReturn(rawOperationFuture); OperationFuture op = diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java index 7a27123bdc3..813c8ea8502 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java @@ -100,6 +100,7 @@ public GceTestEnvConfig() { .setInterceptorProvider(interceptorProvider); builder.setChannelProvider(customChannelProviderBuilder.build()); } + builder.setHost("https://staging-wrenchworks.sandbox.googleapis.com"); options = builder.build(); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientHttpJsonTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientHttpJsonTest.java index 31e6d9d97fb..1cbcb3d6d83 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientHttpJsonTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientHttpJsonTest.java @@ -607,7 +607,10 @@ public void dropDatabaseExceptionTest2() throws Exception { @Test public void getDatabaseDdlTest() throws Exception { GetDatabaseDdlResponse expectedResponse = - GetDatabaseDdlResponse.newBuilder().addAllStatements(new ArrayList()).build(); + GetDatabaseDdlResponse.newBuilder() + .addAllStatements(new ArrayList()) + .setProtoDescriptors(ByteString.EMPTY) + .build(); mockService.addResponse(expectedResponse); DatabaseName database = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); @@ -649,7 +652,10 @@ public void getDatabaseDdlExceptionTest() throws Exception { @Test public void getDatabaseDdlTest2() throws Exception { GetDatabaseDdlResponse expectedResponse = - GetDatabaseDdlResponse.newBuilder().addAllStatements(new ArrayList()).build(); + GetDatabaseDdlResponse.newBuilder() + .addAllStatements(new ArrayList()) + .setProtoDescriptors(ByteString.EMPTY) + .build(); mockService.addResponse(expectedResponse); String database = "projects/project-3102/instances/instance-3102/databases/database-3102"; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java index 51c780c9829..bbea144499f 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java @@ -586,7 +586,10 @@ public void dropDatabaseExceptionTest2() throws Exception { @Test public void getDatabaseDdlTest() throws Exception { GetDatabaseDdlResponse expectedResponse = - GetDatabaseDdlResponse.newBuilder().addAllStatements(new ArrayList()).build(); + GetDatabaseDdlResponse.newBuilder() + .addAllStatements(new ArrayList()) + .setProtoDescriptors(ByteString.EMPTY) + .build(); mockDatabaseAdmin.addResponse(expectedResponse); DatabaseName database = DatabaseName.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"); @@ -622,7 +625,10 @@ public void getDatabaseDdlExceptionTest() throws Exception { @Test public void getDatabaseDdlTest2() throws Exception { GetDatabaseDdlResponse expectedResponse = - GetDatabaseDdlResponse.newBuilder().addAllStatements(new ArrayList()).build(); + GetDatabaseDdlResponse.newBuilder() + .addAllStatements(new ArrayList()) + .setProtoDescriptors(ByteString.EMPTY) + .build(); mockDatabaseAdmin.addResponse(expectedResponse); String database = "database1789464955"; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java new file mode 100644 index 00000000000..0a7e8562974 --- /dev/null +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java @@ -0,0 +1,307 @@ +/* + * 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. + * 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.truth.Truth.assertThat; +import static org.junit.Assume.assumeFalse; + +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.IntegrationTestEnv; +import com.google.cloud.spanner.ParallelIntegrationTest; +import com.google.cloud.spanner.SpannerExceptionFactory; +import com.google.cloud.spanner.testing.RemoteSpannerHelper; +import com.google.common.io.ByteStreams; +import com.google.protobuf.ByteString; +import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; +import com.google.spanner.admin.database.v1.GetDatabaseDdlResponse; +import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import javax.xml.crypto.Data; +import org.junit.After; +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.JUnit4; +import org.threeten.bp.Duration; + +@Category(ParallelIntegrationTest.class) +@RunWith(JUnit4.class) +public class ITCreateDatabaseProtos { + + private static final Duration OPERATION_TIMEOUT = Duration.ofMinutes(2); + private static final String VERSION_RETENTION_PERIOD = "7d"; + + @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); + private RemoteSpannerHelper testHelper; + private DatabaseAdminClient dbAdminClient; + private List databasesToDrop; + + @BeforeClass + public static void doNotRunOnEmulator() { + assumeFalse("PITR-lite features are not supported by the emulator", isUsingEmulator()); + } + + @Before + public void setUp() { + testHelper = env.getTestHelper(); + dbAdminClient = testHelper.getClient().getDatabaseAdminClient(); + databasesToDrop = new ArrayList<>(); + } + + @After + public void tearDown() { + for (Database database : databasesToDrop) { + final DatabaseId id = database.getId(); + dbAdminClient.dropDatabase(id.getInstanceId().getInstance(), id.getDatabase()); + } + } + + /*@Test + public void returnsTheVersionRetentionPeriodSetThroughCreateDatabase() throws Exception { + final String instanceId = testHelper.getInstanceId().getInstance(); + final String databaseId = testHelper.getUniqueDatabaseId(); + final String extraStatement = + "ALTER DATABASE " + + databaseId + + " SET OPTIONS (version_retention_period = '" + + VERSION_RETENTION_PERIOD + + "')"; + + final Database database = createDatabase(instanceId, databaseId, extraStatement); + + assertThat(database.getVersionRetentionPeriod()).isEqualTo(VERSION_RETENTION_PERIOD); + assertThat(database.getEarliestVersionTime()).isNotNull(); + }*/ + + @Test + public void returnsTheVersionRetentionPeriodSetThroughGetDatabase() throws Exception { + final String projectId = "span-cloud-testing"; + final String instanceId = "harsha-test-gcloud"; + final String databaseId = "singer_test"; + /*final String extraStatement = + "ALTER DATABASE " + + databaseId + + " SET OPTIONS (version_retention_period = '" + + VERSION_RETENTION_PERIOD + + "')";*/ + + createDatabase(projectId, instanceId, databaseId); + final Database database = dbAdminClient.getDatabase(instanceId, databaseId); + + assertThat(database.getVersionRetentionPeriod()).isEqualTo(VERSION_RETENTION_PERIOD); + assertThat(database.getEarliestVersionTime()).isNotNull(); + + + final GetDatabaseDdlResponse response = dbAdminClient.getDatabaseDdlWithProtoDescriptors("integration-test-proto-column", "int_test_proto_column_db"); + System.out.println(response.getProtoDescriptors().toByteArray()); + } + + /*@Test(expected = DatabaseNotFoundException.class) + public void returnsAnErrorWhenAnInvalidVersionRetentionPeriodIsGiven() { + final String instanceId = testHelper.getInstanceId().getInstance(); + final String databaseId = testHelper.getUniqueDatabaseId(); + final String extraStatement = + "ALTER DATABASE " + databaseId + " SET OPTIONS (version_retention_period = '0d')"; + + try { + createDatabase(instanceId, databaseId, extraStatement); + fail("Expected invalid argument error when setting invalid version retention period"); + } catch (Exception e) { + SpannerException spannerException = (SpannerException) e.getCause(); + assertThat(spannerException.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + } + + // Expects a database not found exception + dbAdminClient.getDatabase(instanceId, databaseId); + }*/ + + private Database createDatabase( + final String projectId, final String instanceId, final String databaseId) throws IOException { + + //String filePath = "/usr/local/google/home/sriharshach/github/Go/golang-samples-proto-support-v2/spanner/spanner_snippets/spanner/testdata/protos/descriptor.pb"; + // file to byte[], Path + //byte[] bytes = Files.readAllBytes(Paths.get(filePath)); + + InputStream inputStream = new FileInputStream("/usr/local/google/home/sriharshach/github/Go/golang-samples-proto-support-v2/spanner/spanner_snippets/spanner/testdata/protos/descriptors.pb"); + byte[] byteArray = null; + + // Try block to check for exceptions + /*try { + byteArray = inputStream.readAllBytes(); + }catch (IOException e) { + System.out.println(e); + }*/ + + try { + byteArray = ByteStreams.toByteArray(inputStream); + } + catch (IOException e) { + System.out.println(e); + } + + final Database databaseToCreate = + dbAdminClient.newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId)) + .setProtoDescriptors(byteArray) + .build(); + + final OperationFuture operation = + dbAdminClient.createDatabase( + databaseToCreate, + Arrays.asList( + "CREATE PROTO BUNDLE (" + + "spanner.examples.music.SingerInfo," + + "spanner.examples.music.Genre," + + ")", + "CREATE TABLE Singers (" + + " SingerId INT64 NOT NULL," + + " FirstName STRING(1024)," + + " LastName STRING(1024)," + + " SingerInfo spanner.examples.music.SingerInfo," + + " SingerGenre spanner.examples.music.Genre," + + " ) PRIMARY KEY (SingerGenre)")); + + 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()); + + return createdDatabase; + } 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); + } + } + + private Database createDatabaseWithProtos( + final String projectId, final String instanceId, final String databaseId, InputStream protoDescriptorFile) { + + byte[] protoDescriptorByteArray = null; + try { + protoDescriptorByteArray = ByteStreams.toByteArray(protoDescriptorFile); + } + catch (IOException e) { + System.out.println(e); + } + + final Database databaseToCreate = + dbAdminClient.newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId)) + .setProtoDescriptors(protoDescriptorByteArray) + .build(); + + final OperationFuture operation = + dbAdminClient.createDatabase( + databaseToCreate, + Arrays.asList( + "CREATE PROTO BUNDLE (" + + "spanner.examples.music.SingerInfo," + + "spanner.examples.music.Genre," + + ")", + "CREATE TABLE Singers (" + + " SingerId INT64 NOT NULL," + + " FirstName STRING(1024)," + + " LastName STRING(1024)," + + " SingerInfo spanner.examples.music.SingerInfo," + + " SingerGenre spanner.examples.music.Genre," + + " ) PRIMARY KEY (SingerGenre)")); + + try { + System.out.println("Waiting for operation to complete..."); + Database createdDatabase = operation.get(120, TimeUnit.SECONDS); + return createdDatabase; + } catch (Exception e) { + // If the operation failed during execution, expose the cause. + throw SpannerExceptionFactory.asSpannerException(e.getCause()); + } + } + + private void updateDatabaseWithProtos( + final String instanceId, final String databaseId, InputStream protoDescriptorFile) { + + byte[] protoDescriptorByteArray = null; + try { + protoDescriptorByteArray = ByteStreams.toByteArray(protoDescriptorFile); + } + catch (IOException e) { + System.out.println(e); + } + + try { + final OperationFuture updateOperation = + dbAdminClient.updateDatabaseDdl( + instanceId, + databaseId, + Arrays.asList( + "CREATE PROTO BUNDLE (" + + "spanner.examples.music.SingerInfo," + + "spanner.examples.music.Genre," + + ")", + "CREATE TABLE Singers (" + + " SingerId INT64 NOT NULL," + + " FirstName STRING(1024)," + + " LastName STRING(1024)," + + " SingerInfo spanner.examples.music.SingerInfo," + + " SingerGenre spanner.examples.music.Genre," + + " ) PRIMARY KEY (SingerGenre)"), + null, protoDescriptorByteArray); + updateOperation.get(); + System.out.println("Updated Database"); + } catch (Exception e) { + // If the operation failed during execution, expose the cause. + throw SpannerExceptionFactory.asSpannerException(e.getCause()); + } + } + + private void getDatabaseDdl( + String instanceId, String databaseId) { + try { + final GetDatabaseDdlResponse response = dbAdminClient.getDatabaseDdlWithProtoDescriptors(instanceId, databaseId); + System.out.println("Retrieved GetDatabaseDdlResponse for " + databaseId); + for (String ddl : response.getStatementsList()) { + System.out.println(ddl); + } + System.out.println(response.getProtoDescriptors()); + } catch (Exception e) { + } + } +} diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java index 7d689612284..0ecf8548567 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java @@ -17,12 +17,16 @@ package com.google.cloud.spanner.it; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; import static org.junit.Assume.assumeFalse; import com.google.cloud.ByteArray; +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.IntegrationTestEnv; import com.google.cloud.spanner.Key; import com.google.cloud.spanner.KeySet; import com.google.cloud.spanner.Mutation; @@ -35,31 +39,62 @@ import com.google.cloud.spanner.SpannerOptions; import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.testing.EmulatorSpannerHelper; +import com.google.cloud.spanner.testing.RemoteSpannerHelper; import com.google.common.collect.ImmutableList; +import com.google.common.io.ByteStreams; import com.google.protobuf.AbstractMessage; +import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException.InvalidWireTypeException; import com.google.protobuf.ProtocolMessageEnum; import com.google.spanner.admin.database.v1.Backup; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import org.junit.After; +import org.junit.AfterClass; 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.JUnit4; -/** Integrations Tests to test Proto Columns & Enums */ +/** + * Integrations Tests to test DDL, DML and DQL for Proto Columns & Enums + */ @Category(ParallelIntegrationTest.class) @RunWith(JUnit4.class) public class ITProtoColumnTest { - private static String projectId; + + @ClassRule + public static IntegrationTestEnv env = new IntegrationTestEnv(); + // TODO: Replace PROJECT_ID with testHelper.getInstanceId().getProject(); + private static final String PROJECT_ID = "span-cloud-testing"; private static String instanceId; private static String databaseId; + private static DatabaseAdminClient dbAdminClient; + // For reference of databaseClient usage check ITPgJsonbTest.java private static DatabaseClient databaseClient; + private static RemoteSpannerHelper testHelper; @BeforeClass + public static void setUpDatabase() { + // Get default spanner options for an integration test. + SpannerOptions.Builder builder = env.getTestHelper().getOptions().toBuilder(); + builder.setHost("https://staging-wrenchworks.sandbox.googleapis.com").setProjectId(PROJECT_ID); + + // Create a new testHelper with the cloud-devel host. + testHelper = RemoteSpannerHelper.create(builder.build(), env.getTestHelper().getInstanceId()); + dbAdminClient = testHelper.getClient().getDatabaseAdminClient(); + } + + /*@BeforeClass public static void beforeClass() throws Exception { assumeFalse( "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); @@ -76,6 +111,17 @@ public static void beforeClass() throws Exception { .getService(); databaseClient = spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); + }*/ + + @AfterClass + public static void afterClass() throws Exception { + try { + dbAdminClient.dropDatabase(instanceId, databaseId); + } catch (Exception e) { + System.err.println( + "Failed to drop database " + dbAdminClient.getDatabase(instanceId, databaseId).getId() + + ", skipping...: " + e.getMessage()); + } } @After @@ -84,6 +130,49 @@ public void after() throws Exception { databaseClient.write(ImmutableList.of(Mutation.delete("Singers", KeySet.all()))); } + @Test + public void createDatabase() throws Exception { + databaseId = testHelper.getUniqueDatabaseId(); + instanceId = testHelper.getInstanceId().getInstance(); + // PROJECT_ID = testHelper.getInstanceId().getProject(); + databaseClient = testHelper.getClient() + .getDatabaseClient(DatabaseId.of(PROJECT_ID, instanceId, databaseId)); + + final Database databaseToCreate = dbAdminClient + .newDatabaseBuilder(DatabaseId.of(PROJECT_ID, instanceId, databaseId)) + .setProtoDescriptors( + "/usr/local/google/home/sriharshach/github/Go/golang-samples-proto-support-v2/spanner/spanner_snippets/spanner/testdata/protos/descriptors.pb") + .build(); + final Database createdDatabase = dbAdminClient + .createDatabase(databaseToCreate, Arrays.asList( + "CREATE PROTO BUNDLE (" + + "spanner.examples.music.SingerInfo," + + "spanner.examples.music.Genre," + + ")", + "CREATE TABLE Singers (" + + " SingerId INT64 NOT NULL," + + " FirstName STRING(1024)," + + " LastName STRING(1024)," + + " SingerInfo spanner.examples.music.SingerInfo," + + " SingerGenre spanner.examples.music.Genre," + + " ) PRIMARY KEY (SingerGenre)", + "CREATE TABLE Types (" + + " RowID INT64 NOT NULL," + + " Int64a INT64," + + " Bytes BYTES(MAX)," + + " Int64Array ARRAY," + + " BytesArray ARRAY," + + " ProtoMessage spanner.examples.music.SingerInfo," + + " ProtoEnum spanner.examples.music.Genre," + + " ProtoMessageArray ARRAY," + + " ProtoEnumArray ARRAY," + + " ) PRIMARY KEY (RowID)")) + .get(5, TimeUnit.MINUTES); + + assertEquals(databaseId, createdDatabase.getId().getDatabase()); + assertNotNull(createdDatabase.getProtoDescriptors()); + } + /** * Test to check updates and read queries on Proto column and Enums and their arrays. Test also * checks for compatability between following types: 1. Proto Messages & Bytes 2. Proto Enums & @@ -142,7 +231,7 @@ public void testProtoUpdateAndRead() { .set("ProtoEnumArray") .toProtoEnumArray(enumList, Genre.getDescriptor()) .build(), - //Inter Compatability check between ProtoMessages/Bytes and Int64/Enum. + // Inter Compatability check between ProtoMessages/Bytes and Int64/Enum. Mutation.newInsertOrUpdateBuilder("Types") .set("RowID") .to(12) @@ -167,9 +256,9 @@ public void testProtoUpdateAndRead() { try (ResultSet resultSet = databaseClient.singleUse().executeQuery(Statement.of("SELECT * FROM " + "Types"))) { - for(int i=0;i<2;i++) { + for (int i = 0; i < 2; i++) { resultSet.next(); - assertEquals(11 + i, resultSet.getLong("RowID")); + assertEquals(11 + i, resultSet.getLong("RowID")); assertEquals(genreConst, resultSet.getLong("Int64a")); assertEquals(singerInfoBytes, resultSet.getBytes("Bytes")); assertEquals(enumConstList, resultSet.getLongList("Int64Array")); @@ -184,7 +273,8 @@ public void testProtoUpdateAndRead() { // Check compatability between Proto Messages & Bytes assertEquals(singerInfoBytes, resultSet.getBytes("ProtoMessage")); - assertEquals(singerInfo, resultSet.getProtoMessage("Bytes", SingerInfo.getDefaultInstance())); + assertEquals( + singerInfo, resultSet.getProtoMessage("Bytes", SingerInfo.getDefaultInstance())); assertEquals(singerInfoBytesList, resultSet.getBytesList("ProtoMessageArray")); assertEquals( diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequestOrBuilder.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequestOrBuilder.java index 537e9c161fa..f9699e13d91 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequestOrBuilder.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequestOrBuilder.java @@ -225,4 +225,31 @@ public interface CreateDatabaseRequestOrBuilder * @return The databaseDialect. */ com.google.spanner.admin.database.v1.DatabaseDialect getDatabaseDialect(); + + /** + * + * + *

+   * Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements in
+   * 'extra_statements' above.
+   * Contains a protobuf-serialized
+   * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+   * To generate it, [install](https://grpc.io/docs/protoc-installation/) and
+   * run `protoc` with --include_imports and --descriptor_set_out. For example,
+   * to generate for moon/shot/app.proto, run
+   * """
+   * $protoc  --proto_path=/app_path --proto_path=/lib_path \
+   *          --include_imports \
+   *          --descriptor_set_out=descriptors.data \
+   *          moon/shot/app.proto
+   * """
+   * For more details, see protobuffer [self
+   * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+   * 
+ * + * bytes proto_descriptors = 6 [(.google.api.field_behavior) = OPTIONAL]; + * + * @return The protoDescriptors. + */ + com.google.protobuf.ByteString getProtoDescriptors(); } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlResponse.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlResponse.java index 39078a788f9..8a34b0f1df6 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlResponse.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlResponse.java @@ -39,6 +39,7 @@ private GetDatabaseDdlResponse(com.google.protobuf.GeneratedMessageV3.Builder private GetDatabaseDdlResponse() { statements_ = com.google.protobuf.LazyStringArrayList.EMPTY; + protoDescriptors_ = com.google.protobuf.ByteString.EMPTY; } @java.lang.Override @@ -132,6 +133,28 @@ public com.google.protobuf.ByteString getStatementsBytes(int index) { return statements_.getByteString(index); } + public static final int PROTO_DESCRIPTORS_FIELD_NUMBER = 2; + private com.google.protobuf.ByteString protoDescriptors_; + /** + * + * + *
+   * Proto descriptors stored in the database.
+   * Contains a protobuf-serialized
+   * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+   * For more details, see protobuffer [self
+   * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+   * 
+ * + * bytes proto_descriptors = 2; + * + * @return The protoDescriptors. + */ + @java.lang.Override + public com.google.protobuf.ByteString getProtoDescriptors() { + return protoDescriptors_; + } + private byte memoizedIsInitialized = -1; @java.lang.Override @@ -149,6 +172,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io for (int i = 0; i < statements_.size(); i++) { com.google.protobuf.GeneratedMessageV3.writeString(output, 1, statements_.getRaw(i)); } + if (!protoDescriptors_.isEmpty()) { + output.writeBytes(2, protoDescriptors_); + } getUnknownFields().writeTo(output); } @@ -166,6 +192,9 @@ public int getSerializedSize() { size += dataSize; size += 1 * getStatementsList().size(); } + if (!protoDescriptors_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(2, protoDescriptors_); + } size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; @@ -183,6 +212,7 @@ public boolean equals(final java.lang.Object obj) { (com.google.spanner.admin.database.v1.GetDatabaseDdlResponse) obj; if (!getStatementsList().equals(other.getStatementsList())) return false; + if (!getProtoDescriptors().equals(other.getProtoDescriptors())) return false; if (!getUnknownFields().equals(other.getUnknownFields())) return false; return true; } @@ -198,6 +228,8 @@ public int hashCode() { hash = (37 * hash) + STATEMENTS_FIELD_NUMBER; hash = (53 * hash) + getStatementsList().hashCode(); } + hash = (37 * hash) + PROTO_DESCRIPTORS_FIELD_NUMBER; + hash = (53 * hash) + getProtoDescriptors().hashCode(); hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; @@ -339,6 +371,8 @@ public Builder clear() { super.clear(); statements_ = com.google.protobuf.LazyStringArrayList.EMPTY; bitField0_ = (bitField0_ & ~0x00000001); + protoDescriptors_ = com.google.protobuf.ByteString.EMPTY; + return this; } @@ -372,6 +406,7 @@ public com.google.spanner.admin.database.v1.GetDatabaseDdlResponse buildPartial( bitField0_ = (bitField0_ & ~0x00000001); } result.statements_ = statements_; + result.protoDescriptors_ = protoDescriptors_; onBuilt(); return result; } @@ -432,6 +467,9 @@ public Builder mergeFrom(com.google.spanner.admin.database.v1.GetDatabaseDdlResp } onChanged(); } + if (other.getProtoDescriptors() != com.google.protobuf.ByteString.EMPTY) { + setProtoDescriptors(other.getProtoDescriptors()); + } this.mergeUnknownFields(other.getUnknownFields()); onChanged(); return this; @@ -465,6 +503,12 @@ public Builder mergeFrom( statements_.add(s); break; } // case 10 + case 18: + { + protoDescriptors_ = input.readBytes(); + + break; + } // case 18 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { @@ -661,6 +705,73 @@ public Builder addStatementsBytes(com.google.protobuf.ByteString value) { return this; } + private com.google.protobuf.ByteString protoDescriptors_ = com.google.protobuf.ByteString.EMPTY; + /** + * + * + *
+     * Proto descriptors stored in the database.
+     * Contains a protobuf-serialized
+     * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+     * For more details, see protobuffer [self
+     * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+     * 
+ * + * bytes proto_descriptors = 2; + * + * @return The protoDescriptors. + */ + @java.lang.Override + public com.google.protobuf.ByteString getProtoDescriptors() { + return protoDescriptors_; + } + /** + * + * + *
+     * Proto descriptors stored in the database.
+     * Contains a protobuf-serialized
+     * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+     * For more details, see protobuffer [self
+     * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+     * 
+ * + * bytes proto_descriptors = 2; + * + * @param value The protoDescriptors to set. + * @return This builder for chaining. + */ + public Builder setProtoDescriptors(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + + protoDescriptors_ = value; + onChanged(); + return this; + } + /** + * + * + *
+     * Proto descriptors stored in the database.
+     * Contains a protobuf-serialized
+     * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+     * For more details, see protobuffer [self
+     * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+     * 
+ * + * bytes proto_descriptors = 2; + * + * @return This builder for chaining. + */ + public Builder clearProtoDescriptors() { + + protoDescriptors_ = getDefaultInstance().getProtoDescriptors(); + onChanged(); + return this; + } + @java.lang.Override public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { return super.setUnknownFields(unknownFields); diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlResponseOrBuilder.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlResponseOrBuilder.java index 28f7fb2cc5c..8f45b73c48c 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlResponseOrBuilder.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlResponseOrBuilder.java @@ -77,4 +77,21 @@ public interface GetDatabaseDdlResponseOrBuilder * @return The bytes of the statements at the given index. */ com.google.protobuf.ByteString getStatementsBytes(int index); + + /** + * + * + *
+   * Proto descriptors stored in the database.
+   * Contains a protobuf-serialized
+   * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+   * For more details, see protobuffer [self
+   * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+   * 
+ * + * bytes proto_descriptors = 2; + * + * @return The protoDescriptors. + */ + com.google.protobuf.ByteString getProtoDescriptors(); } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/SpannerDatabaseAdminProto.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/SpannerDatabaseAdminProto.java index 9a4c1888ef2..8a0a0250c2f 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/SpannerDatabaseAdminProto.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/SpannerDatabaseAdminProto.java @@ -161,7 +161,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "\030\003 \001(\005\022\022\n\npage_token\030\004 \001(\t\"o\n\025ListDataba" + "sesResponse\022=\n\tdatabases\030\001 \003(\0132*.google." + "spanner.admin.database.v1.Database\022\027\n\017ne" - + "xt_page_token\030\002 \001(\t\"\264\002\n\025CreateDatabaseRe" + + "xt_page_token\030\002 \001(\t\"\324\002\n\025CreateDatabaseRe" + "quest\0227\n\006parent\030\001 \001(\tB\'\340A\002\372A!\n\037spanner.g" + "oogleapis.com/Instance\022\035\n\020create_stateme" + "nt\030\002 \001(\tB\003\340A\002\022\035\n\020extra_statements\030\003 \003(\tB" @@ -169,198 +169,200 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + ".spanner.admin.database.v1.EncryptionCon" + "figB\003\340A\001\022P\n\020database_dialect\030\005 \001(\01621.goo" + "gle.spanner.admin.database.v1.DatabaseDi" - + "alectB\003\340A\001\"P\n\026CreateDatabaseMetadata\0226\n\010" - + "database\030\001 \001(\tB$\372A!\n\037spanner.googleapis." - + "com/Database\"K\n\022GetDatabaseRequest\0225\n\004na" - + "me\030\001 \001(\tB\'\340A\002\372A!\n\037spanner.googleapis.com" - + "/Database\"\204\001\n\030UpdateDatabaseDdlRequest\0229" - + "\n\010database\030\001 \001(\tB\'\340A\002\372A!\n\037spanner.google" - + "apis.com/Database\022\027\n\nstatements\030\002 \003(\tB\003\340" - + "A\002\022\024\n\014operation_id\030\003 \001(\t\"\375\001\n\031UpdateDatab" - + "aseDdlMetadata\0226\n\010database\030\001 \001(\tB$\372A!\n\037s" - + "panner.googleapis.com/Database\022\022\n\nstatem" - + "ents\030\002 \003(\t\0225\n\021commit_timestamps\030\003 \003(\0132\032." - + "google.protobuf.Timestamp\022\026\n\tthrottled\030\004" - + " \001(\010B\003\340A\003\022E\n\010progress\030\005 \003(\01323.google.spa" - + "nner.admin.database.v1.OperationProgress" - + "\"P\n\023DropDatabaseRequest\0229\n\010database\030\001 \001(" - + "\tB\'\340A\002\372A!\n\037spanner.googleapis.com/Databa" - + "se\"R\n\025GetDatabaseDdlRequest\0229\n\010database\030" - + "\001 \001(\tB\'\340A\002\372A!\n\037spanner.googleapis.com/Da" - + "tabase\",\n\026GetDatabaseDdlResponse\022\022\n\nstat" - + "ements\030\001 \003(\t\"\217\001\n\035ListDatabaseOperationsR" - + "equest\0227\n\006parent\030\001 \001(\tB\'\340A\002\372A!\n\037spanner." - + "googleapis.com/Instance\022\016\n\006filter\030\002 \001(\t\022" - + "\021\n\tpage_size\030\003 \001(\005\022\022\n\npage_token\030\004 \001(\t\"l" - + "\n\036ListDatabaseOperationsResponse\0221\n\noper" - + "ations\030\001 \003(\0132\035.google.longrunning.Operat" - + "ion\022\027\n\017next_page_token\030\002 \001(\t\"\216\002\n\026Restore" - + "DatabaseRequest\0227\n\006parent\030\001 \001(\tB\'\340A\002\372A!\n" - + "\037spanner.googleapis.com/Instance\022\030\n\013data" - + "base_id\030\002 \001(\tB\003\340A\002\0224\n\006backup\030\003 \001(\tB\"\372A\037\n" - + "\035spanner.googleapis.com/BackupH\000\022a\n\021encr" - + "yption_config\030\004 \001(\0132A.google.spanner.adm" - + "in.database.v1.RestoreDatabaseEncryption" - + "ConfigB\003\340A\001B\010\n\006source\"\363\002\n\037RestoreDatabas" - + "eEncryptionConfig\022n\n\017encryption_type\030\001 \001" - + "(\0162P.google.spanner.admin.database.v1.Re" - + "storeDatabaseEncryptionConfig.Encryption" - + "TypeB\003\340A\002\022?\n\014kms_key_name\030\002 \001(\tB)\340A\001\372A#\n" - + "!cloudkms.googleapis.com/CryptoKey\"\236\001\n\016E" - + "ncryptionType\022\037\n\033ENCRYPTION_TYPE_UNSPECI" - + "FIED\020\000\022+\n\'USE_CONFIG_DEFAULT_OR_BACKUP_E" - + "NCRYPTION\020\001\022\035\n\031GOOGLE_DEFAULT_ENCRYPTION" - + "\020\002\022\037\n\033CUSTOMER_MANAGED_ENCRYPTION\020\003\"\215\003\n\027" - + "RestoreDatabaseMetadata\0222\n\004name\030\001 \001(\tB$\372" - + "A!\n\037spanner.googleapis.com/Database\022H\n\013s" - + "ource_type\030\002 \001(\01623.google.spanner.admin." - + "database.v1.RestoreSourceType\022C\n\013backup_" - + "info\030\003 \001(\0132,.google.spanner.admin.databa" - + "se.v1.BackupInfoH\000\022E\n\010progress\030\004 \001(\01323.g" - + "oogle.spanner.admin.database.v1.Operatio" - + "nProgress\022/\n\013cancel_time\030\005 \001(\0132\032.google." - + "protobuf.Timestamp\022(\n optimize_database_" - + "operation_name\030\006 \001(\tB\r\n\013source_info\"\235\001\n " - + "OptimizeRestoredDatabaseMetadata\0222\n\004name" + + "alectB\003\340A\001\022\036\n\021proto_descriptors\030\006 \001(\014B\003\340" + + "A\001\"P\n\026CreateDatabaseMetadata\0226\n\010database" + "\030\001 \001(\tB$\372A!\n\037spanner.googleapis.com/Data" - + "base\022E\n\010progress\030\002 \001(\01323.google.spanner." - + "admin.database.v1.OperationProgress\"\236\001\n\014" - + "DatabaseRole\022\021\n\004name\030\001 \001(\tB\003\340A\002:{\352Ax\n#sp" - + "anner.googleapis.com/DatabaseRole\022Qproje" - + "cts/{project}/instances/{instance}/datab" - + "ases/{database}/databaseRoles/{role}\"z\n\030" - + "ListDatabaseRolesRequest\0227\n\006parent\030\001 \001(\t" + + "base\"K\n\022GetDatabaseRequest\0225\n\004name\030\001 \001(\t" + "B\'\340A\002\372A!\n\037spanner.googleapis.com/Databas" - + "e\022\021\n\tpage_size\030\002 \001(\005\022\022\n\npage_token\030\003 \001(\t" - + "\"|\n\031ListDatabaseRolesResponse\022F\n\016databas" - + "e_roles\030\001 \003(\0132..google.spanner.admin.dat" - + "abase.v1.DatabaseRole\022\027\n\017next_page_token" - + "\030\002 \001(\t*5\n\021RestoreSourceType\022\024\n\020TYPE_UNSP" - + "ECIFIED\020\000\022\n\n\006BACKUP\020\0012\374#\n\rDatabaseAdmin\022" - + "\300\001\n\rListDatabases\0226.google.spanner.admin" - + ".database.v1.ListDatabasesRequest\0327.goog" - + "le.spanner.admin.database.v1.ListDatabas" - + "esResponse\">\202\323\344\223\002/\022-/v1/{parent=projects" - + "/*/instances/*}/databases\332A\006parent\022\244\002\n\016C" - + "reateDatabase\0227.google.spanner.admin.dat" - + "abase.v1.CreateDatabaseRequest\032\035.google." - + "longrunning.Operation\"\271\001\202\323\344\223\0022\"-/v1/{par" - + "ent=projects/*/instances/*}/databases:\001*" - + "\332A\027parent,create_statement\312Ad\n)google.sp" - + "anner.admin.database.v1.Database\0227google" - + ".spanner.admin.database.v1.CreateDatabas" - + "eMetadata\022\255\001\n\013GetDatabase\0224.google.spann" - + "er.admin.database.v1.GetDatabaseRequest\032" - + "*.google.spanner.admin.database.v1.Datab" - + "ase\"<\202\323\344\223\002/\022-/v1/{name=projects/*/instan" - + "ces/*/databases/*}\332A\004name\022\235\002\n\021UpdateData" - + "baseDdl\022:.google.spanner.admin.database." - + "v1.UpdateDatabaseDdlRequest\032\035.google.lon" - + "grunning.Operation\"\254\001\202\323\344\223\002:25/v1/{databa" - + "se=projects/*/instances/*/databases/*}/d" - + "dl:\001*\332A\023database,statements\312AS\n\025google.p" - + "rotobuf.Empty\022:google.spanner.admin.data" - + "base.v1.UpdateDatabaseDdlMetadata\022\243\001\n\014Dr" - + "opDatabase\0225.google.spanner.admin.databa" - + "se.v1.DropDatabaseRequest\032\026.google.proto" - + "buf.Empty\"D\202\323\344\223\0023*1/v1/{database=project" - + "s/*/instances/*/databases/*}\332A\010database\022" - + "\315\001\n\016GetDatabaseDdl\0227.google.spanner.admi" - + "n.database.v1.GetDatabaseDdlRequest\0328.go" - + "ogle.spanner.admin.database.v1.GetDataba" - + "seDdlResponse\"H\202\323\344\223\0027\0225/v1/{database=pro" - + "jects/*/instances/*/databases/*}/ddl\332A\010d" - + "atabase\022\353\001\n\014SetIamPolicy\022\".google.iam.v1" - + ".SetIamPolicyRequest\032\025.google.iam.v1.Pol" - + "icy\"\237\001\202\323\344\223\002\206\001\">/v1/{resource=projects/*/" - + "instances/*/databases/*}:setIamPolicy:\001*" - + "ZA\"/v1/{resource=projects/*/in" - + "stances/*/databases/*}:getIamPolicy:\001*ZA" - + "\".google.sp" - + "anner.admin.database.v1.ListBackupOperat" - + "ionsResponse\"E\202\323\344\223\0026\0224/v1/{parent=projec" - + "ts/*/instances/*}/backupOperations\332A\006par" - + "ent\022\334\001\n\021ListDatabaseRoles\022:.google.spann" - + "er.admin.database.v1.ListDatabaseRolesRe" - + "quest\032;.google.spanner.admin.database.v1" - + ".ListDatabaseRolesResponse\"N\202\323\344\223\002?\022=/v1/" - + "{parent=projects/*/instances/*/databases" - + "/*}/databaseRoles\332A\006parent\032x\312A\026spanner.g" - + "oogleapis.com\322A\\https://www.googleapis.c" - + "om/auth/cloud-platform,https://www.googl" - + "eapis.com/auth/spanner.adminB\332\002\n$com.goo" - + "gle.spanner.admin.database.v1B\031SpannerDa" - + "tabaseAdminProtoP\001ZHgoogle.golang.org/ge" - + "nproto/googleapis/spanner/admin/database" - + "/v1;database\252\002&Google.Cloud.Spanner.Admi" - + "n.Database.V1\312\002&Google\\Cloud\\Spanner\\Adm" - + "in\\Database\\V1\352\002+Google::Cloud::Spanner:" - + ":Admin::Database::V1\352AJ\n\037spanner.googlea" - + "pis.com/Instance\022\'projects/{project}/ins" - + "tances/{instance}b\006proto3" + + "e\"\244\001\n\030UpdateDatabaseDdlRequest\0229\n\010databa" + + "se\030\001 \001(\tB\'\340A\002\372A!\n\037spanner.googleapis.com" + + "/Database\022\027\n\nstatements\030\002 \003(\tB\003\340A\002\022\024\n\014op" + + "eration_id\030\003 \001(\t\022\036\n\021proto_descriptors\030\004 " + + "\001(\014B\003\340A\001\"\375\001\n\031UpdateDatabaseDdlMetadata\0226" + + "\n\010database\030\001 \001(\tB$\372A!\n\037spanner.googleapi" + + "s.com/Database\022\022\n\nstatements\030\002 \003(\t\0225\n\021co" + + "mmit_timestamps\030\003 \003(\0132\032.google.protobuf." + + "Timestamp\022\026\n\tthrottled\030\004 \001(\010B\003\340A\003\022E\n\010pro" + + "gress\030\005 \003(\01323.google.spanner.admin.datab" + + "ase.v1.OperationProgress\"P\n\023DropDatabase" + + "Request\0229\n\010database\030\001 \001(\tB\'\340A\002\372A!\n\037spann" + + "er.googleapis.com/Database\"R\n\025GetDatabas" + + "eDdlRequest\0229\n\010database\030\001 \001(\tB\'\340A\002\372A!\n\037s" + + "panner.googleapis.com/Database\"G\n\026GetDat" + + "abaseDdlResponse\022\022\n\nstatements\030\001 \003(\t\022\031\n\021" + + "proto_descriptors\030\002 \001(\014\"\217\001\n\035ListDatabase" + + "OperationsRequest\0227\n\006parent\030\001 \001(\tB\'\340A\002\372A" + + "!\n\037spanner.googleapis.com/Instance\022\016\n\006fi" + + "lter\030\002 \001(\t\022\021\n\tpage_size\030\003 \001(\005\022\022\n\npage_to" + + "ken\030\004 \001(\t\"l\n\036ListDatabaseOperationsRespo" + + "nse\0221\n\noperations\030\001 \003(\0132\035.google.longrun" + + "ning.Operation\022\027\n\017next_page_token\030\002 \001(\t\"" + + "\216\002\n\026RestoreDatabaseRequest\0227\n\006parent\030\001 \001" + + "(\tB\'\340A\002\372A!\n\037spanner.googleapis.com/Insta" + + "nce\022\030\n\013database_id\030\002 \001(\tB\003\340A\002\0224\n\006backup\030" + + "\003 \001(\tB\"\372A\037\n\035spanner.googleapis.com/Backu" + + "pH\000\022a\n\021encryption_config\030\004 \001(\0132A.google." + + "spanner.admin.database.v1.RestoreDatabas" + + "eEncryptionConfigB\003\340A\001B\010\n\006source\"\363\002\n\037Res" + + "toreDatabaseEncryptionConfig\022n\n\017encrypti" + + "on_type\030\001 \001(\0162P.google.spanner.admin.dat" + + "abase.v1.RestoreDatabaseEncryptionConfig" + + ".EncryptionTypeB\003\340A\002\022?\n\014kms_key_name\030\002 \001" + + "(\tB)\340A\001\372A#\n!cloudkms.googleapis.com/Cryp" + + "toKey\"\236\001\n\016EncryptionType\022\037\n\033ENCRYPTION_T" + + "YPE_UNSPECIFIED\020\000\022+\n\'USE_CONFIG_DEFAULT_" + + "OR_BACKUP_ENCRYPTION\020\001\022\035\n\031GOOGLE_DEFAULT" + + "_ENCRYPTION\020\002\022\037\n\033CUSTOMER_MANAGED_ENCRYP" + + "TION\020\003\"\215\003\n\027RestoreDatabaseMetadata\0222\n\004na" + + "me\030\001 \001(\tB$\372A!\n\037spanner.googleapis.com/Da" + + "tabase\022H\n\013source_type\030\002 \001(\01623.google.spa" + + "nner.admin.database.v1.RestoreSourceType" + + "\022C\n\013backup_info\030\003 \001(\0132,.google.spanner.a" + + "dmin.database.v1.BackupInfoH\000\022E\n\010progres" + + "s\030\004 \001(\01323.google.spanner.admin.database." + + "v1.OperationProgress\022/\n\013cancel_time\030\005 \001(" + + "\0132\032.google.protobuf.Timestamp\022(\n optimiz" + + "e_database_operation_name\030\006 \001(\tB\r\n\013sourc" + + "e_info\"\235\001\n OptimizeRestoredDatabaseMetad" + + "ata\0222\n\004name\030\001 \001(\tB$\372A!\n\037spanner.googleap" + + "is.com/Database\022E\n\010progress\030\002 \001(\01323.goog" + + "le.spanner.admin.database.v1.OperationPr" + + "ogress\"\236\001\n\014DatabaseRole\022\021\n\004name\030\001 \001(\tB\003\340" + + "A\002:{\352Ax\n#spanner.googleapis.com/Database" + + "Role\022Qprojects/{project}/instances/{inst" + + "ance}/databases/{database}/databaseRoles" + + "/{role}\"z\n\030ListDatabaseRolesRequest\0227\n\006p" + + "arent\030\001 \001(\tB\'\340A\002\372A!\n\037spanner.googleapis." + + "com/Database\022\021\n\tpage_size\030\002 \001(\005\022\022\n\npage_" + + "token\030\003 \001(\t\"|\n\031ListDatabaseRolesResponse" + + "\022F\n\016database_roles\030\001 \003(\0132..google.spanne" + + "r.admin.database.v1.DatabaseRole\022\027\n\017next" + + "_page_token\030\002 \001(\t*5\n\021RestoreSourceType\022\024" + + "\n\020TYPE_UNSPECIFIED\020\000\022\n\n\006BACKUP\020\0012\374#\n\rDat" + + "abaseAdmin\022\300\001\n\rListDatabases\0226.google.sp" + + "anner.admin.database.v1.ListDatabasesReq" + + "uest\0327.google.spanner.admin.database.v1." + + "ListDatabasesResponse\">\202\323\344\223\002/\022-/v1/{pare" + + "nt=projects/*/instances/*}/databases\332A\006p" + + "arent\022\244\002\n\016CreateDatabase\0227.google.spanne" + + "r.admin.database.v1.CreateDatabaseReques" + + "t\032\035.google.longrunning.Operation\"\271\001\202\323\344\223\002" + + "2\"-/v1/{parent=projects/*/instances/*}/d" + + "atabases:\001*\332A\027parent,create_statement\312Ad" + + "\n)google.spanner.admin.database.v1.Datab" + + "ase\0227google.spanner.admin.database.v1.Cr" + + "eateDatabaseMetadata\022\255\001\n\013GetDatabase\0224.g" + + "oogle.spanner.admin.database.v1.GetDatab" + + "aseRequest\032*.google.spanner.admin.databa" + + "se.v1.Database\"<\202\323\344\223\002/\022-/v1/{name=projec" + + "ts/*/instances/*/databases/*}\332A\004name\022\235\002\n" + + "\021UpdateDatabaseDdl\022:.google.spanner.admi" + + "n.database.v1.UpdateDatabaseDdlRequest\032\035" + + ".google.longrunning.Operation\"\254\001\202\323\344\223\002:25" + + "/v1/{database=projects/*/instances/*/dat" + + "abases/*}/ddl:\001*\332A\023database,statements\312A" + + "S\n\025google.protobuf.Empty\022:google.spanner" + + ".admin.database.v1.UpdateDatabaseDdlMeta" + + "data\022\243\001\n\014DropDatabase\0225.google.spanner.a" + + "dmin.database.v1.DropDatabaseRequest\032\026.g" + + "oogle.protobuf.Empty\"D\202\323\344\223\0023*1/v1/{datab" + + "ase=projects/*/instances/*/databases/*}\332" + + "A\010database\022\315\001\n\016GetDatabaseDdl\0227.google.s" + + "panner.admin.database.v1.GetDatabaseDdlR" + + "equest\0328.google.spanner.admin.database.v" + + "1.GetDatabaseDdlResponse\"H\202\323\344\223\0027\0225/v1/{d" + + "atabase=projects/*/instances/*/databases" + + "/*}/ddl\332A\010database\022\353\001\n\014SetIamPolicy\022\".go" + + "ogle.iam.v1.SetIamPolicyRequest\032\025.google" + + ".iam.v1.Policy\"\237\001\202\323\344\223\002\206\001\">/v1/{resource=" + + "projects/*/instances/*/databases/*}:setI" + + "amPolicy:\001*ZA\"/v1/{resource=pr" + + "ojects/*/instances/*/databases/*}:getIam" + + "Policy:\001*ZA\".google.spanner.admin.database.v1.ListB" + + "ackupOperationsResponse\"E\202\323\344\223\0026\0224/v1/{pa" + + "rent=projects/*/instances/*}/backupOpera" + + "tions\332A\006parent\022\334\001\n\021ListDatabaseRoles\022:.g" + + "oogle.spanner.admin.database.v1.ListData" + + "baseRolesRequest\032;.google.spanner.admin." + + "database.v1.ListDatabaseRolesResponse\"N\202" + + "\323\344\223\002?\022=/v1/{parent=projects/*/instances/" + + "*/databases/*}/databaseRoles\332A\006parent\032x\312" + + "A\026spanner.googleapis.com\322A\\https://www.g" + + "oogleapis.com/auth/cloud-platform,https:" + + "//www.googleapis.com/auth/spanner.adminB" + + "\332\002\n$com.google.spanner.admin.database.v1" + + "B\031SpannerDatabaseAdminProtoP\001ZHgoogle.go" + + "lang.org/genproto/googleapis/spanner/adm" + + "in/database/v1;database\252\002&Google.Cloud.S" + + "panner.Admin.Database.V1\312\002&Google\\Cloud\\" + + "Spanner\\Admin\\Database\\V1\352\002+Google::Clou" + + "d::Spanner::Admin::Database::V1\352AJ\n\037span" + + "ner.googleapis.com/Instance\022\'projects/{p" + + "roject}/instances/{instance}b\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( @@ -425,7 +427,12 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_google_spanner_admin_database_v1_CreateDatabaseRequest_descriptor, new java.lang.String[] { - "Parent", "CreateStatement", "ExtraStatements", "EncryptionConfig", "DatabaseDialect", + "Parent", + "CreateStatement", + "ExtraStatements", + "EncryptionConfig", + "DatabaseDialect", + "ProtoDescriptors", }); internal_static_google_spanner_admin_database_v1_CreateDatabaseMetadata_descriptor = getDescriptor().getMessageTypes().get(5); @@ -449,7 +456,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_google_spanner_admin_database_v1_UpdateDatabaseDdlRequest_descriptor, new java.lang.String[] { - "Database", "Statements", "OperationId", + "Database", "Statements", "OperationId", "ProtoDescriptors", }); internal_static_google_spanner_admin_database_v1_UpdateDatabaseDdlMetadata_descriptor = getDescriptor().getMessageTypes().get(8); @@ -481,7 +488,7 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_google_spanner_admin_database_v1_GetDatabaseDdlResponse_descriptor, new java.lang.String[] { - "Statements", + "Statements", "ProtoDescriptors", }); internal_static_google_spanner_admin_database_v1_ListDatabaseOperationsRequest_descriptor = getDescriptor().getMessageTypes().get(12); diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequest.java index 3911178f357..b698ca808f4 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequest.java @@ -55,6 +55,7 @@ private UpdateDatabaseDdlRequest() { database_ = ""; statements_ = com.google.protobuf.LazyStringArrayList.EMPTY; operationId_ = ""; + protoDescriptors_ = com.google.protobuf.ByteString.EMPTY; } @java.lang.Override @@ -278,6 +279,43 @@ public com.google.protobuf.ByteString getOperationIdBytes() { } } + public static final int PROTO_DESCRIPTORS_FIELD_NUMBER = 4; + private com.google.protobuf.ByteString protoDescriptors_; + /** + * + * + *
+   * Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements.
+   * Contains a protobuf-serialized
+   * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+   * To generate it, [install](https://grpc.io/docs/protoc-installation/) and
+   * run `protoc` with --include_imports and --descriptor_set_out. For example,
+   * to generate for moon/shot/app.proto, run
+   * """
+   * $protoc  --proto_path=/app_path --proto_path=/lib_path \
+   *          --include_imports \
+   *          --descriptor_set_out=descriptors.data \
+   *          moon/shot/app.proto
+   * """
+   * For more details, see protobuffer [self
+   * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+   * (--
+   * TODO(b/236424835) remove visibility check before launch.
+   * --)
+   * (-- api-linter: core::0134::request-unknown-fields=disabled
+   *     aip.dev/not-precedent: This Update*Request provides an alter action
+   *     rather than the usual entity field updating. --)
+   * 
+ * + * bytes proto_descriptors = 4 [(.google.api.field_behavior) = OPTIONAL]; + * + * @return The protoDescriptors. + */ + @java.lang.Override + public com.google.protobuf.ByteString getProtoDescriptors() { + return protoDescriptors_; + } + private byte memoizedIsInitialized = -1; @java.lang.Override @@ -301,6 +339,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(operationId_)) { com.google.protobuf.GeneratedMessageV3.writeString(output, 3, operationId_); } + if (!protoDescriptors_.isEmpty()) { + output.writeBytes(4, protoDescriptors_); + } getUnknownFields().writeTo(output); } @@ -324,6 +365,9 @@ public int getSerializedSize() { if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(operationId_)) { size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, operationId_); } + if (!protoDescriptors_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(4, protoDescriptors_); + } size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; @@ -343,6 +387,7 @@ public boolean equals(final java.lang.Object obj) { if (!getDatabase().equals(other.getDatabase())) return false; if (!getStatementsList().equals(other.getStatementsList())) return false; if (!getOperationId().equals(other.getOperationId())) return false; + if (!getProtoDescriptors().equals(other.getProtoDescriptors())) return false; if (!getUnknownFields().equals(other.getUnknownFields())) return false; return true; } @@ -362,6 +407,8 @@ public int hashCode() { } hash = (37 * hash) + OPERATION_ID_FIELD_NUMBER; hash = (53 * hash) + getOperationId().hashCode(); + hash = (37 * hash) + PROTO_DESCRIPTORS_FIELD_NUMBER; + hash = (53 * hash) + getProtoDescriptors().hashCode(); hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; @@ -521,6 +568,8 @@ public Builder clear() { bitField0_ = (bitField0_ & ~0x00000001); operationId_ = ""; + protoDescriptors_ = com.google.protobuf.ByteString.EMPTY; + return this; } @@ -557,6 +606,7 @@ public com.google.spanner.admin.database.v1.UpdateDatabaseDdlRequest buildPartia } result.statements_ = statements_; result.operationId_ = operationId_; + result.protoDescriptors_ = protoDescriptors_; onBuilt(); return result; } @@ -626,6 +676,9 @@ public Builder mergeFrom(com.google.spanner.admin.database.v1.UpdateDatabaseDdlR operationId_ = other.operationId_; onChanged(); } + if (other.getProtoDescriptors() != com.google.protobuf.ByteString.EMPTY) { + setProtoDescriptors(other.getProtoDescriptors()); + } this.mergeUnknownFields(other.getUnknownFields()); onChanged(); return this; @@ -671,6 +724,12 @@ public Builder mergeFrom( break; } // case 26 + case 34: + { + protoDescriptors_ = input.readBytes(); + + break; + } // case 34 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { @@ -1160,6 +1219,118 @@ public Builder setOperationIdBytes(com.google.protobuf.ByteString value) { return this; } + private com.google.protobuf.ByteString protoDescriptors_ = com.google.protobuf.ByteString.EMPTY; + /** + * + * + *
+     * Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements.
+     * Contains a protobuf-serialized
+     * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+     * To generate it, [install](https://grpc.io/docs/protoc-installation/) and
+     * run `protoc` with --include_imports and --descriptor_set_out. For example,
+     * to generate for moon/shot/app.proto, run
+     * """
+     * $protoc  --proto_path=/app_path --proto_path=/lib_path \
+     *          --include_imports \
+     *          --descriptor_set_out=descriptors.data \
+     *          moon/shot/app.proto
+     * """
+     * For more details, see protobuffer [self
+     * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+     * (--
+     * TODO(b/236424835) remove visibility check before launch.
+     * --)
+     * (-- api-linter: core::0134::request-unknown-fields=disabled
+     *     aip.dev/not-precedent: This Update*Request provides an alter action
+     *     rather than the usual entity field updating. --)
+     * 
+ * + * bytes proto_descriptors = 4 [(.google.api.field_behavior) = OPTIONAL]; + * + * @return The protoDescriptors. + */ + @java.lang.Override + public com.google.protobuf.ByteString getProtoDescriptors() { + return protoDescriptors_; + } + /** + * + * + *
+     * Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements.
+     * Contains a protobuf-serialized
+     * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+     * To generate it, [install](https://grpc.io/docs/protoc-installation/) and
+     * run `protoc` with --include_imports and --descriptor_set_out. For example,
+     * to generate for moon/shot/app.proto, run
+     * """
+     * $protoc  --proto_path=/app_path --proto_path=/lib_path \
+     *          --include_imports \
+     *          --descriptor_set_out=descriptors.data \
+     *          moon/shot/app.proto
+     * """
+     * For more details, see protobuffer [self
+     * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+     * (--
+     * TODO(b/236424835) remove visibility check before launch.
+     * --)
+     * (-- api-linter: core::0134::request-unknown-fields=disabled
+     *     aip.dev/not-precedent: This Update*Request provides an alter action
+     *     rather than the usual entity field updating. --)
+     * 
+ * + * bytes proto_descriptors = 4 [(.google.api.field_behavior) = OPTIONAL]; + * + * @param value The protoDescriptors to set. + * @return This builder for chaining. + */ + public Builder setProtoDescriptors(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + + protoDescriptors_ = value; + onChanged(); + return this; + } + /** + * + * + *
+     * Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements.
+     * Contains a protobuf-serialized
+     * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+     * To generate it, [install](https://grpc.io/docs/protoc-installation/) and
+     * run `protoc` with --include_imports and --descriptor_set_out. For example,
+     * to generate for moon/shot/app.proto, run
+     * """
+     * $protoc  --proto_path=/app_path --proto_path=/lib_path \
+     *          --include_imports \
+     *          --descriptor_set_out=descriptors.data \
+     *          moon/shot/app.proto
+     * """
+     * For more details, see protobuffer [self
+     * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+     * (--
+     * TODO(b/236424835) remove visibility check before launch.
+     * --)
+     * (-- api-linter: core::0134::request-unknown-fields=disabled
+     *     aip.dev/not-precedent: This Update*Request provides an alter action
+     *     rather than the usual entity field updating. --)
+     * 
+ * + * bytes proto_descriptors = 4 [(.google.api.field_behavior) = OPTIONAL]; + * + * @return This builder for chaining. + */ + public Builder clearProtoDescriptors() { + + protoDescriptors_ = getDefaultInstance().getProtoDescriptors(); + onChanged(); + return this; + } + @java.lang.Override public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { return super.setUnknownFields(unknownFields); diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequestOrBuilder.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequestOrBuilder.java index cad7c3a28a2..ba445dc1a18 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequestOrBuilder.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequestOrBuilder.java @@ -159,4 +159,36 @@ public interface UpdateDatabaseDdlRequestOrBuilder * @return The bytes for operationId. */ com.google.protobuf.ByteString getOperationIdBytes(); + + /** + * + * + *
+   * Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements.
+   * Contains a protobuf-serialized
+   * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+   * To generate it, [install](https://grpc.io/docs/protoc-installation/) and
+   * run `protoc` with --include_imports and --descriptor_set_out. For example,
+   * to generate for moon/shot/app.proto, run
+   * """
+   * $protoc  --proto_path=/app_path --proto_path=/lib_path \
+   *          --include_imports \
+   *          --descriptor_set_out=descriptors.data \
+   *          moon/shot/app.proto
+   * """
+   * For more details, see protobuffer [self
+   * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+   * (--
+   * TODO(b/236424835) remove visibility check before launch.
+   * --)
+   * (-- api-linter: core::0134::request-unknown-fields=disabled
+   *     aip.dev/not-precedent: This Update*Request provides an alter action
+   *     rather than the usual entity field updating. --)
+   * 
+ * + * bytes proto_descriptors = 4 [(.google.api.field_behavior) = OPTIONAL]; + * + * @return The protoDescriptors. + */ + com.google.protobuf.ByteString getProtoDescriptors(); } diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/spanner_database_admin.proto b/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/spanner_database_admin.proto index 91489ae4b45..f27617c4f09 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/spanner_database_admin.proto +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/spanner_database_admin.proto @@ -514,6 +514,23 @@ message CreateDatabaseRequest { // Optional. The dialect of the Cloud Spanner Database. DatabaseDialect database_dialect = 5 [(google.api.field_behavior) = OPTIONAL]; + + // Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements in + // 'extra_statements' above. + // Contains a protobuf-serialized + // [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto). + // To generate it, [install](https://grpc.io/docs/protoc-installation/) and + // run `protoc` with --include_imports and --descriptor_set_out. For example, + // to generate for moon/shot/app.proto, run + // """ + // $protoc --proto_path=/app_path --proto_path=/lib_path \ + // --include_imports \ + // --descriptor_set_out=descriptors.data \ + // moon/shot/app.proto + // """ + // For more details, see protobuffer [self + // description](https://developers.google.com/protocol-buffers/docs/techniques#self-description). + bytes proto_descriptors = 6 [(google.api.field_behavior) = OPTIONAL]; } // Metadata type for the operation returned by @@ -585,6 +602,28 @@ message UpdateDatabaseDdlRequest { // [UpdateDatabaseDdl][google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabaseDdl] returns // `ALREADY_EXISTS`. string operation_id = 3; + + // Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements. + // Contains a protobuf-serialized + // [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto). + // To generate it, [install](https://grpc.io/docs/protoc-installation/) and + // run `protoc` with --include_imports and --descriptor_set_out. For example, + // to generate for moon/shot/app.proto, run + // """ + // $protoc --proto_path=/app_path --proto_path=/lib_path \ + // --include_imports \ + // --descriptor_set_out=descriptors.data \ + // moon/shot/app.proto + // """ + // For more details, see protobuffer [self + // description](https://developers.google.com/protocol-buffers/docs/techniques#self-description). + // (-- + // TODO(b/236424835) remove visibility check before launch. + // --) + // (-- api-linter: core::0134::request-unknown-fields=disabled + // aip.dev/not-precedent: This Update*Request provides an alter action + // rather than the usual entity field updating. --) + bytes proto_descriptors = 4 [(google.api.field_behavior) = OPTIONAL]; } // Metadata type for the operation returned by @@ -649,6 +688,13 @@ message GetDatabaseDdlResponse { // A list of formatted DDL statements defining the schema of the database // specified in the request. repeated string statements = 1; + + // Proto descriptors stored in the database. + // Contains a protobuf-serialized + // [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto). + // For more details, see protobuffer [self + // description](https://developers.google.com/protocol-buffers/docs/techniques#self-description). + bytes proto_descriptors = 2; } // The request for From 16539168c3739c6035f5a23a3ef5e310e73216a4 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Mon, 30 Jan 2023 10:52:02 +0000 Subject: [PATCH 02/25] feat: add auto generated code --- .../database/v1/CreateDatabaseRequest.java | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequest.java b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequest.java index 067490d01b5..2b2b510e56e 100644 --- a/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequest.java +++ b/proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequest.java @@ -42,6 +42,7 @@ private CreateDatabaseRequest() { createStatement_ = ""; extraStatements_ = com.google.protobuf.LazyStringArrayList.EMPTY; databaseDialect_ = 0; + protoDescriptors_ = com.google.protobuf.ByteString.EMPTY; } @java.lang.Override @@ -358,6 +359,38 @@ public com.google.spanner.admin.database.v1.DatabaseDialect getDatabaseDialect() : result; } + public static final int PROTO_DESCRIPTORS_FIELD_NUMBER = 6; + private com.google.protobuf.ByteString protoDescriptors_; + /** + * + * + *
+   * Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements in
+   * 'extra_statements' above.
+   * Contains a protobuf-serialized
+   * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+   * To generate it, [install](https://grpc.io/docs/protoc-installation/) and
+   * run `protoc` with --include_imports and --descriptor_set_out. For example,
+   * to generate for moon/shot/app.proto, run
+   * """
+   * $protoc  --proto_path=/app_path --proto_path=/lib_path \
+   *          --include_imports \
+   *          --descriptor_set_out=descriptors.data \
+   *          moon/shot/app.proto
+   * """
+   * For more details, see protobuffer [self
+   * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+   * 
+ * + * bytes proto_descriptors = 6 [(.google.api.field_behavior) = OPTIONAL]; + * + * @return The protoDescriptors. + */ + @java.lang.Override + public com.google.protobuf.ByteString getProtoDescriptors() { + return protoDescriptors_; + } + private byte memoizedIsInitialized = -1; @java.lang.Override @@ -389,6 +422,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io .getNumber()) { output.writeEnum(5, databaseDialect_); } + if (!protoDescriptors_.isEmpty()) { + output.writeBytes(6, protoDescriptors_); + } getUnknownFields().writeTo(output); } @@ -420,6 +456,9 @@ public int getSerializedSize() { .getNumber()) { size += com.google.protobuf.CodedOutputStream.computeEnumSize(5, databaseDialect_); } + if (!protoDescriptors_.isEmpty()) { + size += com.google.protobuf.CodedOutputStream.computeBytesSize(6, protoDescriptors_); + } size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; @@ -444,6 +483,7 @@ public boolean equals(final java.lang.Object obj) { if (!getEncryptionConfig().equals(other.getEncryptionConfig())) return false; } if (databaseDialect_ != other.databaseDialect_) return false; + if (!getProtoDescriptors().equals(other.getProtoDescriptors())) return false; if (!getUnknownFields().equals(other.getUnknownFields())) return false; return true; } @@ -469,6 +509,8 @@ public int hashCode() { } hash = (37 * hash) + DATABASE_DIALECT_FIELD_NUMBER; hash = (53 * hash) + databaseDialect_; + hash = (37 * hash) + PROTO_DESCRIPTORS_FIELD_NUMBER; + hash = (53 * hash) + getProtoDescriptors().hashCode(); hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; @@ -622,6 +664,8 @@ public Builder clear() { } databaseDialect_ = 0; + protoDescriptors_ = com.google.protobuf.ByteString.EMPTY; + return this; } @@ -663,6 +707,7 @@ public com.google.spanner.admin.database.v1.CreateDatabaseRequest buildPartial() result.encryptionConfig_ = encryptionConfigBuilder_.build(); } result.databaseDialect_ = databaseDialect_; + result.protoDescriptors_ = protoDescriptors_; onBuilt(); return result; } @@ -737,6 +782,9 @@ public Builder mergeFrom(com.google.spanner.admin.database.v1.CreateDatabaseRequ if (other.databaseDialect_ != 0) { setDatabaseDialectValue(other.getDatabaseDialectValue()); } + if (other.getProtoDescriptors() != com.google.protobuf.ByteString.EMPTY) { + setProtoDescriptors(other.getProtoDescriptors()); + } this.mergeUnknownFields(other.getUnknownFields()); onChanged(); return this; @@ -795,6 +843,12 @@ public Builder mergeFrom( break; } // case 40 + case 50: + { + protoDescriptors_ = input.readBytes(); + + break; + } // case 50 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { @@ -1585,6 +1639,103 @@ public Builder clearDatabaseDialect() { return this; } + private com.google.protobuf.ByteString protoDescriptors_ = com.google.protobuf.ByteString.EMPTY; + /** + * + * + *
+     * Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements in
+     * 'extra_statements' above.
+     * Contains a protobuf-serialized
+     * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+     * To generate it, [install](https://grpc.io/docs/protoc-installation/) and
+     * run `protoc` with --include_imports and --descriptor_set_out. For example,
+     * to generate for moon/shot/app.proto, run
+     * """
+     * $protoc  --proto_path=/app_path --proto_path=/lib_path \
+     *          --include_imports \
+     *          --descriptor_set_out=descriptors.data \
+     *          moon/shot/app.proto
+     * """
+     * For more details, see protobuffer [self
+     * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+     * 
+ * + * bytes proto_descriptors = 6 [(.google.api.field_behavior) = OPTIONAL]; + * + * @return The protoDescriptors. + */ + @java.lang.Override + public com.google.protobuf.ByteString getProtoDescriptors() { + return protoDescriptors_; + } + /** + * + * + *
+     * Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements in
+     * 'extra_statements' above.
+     * Contains a protobuf-serialized
+     * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+     * To generate it, [install](https://grpc.io/docs/protoc-installation/) and
+     * run `protoc` with --include_imports and --descriptor_set_out. For example,
+     * to generate for moon/shot/app.proto, run
+     * """
+     * $protoc  --proto_path=/app_path --proto_path=/lib_path \
+     *          --include_imports \
+     *          --descriptor_set_out=descriptors.data \
+     *          moon/shot/app.proto
+     * """
+     * For more details, see protobuffer [self
+     * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+     * 
+ * + * bytes proto_descriptors = 6 [(.google.api.field_behavior) = OPTIONAL]; + * + * @param value The protoDescriptors to set. + * @return This builder for chaining. + */ + public Builder setProtoDescriptors(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + + protoDescriptors_ = value; + onChanged(); + return this; + } + /** + * + * + *
+     * Proto descriptors used by CREATE/ALTER PROTO BUNDLE statements in
+     * 'extra_statements' above.
+     * Contains a protobuf-serialized
+     * [google.protobuf.FileDescriptorSet](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/descriptor.proto).
+     * To generate it, [install](https://grpc.io/docs/protoc-installation/) and
+     * run `protoc` with --include_imports and --descriptor_set_out. For example,
+     * to generate for moon/shot/app.proto, run
+     * """
+     * $protoc  --proto_path=/app_path --proto_path=/lib_path \
+     *          --include_imports \
+     *          --descriptor_set_out=descriptors.data \
+     *          moon/shot/app.proto
+     * """
+     * For more details, see protobuffer [self
+     * description](https://developers.google.com/protocol-buffers/docs/techniques#self-description).
+     * 
+ * + * bytes proto_descriptors = 6 [(.google.api.field_behavior) = OPTIONAL]; + * + * @return This builder for chaining. + */ + public Builder clearProtoDescriptors() { + + protoDescriptors_ = getDefaultInstance().getProtoDescriptors(); + onChanged(); + return this; + } + @java.lang.Override public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { return super.setUnknownFields(unknownFields); From 88cb28dcd33a8d4888c1e8239c75691d5cd68066 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Wed, 1 Feb 2023 05:27:37 +0000 Subject: [PATCH 03/25] feat: code changes and tests for Proto columns DDL support --- .../com/google/cloud/spanner/Database.java | 5 +- .../cloud/spanner/DatabaseAdminClient.java | 14 +-- .../spanner/DatabaseAdminClientImpl.java | 30 +++--- .../google/cloud/spanner/DatabaseInfo.java | 11 ++- .../java/com/google/cloud/spanner/Type.java | 41 +++------ .../cloud/spanner/spi/v1/GapicSpannerRpc.java | 31 ++++--- .../cloud/spanner/spi/v1/SpannerRpc.java | 10 +- .../spanner/DatabaseAdminClientImplTest.java | 41 +++++---- .../cloud/spanner/it/ITProtoColumnTest.java | 91 +++++++++---------- 9 files changed, 130 insertions(+), 144 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java index 89206119c79..2aab03c4033 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java @@ -25,7 +25,6 @@ import com.google.cloud.spanner.encryption.CustomerManagedEncryption; import com.google.common.base.Preconditions; import com.google.longrunning.Operation; -import com.google.protobuf.ByteString; import com.google.spanner.admin.database.v1.CreateBackupMetadata; import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; @@ -90,8 +89,8 @@ public OperationFuture updateDdl( } public OperationFuture updateDdl( - Iterable statements, String operationId, byte[] protoDescriptors) throws SpannerException { - return dbClient.updateDatabaseDdl(instance(), database(), statements, operationId, protoDescriptors); + Database database, Iterable statements, String operationId) throws SpannerException { + return dbClient.updateDatabaseDdl(database, statements, operationId); } /** Drops this database. */ diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java index 69e1c6187e3..5dab8b4c744 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java @@ -22,7 +22,6 @@ import com.google.cloud.Timestamp; import com.google.cloud.spanner.Options.ListOption; import com.google.longrunning.Operation; -import com.google.protobuf.ByteString; import com.google.spanner.admin.database.v1.CopyBackupMetadata; import com.google.spanner.admin.database.v1.CreateBackupMetadata; import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; @@ -384,8 +383,9 @@ OperationFuture restoreDatabase(Restore resto * *

If an operation already exists with the given operation id, the operation will be resumed * and the returned future will complete when the original operation finishes. See more - * information in {@link com.google.cloud.spanner.spi.v1.GapicSpannerRpc#updateDatabaseDdl(String, - * Iterable, String, ByteString)} + * information in {@link + * com.google.cloud.spanner.spi.v1.GapicSpannerRpc#updateDatabaseDdl(com.google.cloud.spanner.Database, + * Iterable, String)} * *

Example to update the database DDL. * @@ -410,11 +410,7 @@ OperationFuture updateDatabaseDdl( throws SpannerException; OperationFuture updateDatabaseDdl( - String instanceId, - String databaseId, - Iterable statements, - @Nullable String operationId, - @Nullable byte[] protoDescriptors) + Database database, Iterable statements, @Nullable String operationId) throws SpannerException; /** @@ -444,7 +440,7 @@ OperationFuture updateDatabaseDdl( */ List getDatabaseDdl(String instanceId, String databaseId); - GetDatabaseDdlResponse getDatabaseDdlWithProtoDescriptors(String instanceId, String databaseId); + GetDatabaseDdlResponse getDatabaseDdlResponse(String instanceId, String databaseId); /** * Returns the list of Cloud Spanner database in the given instance. diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java index 9f170096386..fe39571e2f7 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java @@ -31,7 +31,6 @@ import com.google.common.base.Preconditions; import com.google.iam.v1.GetPolicyOptions; import com.google.longrunning.Operation; -import com.google.protobuf.ByteString; import com.google.protobuf.Empty; import com.google.protobuf.FieldMask; import com.google.spanner.admin.database.v1.*; @@ -41,7 +40,9 @@ /** Default implementation of {@link DatabaseAdminClient}. */ class DatabaseAdminClientImpl implements DatabaseAdminClient { + private static final class PolicyMarshaller extends DefaultMarshaller { + @Override protected Policy fromPb(com.google.iam.v1.Policy policyPb) { return super.fromPb(policyPb); @@ -417,24 +418,26 @@ public Database getDatabase(String instanceId, String databaseId) throws Spanner } @Override - public OperationFuture updateDatabaseDdl(String instanceId, - String databaseId, Iterable statements, @Nullable String operationId) + public OperationFuture updateDatabaseDdl( + String instanceId, + String databaseId, + Iterable statements, + @Nullable String operationId) throws SpannerException { - return updateDatabaseDdl(instanceId, databaseId, statements, operationId, null); + + return updateDatabaseDdl( + newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId)).build(), + statements, + operationId); } @Override public OperationFuture updateDatabaseDdl( - final String instanceId, - final String databaseId, - final Iterable statements, - @Nullable String operationId, - @Nullable byte[] protoDescriptors) + Database database, final Iterable statements, @Nullable String operationId) throws SpannerException { - final String dbName = getDatabaseName(instanceId, databaseId); final String opId = operationId != null ? operationId : randomOperationId(); OperationFuture rawOperationFuture = - rpc.updateDatabaseDdl(dbName, statements, opId, ByteString.copyFrom(protoDescriptors)); + rpc.updateDatabaseDdl(database, statements, opId); return new OperationFutureImpl<>( rawOperationFuture.getPollingFuture(), rawOperationFuture.getInitialFuture(), @@ -456,11 +459,12 @@ public void dropDatabase(String instanceId, String databaseId) throws SpannerExc @Override public List getDatabaseDdl(String instanceId, String databaseId) { - return getDatabaseDdlWithProtoDescriptors(instanceId, databaseId).getStatementsList(); + return getDatabaseDdlResponse(instanceId, databaseId).getStatementsList(); } @Override - public GetDatabaseDdlResponse getDatabaseDdlWithProtoDescriptors(String instanceId, String databaseId) { + public GetDatabaseDdlResponse getDatabaseDdlResponse( + String instanceId, String databaseId) { String dbName = getDatabaseName(instanceId, databaseId); return rpc.getDatabaseDdl(dbName); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java index d49c5279da3..d702f5c803a 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java @@ -21,7 +21,6 @@ import com.google.common.base.Preconditions; import com.google.common.io.ByteStreams; import com.google.protobuf.ByteString; -import java.io.FileInputStream; import java.io.InputStream; import java.util.Objects; import javax.annotation.Nonnull; @@ -161,15 +160,17 @@ public Builder setProtoDescriptors(@Nonnull byte[] protoDescriptors) { } @Override - public Builder setProtoDescriptors(InputStream inputStream) throws Exception{ + public Builder setProtoDescriptors(InputStream inputStream) throws Exception { byte[] byteArray = ByteStreams.toByteArray(inputStream); this.protoDescriptors = byteArray != null ? ByteString.copyFrom(byteArray) : ByteString.EMPTY; return this; } @Override - public Builder setProtoDescriptors(String filePath) throws Exception{ - InputStream inputStream = new FileInputStream(filePath); + // TODO(harsha): This overload method needs to be completed + public Builder setProtoDescriptors(String filePath) throws Exception { + InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filePath); + // InputStream inputStream = new FileInputStream(filePath); return setProtoDescriptors(inputStream); } @@ -297,7 +298,7 @@ public Timestamp getEarliestVersionTime() { return dialect; } - public ByteString getProtoDescriptors(){ + public ByteString getProtoDescriptors() { return protoDescriptors; } 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 737b5828e99..c483a0a6ee9 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 @@ -73,9 +73,7 @@ public final class Type implements Serializable { private static final int AMBIGUOUS_FIELD = -1; private static final long serialVersionUID = -3076152125004114582L; - /** - * Returns the descriptor for the {@code BOOL type}. - */ + /** Returns the descriptor for the {@code BOOL type}. */ public static Type bool() { return TYPE_BOOL; } @@ -96,9 +94,7 @@ public static Type float64() { return TYPE_FLOAT64; } - /** - * Returns the descriptor for the {@code NUMERIC} type. - */ + /** Returns the descriptor for the {@code NUMERIC} type. */ public static Type numeric() { return TYPE_NUMERIC; } @@ -112,23 +108,18 @@ public static Type pgNumeric() { } /** - * Returns the descriptor for the {@code STRING} type: a variable-length Unicode character - * string. + * Returns the descriptor for the {@code STRING} type: a variable-length Unicode character string. */ public static Type string() { return TYPE_STRING; } - /** - * Returns the descriptor for the {@code JSON} type. - */ + /** Returns the descriptor for the {@code JSON} type. */ public static Type json() { return TYPE_JSON; } - /** - * Returns the descriptor for the {@code JSONB} type. - */ + /** Returns the descriptor for the {@code JSONB} type. */ public static Type pgJsonb() { return TYPE_PG_JSONB; } @@ -151,9 +142,7 @@ public static Type protoEnum(String protoTypeFqn) { return new Type(Code.ENUM, protoTypeFqn); } - /** - * Returns the descriptor for the {@code BYTES} type: a variable-length byte string. - */ + /** Returns the descriptor for the {@code BYTES} type: a variable-length byte string. */ public static Type bytes() { return TYPE_BYTES; } @@ -174,9 +163,7 @@ public static Type date() { return TYPE_DATE; } - /** - * Returns a descriptor for an array of {@code elementType}. - */ + /** Returns a descriptor for an array of {@code elementType}. */ public static Type array(Type elementType) { Preconditions.checkNotNull(elementType); switch (elementType.getCode()) { @@ -248,9 +235,7 @@ private Type(Code code, @Nonnull String protoTypeFqn) { this.protoTypeFqn = protoTypeFqn; } - /** - * Enumerates the categories of types. - */ + /** Enumerates the categories of types. */ public enum Code { BOOL(TypeCode.BOOL), INT64(TypeCode.INT64), @@ -315,9 +300,7 @@ public String toString() { } } - /** - * Describes an individual field in a {@code STRUCT type}. - */ + /** Describes an individual field in a {@code STRUCT type}. */ public static final class StructField implements Serializable { private static final long serialVersionUID = 8640511292704408210L; @@ -360,9 +343,7 @@ public int hashCode() { } } - /** - * Returns the type code corresponding to this type. - */ + /** Returns the type code corresponding to this type. */ public Code getCode() { return code; } @@ -403,7 +384,7 @@ public String getProtoTypeFqn() { * Returns the index of the field named {@code fieldName} in this {@code STRUCT} type. * * @throws IllegalArgumentException if there is not exactly one element of {@link - * #getStructFields()} with {@link StructField#getName()} equal to {@code fieldName} + * #getStructFields()} with {@link StructField#getName()} equal to {@code fieldName} * @throws IllegalStateException if {@code code() != Code.STRUCT} */ public int getFieldIndex(String fieldName) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index ebf4544ee1e..ce151a9edf3 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -98,7 +98,6 @@ import com.google.longrunning.GetOperationRequest; import com.google.longrunning.Operation; import com.google.longrunning.OperationsGrpc; -import com.google.protobuf.ByteString; import com.google.protobuf.Empty; import com.google.protobuf.FieldMask; import com.google.protobuf.InvalidProtocolBufferException; @@ -1192,7 +1191,7 @@ public OperationFuture createDatabase( if (databaseInfo.getDialect() != null) { requestBuilder.setDatabaseDialect(databaseInfo.getDialect().toProto()); } - if (databaseInfo.getProtoDescriptors() != null){ + if (databaseInfo.getProtoDescriptors() != null) { requestBuilder.setProtoDescriptors(databaseInfo.getProtoDescriptors()); } final CreateDatabaseRequest request = requestBuilder.build(); @@ -1252,21 +1251,26 @@ public OperationFuture createDatabase( */ @Override public OperationFuture updateDatabaseDdl( - final String databaseName, + com.google.cloud.spanner.Database databaseInfo, final Iterable updateDatabaseStatements, - @Nullable final String updateId, - @Nullable ByteString protoDescriptors) + @Nullable final String updateId) throws SpannerException { acquireAdministrativeRequestsRateLimiter(); - final UpdateDatabaseDdlRequest request = + UpdateDatabaseDdlRequest.Builder requestBuilder = UpdateDatabaseDdlRequest.newBuilder() - .setDatabase(databaseName) + .setDatabase(databaseInfo.getId().getName()) .addAllStatements(updateDatabaseStatements) - .setOperationId(MoreObjects.firstNonNull(updateId, "")) - .setProtoDescriptors(protoDescriptors) - .build(); + .setOperationId(MoreObjects.firstNonNull(updateId, "")); + if (databaseInfo.getProtoDescriptors() != null) { + requestBuilder.setProtoDescriptors(databaseInfo.getProtoDescriptors()); + } + final UpdateDatabaseDdlRequest request = requestBuilder.build(); final GrpcCallContext context = - newCallContext(null, databaseName, request, DatabaseAdminGrpc.getUpdateDatabaseDdlMethod()); + newCallContext( + null, + databaseInfo.getId().getName(), + request, + DatabaseAdminGrpc.getUpdateDatabaseDdlMethod()); final OperationCallable callable = databaseAdminStub.updateDatabaseDdlOperationCallable(); @@ -1288,7 +1292,7 @@ public OperationFuture updateDatabaseDdl( if (t instanceof AlreadyExistsException) { String operationName = OPERATION_NAME_TEMPLATE.instantiate( - "database", databaseName, "operation", updateId); + "database", databaseInfo.getId().getName(), "operation", updateId); return callable.resumeFutureCall(operationName, context); } } @@ -1332,8 +1336,7 @@ public GetDatabaseDdlResponse getDatabaseDdl(String databaseName) throws Spanner final GrpcCallContext context = newCallContext(null, databaseName, request, DatabaseAdminGrpc.getGetDatabaseDdlMethod()); return runWithRetryOnAdministrativeRequestsExceeded( - () -> - get(databaseAdminStub.getDatabaseDdlCallable().futureCall(request, context))); + () -> get(databaseAdminStub.getDatabaseDdlCallable().futureCall(request, context))); } @Override diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java index 2c30e9a7d00..e2db1d902bd 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java @@ -32,7 +32,6 @@ import com.google.iam.v1.Policy; import com.google.iam.v1.TestIamPermissionsResponse; import com.google.longrunning.Operation; -import com.google.protobuf.ByteString; import com.google.protobuf.Empty; import com.google.protobuf.FieldMask; import com.google.spanner.admin.database.v1.Backup; @@ -70,6 +69,7 @@ */ @InternalApi public interface SpannerRpc extends ServiceRpc { + /** Options passed in {@link SpannerRpc} methods to control how an RPC is issued. */ enum Option { CHANNEL_HINT("Channel Hint"); @@ -105,6 +105,7 @@ public String toString() { * @param the type of result */ final class Paginated { + private final Iterable results; private final String nextPageToken; @@ -141,6 +142,7 @@ public String getNextPageToken() { /** Consumer for the results produced by a streaming read or query call. */ interface ResultStreamConsumer { + void onPartialResultSet(PartialResultSet results); void onCompleted(); @@ -227,8 +229,9 @@ OperationFuture createDatabase( throws SpannerException; OperationFuture updateDatabaseDdl( - String databaseName, Iterable updateDatabaseStatements, @Nullable String updateId, @Nullable - ByteString protoDescriptors) + com.google.cloud.spanner.Database database, + Iterable updateDatabaseStatements, + @Nullable String updateId) throws SpannerException; void dropDatabase(String databaseName) throws SpannerException; @@ -236,6 +239,7 @@ OperationFuture updateDatabaseDdl( Database getDatabase(String databaseName) throws SpannerException; GetDatabaseDdlResponse getDatabaseDdl(String databaseName) throws SpannerException; + /** Lists the backups in the specified instance. */ Paginated listBackups( String instanceName, int pageSize, @Nullable String filter, @Nullable String pageToken) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java index cd4d6480f57..024a6ca4b5d 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java @@ -89,8 +89,7 @@ public class DatabaseAdminClientImplTest { private static final String KMS_KEY_VERSION = "1"; private static final DatabaseDialect DIALECT = GOOGLE_STANDARD_SQL; - @Mock - SpannerRpc rpc; + @Mock SpannerRpc rpc; DatabaseAdminClientImpl client; @Before @@ -179,14 +178,14 @@ public void createDatabase() throws Exception { OperationFutureUtil.immediateOperationFuture( "createDatabase", getDatabaseProto(), CreateDatabaseMetadata.getDefaultInstance()); when(rpc.createDatabase( - INSTANCE_NAME, - "CREATE DATABASE `" + DB_ID + "`", - Collections.emptyList(), - client - .newDatabaseBuilder(DatabaseId.of(DB_NAME)) - .setState(State.UNSPECIFIED) - .setDialect(Dialect.GOOGLE_STANDARD_SQL) - .build())) + INSTANCE_NAME, + "CREATE DATABASE `" + DB_ID + "`", + Collections.emptyList(), + client + .newDatabaseBuilder(DatabaseId.of(DB_NAME)) + .setState(State.UNSPECIFIED) + .setDialect(Dialect.GOOGLE_STANDARD_SQL) + .build())) .thenReturn(rawOperationFuture); OperationFuture op = client.createDatabase(INSTANCE_ID, DB_ID, Collections.emptyList()); @@ -209,7 +208,7 @@ public void createEncryptedDatabase() throws Exception { getEncryptedDatabaseProto(), CreateDatabaseMetadata.getDefaultInstance()); when(rpc.createDatabase( - INSTANCE_NAME, "CREATE DATABASE `" + DB_ID + "`", Collections.emptyList(), database)) + INSTANCE_NAME, "CREATE DATABASE `" + DB_ID + "`", Collections.emptyList(), database)) .thenReturn(rawOperationFuture); OperationFuture op = client.createDatabase(database, Collections.emptyList()); @@ -225,7 +224,9 @@ public void updateDatabaseDdl() throws Exception { OperationFuture rawOperationFuture = OperationFutureUtil.immediateOperationFuture( opName, Empty.getDefaultInstance(), UpdateDatabaseDdlMetadata.getDefaultInstance()); - when(rpc.updateDatabaseDdl(DB_NAME, ddl, opId, null)).thenReturn(rawOperationFuture); + when(rpc.updateDatabaseDdl( + client.newDatabaseBuilder(DatabaseId.of(DB_NAME)).build(), ddl, opId)) + .thenReturn(rawOperationFuture); OperationFuture op = client.updateDatabaseDdl(INSTANCE_ID, DB_ID, ddl, opId); assertThat(op.isDone()).isTrue(); @@ -243,7 +244,9 @@ public void updateDatabaseDdlOpAlreadyExists() throws Exception { UpdateDatabaseDdlMetadata.getDefaultInstance()); String newOpId = "newop"; - when(rpc.updateDatabaseDdl(DB_NAME, ddl, newOpId, null)).thenReturn(originalOp); + when(rpc.updateDatabaseDdl( + client.newDatabaseBuilder(DatabaseId.of(DB_NAME)).build(), ddl, newOpId)) + .thenReturn(originalOp); OperationFuture op = client.updateDatabaseDdl(INSTANCE_ID, DB_ID, ddl, newOpId); assertThat(op.getName()).isEqualTo(originalOpName); @@ -258,8 +261,8 @@ public void dropDatabase() { @Test public void getDatabaseDdl() { List ddl = ImmutableList.of("CREATE TABLE mytable()"); - when(rpc.getDatabaseDdl(DB_NAME)).thenReturn( - GetDatabaseDdlResponse.newBuilder().addAllStatements(ddl).build()); + when(rpc.getDatabaseDdl(DB_NAME)) + .thenReturn(GetDatabaseDdlResponse.newBuilder().addAllStatements(ddl).build()); assertThat(client.getDatabaseDdl(INSTANCE_ID, DB_ID)).isEqualTo(ddl); } @@ -652,8 +655,8 @@ public void restoreDatabase() throws Exception { "restoreDatabase", getDatabaseProto(), RestoreDatabaseMetadata.getDefaultInstance()); final Restore restore = new Restore.Builder( - BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID), - DatabaseId.of(PROJECT_ID, INSTANCE_ID, DB_ID)) + BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID), + DatabaseId.of(PROJECT_ID, INSTANCE_ID, DB_ID)) .build(); when(rpc.restoreDatabase(restore)).thenReturn(rawOperationFuture); OperationFuture op = @@ -671,8 +674,8 @@ public void restoreEncryptedDatabase() throws Exception { RestoreDatabaseMetadata.getDefaultInstance()); final Restore restore = new Restore.Builder( - BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID), - DatabaseId.of(PROJECT_ID, INSTANCE_ID, DB_ID)) + BackupId.of(PROJECT_ID, INSTANCE_ID, BK_ID), + DatabaseId.of(PROJECT_ID, INSTANCE_ID, DB_ID)) .build(); when(rpc.restoreDatabase(restore)).thenReturn(rawOperationFuture); OperationFuture op = diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java index 0ecf8548567..3455f611fa1 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java @@ -34,28 +34,20 @@ 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.Spanner; import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.SpannerOptions; import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.testing.EmulatorSpannerHelper; import com.google.cloud.spanner.testing.RemoteSpannerHelper; import com.google.common.collect.ImmutableList; -import com.google.common.io.ByteStreams; import com.google.protobuf.AbstractMessage; -import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException.InvalidWireTypeException; import com.google.protobuf.ProtocolMessageEnum; import com.google.spanner.admin.database.v1.Backup; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -65,15 +57,12 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -/** - * Integrations Tests to test DDL, DML and DQL for Proto Columns & Enums - */ +/** Integrations Tests to test DDL, DML and DQL for Proto Columns & Enums */ @Category(ParallelIntegrationTest.class) @RunWith(JUnit4.class) public class ITProtoColumnTest { - @ClassRule - public static IntegrationTestEnv env = new IntegrationTestEnv(); + @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); // TODO: Replace PROJECT_ID with testHelper.getInstanceId().getProject(); private static final String PROJECT_ID = "span-cloud-testing"; private static String instanceId; @@ -119,8 +108,10 @@ public static void afterClass() throws Exception { dbAdminClient.dropDatabase(instanceId, databaseId); } catch (Exception e) { System.err.println( - "Failed to drop database " + dbAdminClient.getDatabase(instanceId, databaseId).getId() - + ", skipping...: " + e.getMessage()); + "Failed to drop database " + + dbAdminClient.getDatabase(instanceId, databaseId).getId() + + ", skipping...: " + + e.getMessage()); } } @@ -135,39 +126,43 @@ public void createDatabase() throws Exception { databaseId = testHelper.getUniqueDatabaseId(); instanceId = testHelper.getInstanceId().getInstance(); // PROJECT_ID = testHelper.getInstanceId().getProject(); - databaseClient = testHelper.getClient() - .getDatabaseClient(DatabaseId.of(PROJECT_ID, instanceId, databaseId)); - - final Database databaseToCreate = dbAdminClient - .newDatabaseBuilder(DatabaseId.of(PROJECT_ID, instanceId, databaseId)) - .setProtoDescriptors( - "/usr/local/google/home/sriharshach/github/Go/golang-samples-proto-support-v2/spanner/spanner_snippets/spanner/testdata/protos/descriptors.pb") - .build(); - final Database createdDatabase = dbAdminClient - .createDatabase(databaseToCreate, Arrays.asList( - "CREATE PROTO BUNDLE (" - + "spanner.examples.music.SingerInfo," - + "spanner.examples.music.Genre," - + ")", - "CREATE TABLE Singers (" - + " SingerId INT64 NOT NULL," - + " FirstName STRING(1024)," - + " LastName STRING(1024)," - + " SingerInfo spanner.examples.music.SingerInfo," - + " SingerGenre spanner.examples.music.Genre," - + " ) PRIMARY KEY (SingerGenre)", - "CREATE TABLE Types (" - + " RowID INT64 NOT NULL," - + " Int64a INT64," - + " Bytes BYTES(MAX)," - + " Int64Array ARRAY," - + " BytesArray ARRAY," - + " ProtoMessage spanner.examples.music.SingerInfo," - + " ProtoEnum spanner.examples.music.Genre," - + " ProtoMessageArray ARRAY," - + " ProtoEnumArray ARRAY," - + " ) PRIMARY KEY (RowID)")) - .get(5, TimeUnit.MINUTES); + databaseClient = + testHelper.getClient().getDatabaseClient(DatabaseId.of(PROJECT_ID, instanceId, databaseId)); + + // "/usr/local/google/home/sriharshach/github/Go/golang-samples-proto-support-v2/spanner/spanner_snippets/spanner/testdata/protos/descriptors.pb" + final Database databaseToCreate = + dbAdminClient + .newDatabaseBuilder(DatabaseId.of(PROJECT_ID, instanceId, databaseId)) + .setProtoDescriptors("com/google/cloud/spanner/descriptors.pb") + .build(); + final Database createdDatabase = + dbAdminClient + .createDatabase( + databaseToCreate, + Arrays.asList( + "CREATE PROTO BUNDLE (" + + "spanner.examples.music.SingerInfo," + + "spanner.examples.music.Genre," + + ")", + "CREATE TABLE Singers (" + + " SingerId INT64 NOT NULL," + + " FirstName STRING(1024)," + + " LastName STRING(1024)," + + " SingerInfo spanner.examples.music.SingerInfo," + + " SingerGenre spanner.examples.music.Genre," + + " ) PRIMARY KEY (SingerGenre)", + "CREATE TABLE Types (" + + " RowID INT64 NOT NULL," + + " Int64a INT64," + + " Bytes BYTES(MAX)," + + " Int64Array ARRAY," + + " BytesArray ARRAY," + + " ProtoMessage spanner.examples.music.SingerInfo," + + " ProtoEnum spanner.examples.music.Genre," + + " ProtoMessageArray ARRAY," + + " ProtoEnumArray ARRAY," + + " ) PRIMARY KEY (RowID)")) + .get(5, TimeUnit.MINUTES); assertEquals(databaseId, createdDatabase.getId().getDatabase()); assertNotNull(createdDatabase.getProtoDescriptors()); From 75a23de95aa909c600493e6c193fc7c6873f1d8c Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Wed, 1 Feb 2023 11:05:26 +0000 Subject: [PATCH 04/25] feat: add descriptors file --- .../com/google/cloud/spanner/descriptors.pb | Bin 0 -> 251 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 google-cloud-spanner/src/test/resources/com/google/cloud/spanner/descriptors.pb diff --git a/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/descriptors.pb b/google-cloud-spanner/src/test/resources/com/google/cloud/spanner/descriptors.pb new file mode 100644 index 0000000000000000000000000000000000000000..3ebb79420b3ffd2ca3b3b57433a4a10bfa22b675 GIT binary patch literal 251 zcmd=3!N|o^oSB!NTBKJ{lwXoBBvxFIn3o6SrdA~87UZNB>*bafXC^DnXXN4v1}pT; zOUoCM=Hi5Ci_c7vU{qk#U=HGd2zaIl$#QWeWfqlW#HS>dq)IRWWjTX5!6Gg|0U-r0 z?!3g3%>2B>oXnC+31+Z7vXGE57i)TIUQwz93s8>FNLCNKqx9TCih>|&we+}H!F(Zh lF6IFL009Oe4lWii$EYX)Mi9%*-^W{k3B(HWclH)w1^^+RM@0Yt literal 0 HcmV?d00001 From f738af62a6295dfb08e236d466464bac1d65ad67 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Wed, 8 Feb 2023 10:37:16 +0530 Subject: [PATCH 05/25] feat: code refactoring --- .../src/main/java/com/google/cloud/spanner/DatabaseInfo.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java index d702f5c803a..c218f2f08f6 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java @@ -154,7 +154,8 @@ public Builder setDialect(Dialect dialect) { } @Override - public Builder setProtoDescriptors(@Nonnull byte[] protoDescriptors) { + public Builder setProtoDescriptors(byte[] protoDescriptors) { + Preconditions.checkNotNull(protoDescriptors); this.protoDescriptors = ByteString.copyFrom(protoDescriptors); return this; } From a1b5ab071aff0fe5e1185f2c4ffbec3560410f06 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Sat, 11 Feb 2023 19:11:09 +0530 Subject: [PATCH 06/25] feat: Integration tests and code refactoring --- .../google/cloud/spanner/DatabaseInfo.java | 20 +- .../spanner/it/ITCreateDatabaseProtos.java | 8 +- .../cloud/spanner/it/ITProtoColumnTest.java | 710 ++++++++---------- 3 files changed, 346 insertions(+), 392 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java index c218f2f08f6..dec2f31e1f2 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java @@ -21,6 +21,8 @@ import com.google.common.base.Preconditions; import com.google.common.io.ByteStreams; import com.google.protobuf.ByteString; + +import java.io.IOException; import java.io.InputStream; import java.util.Objects; import javax.annotation.Nonnull; @@ -62,11 +64,11 @@ public Builder setDialect(Dialect dialect) { throw new UnsupportedOperationException("Unimplemented"); } - public abstract Builder setProtoDescriptors(byte[] protoDescriptors); + public abstract Builder setProtoDescriptors(@Nonnull byte[] protoDescriptors); - public abstract Builder setProtoDescriptors(InputStream inputStream) throws Exception; + public abstract Builder setProtoDescriptors(@Nonnull InputStream inputStream) throws IOException; - public abstract Builder setProtoDescriptors(String filePath) throws Exception; + public abstract Builder setProtoDescriptors(String filePath) throws IOException; abstract Builder setProto(com.google.spanner.admin.database.v1.Database proto); @@ -154,24 +156,26 @@ public Builder setDialect(Dialect dialect) { } @Override - public Builder setProtoDescriptors(byte[] protoDescriptors) { + public Builder setProtoDescriptors(@Nonnull byte[] protoDescriptors) { Preconditions.checkNotNull(protoDescriptors); this.protoDescriptors = ByteString.copyFrom(protoDescriptors); return this; } @Override - public Builder setProtoDescriptors(InputStream inputStream) throws Exception { + public Builder setProtoDescriptors(@Nonnull InputStream inputStream) throws IOException { + Preconditions.checkNotNull(inputStream); byte[] byteArray = ByteStreams.toByteArray(inputStream); - this.protoDescriptors = byteArray != null ? ByteString.copyFrom(byteArray) : ByteString.EMPTY; + this.protoDescriptors = ByteString.copyFrom(byteArray); return this; } @Override // TODO(harsha): This overload method needs to be completed - public Builder setProtoDescriptors(String filePath) throws Exception { + public Builder setProtoDescriptors(String filePath) throws IOException { + Preconditions.checkState(filePath.length() != 0, "Input File Path cannot be empty."); InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filePath); - // InputStream inputStream = new FileInputStream(filePath); + Preconditions.checkNotNull(inputStream, "Input File path is invalid."); return setProtoDescriptors(inputStream); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java index 0a7e8562974..1a153bdea74 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java @@ -123,7 +123,7 @@ public void returnsTheVersionRetentionPeriodSetThroughGetDatabase() throws Excep assertThat(database.getEarliestVersionTime()).isNotNull(); - final GetDatabaseDdlResponse response = dbAdminClient.getDatabaseDdlWithProtoDescriptors("integration-test-proto-column", "int_test_proto_column_db"); + final GetDatabaseDdlResponse response = dbAdminClient.getDatabaseDdlResponse("integration-test-proto-column", "int_test_proto_column_db"); System.out.println(response.getProtoDescriptors().toByteArray()); } @@ -255,7 +255,7 @@ private Database createDatabaseWithProtos( } } - private void updateDatabaseWithProtos( + /*private void updateDatabaseWithProtos( final String instanceId, final String databaseId, InputStream protoDescriptorFile) { byte[] protoDescriptorByteArray = null; @@ -290,12 +290,12 @@ private void updateDatabaseWithProtos( // If the operation failed during execution, expose the cause. throw SpannerExceptionFactory.asSpannerException(e.getCause()); } - } + }*/ private void getDatabaseDdl( String instanceId, String databaseId) { try { - final GetDatabaseDdlResponse response = dbAdminClient.getDatabaseDdlWithProtoDescriptors(instanceId, databaseId); + final GetDatabaseDdlResponse response = dbAdminClient.getDatabaseDdlResponse(instanceId, databaseId); System.out.println("Retrieved GetDatabaseDdlResponse for " + databaseId); for (String ddl : response.getStatementsList()) { System.out.println(ddl); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java index 3455f611fa1..2d2c5d02a94 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java @@ -22,21 +22,9 @@ import static org.junit.Assume.assumeFalse; import com.google.cloud.ByteArray; -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.IntegrationTestEnv; -import com.google.cloud.spanner.Key; -import com.google.cloud.spanner.KeySet; -import com.google.cloud.spanner.Mutation; -import com.google.cloud.spanner.ParallelIntegrationTest; -import com.google.cloud.spanner.ResultSet; +import com.google.cloud.spanner.*; import com.google.cloud.spanner.SingerProto.Genre; import com.google.cloud.spanner.SingerProto.SingerInfo; -import com.google.cloud.spanner.SpannerException; -import com.google.cloud.spanner.SpannerOptions; -import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.testing.EmulatorSpannerHelper; import com.google.cloud.spanner.testing.RemoteSpannerHelper; import com.google.common.collect.ImmutableList; @@ -44,10 +32,13 @@ import com.google.protobuf.InvalidProtocolBufferException.InvalidWireTypeException; import com.google.protobuf.ProtocolMessageEnum; import com.google.spanner.admin.database.v1.Backup; + import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; + +import com.google.spanner.admin.database.v1.GetDatabaseDdlResponse; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -57,384 +48,343 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -/** Integrations Tests to test DDL, DML and DQL for Proto Columns & Enums */ +import javax.xml.crypto.Data; + +// Integration Tests to test DDL, DML and DQL for Proto Columns & Enums +// TODO(harsha): Check session leak warning @Category(ParallelIntegrationTest.class) @RunWith(JUnit4.class) public class ITProtoColumnTest { - @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); - // TODO: Replace PROJECT_ID with testHelper.getInstanceId().getProject(); - private static final String PROJECT_ID = "span-cloud-testing"; - private static String instanceId; - private static String databaseId; - private static DatabaseAdminClient dbAdminClient; - // For reference of databaseClient usage check ITPgJsonbTest.java - private static DatabaseClient databaseClient; - private static RemoteSpannerHelper testHelper; - - @BeforeClass - public static void setUpDatabase() { - // Get default spanner options for an integration test. - SpannerOptions.Builder builder = env.getTestHelper().getOptions().toBuilder(); - builder.setHost("https://staging-wrenchworks.sandbox.googleapis.com").setProjectId(PROJECT_ID); - - // Create a new testHelper with the cloud-devel host. - testHelper = RemoteSpannerHelper.create(builder.build(), env.getTestHelper().getInstanceId()); - dbAdminClient = testHelper.getClient().getDatabaseAdminClient(); - } - - /*@BeforeClass - public static void beforeClass() throws Exception { - assumeFalse( - "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); - // ToDo: Update project, instance and database parameter before GA - projectId = "span-cloud-testing"; - databaseId = "int_test_proto_column_db"; - instanceId = "integration-test-proto-column"; - - Spanner spanner = - SpannerOptions.newBuilder() - .setHost("https://staging-wrenchworks.sandbox.googleapis.com") - .setProjectId(projectId) - .build() - .getService(); - - databaseClient = spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); - }*/ - - @AfterClass - public static void afterClass() throws Exception { - try { - dbAdminClient.dropDatabase(instanceId, databaseId); - } catch (Exception e) { - System.err.println( - "Failed to drop database " - + dbAdminClient.getDatabase(instanceId, databaseId).getId() - + ", skipping...: " - + e.getMessage()); + @ClassRule + public static IntegrationTestEnv env = new IntegrationTestEnv(); + private static DatabaseId databaseID; + // For reference of databaseClient and dbAdminClient usage check ITPgJsonbTest.java or ITWithGrpcGcpTest.java + private static DatabaseAdminClient dbAdminClient; + private static DatabaseClient databaseClient; + + @BeforeClass + public static void setUpDatabase() throws Exception { + // Get default spanner options for an integration test. + //SpannerOptions.Builder builder = env.getTestHelper().getOptions().toBuilder(); + // Create a new testHelper with the cloud-devel host. + // testHelper = RemoteSpannerHelper.create(builder.build(), env.getTestHelper().getInstanceId()); + RemoteSpannerHelper testHelper = env.getTestHelper(); + databaseID = DatabaseId.of(testHelper.getInstanceId(), testHelper.getUniqueDatabaseId()); + dbAdminClient = testHelper.getClient().getDatabaseAdminClient(); + createDatabase(); + databaseClient = testHelper.getClient().getDatabaseClient(databaseID); + } + + public static void createDatabase() throws Exception { + final Database databaseToCreate = + dbAdminClient + .newDatabaseBuilder(databaseID) + .setProtoDescriptors("com/google/cloud/spanner/descriptors.pb") + .build(); + final Database createdDatabase = + dbAdminClient + .createDatabase( + databaseToCreate, + Arrays.asList( + "CREATE PROTO BUNDLE (" + + "spanner.examples.music.SingerInfo," + + "spanner.examples.music.Genre," + + ")", + "CREATE TABLE Singers (" + + " SingerId INT64 NOT NULL," + + " FirstName STRING(1024)," + + " LastName STRING(1024)," + + " SingerInfo spanner.examples.music.SingerInfo," + + " SingerGenre spanner.examples.music.Genre," + + " SingerNationality STRING(1024) AS (SingerInfo.nationality) STORED," + + " ) PRIMARY KEY (SingerNationality, SingerGenre)", + "CREATE TABLE Types (" + + " RowID INT64 NOT NULL," + + " Int64a INT64," + + " Bytes BYTES(MAX)," + + " Int64Array ARRAY," + + " BytesArray ARRAY," + + " ProtoMessage spanner.examples.music.SingerInfo," + + " ProtoEnum spanner.examples.music.Genre," + + " ProtoMessageArray ARRAY," + + " ProtoEnumArray ARRAY," + + " ) PRIMARY KEY (RowID)", + "CREATE INDEX SingerByNationalityAndGenre ON Singers(SingerNationality, SingerGenre)" + + " STORING (SingerId, FirstName, LastName)")) + .get(5, TimeUnit.MINUTES); + + assertEquals(databaseID.getDatabase(), createdDatabase.getId().getDatabase()); + + // TODO(harsha): Check with backend team as this is not working for generated columns yet. + // GetDatabaseDdlResponse response = dbAdminClient.getDatabaseDdlResponse(databaseID.getInstanceId().getInstance(), databaseID.getDatabase()); + // assertNotNull(response.getProtoDescriptors()); + } + + @AfterClass + public static void afterClass() throws Exception { + try { + dbAdminClient.dropDatabase(databaseID.getInstanceId().getInstance(), databaseID.getDatabase()); + } catch (Exception e) { + System.err.println( + "Failed to drop database " + + dbAdminClient.getDatabase(databaseID.getInstanceId().getInstance(), databaseID.getDatabase()).getId() + + ", skipping...: " + + e.getMessage()); + } } - } - - @After - public void after() throws Exception { - databaseClient.write(ImmutableList.of(Mutation.delete("Types", KeySet.all()))); - databaseClient.write(ImmutableList.of(Mutation.delete("Singers", KeySet.all()))); - } - - @Test - public void createDatabase() throws Exception { - databaseId = testHelper.getUniqueDatabaseId(); - instanceId = testHelper.getInstanceId().getInstance(); - // PROJECT_ID = testHelper.getInstanceId().getProject(); - databaseClient = - testHelper.getClient().getDatabaseClient(DatabaseId.of(PROJECT_ID, instanceId, databaseId)); - - // "/usr/local/google/home/sriharshach/github/Go/golang-samples-proto-support-v2/spanner/spanner_snippets/spanner/testdata/protos/descriptors.pb" - final Database databaseToCreate = - dbAdminClient - .newDatabaseBuilder(DatabaseId.of(PROJECT_ID, instanceId, databaseId)) - .setProtoDescriptors("com/google/cloud/spanner/descriptors.pb") - .build(); - final Database createdDatabase = - dbAdminClient - .createDatabase( - databaseToCreate, + + @After + public void after() throws Exception { + databaseClient.write(ImmutableList.of(Mutation.delete("Types", KeySet.all()))); + databaseClient.write(ImmutableList.of(Mutation.delete("Singers", KeySet.all()))); + } + + /** + * Test to check data update and read queries on Proto columns and Enums and their arrays. + * Test also checks for compatability between following types: + * 1. Proto Messages & Bytes + * 2. Proto Enums & Int64 + */ + @Test + public void testProtoColumnsUpdateAndRead() { + assumeFalse( + "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); + SingerInfo singerInfo = + SingerInfo.newBuilder().setSingerId(1).setNationality("Country1").build(); + ByteArray singerInfoBytes = ByteArray.copyFrom(singerInfo.toByteArray()); + + Genre genre = Genre.JAZZ; + long genreConst = genre.getNumber(); + + List singerInfoList = + Arrays.asList(singerInfo, null, SingerInfo.getDefaultInstance()); + List singerInfoBytesList = Arrays.asList( - "CREATE PROTO BUNDLE (" - + "spanner.examples.music.SingerInfo," - + "spanner.examples.music.Genre," - + ")", - "CREATE TABLE Singers (" - + " SingerId INT64 NOT NULL," - + " FirstName STRING(1024)," - + " LastName STRING(1024)," - + " SingerInfo spanner.examples.music.SingerInfo," - + " SingerGenre spanner.examples.music.Genre," - + " ) PRIMARY KEY (SingerGenre)", - "CREATE TABLE Types (" - + " RowID INT64 NOT NULL," - + " Int64a INT64," - + " Bytes BYTES(MAX)," - + " Int64Array ARRAY," - + " BytesArray ARRAY," - + " ProtoMessage spanner.examples.music.SingerInfo," - + " ProtoEnum spanner.examples.music.Genre," - + " ProtoMessageArray ARRAY," - + " ProtoEnumArray ARRAY," - + " ) PRIMARY KEY (RowID)")) - .get(5, TimeUnit.MINUTES); - - assertEquals(databaseId, createdDatabase.getId().getDatabase()); - assertNotNull(createdDatabase.getProtoDescriptors()); - } - - /** - * Test to check updates and read queries on Proto column and Enums and their arrays. Test also - * checks for compatability between following types: 1. Proto Messages & Bytes 2. Proto Enums & - * Int64 - * - *

Table `Types` was created through gcloud using following DDL: - * ************************************** CREATE TABLE Types ( RowID INT64 NOT NULL, Int64a INT64, - * Bytes BYTES(MAX), Int64Array ARRAY, BytesArray ARRAY, ProtoMessage - * spanner.examples.music.SingerInfo, ProtoEnum spanner.examples.music.Genre, ProtoMessageArray - * ARRAY, ProtoEnumArray ARRAY, ) - * PRIMARY KEY (RowID); ************************************** - */ - @Test - public void testProtoUpdateAndRead() { - assumeFalse( - "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); - SingerInfo singerInfo = - SingerInfo.newBuilder().setSingerId(11).setNationality("Country1").build(); - ByteArray singerInfoBytes = ByteArray.copyFrom(singerInfo.toByteArray()); - - Genre genre = Genre.JAZZ; - long genreConst = genre.getNumber(); - - List singerInfoList = - Arrays.asList(singerInfo, null, SingerInfo.getDefaultInstance()); - List singerInfoBytesList = - Arrays.asList( - singerInfoBytes, - null, - ByteArray.copyFrom(SingerInfo.getDefaultInstance().toByteArray())); - - List enumList = Arrays.asList(Genre.FOLK, null, Genre.ROCK); - List enumConstList = - Arrays.asList((long) Genre.FOLK_VALUE, null, (long) Genre.ROCK_VALUE); - - // Inserting two rows with same data except rowID as it's used as PK. - databaseClient.write( - ImmutableList.of( - Mutation.newInsertOrUpdateBuilder("Types") - .set("RowID") - .to(11) - .set("Int64a") - .to(genreConst) - .set("Bytes") - .to(singerInfoBytes) - .set("Int64Array") - .toInt64Array(enumConstList) - .set("BytesArray") - .toBytesArray(singerInfoBytesList) - .set("ProtoMessage") - .to(singerInfo) - .set("ProtoEnum") - .to(genre) - .set("ProtoMessageArray") - .toProtoMessageArray(singerInfoList, SingerInfo.getDescriptor()) - .set("ProtoEnumArray") - .toProtoEnumArray(enumList, Genre.getDescriptor()) - .build(), - // Inter Compatability check between ProtoMessages/Bytes and Int64/Enum. - Mutation.newInsertOrUpdateBuilder("Types") - .set("RowID") - .to(12) - .set("Int64a") - .to(genre) - .set("Bytes") - .to(singerInfo) - .set("Int64Array") - .toProtoEnumArray(enumList, Genre.getDescriptor()) - .set("BytesArray") - .toProtoMessageArray(singerInfoList, SingerInfo.getDescriptor()) - .set("ProtoMessage") - .to(singerInfoBytes) - .set("ProtoEnum") - .to(genreConst) - .set("ProtoMessageArray") - .toBytesArray(singerInfoBytesList) - .set("ProtoEnumArray") - .toInt64Array(enumConstList) - .build())); - - try (ResultSet resultSet = - databaseClient.singleUse().executeQuery(Statement.of("SELECT * FROM " + "Types"))) { - - for (int i = 0; i < 2; i++) { - resultSet.next(); - assertEquals(11 + i, resultSet.getLong("RowID")); - assertEquals(genreConst, resultSet.getLong("Int64a")); - assertEquals(singerInfoBytes, resultSet.getBytes("Bytes")); - assertEquals(enumConstList, resultSet.getLongList("Int64Array")); - assertEquals(singerInfoBytesList, resultSet.getBytesList("BytesArray")); - assertEquals( - singerInfo, resultSet.getProtoMessage("ProtoMessage", SingerInfo.getDefaultInstance())); - assertEquals(genre, resultSet.getProtoEnum("ProtoEnum", Genre::forNumber)); - assertEquals( - singerInfoList, - resultSet.getProtoMessageList("ProtoMessageArray", SingerInfo.getDefaultInstance())); - assertEquals(enumList, resultSet.getProtoEnumList("ProtoEnumArray", Genre::forNumber)); + singerInfoBytes, + null, + ByteArray.copyFrom(SingerInfo.getDefaultInstance().toByteArray())); + + List enumList = Arrays.asList(Genre.FOLK, null, Genre.ROCK); + List enumConstList = + Arrays.asList((long) Genre.FOLK_VALUE, null, (long) Genre.ROCK_VALUE); + + // Inserting two rows with same data except rowID as it's used as PK. + databaseClient.write( + ImmutableList.of( + Mutation.newInsertOrUpdateBuilder("Types") + .set("RowID") + .to(1) + .set("Int64a") + .to(genreConst) + .set("Bytes") + .to(singerInfoBytes) + .set("Int64Array") + .toInt64Array(enumConstList) + .set("BytesArray") + .toBytesArray(singerInfoBytesList) + .set("ProtoMessage") + .to(singerInfo) + .set("ProtoEnum") + .to(genre) + .set("ProtoMessageArray") + .toProtoMessageArray(singerInfoList, SingerInfo.getDescriptor()) + .set("ProtoEnumArray") + .toProtoEnumArray(enumList, Genre.getDescriptor()) + .build(), + // Inter Compatability check between ProtoMessages/Bytes and Int64/Enum. + Mutation.newInsertOrUpdateBuilder("Types") + .set("RowID") + .to(2) + .set("Int64a") + .to(genre) + .set("Bytes") + .to(singerInfo) + .set("Int64Array") + .toProtoEnumArray(enumList, Genre.getDescriptor()) + .set("BytesArray") + .toProtoMessageArray(singerInfoList, SingerInfo.getDescriptor()) + .set("ProtoMessage") + .to(singerInfoBytes) + .set("ProtoEnum") + .to(genreConst) + .set("ProtoMessageArray") + .toBytesArray(singerInfoBytesList) + .set("ProtoEnumArray") + .toInt64Array(enumConstList) + .build())); + + try (ResultSet resultSet = + databaseClient.singleUse().executeQuery(Statement.of("SELECT * FROM " + "Types"))) { + + for (int i = 0; i < 2; i++) { + resultSet.next(); + assertEquals(i + 1, resultSet.getLong("RowID")); + assertEquals(genreConst, resultSet.getLong("Int64a")); + assertEquals(singerInfoBytes, resultSet.getBytes("Bytes")); + assertEquals(enumConstList, resultSet.getLongList("Int64Array")); + assertEquals(singerInfoBytesList, resultSet.getBytesList("BytesArray")); + assertEquals( + singerInfo, resultSet.getProtoMessage("ProtoMessage", SingerInfo.getDefaultInstance())); + assertEquals(genre, resultSet.getProtoEnum("ProtoEnum", Genre::forNumber)); + assertEquals( + singerInfoList, + resultSet.getProtoMessageList("ProtoMessageArray", SingerInfo.getDefaultInstance())); + assertEquals(enumList, resultSet.getProtoEnumList("ProtoEnumArray", Genre::forNumber)); + + // Check compatability between Proto Messages & Bytes + assertEquals(singerInfoBytes, resultSet.getBytes("ProtoMessage")); + assertEquals( + singerInfo, resultSet.getProtoMessage("Bytes", SingerInfo.getDefaultInstance())); + + assertEquals(singerInfoBytesList, resultSet.getBytesList("ProtoMessageArray")); + assertEquals( + singerInfoList, + resultSet.getProtoMessageList("BytesArray", SingerInfo.getDefaultInstance())); + + // Check compatability between Proto Enum & Int64 + assertEquals(genreConst, resultSet.getLong("ProtoEnum")); + assertEquals(genre, resultSet.getProtoEnum("Int64a", Genre::forNumber)); + + assertEquals(enumConstList, resultSet.getLongList("ProtoEnumArray")); + assertEquals(enumList, resultSet.getProtoEnumList("Int64Array", Genre::forNumber)); + } + } + } + + // Test to check Parameterized Queries, Primary Keys and Indexes. + @Test + public void testProtoColumnsDMLParameterizedQueriesPKAndIndexes() { + assumeFalse( + "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); + + SingerInfo singerInfo1 = + SingerInfo.newBuilder().setSingerId(1).setNationality("Country1").build(); + Genre genre1 = Genre.FOLK; + + SingerInfo singerInfo2 = + SingerInfo.newBuilder().setSingerId(2).setNationality("Country2").build(); + Genre genre2 = Genre.JAZZ; - // Check compatability between Proto Messages & Bytes - assertEquals(singerInfoBytes, resultSet.getBytes("ProtoMessage")); + databaseClient + .readWriteTransaction() + .run( + transaction -> { + Statement statement1 = + Statement.newBuilder( + "INSERT INTO Singers (SingerId, FirstName, LastName, SingerInfo, SingerGenre) VALUES (1, \"FirstName1\", \"LastName1\", @singerInfo, @singerGenre)") + .bind("singerInfo") + .to(singerInfo1) + .bind("singerGenre") + .to(genre1) + .build(); + + Statement statement2 = + Statement.newBuilder( + "INSERT INTO Singers (SingerId, FirstName, LastName, SingerInfo, SingerGenre) VALUES (2, \"FirstName2\", \"LastName2\", @singerInfo, @singerGenre)") + .bind("singerInfo") + .to(singerInfo2) + .bind("singerGenre") + .to(genre2) + .build(); + + transaction.batchUpdate(Arrays.asList(statement1, statement2)); + return null; + }); + + // Read all rows based on Proto Message field and Proto Enum Primary key column values + ResultSet resultSet1 = + databaseClient + .singleUse() + .read( + "Singers", + KeySet.newBuilder() + .addKey(Key.of("Country1", Genre.FOLK)) + .addKey(Key.of("Country2", Genre.JAZZ)) + .build(), + Arrays.asList("SingerId", "FirstName", "LastName", "SingerInfo", "SingerGenre")); + + resultSet1.next(); + assertEquals(1, resultSet1.getLong("SingerId")); + assertEquals("FirstName1", resultSet1.getString("FirstName")); + assertEquals("LastName1", resultSet1.getString("LastName")); assertEquals( - singerInfo, resultSet.getProtoMessage("Bytes", SingerInfo.getDefaultInstance())); + singerInfo1, resultSet1.getProtoMessage("SingerInfo", SingerInfo.getDefaultInstance())); + assertEquals(genre1, resultSet1.getProtoEnum("SingerGenre", Genre::forNumber)); - assertEquals(singerInfoBytesList, resultSet.getBytesList("ProtoMessageArray")); + resultSet1.next(); + assertEquals(2, resultSet1.getLong("SingerId")); + assertEquals("FirstName2", resultSet1.getString("FirstName")); + assertEquals("LastName2", resultSet1.getString("LastName")); + assertEquals( + singerInfo2, resultSet1.getProtoMessage("SingerInfo", SingerInfo.getDefaultInstance())); + assertEquals(genre2, resultSet1.getProtoEnum("SingerGenre", Genre::forNumber)); + + // Read rows using Index on Proto Message field and Proto Enum column + ResultSet resultSet2 = + databaseClient + .singleUse() + .readUsingIndex( + "Singers", + "SingerByNationalityAndGenre", + KeySet.singleKey(Key.of("Country2", Genre.JAZZ)), + Arrays.asList("SingerId", "FirstName", "LastName")); + resultSet2.next(); + assertEquals(2, resultSet2.getLong("SingerId")); + assertEquals("FirstName2", resultSet2.getString("FirstName")); + assertEquals("LastName2", resultSet2.getString("LastName")); + + // Filter using Parameterized DQL + ResultSet resultSet3 = + databaseClient + .singleUse() + .executeQuery( + Statement.newBuilder( + "SELECT SingerId, SingerInfo, SingerGenre FROM " + + "Singers WHERE SingerInfo.Nationality=@country AND SingerGenre=@genre") + .bind("country") + .to("Country2") + .bind("genre") + .to(Genre.JAZZ) + .build()); + + resultSet3.next(); + assertEquals(2, resultSet1.getLong("SingerId")); assertEquals( - singerInfoList, - resultSet.getProtoMessageList("BytesArray", SingerInfo.getDefaultInstance())); + singerInfo2, resultSet1.getProtoMessage("SingerInfo", SingerInfo.getDefaultInstance())); + assertEquals(genre2, resultSet1.getProtoEnum("SingerGenre", Genre::forNumber)); + } - // Check compatability between Proto Enum & Int64 - assertEquals(genreConst, resultSet.getLong("ProtoEnum")); - assertEquals(genre, resultSet.getProtoEnum("Int64a", Genre::forNumber)); + // Test the exception in case Invalid protocol message object is provided while deserializing the data. + @Test + public void testProtoMessageDeserializationError() { + assumeFalse( + "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); + + SingerInfo singerInfo = + SingerInfo.newBuilder().setSingerId(1).setNationality("Country1").build(); + + databaseClient.write( + ImmutableList.of( + Mutation.newInsertOrUpdateBuilder("Types") + .set("RowID") + .to(1) + .set("ProtoMessage") + .to(singerInfo) + .build())); + + ResultSet resultSet = + databaseClient + .singleUse() + .read("Types", KeySet.all(), Collections.singletonList("ProtoMessage")); + resultSet.next(); + + SpannerException e = + assertThrows( + SpannerException.class, + () -> resultSet.getProtoMessage("ProtoMessage", Backup.getDefaultInstance())); - assertEquals(enumConstList, resultSet.getLongList("ProtoEnumArray")); - assertEquals(enumList, resultSet.getProtoEnumList("Int64Array", Genre::forNumber)); - } + // Underlying cause is InvalidWireTypeException + assertEquals(InvalidWireTypeException.class, e.getCause().getClass()); } - } - - /** - * Test to check Parameterized Queries, Primary Keys and Indexes. - * - *

Table `Singers` and Index `SingerByNationalityAndGenre` for Proto column integration tests - * is created through gcloud using following DDL: - * - *

************************************** CREATE TABLE Singers ( SingerId INT64 NOT NULL, - * FirstName STRING(1024), LastName STRING(1024), SingerInfo spanner.examples.music.SingerInfo, - * SingerGenre spanner.examples.music.Genre, SingerNationality STRING(1024) AS - * (SingerInfo.nationality) STORED, ) PRIMARY KEY (SingerNationality, SingerGenre); - * - *

CREATE INDEX SingerByNationalityAndGenre ON Singers(SingerNationality, SingerGenre) STORING - * (SingerId, FirstName, LastName); ************************************** - */ - @Test - public void testProtoColumnsDMLParameterizedQueriesAndPKIndexes() { - assumeFalse( - "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); - - SingerInfo singerInfo1 = - SingerInfo.newBuilder().setSingerId(11).setNationality("Country1").build(); - Genre genre1 = Genre.FOLK; - - SingerInfo singerInfo2 = - SingerInfo.newBuilder().setSingerId(11).setNationality("Country2").build(); - Genre genre2 = Genre.JAZZ; - - databaseClient - .readWriteTransaction() - .run( - transaction -> { - Statement statement1 = - Statement.newBuilder( - "INSERT INTO Singers (SingerId, FirstName, LastName, SingerInfo, SingerGenre) VALUES (11, \"FirstName1\", \"LastName1\", @singerInfo, @singerGenre)") - .bind("singerInfo") - .to(singerInfo1) - .bind("singerGenre") - .to(genre1) - .build(); - - Statement statement2 = - Statement.newBuilder( - "INSERT INTO Singers (SingerId, FirstName, LastName, SingerInfo, SingerGenre) VALUES (22, \"FirstName2\", \"LastName2\", @singerInfo, @singerGenre)") - .bind("singerInfo") - .to(singerInfo2) - .bind("singerGenre") - .to(genre2) - .build(); - - transaction.batchUpdate(Arrays.asList(statement1, statement2)); - return null; - }); - - // Read all rows based on Proto Message field and Proto Enum Primary key column values - ResultSet resultSet1 = - databaseClient - .singleUse() - .read( - "Singers", - KeySet.newBuilder() - .addKey(Key.of("Country1", Genre.FOLK)) - .addKey(Key.of("Country2", Genre.JAZZ)) - .build(), - Arrays.asList("SingerId", "FirstName", "LastName", "SingerInfo", "SingerGenre")); - - resultSet1.next(); - assertEquals(11, resultSet1.getLong("SingerId")); - assertEquals("FirstName1", resultSet1.getString("FirstName")); - assertEquals("LastName1", resultSet1.getString("LastName")); - assertEquals( - singerInfo1, resultSet1.getProtoMessage("SingerInfo", SingerInfo.getDefaultInstance())); - assertEquals(genre1, resultSet1.getProtoEnum("SingerGenre", Genre::forNumber)); - - resultSet1.next(); - assertEquals(22, resultSet1.getLong("SingerId")); - assertEquals("FirstName2", resultSet1.getString("FirstName")); - assertEquals("LastName2", resultSet1.getString("LastName")); - assertEquals( - singerInfo2, resultSet1.getProtoMessage("SingerInfo", SingerInfo.getDefaultInstance())); - assertEquals(genre2, resultSet1.getProtoEnum("SingerGenre", Genre::forNumber)); - - // Read rows using Index on Proto Message field and Proto Enum column - ResultSet resultSet2 = - databaseClient - .singleUse() - .readUsingIndex( - "Singers", - "SingerByNationalityAndGenre", - KeySet.singleKey(Key.of("Country2", Genre.JAZZ)), - Arrays.asList("SingerId", "FirstName", "LastName")); - resultSet2.next(); - assertEquals(22, resultSet2.getLong("SingerId")); - assertEquals("FirstName2", resultSet2.getString("FirstName")); - assertEquals("LastName2", resultSet2.getString("LastName")); - - // Filter using Parameterized DQL - ResultSet resultSet3 = - databaseClient - .singleUse() - .executeQuery( - Statement.newBuilder( - "SELECT SingerId, SingerInfo, SingerGenre FROM " - + "Singers WHERE SingerInfo.Nationality=@country AND SingerGenre=@genre") - .bind("country") - .to("Country2") - .bind("genre") - .to(Genre.JAZZ) - .build()); - - resultSet3.next(); - assertEquals(22, resultSet1.getLong("SingerId")); - assertEquals( - singerInfo2, resultSet1.getProtoMessage("SingerInfo", SingerInfo.getDefaultInstance())); - assertEquals(genre2, resultSet1.getProtoEnum("SingerGenre", Genre::forNumber)); - } - - /** - * Test the exception in case Invalid protocol message object is provided while deserializing the - * data. - */ - @Test - public void testProtoMessageDeserializationError() { - assumeFalse( - "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); - - SingerInfo singerInfo = - SingerInfo.newBuilder().setSingerId(11).setNationality("Country1").build(); - - databaseClient.write( - ImmutableList.of( - Mutation.newInsertOrUpdateBuilder("Types") - .set("RowID") - .to(11) - .set("ProtoMessage") - .to(singerInfo) - .build())); - - ResultSet resultSet = - databaseClient - .singleUse() - .read("Types", KeySet.all(), Collections.singletonList("ProtoMessage")); - resultSet.next(); - - SpannerException e = - assertThrows( - SpannerException.class, - () -> resultSet.getProtoMessage("ProtoMessage", Backup.getDefaultInstance())); - - // Underlying cause is InvalidWireTypeException - assertEquals(InvalidWireTypeException.class, e.getCause().getClass()); - } } From 678e8ee05ea6b9baa1a1a737b541ebf73d7d404c Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Sun, 12 Feb 2023 18:43:16 +0530 Subject: [PATCH 07/25] feat: code refactoring --- .../spanner/DatabaseAdminClientImpl.java | 3 +- .../google/cloud/spanner/DatabaseInfo.java | 4 +- .../cloud/spanner/spi/v1/GapicSpannerRpc.java | 2 - .../spanner/it/ITCreateDatabaseProtos.java | 42 +- .../cloud/spanner/it/ITProtoColumnTest.java | 656 +++++++++--------- 5 files changed, 353 insertions(+), 354 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java index fe39571e2f7..3464b2a4727 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java @@ -463,8 +463,7 @@ public List getDatabaseDdl(String instanceId, String databaseId) { } @Override - public GetDatabaseDdlResponse getDatabaseDdlResponse( - String instanceId, String databaseId) { + public GetDatabaseDdlResponse getDatabaseDdlResponse(String instanceId, String databaseId) { String dbName = getDatabaseName(instanceId, databaseId); return rpc.getDatabaseDdl(dbName); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java index dec2f31e1f2..55da2524abc 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java @@ -21,7 +21,6 @@ import com.google.common.base.Preconditions; import com.google.common.io.ByteStreams; import com.google.protobuf.ByteString; - import java.io.IOException; import java.io.InputStream; import java.util.Objects; @@ -66,7 +65,8 @@ public Builder setDialect(Dialect dialect) { public abstract Builder setProtoDescriptors(@Nonnull byte[] protoDescriptors); - public abstract Builder setProtoDescriptors(@Nonnull InputStream inputStream) throws IOException; + public abstract Builder setProtoDescriptors(@Nonnull InputStream inputStream) + throws IOException; public abstract Builder setProtoDescriptors(String filePath) throws IOException; diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index ce151a9edf3..483314d4d34 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -1195,8 +1195,6 @@ public OperationFuture createDatabase( requestBuilder.setProtoDescriptors(databaseInfo.getProtoDescriptors()); } final CreateDatabaseRequest request = requestBuilder.build(); - String req_string = request.toString(); - System.out.println(req_string); OperationFutureCallable callable = new OperationFutureCallable<>( databaseAdminStub.createDatabaseOperationCallable(), diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java index 1a153bdea74..f5073137929 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java @@ -29,22 +29,17 @@ import com.google.cloud.spanner.SpannerExceptionFactory; import com.google.cloud.spanner.testing.RemoteSpannerHelper; import com.google.common.io.ByteStreams; -import com.google.protobuf.ByteString; import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; import com.google.spanner.admin.database.v1.GetDatabaseDdlResponse; -import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import javax.xml.crypto.Data; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -122,8 +117,9 @@ public void returnsTheVersionRetentionPeriodSetThroughGetDatabase() throws Excep assertThat(database.getVersionRetentionPeriod()).isEqualTo(VERSION_RETENTION_PERIOD); assertThat(database.getEarliestVersionTime()).isNotNull(); - - final GetDatabaseDdlResponse response = dbAdminClient.getDatabaseDdlResponse("integration-test-proto-column", "int_test_proto_column_db"); + final GetDatabaseDdlResponse response = + dbAdminClient.getDatabaseDdlResponse( + "integration-test-proto-column", "int_test_proto_column_db"); System.out.println(response.getProtoDescriptors().toByteArray()); } @@ -149,11 +145,14 @@ public void returnsAnErrorWhenAnInvalidVersionRetentionPeriodIsGiven() { private Database createDatabase( final String projectId, final String instanceId, final String databaseId) throws IOException { - //String filePath = "/usr/local/google/home/sriharshach/github/Go/golang-samples-proto-support-v2/spanner/spanner_snippets/spanner/testdata/protos/descriptor.pb"; + // String filePath = + // "/usr/local/google/home/sriharshach/github/Go/golang-samples-proto-support-v2/spanner/spanner_snippets/spanner/testdata/protos/descriptor.pb"; // file to byte[], Path - //byte[] bytes = Files.readAllBytes(Paths.get(filePath)); + // byte[] bytes = Files.readAllBytes(Paths.get(filePath)); - InputStream inputStream = new FileInputStream("/usr/local/google/home/sriharshach/github/Go/golang-samples-proto-support-v2/spanner/spanner_snippets/spanner/testdata/protos/descriptors.pb"); + InputStream inputStream = + new FileInputStream( + "/usr/local/google/home/sriharshach/github/Go/golang-samples-proto-support-v2/spanner/spanner_snippets/spanner/testdata/protos/descriptors.pb"); byte[] byteArray = null; // Try block to check for exceptions @@ -165,13 +164,13 @@ private Database createDatabase( try { byteArray = ByteStreams.toByteArray(inputStream); - } - catch (IOException e) { + } catch (IOException e) { System.out.println(e); } final Database databaseToCreate = - dbAdminClient.newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId)) + dbAdminClient + .newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId)) .setProtoDescriptors(byteArray) .build(); @@ -214,18 +213,21 @@ private Database createDatabase( } private Database createDatabaseWithProtos( - final String projectId, final String instanceId, final String databaseId, InputStream protoDescriptorFile) { + final String projectId, + final String instanceId, + final String databaseId, + InputStream protoDescriptorFile) { byte[] protoDescriptorByteArray = null; try { protoDescriptorByteArray = ByteStreams.toByteArray(protoDescriptorFile); - } - catch (IOException e) { + } catch (IOException e) { System.out.println(e); } final Database databaseToCreate = - dbAdminClient.newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId)) + dbAdminClient + .newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId)) .setProtoDescriptors(protoDescriptorByteArray) .build(); @@ -292,10 +294,10 @@ private Database createDatabaseWithProtos( } }*/ - private void getDatabaseDdl( - String instanceId, String databaseId) { + private void getDatabaseDdl(String instanceId, String databaseId) { try { - final GetDatabaseDdlResponse response = dbAdminClient.getDatabaseDdlResponse(instanceId, databaseId); + final GetDatabaseDdlResponse response = + dbAdminClient.getDatabaseDdlResponse(instanceId, databaseId); System.out.println("Retrieved GetDatabaseDdlResponse for " + databaseId); for (String ddl : response.getStatementsList()) { System.out.println(ddl); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java index 2d2c5d02a94..f119ebef0d3 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java @@ -17,7 +17,6 @@ package com.google.cloud.spanner.it; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; import static org.junit.Assume.assumeFalse; @@ -32,13 +31,10 @@ import com.google.protobuf.InvalidProtocolBufferException.InvalidWireTypeException; import com.google.protobuf.ProtocolMessageEnum; import com.google.spanner.admin.database.v1.Backup; - import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; - -import com.google.spanner.admin.database.v1.GetDatabaseDdlResponse; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -48,343 +44,347 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import javax.xml.crypto.Data; - // Integration Tests to test DDL, DML and DQL for Proto Columns & Enums // TODO(harsha): Check session leak warning @Category(ParallelIntegrationTest.class) @RunWith(JUnit4.class) public class ITProtoColumnTest { - @ClassRule - public static IntegrationTestEnv env = new IntegrationTestEnv(); - private static DatabaseId databaseID; - // For reference of databaseClient and dbAdminClient usage check ITPgJsonbTest.java or ITWithGrpcGcpTest.java - private static DatabaseAdminClient dbAdminClient; - private static DatabaseClient databaseClient; - - @BeforeClass - public static void setUpDatabase() throws Exception { - // Get default spanner options for an integration test. - //SpannerOptions.Builder builder = env.getTestHelper().getOptions().toBuilder(); - // Create a new testHelper with the cloud-devel host. - // testHelper = RemoteSpannerHelper.create(builder.build(), env.getTestHelper().getInstanceId()); - RemoteSpannerHelper testHelper = env.getTestHelper(); - databaseID = DatabaseId.of(testHelper.getInstanceId(), testHelper.getUniqueDatabaseId()); - dbAdminClient = testHelper.getClient().getDatabaseAdminClient(); - createDatabase(); - databaseClient = testHelper.getClient().getDatabaseClient(databaseID); - } - - public static void createDatabase() throws Exception { - final Database databaseToCreate = - dbAdminClient - .newDatabaseBuilder(databaseID) - .setProtoDescriptors("com/google/cloud/spanner/descriptors.pb") - .build(); - final Database createdDatabase = - dbAdminClient - .createDatabase( - databaseToCreate, - Arrays.asList( - "CREATE PROTO BUNDLE (" - + "spanner.examples.music.SingerInfo," - + "spanner.examples.music.Genre," - + ")", - "CREATE TABLE Singers (" - + " SingerId INT64 NOT NULL," - + " FirstName STRING(1024)," - + " LastName STRING(1024)," - + " SingerInfo spanner.examples.music.SingerInfo," - + " SingerGenre spanner.examples.music.Genre," - + " SingerNationality STRING(1024) AS (SingerInfo.nationality) STORED," - + " ) PRIMARY KEY (SingerNationality, SingerGenre)", - "CREATE TABLE Types (" - + " RowID INT64 NOT NULL," - + " Int64a INT64," - + " Bytes BYTES(MAX)," - + " Int64Array ARRAY," - + " BytesArray ARRAY," - + " ProtoMessage spanner.examples.music.SingerInfo," - + " ProtoEnum spanner.examples.music.Genre," - + " ProtoMessageArray ARRAY," - + " ProtoEnumArray ARRAY," - + " ) PRIMARY KEY (RowID)", - "CREATE INDEX SingerByNationalityAndGenre ON Singers(SingerNationality, SingerGenre)" - + " STORING (SingerId, FirstName, LastName)")) - .get(5, TimeUnit.MINUTES); - - assertEquals(databaseID.getDatabase(), createdDatabase.getId().getDatabase()); - - // TODO(harsha): Check with backend team as this is not working for generated columns yet. - // GetDatabaseDdlResponse response = dbAdminClient.getDatabaseDdlResponse(databaseID.getInstanceId().getInstance(), databaseID.getDatabase()); - // assertNotNull(response.getProtoDescriptors()); - } - - @AfterClass - public static void afterClass() throws Exception { - try { - dbAdminClient.dropDatabase(databaseID.getInstanceId().getInstance(), databaseID.getDatabase()); - } catch (Exception e) { - System.err.println( - "Failed to drop database " - + dbAdminClient.getDatabase(databaseID.getInstanceId().getInstance(), databaseID.getDatabase()).getId() - + ", skipping...: " - + e.getMessage()); - } - } - - @After - public void after() throws Exception { - databaseClient.write(ImmutableList.of(Mutation.delete("Types", KeySet.all()))); - databaseClient.write(ImmutableList.of(Mutation.delete("Singers", KeySet.all()))); - } - - /** - * Test to check data update and read queries on Proto columns and Enums and their arrays. - * Test also checks for compatability between following types: - * 1. Proto Messages & Bytes - * 2. Proto Enums & Int64 - */ - @Test - public void testProtoColumnsUpdateAndRead() { - assumeFalse( - "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); - SingerInfo singerInfo = - SingerInfo.newBuilder().setSingerId(1).setNationality("Country1").build(); - ByteArray singerInfoBytes = ByteArray.copyFrom(singerInfo.toByteArray()); - - Genre genre = Genre.JAZZ; - long genreConst = genre.getNumber(); - - List singerInfoList = - Arrays.asList(singerInfo, null, SingerInfo.getDefaultInstance()); - List singerInfoBytesList = + @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); + private static DatabaseId databaseID; + // For reference of databaseClient and dbAdminClient usage check ITPgJsonbTest.java or + // ITWithGrpcGcpTest.java + private static DatabaseAdminClient dbAdminClient; + private static DatabaseClient databaseClient; + + @BeforeClass + public static void setUpDatabase() throws Exception { + // Get default spanner options for an integration test. + // SpannerOptions.Builder builder = env.getTestHelper().getOptions().toBuilder(); + // Create a new testHelper with the cloud-devel host. + // testHelper = RemoteSpannerHelper.create(builder.build(), + // env.getTestHelper().getInstanceId()); + RemoteSpannerHelper testHelper = env.getTestHelper(); + databaseID = DatabaseId.of(testHelper.getInstanceId(), testHelper.getUniqueDatabaseId()); + dbAdminClient = testHelper.getClient().getDatabaseAdminClient(); + createDatabase(); + databaseClient = testHelper.getClient().getDatabaseClient(databaseID); + } + + public static void createDatabase() throws Exception { + final Database databaseToCreate = + dbAdminClient + .newDatabaseBuilder(databaseID) + .setProtoDescriptors("com/google/cloud/spanner/descriptors.pb") + .build(); + final Database createdDatabase = + dbAdminClient + .createDatabase( + databaseToCreate, Arrays.asList( - singerInfoBytes, - null, - ByteArray.copyFrom(SingerInfo.getDefaultInstance().toByteArray())); - - List enumList = Arrays.asList(Genre.FOLK, null, Genre.ROCK); - List enumConstList = - Arrays.asList((long) Genre.FOLK_VALUE, null, (long) Genre.ROCK_VALUE); - - // Inserting two rows with same data except rowID as it's used as PK. - databaseClient.write( - ImmutableList.of( - Mutation.newInsertOrUpdateBuilder("Types") - .set("RowID") - .to(1) - .set("Int64a") - .to(genreConst) - .set("Bytes") - .to(singerInfoBytes) - .set("Int64Array") - .toInt64Array(enumConstList) - .set("BytesArray") - .toBytesArray(singerInfoBytesList) - .set("ProtoMessage") - .to(singerInfo) - .set("ProtoEnum") - .to(genre) - .set("ProtoMessageArray") - .toProtoMessageArray(singerInfoList, SingerInfo.getDescriptor()) - .set("ProtoEnumArray") - .toProtoEnumArray(enumList, Genre.getDescriptor()) - .build(), - // Inter Compatability check between ProtoMessages/Bytes and Int64/Enum. - Mutation.newInsertOrUpdateBuilder("Types") - .set("RowID") - .to(2) - .set("Int64a") - .to(genre) - .set("Bytes") - .to(singerInfo) - .set("Int64Array") - .toProtoEnumArray(enumList, Genre.getDescriptor()) - .set("BytesArray") - .toProtoMessageArray(singerInfoList, SingerInfo.getDescriptor()) - .set("ProtoMessage") - .to(singerInfoBytes) - .set("ProtoEnum") - .to(genreConst) - .set("ProtoMessageArray") - .toBytesArray(singerInfoBytesList) - .set("ProtoEnumArray") - .toInt64Array(enumConstList) - .build())); - - try (ResultSet resultSet = - databaseClient.singleUse().executeQuery(Statement.of("SELECT * FROM " + "Types"))) { - - for (int i = 0; i < 2; i++) { - resultSet.next(); - assertEquals(i + 1, resultSet.getLong("RowID")); - assertEquals(genreConst, resultSet.getLong("Int64a")); - assertEquals(singerInfoBytes, resultSet.getBytes("Bytes")); - assertEquals(enumConstList, resultSet.getLongList("Int64Array")); - assertEquals(singerInfoBytesList, resultSet.getBytesList("BytesArray")); - assertEquals( - singerInfo, resultSet.getProtoMessage("ProtoMessage", SingerInfo.getDefaultInstance())); - assertEquals(genre, resultSet.getProtoEnum("ProtoEnum", Genre::forNumber)); - assertEquals( - singerInfoList, - resultSet.getProtoMessageList("ProtoMessageArray", SingerInfo.getDefaultInstance())); - assertEquals(enumList, resultSet.getProtoEnumList("ProtoEnumArray", Genre::forNumber)); - - // Check compatability between Proto Messages & Bytes - assertEquals(singerInfoBytes, resultSet.getBytes("ProtoMessage")); - assertEquals( - singerInfo, resultSet.getProtoMessage("Bytes", SingerInfo.getDefaultInstance())); - - assertEquals(singerInfoBytesList, resultSet.getBytesList("ProtoMessageArray")); - assertEquals( - singerInfoList, - resultSet.getProtoMessageList("BytesArray", SingerInfo.getDefaultInstance())); - - // Check compatability between Proto Enum & Int64 - assertEquals(genreConst, resultSet.getLong("ProtoEnum")); - assertEquals(genre, resultSet.getProtoEnum("Int64a", Genre::forNumber)); - - assertEquals(enumConstList, resultSet.getLongList("ProtoEnumArray")); - assertEquals(enumList, resultSet.getProtoEnumList("Int64Array", Genre::forNumber)); - } - } + "CREATE PROTO BUNDLE (" + + "spanner.examples.music.SingerInfo," + + "spanner.examples.music.Genre," + + ")", + "CREATE TABLE Singers (" + + " SingerId INT64 NOT NULL," + + " FirstName STRING(1024)," + + " LastName STRING(1024)," + + " SingerInfo spanner.examples.music.SingerInfo," + + " SingerGenre spanner.examples.music.Genre," + + " SingerNationality STRING(1024) AS (SingerInfo.nationality) STORED," + + " ) PRIMARY KEY (SingerNationality, SingerGenre)", + "CREATE TABLE Types (" + + " RowID INT64 NOT NULL," + + " Int64a INT64," + + " Bytes BYTES(MAX)," + + " Int64Array ARRAY," + + " BytesArray ARRAY," + + " ProtoMessage spanner.examples.music.SingerInfo," + + " ProtoEnum spanner.examples.music.Genre," + + " ProtoMessageArray ARRAY," + + " ProtoEnumArray ARRAY," + + " ) PRIMARY KEY (RowID)", + "CREATE INDEX SingerByNationalityAndGenre ON Singers(SingerNationality, SingerGenre)" + + " STORING (SingerId, FirstName, LastName)")) + .get(5, TimeUnit.MINUTES); + + assertEquals(databaseID.getDatabase(), createdDatabase.getId().getDatabase()); + + // TODO(harsha): Check with backend team as this is not working for generated columns yet. + // GetDatabaseDdlResponse response = + // dbAdminClient.getDatabaseDdlResponse(databaseID.getInstanceId().getInstance(), + // databaseID.getDatabase()); + // assertNotNull(response.getProtoDescriptors()); + } + + @AfterClass + public static void afterClass() throws Exception { + try { + dbAdminClient.dropDatabase( + databaseID.getInstanceId().getInstance(), databaseID.getDatabase()); + } catch (Exception e) { + System.err.println( + "Failed to drop database " + + dbAdminClient + .getDatabase(databaseID.getInstanceId().getInstance(), databaseID.getDatabase()) + .getId() + + ", skipping...: " + + e.getMessage()); } - - // Test to check Parameterized Queries, Primary Keys and Indexes. - @Test - public void testProtoColumnsDMLParameterizedQueriesPKAndIndexes() { - assumeFalse( - "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); - - SingerInfo singerInfo1 = - SingerInfo.newBuilder().setSingerId(1).setNationality("Country1").build(); - Genre genre1 = Genre.FOLK; - - SingerInfo singerInfo2 = - SingerInfo.newBuilder().setSingerId(2).setNationality("Country2").build(); - Genre genre2 = Genre.JAZZ; - - databaseClient - .readWriteTransaction() - .run( - transaction -> { - Statement statement1 = - Statement.newBuilder( - "INSERT INTO Singers (SingerId, FirstName, LastName, SingerInfo, SingerGenre) VALUES (1, \"FirstName1\", \"LastName1\", @singerInfo, @singerGenre)") - .bind("singerInfo") - .to(singerInfo1) - .bind("singerGenre") - .to(genre1) - .build(); - - Statement statement2 = - Statement.newBuilder( - "INSERT INTO Singers (SingerId, FirstName, LastName, SingerInfo, SingerGenre) VALUES (2, \"FirstName2\", \"LastName2\", @singerInfo, @singerGenre)") - .bind("singerInfo") - .to(singerInfo2) - .bind("singerGenre") - .to(genre2) - .build(); - - transaction.batchUpdate(Arrays.asList(statement1, statement2)); - return null; - }); - - // Read all rows based on Proto Message field and Proto Enum Primary key column values - ResultSet resultSet1 = - databaseClient - .singleUse() - .read( - "Singers", - KeySet.newBuilder() - .addKey(Key.of("Country1", Genre.FOLK)) - .addKey(Key.of("Country2", Genre.JAZZ)) - .build(), - Arrays.asList("SingerId", "FirstName", "LastName", "SingerInfo", "SingerGenre")); - - resultSet1.next(); - assertEquals(1, resultSet1.getLong("SingerId")); - assertEquals("FirstName1", resultSet1.getString("FirstName")); - assertEquals("LastName1", resultSet1.getString("LastName")); + } + + @After + public void after() throws Exception { + databaseClient.write(ImmutableList.of(Mutation.delete("Types", KeySet.all()))); + databaseClient.write(ImmutableList.of(Mutation.delete("Singers", KeySet.all()))); + } + + /** + * Test to check data update and read queries on Proto columns and Enums and their arrays. Test + * also checks for compatability between following types: 1. Proto Messages & Bytes 2. Proto Enums + * & Int64 + */ + @Test + public void testProtoColumnsUpdateAndRead() { + assumeFalse( + "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); + SingerInfo singerInfo = + SingerInfo.newBuilder().setSingerId(1).setNationality("Country1").build(); + ByteArray singerInfoBytes = ByteArray.copyFrom(singerInfo.toByteArray()); + + Genre genre = Genre.JAZZ; + long genreConst = genre.getNumber(); + + List singerInfoList = + Arrays.asList(singerInfo, null, SingerInfo.getDefaultInstance()); + List singerInfoBytesList = + Arrays.asList( + singerInfoBytes, + null, + ByteArray.copyFrom(SingerInfo.getDefaultInstance().toByteArray())); + + List enumList = Arrays.asList(Genre.FOLK, null, Genre.ROCK); + List enumConstList = + Arrays.asList((long) Genre.FOLK_VALUE, null, (long) Genre.ROCK_VALUE); + + // Inserting two rows with same data except rowID as it's used as PK. + databaseClient.write( + ImmutableList.of( + Mutation.newInsertOrUpdateBuilder("Types") + .set("RowID") + .to(1) + .set("Int64a") + .to(genreConst) + .set("Bytes") + .to(singerInfoBytes) + .set("Int64Array") + .toInt64Array(enumConstList) + .set("BytesArray") + .toBytesArray(singerInfoBytesList) + .set("ProtoMessage") + .to(singerInfo) + .set("ProtoEnum") + .to(genre) + .set("ProtoMessageArray") + .toProtoMessageArray(singerInfoList, SingerInfo.getDescriptor()) + .set("ProtoEnumArray") + .toProtoEnumArray(enumList, Genre.getDescriptor()) + .build(), + // Inter Compatability check between ProtoMessages/Bytes and Int64/Enum. + Mutation.newInsertOrUpdateBuilder("Types") + .set("RowID") + .to(2) + .set("Int64a") + .to(genre) + .set("Bytes") + .to(singerInfo) + .set("Int64Array") + .toProtoEnumArray(enumList, Genre.getDescriptor()) + .set("BytesArray") + .toProtoMessageArray(singerInfoList, SingerInfo.getDescriptor()) + .set("ProtoMessage") + .to(singerInfoBytes) + .set("ProtoEnum") + .to(genreConst) + .set("ProtoMessageArray") + .toBytesArray(singerInfoBytesList) + .set("ProtoEnumArray") + .toInt64Array(enumConstList) + .build())); + + try (ResultSet resultSet = + databaseClient.singleUse().executeQuery(Statement.of("SELECT * FROM " + "Types"))) { + + for (int i = 0; i < 2; i++) { + resultSet.next(); + assertEquals(i + 1, resultSet.getLong("RowID")); + assertEquals(genreConst, resultSet.getLong("Int64a")); + assertEquals(singerInfoBytes, resultSet.getBytes("Bytes")); + assertEquals(enumConstList, resultSet.getLongList("Int64Array")); + assertEquals(singerInfoBytesList, resultSet.getBytesList("BytesArray")); assertEquals( - singerInfo1, resultSet1.getProtoMessage("SingerInfo", SingerInfo.getDefaultInstance())); - assertEquals(genre1, resultSet1.getProtoEnum("SingerGenre", Genre::forNumber)); - - resultSet1.next(); - assertEquals(2, resultSet1.getLong("SingerId")); - assertEquals("FirstName2", resultSet1.getString("FirstName")); - assertEquals("LastName2", resultSet1.getString("LastName")); + singerInfo, resultSet.getProtoMessage("ProtoMessage", SingerInfo.getDefaultInstance())); + assertEquals(genre, resultSet.getProtoEnum("ProtoEnum", Genre::forNumber)); assertEquals( - singerInfo2, resultSet1.getProtoMessage("SingerInfo", SingerInfo.getDefaultInstance())); - assertEquals(genre2, resultSet1.getProtoEnum("SingerGenre", Genre::forNumber)); - - // Read rows using Index on Proto Message field and Proto Enum column - ResultSet resultSet2 = - databaseClient - .singleUse() - .readUsingIndex( - "Singers", - "SingerByNationalityAndGenre", - KeySet.singleKey(Key.of("Country2", Genre.JAZZ)), - Arrays.asList("SingerId", "FirstName", "LastName")); - resultSet2.next(); - assertEquals(2, resultSet2.getLong("SingerId")); - assertEquals("FirstName2", resultSet2.getString("FirstName")); - assertEquals("LastName2", resultSet2.getString("LastName")); - - // Filter using Parameterized DQL - ResultSet resultSet3 = - databaseClient - .singleUse() - .executeQuery( - Statement.newBuilder( - "SELECT SingerId, SingerInfo, SingerGenre FROM " - + "Singers WHERE SingerInfo.Nationality=@country AND SingerGenre=@genre") - .bind("country") - .to("Country2") - .bind("genre") - .to(Genre.JAZZ) - .build()); - - resultSet3.next(); - assertEquals(2, resultSet1.getLong("SingerId")); + singerInfoList, + resultSet.getProtoMessageList("ProtoMessageArray", SingerInfo.getDefaultInstance())); + assertEquals(enumList, resultSet.getProtoEnumList("ProtoEnumArray", Genre::forNumber)); + + // Check compatability between Proto Messages & Bytes + assertEquals(singerInfoBytes, resultSet.getBytes("ProtoMessage")); assertEquals( - singerInfo2, resultSet1.getProtoMessage("SingerInfo", SingerInfo.getDefaultInstance())); - assertEquals(genre2, resultSet1.getProtoEnum("SingerGenre", Genre::forNumber)); - } + singerInfo, resultSet.getProtoMessage("Bytes", SingerInfo.getDefaultInstance())); - // Test the exception in case Invalid protocol message object is provided while deserializing the data. - @Test - public void testProtoMessageDeserializationError() { - assumeFalse( - "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); - - SingerInfo singerInfo = - SingerInfo.newBuilder().setSingerId(1).setNationality("Country1").build(); - - databaseClient.write( - ImmutableList.of( - Mutation.newInsertOrUpdateBuilder("Types") - .set("RowID") - .to(1) - .set("ProtoMessage") - .to(singerInfo) - .build())); - - ResultSet resultSet = - databaseClient - .singleUse() - .read("Types", KeySet.all(), Collections.singletonList("ProtoMessage")); - resultSet.next(); + assertEquals(singerInfoBytesList, resultSet.getBytesList("ProtoMessageArray")); + assertEquals( + singerInfoList, + resultSet.getProtoMessageList("BytesArray", SingerInfo.getDefaultInstance())); - SpannerException e = - assertThrows( - SpannerException.class, - () -> resultSet.getProtoMessage("ProtoMessage", Backup.getDefaultInstance())); + // Check compatability between Proto Enum & Int64 + assertEquals(genreConst, resultSet.getLong("ProtoEnum")); + assertEquals(genre, resultSet.getProtoEnum("Int64a", Genre::forNumber)); - // Underlying cause is InvalidWireTypeException - assertEquals(InvalidWireTypeException.class, e.getCause().getClass()); + assertEquals(enumConstList, resultSet.getLongList("ProtoEnumArray")); + assertEquals(enumList, resultSet.getProtoEnumList("Int64Array", Genre::forNumber)); + } } + } + + // Test to check Parameterized Queries, Primary Keys and Indexes. + @Test + public void testProtoColumnsDMLParameterizedQueriesPKAndIndexes() { + assumeFalse( + "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); + + SingerInfo singerInfo1 = + SingerInfo.newBuilder().setSingerId(1).setNationality("Country1").build(); + Genre genre1 = Genre.FOLK; + + SingerInfo singerInfo2 = + SingerInfo.newBuilder().setSingerId(2).setNationality("Country2").build(); + Genre genre2 = Genre.JAZZ; + + databaseClient + .readWriteTransaction() + .run( + transaction -> { + Statement statement1 = + Statement.newBuilder( + "INSERT INTO Singers (SingerId, FirstName, LastName, SingerInfo, SingerGenre) VALUES (1, \"FirstName1\", \"LastName1\", @singerInfo, @singerGenre)") + .bind("singerInfo") + .to(singerInfo1) + .bind("singerGenre") + .to(genre1) + .build(); + + Statement statement2 = + Statement.newBuilder( + "INSERT INTO Singers (SingerId, FirstName, LastName, SingerInfo, SingerGenre) VALUES (2, \"FirstName2\", \"LastName2\", @singerInfo, @singerGenre)") + .bind("singerInfo") + .to(singerInfo2) + .bind("singerGenre") + .to(genre2) + .build(); + + transaction.batchUpdate(Arrays.asList(statement1, statement2)); + return null; + }); + + // Read all rows based on Proto Message field and Proto Enum Primary key column values + ResultSet resultSet1 = + databaseClient + .singleUse() + .read( + "Singers", + KeySet.newBuilder() + .addKey(Key.of("Country1", Genre.FOLK)) + .addKey(Key.of("Country2", Genre.JAZZ)) + .build(), + Arrays.asList("SingerId", "FirstName", "LastName", "SingerInfo", "SingerGenre")); + + resultSet1.next(); + assertEquals(1, resultSet1.getLong("SingerId")); + assertEquals("FirstName1", resultSet1.getString("FirstName")); + assertEquals("LastName1", resultSet1.getString("LastName")); + assertEquals( + singerInfo1, resultSet1.getProtoMessage("SingerInfo", SingerInfo.getDefaultInstance())); + assertEquals(genre1, resultSet1.getProtoEnum("SingerGenre", Genre::forNumber)); + + resultSet1.next(); + assertEquals(2, resultSet1.getLong("SingerId")); + assertEquals("FirstName2", resultSet1.getString("FirstName")); + assertEquals("LastName2", resultSet1.getString("LastName")); + assertEquals( + singerInfo2, resultSet1.getProtoMessage("SingerInfo", SingerInfo.getDefaultInstance())); + assertEquals(genre2, resultSet1.getProtoEnum("SingerGenre", Genre::forNumber)); + + // Read rows using Index on Proto Message field and Proto Enum column + ResultSet resultSet2 = + databaseClient + .singleUse() + .readUsingIndex( + "Singers", + "SingerByNationalityAndGenre", + KeySet.singleKey(Key.of("Country2", Genre.JAZZ)), + Arrays.asList("SingerId", "FirstName", "LastName")); + resultSet2.next(); + assertEquals(2, resultSet2.getLong("SingerId")); + assertEquals("FirstName2", resultSet2.getString("FirstName")); + assertEquals("LastName2", resultSet2.getString("LastName")); + + // Filter using Parameterized DQL + ResultSet resultSet3 = + databaseClient + .singleUse() + .executeQuery( + Statement.newBuilder( + "SELECT SingerId, SingerInfo, SingerGenre FROM " + + "Singers WHERE SingerInfo.Nationality=@country AND SingerGenre=@genre") + .bind("country") + .to("Country2") + .bind("genre") + .to(Genre.JAZZ) + .build()); + + resultSet3.next(); + assertEquals(2, resultSet1.getLong("SingerId")); + assertEquals( + singerInfo2, resultSet1.getProtoMessage("SingerInfo", SingerInfo.getDefaultInstance())); + assertEquals(genre2, resultSet1.getProtoEnum("SingerGenre", Genre::forNumber)); + } + + // Test the exception in case Invalid protocol message object is provided while deserializing the + // data. + @Test + public void testProtoMessageDeserializationError() { + assumeFalse( + "Proto Column is not supported in the emulator", EmulatorSpannerHelper.isUsingEmulator()); + + SingerInfo singerInfo = + SingerInfo.newBuilder().setSingerId(1).setNationality("Country1").build(); + + databaseClient.write( + ImmutableList.of( + Mutation.newInsertOrUpdateBuilder("Types") + .set("RowID") + .to(1) + .set("ProtoMessage") + .to(singerInfo) + .build())); + + ResultSet resultSet = + databaseClient + .singleUse() + .read("Types", KeySet.all(), Collections.singletonList("ProtoMessage")); + resultSet.next(); + + SpannerException e = + assertThrows( + SpannerException.class, + () -> resultSet.getProtoMessage("ProtoMessage", Backup.getDefaultInstance())); + + // Underlying cause is InvalidWireTypeException + assertEquals(InvalidWireTypeException.class, e.getCause().getClass()); + } } From e85e350fce81800542e90a03e675c22dc8c91990 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Sun, 12 Feb 2023 22:47:10 +0530 Subject: [PATCH 08/25] feat: unit tests and clirr differences --- .../clirr-ignored-differences.xml | 51 +++++++++++++ .../spanner/DatabaseAdminClientImplTest.java | 10 +++ .../google/cloud/spanner/DatabaseTest.java | 74 ++++++++++++++++--- 3 files changed, 125 insertions(+), 10 deletions(-) diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml index 8e4710354e3..9950d9f62b3 100644 --- a/google-cloud-spanner/clirr-ignored-differences.xml +++ b/google-cloud-spanner/clirr-ignored-differences.xml @@ -262,4 +262,55 @@ com/google/cloud/spanner/connection/Connection com.google.cloud.spanner.ResultSet analyzeUpdateStatement(com.google.cloud.spanner.Statement, com.google.cloud.spanner.ReadContext$QueryAnalyzeMode, com.google.cloud.spanner.Options$UpdateOption[]) + + 7012 + com/google/cloud/spanner/DatabaseAdminClient + com.google.spanner.admin.database.v1.GetDatabaseDdlResponse getDatabaseDdlResponse(java.lang.String, java.lang.String) + + + 7012 + com/google/cloud/spanner/DatabaseAdminClient + com.google.api.gax.longrunning.OperationFuture updateDatabaseDdl(com.google.cloud.spanner.Database, java.lang.Iterable, java.lang.String) + + + 7013 + com/google/cloud/spanner/DatabaseInfo$Builder + com.google.cloud.spanner.DatabaseInfo$Builder setProtoDescriptors(byte[]) + + + 7013 + com/google/cloud/spanner/DatabaseInfo$Builder + com.google.cloud.spanner.DatabaseInfo$Builder setProtoDescriptors(java.io.InputStream) + + + 7013 + com/google/cloud/spanner/DatabaseInfo$Builder + com.google.cloud.spanner.DatabaseInfo$Builder setProtoDescriptors(java.lang.String) + + + 7006 + com/google/cloud/spanner/spi/v1/GapicSpannerRpc + java.util.List getDatabaseDdl(java.lang.String) + java.util.List + com.google.spanner.admin.database.v1.GetDatabaseDdlResponse + + + 7005 + com/google/cloud/spanner/spi/v1/GapicSpannerRpc + com.google.api.gax.longrunning.OperationFuture updateDatabaseDdl(java.lang.String, java.lang.Iterable, java.lang.String) + com.google.api.gax.longrunning.OperationFuture updateDatabaseDdl(com.google.cloud.spanner.Database, java.lang.Iterable, java.lang.String) + + + 7006 + com/google/cloud/spanner/spi/v1/SpannerRpc + java.util.List getDatabaseDdl(java.lang.String) + java.util.List + com.google.spanner.admin.database.v1.GetDatabaseDdlResponse + + + 7005 + com/google/cloud/spanner/spi/v1/SpannerRpc + com.google.api.gax.longrunning.OperationFuture updateDatabaseDdl(java.lang.String, java.lang.Iterable, java.lang.String) + com.google.api.gax.longrunning.OperationFuture updateDatabaseDdl(com.google.cloud.spanner.Database, java.lang.Iterable, java.lang.String) + diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java index 024a6ca4b5d..e7729dc7e0b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java @@ -266,6 +266,16 @@ public void getDatabaseDdl() { assertThat(client.getDatabaseDdl(INSTANCE_ID, DB_ID)).isEqualTo(ddl); } + @Test + public void getDatabaseDdlResponse() { + List ddl = ImmutableList.of("CREATE TABLE mytable()"); + when(rpc.getDatabaseDdl(DB_NAME)) + .thenReturn(GetDatabaseDdlResponse.newBuilder().addAllStatements(ddl).setProtoDescriptors(ByteString.EMPTY).build()); + GetDatabaseDdlResponse response = client.getDatabaseDdlResponse(INSTANCE_ID, DB_ID); + assertThat(response.getStatementsList()).isEqualTo(ddl); + assertThat(response.getProtoDescriptors()).isEqualTo(ByteString.EMPTY); + } + @Test public void listDatabases() { String pageToken = "token"; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java index 1eb2794c8ee..73fa5f85213 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java @@ -16,26 +16,18 @@ package com.google.cloud.spanner; -import static com.google.cloud.spanner.DatabaseInfo.State.CREATING; -import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - import com.google.cloud.Identity; import com.google.cloud.Policy; import com.google.cloud.Role; import com.google.cloud.Timestamp; import com.google.cloud.spanner.DatabaseInfo.State; import com.google.cloud.spanner.encryption.EncryptionConfigs; +import com.google.common.io.ByteStreams; +import com.google.protobuf.ByteString; import com.google.rpc.Code; import com.google.rpc.Status; import com.google.spanner.admin.database.v1.DatabaseDialect; import com.google.spanner.admin.database.v1.EncryptionInfo; -import java.util.Collections; -import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -43,6 +35,20 @@ import org.mockito.Mock; import org.mockito.Mockito; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.List; + +import static com.google.cloud.spanner.DatabaseInfo.State.CREATING; +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + /** Unit tests for {@link com.google.cloud.spanner.Database}. */ @RunWith(JUnit4.class) public class DatabaseTest { @@ -66,6 +72,9 @@ public class DatabaseTest { .build()); private static final String DEFAULT_LEADER = "default-leader"; private static final DatabaseDialect DEFAULT_DIALECT = DatabaseDialect.GOOGLE_STANDARD_SQL; + private static ByteString protoDescriptors; + private static InputStream protoDescriptorsInputStream; + private static byte[] protoDescriptorsByteArray; @Mock DatabaseAdminClient dbClient; @@ -79,6 +88,15 @@ public void setUp() { .thenAnswer( invocation -> new Database.Builder(dbClient, (DatabaseId) invocation.getArguments()[0])); + try { + protoDescriptorsInputStream = getClass().getClassLoader().getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); + protoDescriptorsByteArray = ByteStreams.toByteArray(protoDescriptorsInputStream); + protoDescriptors = ByteString.copyFrom(protoDescriptorsByteArray); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } } @Test @@ -178,6 +196,42 @@ public void testBuildWithDatabaseDialect() { assertEquals(Dialect.GOOGLE_STANDARD_SQL, database.getDialect()); } + @Test + public void testBuildWithProtoDescriptors() throws IOException { + final Database database = + dbClient + .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) + .setProtoDescriptors("com/google/cloud/spanner/descriptors.pb") + .build(); + + assertEquals(protoDescriptors, database.getProtoDescriptors()); + } + + // TODO(harsha): need to recheck, not passing + @Test + public void testBuildWithProtoDescriptorsFromInputStream() throws IOException { + InputStream in = getClass().getClassLoader().getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); + //byte[] test = ByteStreams.toByteArray(in); + final Database database = + dbClient + .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) + .setProtoDescriptors(in) + .build(); + + assertEquals(protoDescriptors, database.getProtoDescriptors()); + } + + @Test + public void testBuildWithProtoDescriptorsFromByteArray() throws IOException { + final Database database = + dbClient + .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) + .setProtoDescriptors(protoDescriptorsByteArray) + .build(); + + assertEquals(protoDescriptors, database.getProtoDescriptors()); + } + @Test public void getIAMPolicy() { Database database = From bb04177867f12c7058cb4b6133817b6636abed2d Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Mon, 13 Feb 2023 09:01:38 +0530 Subject: [PATCH 09/25] feat: lint changes --- .../spanner/DatabaseAdminClientImplTest.java | 6 +- .../google/cloud/spanner/DatabaseTest.java | 61 ++++++++++--------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java index e7729dc7e0b..900e6948245 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java @@ -270,7 +270,11 @@ public void getDatabaseDdl() { public void getDatabaseDdlResponse() { List ddl = ImmutableList.of("CREATE TABLE mytable()"); when(rpc.getDatabaseDdl(DB_NAME)) - .thenReturn(GetDatabaseDdlResponse.newBuilder().addAllStatements(ddl).setProtoDescriptors(ByteString.EMPTY).build()); + .thenReturn( + GetDatabaseDdlResponse.newBuilder() + .addAllStatements(ddl) + .setProtoDescriptors(ByteString.EMPTY) + .build()); GetDatabaseDdlResponse response = client.getDatabaseDdlResponse(INSTANCE_ID, DB_ID); assertThat(response.getStatementsList()).isEqualTo(ddl); assertThat(response.getProtoDescriptors()).isEqualTo(ByteString.EMPTY); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java index 73fa5f85213..23acff7b5e6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java @@ -16,6 +16,14 @@ package com.google.cloud.spanner; +import static com.google.cloud.spanner.DatabaseInfo.State.CREATING; +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + import com.google.cloud.Identity; import com.google.cloud.Policy; import com.google.cloud.Role; @@ -28,6 +36,11 @@ import com.google.rpc.Status; import com.google.spanner.admin.database.v1.DatabaseDialect; import com.google.spanner.admin.database.v1.EncryptionInfo; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -35,20 +48,6 @@ import org.mockito.Mock; import org.mockito.Mockito; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collections; -import java.util.List; - -import static com.google.cloud.spanner.DatabaseInfo.State.CREATING; -import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.initMocks; - /** Unit tests for {@link com.google.cloud.spanner.Database}. */ @RunWith(JUnit4.class) public class DatabaseTest { @@ -89,7 +88,10 @@ public void setUp() { invocation -> new Database.Builder(dbClient, (DatabaseId) invocation.getArguments()[0])); try { - protoDescriptorsInputStream = getClass().getClassLoader().getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); + protoDescriptorsInputStream = + getClass() + .getClassLoader() + .getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); protoDescriptorsByteArray = ByteStreams.toByteArray(protoDescriptorsInputStream); protoDescriptors = ByteString.copyFrom(protoDescriptorsByteArray); } catch (FileNotFoundException e) { @@ -199,10 +201,10 @@ public void testBuildWithDatabaseDialect() { @Test public void testBuildWithProtoDescriptors() throws IOException { final Database database = - dbClient - .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) - .setProtoDescriptors("com/google/cloud/spanner/descriptors.pb") - .build(); + dbClient + .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) + .setProtoDescriptors("com/google/cloud/spanner/descriptors.pb") + .build(); assertEquals(protoDescriptors, database.getProtoDescriptors()); } @@ -210,13 +212,14 @@ public void testBuildWithProtoDescriptors() throws IOException { // TODO(harsha): need to recheck, not passing @Test public void testBuildWithProtoDescriptorsFromInputStream() throws IOException { - InputStream in = getClass().getClassLoader().getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); - //byte[] test = ByteStreams.toByteArray(in); + InputStream in = + getClass().getClassLoader().getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); + // byte[] test = ByteStreams.toByteArray(in); final Database database = - dbClient - .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) - .setProtoDescriptors(in) - .build(); + dbClient + .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) + .setProtoDescriptors(in) + .build(); assertEquals(protoDescriptors, database.getProtoDescriptors()); } @@ -224,10 +227,10 @@ public void testBuildWithProtoDescriptorsFromInputStream() throws IOException { @Test public void testBuildWithProtoDescriptorsFromByteArray() throws IOException { final Database database = - dbClient - .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) - .setProtoDescriptors(protoDescriptorsByteArray) - .build(); + dbClient + .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) + .setProtoDescriptors(protoDescriptorsByteArray) + .build(); assertEquals(protoDescriptors, database.getProtoDescriptors()); } From f4c7c962d97b137bca832dbb662b8233c2ddccbb Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Mon, 13 Feb 2023 09:21:04 +0530 Subject: [PATCH 10/25] feat: code refactor --- google-cloud-spanner/pom.xml | 5 ++--- .../test/java/com/google/cloud/spanner/GceTestEnvConfig.java | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index 0ea72e5300b..c8246a4bd16 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -18,9 +18,8 @@ 0.31.1 22.3.0 com.google.cloud.spanner.GceTestEnvConfig - projects/span-cloud-testing/instances/harsha-test-gcloud - span-cloud-testing - https://staging-wrenchworks.sandbox.googleapis.com + projects/gcloud-devel/instances/spanner-testing-east1 + gcloud-devel projects/gcloud-devel/locations/us-east1/keyRings/cmek-test-key-ring/cryptoKeys/cmek-test-key diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java index 813c8ea8502..7a27123bdc3 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/GceTestEnvConfig.java @@ -100,7 +100,6 @@ public GceTestEnvConfig() { .setInterceptorProvider(interceptorProvider); builder.setChannelProvider(customChannelProviderBuilder.build()); } - builder.setHost("https://staging-wrenchworks.sandbox.googleapis.com"); options = builder.build(); } From 80526b5fc54ae35637283525602bc55ae107403f Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Mon, 13 Feb 2023 10:23:10 +0530 Subject: [PATCH 11/25] feat: code refactoring --- .../spanner/DatabaseAdminClientImpl.java | 6 +- .../spanner/it/ITCreateDatabaseProtos.java | 309 ------------------ 2 files changed, 3 insertions(+), 312 deletions(-) delete mode 100644 google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java index 3464b2a4727..da0ca529fa7 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java @@ -419,9 +419,9 @@ public Database getDatabase(String instanceId, String databaseId) throws Spanner @Override public OperationFuture updateDatabaseDdl( - String instanceId, - String databaseId, - Iterable statements, + final String instanceId, + final String databaseId, + final Iterable statements, @Nullable String operationId) throws SpannerException { diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java deleted file mode 100644 index f5073137929..00000000000 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITCreateDatabaseProtos.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * 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. - * 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.truth.Truth.assertThat; -import static org.junit.Assume.assumeFalse; - -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.IntegrationTestEnv; -import com.google.cloud.spanner.ParallelIntegrationTest; -import com.google.cloud.spanner.SpannerExceptionFactory; -import com.google.cloud.spanner.testing.RemoteSpannerHelper; -import com.google.common.io.ByteStreams; -import com.google.spanner.admin.database.v1.CreateDatabaseMetadata; -import com.google.spanner.admin.database.v1.GetDatabaseDdlResponse; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import org.junit.After; -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.JUnit4; -import org.threeten.bp.Duration; - -@Category(ParallelIntegrationTest.class) -@RunWith(JUnit4.class) -public class ITCreateDatabaseProtos { - - private static final Duration OPERATION_TIMEOUT = Duration.ofMinutes(2); - private static final String VERSION_RETENTION_PERIOD = "7d"; - - @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); - private RemoteSpannerHelper testHelper; - private DatabaseAdminClient dbAdminClient; - private List databasesToDrop; - - @BeforeClass - public static void doNotRunOnEmulator() { - assumeFalse("PITR-lite features are not supported by the emulator", isUsingEmulator()); - } - - @Before - public void setUp() { - testHelper = env.getTestHelper(); - dbAdminClient = testHelper.getClient().getDatabaseAdminClient(); - databasesToDrop = new ArrayList<>(); - } - - @After - public void tearDown() { - for (Database database : databasesToDrop) { - final DatabaseId id = database.getId(); - dbAdminClient.dropDatabase(id.getInstanceId().getInstance(), id.getDatabase()); - } - } - - /*@Test - public void returnsTheVersionRetentionPeriodSetThroughCreateDatabase() throws Exception { - final String instanceId = testHelper.getInstanceId().getInstance(); - final String databaseId = testHelper.getUniqueDatabaseId(); - final String extraStatement = - "ALTER DATABASE " - + databaseId - + " SET OPTIONS (version_retention_period = '" - + VERSION_RETENTION_PERIOD - + "')"; - - final Database database = createDatabase(instanceId, databaseId, extraStatement); - - assertThat(database.getVersionRetentionPeriod()).isEqualTo(VERSION_RETENTION_PERIOD); - assertThat(database.getEarliestVersionTime()).isNotNull(); - }*/ - - @Test - public void returnsTheVersionRetentionPeriodSetThroughGetDatabase() throws Exception { - final String projectId = "span-cloud-testing"; - final String instanceId = "harsha-test-gcloud"; - final String databaseId = "singer_test"; - /*final String extraStatement = - "ALTER DATABASE " - + databaseId - + " SET OPTIONS (version_retention_period = '" - + VERSION_RETENTION_PERIOD - + "')";*/ - - createDatabase(projectId, instanceId, databaseId); - final Database database = dbAdminClient.getDatabase(instanceId, databaseId); - - assertThat(database.getVersionRetentionPeriod()).isEqualTo(VERSION_RETENTION_PERIOD); - assertThat(database.getEarliestVersionTime()).isNotNull(); - - final GetDatabaseDdlResponse response = - dbAdminClient.getDatabaseDdlResponse( - "integration-test-proto-column", "int_test_proto_column_db"); - System.out.println(response.getProtoDescriptors().toByteArray()); - } - - /*@Test(expected = DatabaseNotFoundException.class) - public void returnsAnErrorWhenAnInvalidVersionRetentionPeriodIsGiven() { - final String instanceId = testHelper.getInstanceId().getInstance(); - final String databaseId = testHelper.getUniqueDatabaseId(); - final String extraStatement = - "ALTER DATABASE " + databaseId + " SET OPTIONS (version_retention_period = '0d')"; - - try { - createDatabase(instanceId, databaseId, extraStatement); - fail("Expected invalid argument error when setting invalid version retention period"); - } catch (Exception e) { - SpannerException spannerException = (SpannerException) e.getCause(); - assertThat(spannerException.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); - } - - // Expects a database not found exception - dbAdminClient.getDatabase(instanceId, databaseId); - }*/ - - private Database createDatabase( - final String projectId, final String instanceId, final String databaseId) throws IOException { - - // String filePath = - // "/usr/local/google/home/sriharshach/github/Go/golang-samples-proto-support-v2/spanner/spanner_snippets/spanner/testdata/protos/descriptor.pb"; - // file to byte[], Path - // byte[] bytes = Files.readAllBytes(Paths.get(filePath)); - - InputStream inputStream = - new FileInputStream( - "/usr/local/google/home/sriharshach/github/Go/golang-samples-proto-support-v2/spanner/spanner_snippets/spanner/testdata/protos/descriptors.pb"); - byte[] byteArray = null; - - // Try block to check for exceptions - /*try { - byteArray = inputStream.readAllBytes(); - }catch (IOException e) { - System.out.println(e); - }*/ - - try { - byteArray = ByteStreams.toByteArray(inputStream); - } catch (IOException e) { - System.out.println(e); - } - - final Database databaseToCreate = - dbAdminClient - .newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId)) - .setProtoDescriptors(byteArray) - .build(); - - final OperationFuture operation = - dbAdminClient.createDatabase( - databaseToCreate, - Arrays.asList( - "CREATE PROTO BUNDLE (" - + "spanner.examples.music.SingerInfo," - + "spanner.examples.music.Genre," - + ")", - "CREATE TABLE Singers (" - + " SingerId INT64 NOT NULL," - + " FirstName STRING(1024)," - + " LastName STRING(1024)," - + " SingerInfo spanner.examples.music.SingerInfo," - + " SingerGenre spanner.examples.music.Genre," - + " ) PRIMARY KEY (SingerGenre)")); - - 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()); - - return createdDatabase; - } 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); - } - } - - private Database createDatabaseWithProtos( - final String projectId, - final String instanceId, - final String databaseId, - InputStream protoDescriptorFile) { - - byte[] protoDescriptorByteArray = null; - try { - protoDescriptorByteArray = ByteStreams.toByteArray(protoDescriptorFile); - } catch (IOException e) { - System.out.println(e); - } - - final Database databaseToCreate = - dbAdminClient - .newDatabaseBuilder(DatabaseId.of(projectId, instanceId, databaseId)) - .setProtoDescriptors(protoDescriptorByteArray) - .build(); - - final OperationFuture operation = - dbAdminClient.createDatabase( - databaseToCreate, - Arrays.asList( - "CREATE PROTO BUNDLE (" - + "spanner.examples.music.SingerInfo," - + "spanner.examples.music.Genre," - + ")", - "CREATE TABLE Singers (" - + " SingerId INT64 NOT NULL," - + " FirstName STRING(1024)," - + " LastName STRING(1024)," - + " SingerInfo spanner.examples.music.SingerInfo," - + " SingerGenre spanner.examples.music.Genre," - + " ) PRIMARY KEY (SingerGenre)")); - - try { - System.out.println("Waiting for operation to complete..."); - Database createdDatabase = operation.get(120, TimeUnit.SECONDS); - return createdDatabase; - } catch (Exception e) { - // If the operation failed during execution, expose the cause. - throw SpannerExceptionFactory.asSpannerException(e.getCause()); - } - } - - /*private void updateDatabaseWithProtos( - final String instanceId, final String databaseId, InputStream protoDescriptorFile) { - - byte[] protoDescriptorByteArray = null; - try { - protoDescriptorByteArray = ByteStreams.toByteArray(protoDescriptorFile); - } - catch (IOException e) { - System.out.println(e); - } - - try { - final OperationFuture updateOperation = - dbAdminClient.updateDatabaseDdl( - instanceId, - databaseId, - Arrays.asList( - "CREATE PROTO BUNDLE (" - + "spanner.examples.music.SingerInfo," - + "spanner.examples.music.Genre," - + ")", - "CREATE TABLE Singers (" - + " SingerId INT64 NOT NULL," - + " FirstName STRING(1024)," - + " LastName STRING(1024)," - + " SingerInfo spanner.examples.music.SingerInfo," - + " SingerGenre spanner.examples.music.Genre," - + " ) PRIMARY KEY (SingerGenre)"), - null, protoDescriptorByteArray); - updateOperation.get(); - System.out.println("Updated Database"); - } catch (Exception e) { - // If the operation failed during execution, expose the cause. - throw SpannerExceptionFactory.asSpannerException(e.getCause()); - } - }*/ - - private void getDatabaseDdl(String instanceId, String databaseId) { - try { - final GetDatabaseDdlResponse response = - dbAdminClient.getDatabaseDdlResponse(instanceId, databaseId); - System.out.println("Retrieved GetDatabaseDdlResponse for " + databaseId); - for (String ddl : response.getStatementsList()) { - System.out.println(ddl); - } - System.out.println(response.getProtoDescriptors()); - } catch (Exception e) { - } - } -} From 88fa5334d09f5f3c7be89fbc1760b4ca66f991c8 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Mon, 13 Feb 2023 11:55:36 +0530 Subject: [PATCH 12/25] feat: code refactoring --- .../src/main/java/com/google/cloud/spanner/DatabaseInfo.java | 1 - .../src/test/java/com/google/cloud/spanner/DatabaseTest.java | 2 -- 2 files changed, 3 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java index 55da2524abc..e1e65354f3d 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java @@ -171,7 +171,6 @@ public Builder setProtoDescriptors(@Nonnull InputStream inputStream) throws IOEx } @Override - // TODO(harsha): This overload method needs to be completed public Builder setProtoDescriptors(String filePath) throws IOException { Preconditions.checkState(filePath.length() != 0, "Input File Path cannot be empty."); InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filePath); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java index 23acff7b5e6..b2cf4759f1e 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java @@ -209,12 +209,10 @@ public void testBuildWithProtoDescriptors() throws IOException { assertEquals(protoDescriptors, database.getProtoDescriptors()); } - // TODO(harsha): need to recheck, not passing @Test public void testBuildWithProtoDescriptorsFromInputStream() throws IOException { InputStream in = getClass().getClassLoader().getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); - // byte[] test = ByteStreams.toByteArray(in); final Database database = dbClient .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) From d33f8166fad1ff3cfe0e587d28acd62ca8f5a74a Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Tue, 14 Feb 2023 19:27:53 +0530 Subject: [PATCH 13/25] feat: code refactoring --- .../java/com/google/cloud/spanner/Type.java | 1 - .../cloud/spanner/spi/v1/SpannerRpc.java | 4 ---- .../google/cloud/spanner/DatabaseTest.java | 10 ++++---- .../cloud/spanner/it/ITProtoColumnTest.java | 24 ++++++++++++------- 4 files changed, 20 insertions(+), 19 deletions(-) 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 c483a0a6ee9..9ccdf82d4c8 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 @@ -46,7 +46,6 @@ */ @Immutable 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_FLOAT64 = new Type(Code.FLOAT64, null, null); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java index e2db1d902bd..e566057929d 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/SpannerRpc.java @@ -69,7 +69,6 @@ */ @InternalApi public interface SpannerRpc extends ServiceRpc { - /** Options passed in {@link SpannerRpc} methods to control how an RPC is issued. */ enum Option { CHANNEL_HINT("Channel Hint"); @@ -105,7 +104,6 @@ public String toString() { * @param the type of result */ final class Paginated { - private final Iterable results; private final String nextPageToken; @@ -142,7 +140,6 @@ public String getNextPageToken() { /** Consumer for the results produced by a streaming read or query call. */ interface ResultStreamConsumer { - void onPartialResultSet(PartialResultSet results); void onCompleted(); @@ -152,7 +149,6 @@ interface ResultStreamConsumer { /** Handle for cancellation of a streaming read or query call. */ interface StreamingCall { - /** * Requests more messages from the stream. We disable the auto flow control mechanism in grpc, * so we need to request messages ourself. This gives us more control over how much buffer we diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java index b2cf4759f1e..3e2ca094882 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java @@ -74,6 +74,8 @@ public class DatabaseTest { private static ByteString protoDescriptors; private static InputStream protoDescriptorsInputStream; private static byte[] protoDescriptorsByteArray; + private static final String PROTO_DESCRIPTORS_RESOURCE_PATH = + "com/google/cloud/spanner/descriptors.pb"; @Mock DatabaseAdminClient dbClient; @@ -89,9 +91,7 @@ public void setUp() { new Database.Builder(dbClient, (DatabaseId) invocation.getArguments()[0])); try { protoDescriptorsInputStream = - getClass() - .getClassLoader() - .getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); + getClass().getClassLoader().getResourceAsStream(PROTO_DESCRIPTORS_RESOURCE_PATH); protoDescriptorsByteArray = ByteStreams.toByteArray(protoDescriptorsInputStream); protoDescriptors = ByteString.copyFrom(protoDescriptorsByteArray); } catch (FileNotFoundException e) { @@ -203,7 +203,7 @@ public void testBuildWithProtoDescriptors() throws IOException { final Database database = dbClient .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) - .setProtoDescriptors("com/google/cloud/spanner/descriptors.pb") + .setProtoDescriptors(PROTO_DESCRIPTORS_RESOURCE_PATH) .build(); assertEquals(protoDescriptors, database.getProtoDescriptors()); @@ -212,7 +212,7 @@ public void testBuildWithProtoDescriptors() throws IOException { @Test public void testBuildWithProtoDescriptorsFromInputStream() throws IOException { InputStream in = - getClass().getClassLoader().getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); + getClass().getClassLoader().getResourceAsStream(PROTO_DESCRIPTORS_RESOURCE_PATH); final Database database = dbClient .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java index f119ebef0d3..2edf35ae30c 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java @@ -21,9 +21,20 @@ import static org.junit.Assume.assumeFalse; import com.google.cloud.ByteArray; -import com.google.cloud.spanner.*; +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.IntegrationTestEnv; +import com.google.cloud.spanner.Key; +import com.google.cloud.spanner.KeySet; +import com.google.cloud.spanner.Mutation; +import com.google.cloud.spanner.ParallelIntegrationTest; +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.SpannerException; +import com.google.cloud.spanner.Statement; import com.google.cloud.spanner.testing.EmulatorSpannerHelper; import com.google.cloud.spanner.testing.RemoteSpannerHelper; import com.google.common.collect.ImmutableList; @@ -59,11 +70,6 @@ public class ITProtoColumnTest { @BeforeClass public static void setUpDatabase() throws Exception { - // Get default spanner options for an integration test. - // SpannerOptions.Builder builder = env.getTestHelper().getOptions().toBuilder(); - // Create a new testHelper with the cloud-devel host. - // testHelper = RemoteSpannerHelper.create(builder.build(), - // env.getTestHelper().getInstanceId()); RemoteSpannerHelper testHelper = env.getTestHelper(); databaseID = DatabaseId.of(testHelper.getInstanceId(), testHelper.getUniqueDatabaseId()); dbAdminClient = testHelper.getClient().getDatabaseAdminClient(); @@ -141,9 +147,9 @@ public void after() throws Exception { } /** - * Test to check data update and read queries on Proto columns and Enums and their arrays. Test - * also checks for compatability between following types: 1. Proto Messages & Bytes 2. Proto Enums - * & Int64 + * Test to check data update and read queries on Proto Messages, Proto Enums and their arrays. + * Test also checks for compatability between following types: 1. Proto Messages & Bytes 2. Proto + * Enums & Int64 */ @Test public void testProtoColumnsUpdateAndRead() { From fb0293ad472c46bfd324328b4273b5d4b6eb5553 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Tue, 14 Feb 2023 20:43:07 +0530 Subject: [PATCH 14/25] feat: add java docs to new methods --- .../com/google/cloud/spanner/Database.java | 9 ++++ .../cloud/spanner/DatabaseAdminClient.java | 44 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java index 2aab03c4033..2a505f86cbd 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java @@ -88,6 +88,15 @@ public OperationFuture updateDdl( return dbClient.updateDatabaseDdl(instance(), database(), statements, operationId); } + /** + * Updates a database in a Cloud Spanner instance + * + * @param database Database object to set configuration options such as proto_descriptors. + * @param statements DDL statements to run while updating the database. + * @param operationId Operation id assigned to this operation. If null, system will autogenerate + * one. This must be unique within a database abd must be a valid identifier + * [a-zA-Z][a-zA-Z0-9_]*. + */ public OperationFuture updateDdl( Database database, Iterable statements, String operationId) throws SpannerException { return dbClient.updateDatabaseDdl(database, statements, operationId); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java index 5dab8b4c744..4ec3edd45b6 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java @@ -409,6 +409,35 @@ OperationFuture updateDatabaseDdl( @Nullable String operationId) throws SpannerException; + /** + * Updates a database in a Cloud Spanner instance. Few configuration options in the {@link + * Database} instance will be included in the {@link UpdateDatabaseDdlRequest}. + * + *

If an operation already exists with the given operation id, the operation will be resumed + * and the returned future will complete when the original operation finishes. See more + * information in {@link + * com.google.cloud.spanner.spi.v1.GapicSpannerRpc#updateDatabaseDdl(com.google.cloud.spanner.Database, + * Iterable, String)} + * + *

Example to update the database DDL with proto descriptors. + * + *

{@code
+   * Database dbInfo =
+   *         dbClient
+   *            .newDatabaseBuilder(DatabaseId.of("my_project_id", "my_instance_id", "my_database_id"))
+   *            .setProtoDescriptors("com/google/cloud/spanner/descriptors.pb")
+   *            .build();
+   * dbAdminClient.updateDatabaseDdl(dbInfo,
+   *     Arrays.asList("ALTER TABLE Albums ADD COLUMN MarketingBudget INT64"),
+   *     null).waitFor();
+   * }
+ * + * @param database Database object to set configuration options such as proto_descriptors. + * @param statements DDL statements to run while updating the database. + * @param operationId Operation id assigned to this operation. If null, system will autogenerate + * one. This must be unique within a database abd must be a valid identifier + * [a-zA-Z][a-zA-Z0-9_]*. + */ OperationFuture updateDatabaseDdl( Database database, Iterable statements, @Nullable String operationId) throws SpannerException; @@ -440,6 +469,21 @@ OperationFuture updateDatabaseDdl( */ List getDatabaseDdl(String instanceId, String databaseId); + /** + * Returns the GetDatabaseDdlResponse object of a Cloud Spanner database. + * + *

Example to get GetDatabaseDdlResponse object of a Cloud Spanner database. + * + *

{@code
+   * String instanceId = my_instance_id;
+   * String databaseId = my_database_id;
+   * GetDatabaseDdlResponse response = dbAdminClient.getDatabaseDdl(instanceId, databaseId);
+   * }
+ * + * @param instanceId the id of the instance where the database was created. + * @param databaseId the id of the database. + * @return GetDatabaseDdlResponse object + */ GetDatabaseDdlResponse getDatabaseDdlResponse(String instanceId, String databaseId); /** From c45143cab184ccebb86c754a4f2bdaabdd1cdb22 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Tue, 14 Feb 2023 22:21:18 +0530 Subject: [PATCH 15/25] feat: lint formatting --- .../com/google/cloud/spanner/DatabaseAdminClientImpl.java | 1 - .../spanner/admin/database/v1/DatabaseAdminSettings.java | 5 +---- .../admin/database/v1/stub/DatabaseAdminStubSettings.java | 5 +---- .../spanner/admin/instance/v1/InstanceAdminSettings.java | 5 +---- .../admin/instance/v1/stub/InstanceAdminStubSettings.java | 5 +---- 5 files changed, 4 insertions(+), 17 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java index da0ca529fa7..f8adc278e38 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java @@ -42,7 +42,6 @@ class DatabaseAdminClientImpl implements DatabaseAdminClient { private static final class PolicyMarshaller extends DefaultMarshaller { - @Override protected Policy fromPb(com.google.iam.v1.Policy policyPb) { return super.fromPb(policyPb); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java index 7f86f2a522a..9a353025074 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminSettings.java @@ -103,10 +103,7 @@ * databaseAdminSettingsBuilder * .getDatabaseSettings() * .setRetrySettings( - * databaseAdminSettingsBuilder - * .getDatabaseSettings() - * .getRetrySettings() - * .toBuilder() + * databaseAdminSettingsBuilder.getDatabaseSettings().getRetrySettings().toBuilder() * .setTotalTimeout(Duration.ofSeconds(30)) * .build()); * DatabaseAdminSettings databaseAdminSettings = databaseAdminSettingsBuilder.build(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStubSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStubSettings.java index f7836e028eb..9c209ed0fef 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStubSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/stub/DatabaseAdminStubSettings.java @@ -125,10 +125,7 @@ * databaseAdminSettingsBuilder * .getDatabaseSettings() * .setRetrySettings( - * databaseAdminSettingsBuilder - * .getDatabaseSettings() - * .getRetrySettings() - * .toBuilder() + * databaseAdminSettingsBuilder.getDatabaseSettings().getRetrySettings().toBuilder() * .setTotalTimeout(Duration.ofSeconds(30)) * .build()); * DatabaseAdminStubSettings databaseAdminSettings = databaseAdminSettingsBuilder.build(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminSettings.java index 4409fa180e2..bed7960d4f0 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/InstanceAdminSettings.java @@ -92,10 +92,7 @@ * instanceAdminSettingsBuilder * .getInstanceConfigSettings() * .setRetrySettings( - * instanceAdminSettingsBuilder - * .getInstanceConfigSettings() - * .getRetrySettings() - * .toBuilder() + * instanceAdminSettingsBuilder.getInstanceConfigSettings().getRetrySettings().toBuilder() * .setTotalTimeout(Duration.ofSeconds(30)) * .build()); * InstanceAdminSettings instanceAdminSettings = instanceAdminSettingsBuilder.build(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStubSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStubSettings.java index 547107b4c98..9a22ef3eddd 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStubSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/instance/v1/stub/InstanceAdminStubSettings.java @@ -113,10 +113,7 @@ * instanceAdminSettingsBuilder * .getInstanceConfigSettings() * .setRetrySettings( - * instanceAdminSettingsBuilder - * .getInstanceConfigSettings() - * .getRetrySettings() - * .toBuilder() + * instanceAdminSettingsBuilder.getInstanceConfigSettings().getRetrySettings().toBuilder() * .setTotalTimeout(Duration.ofSeconds(30)) * .build()); * InstanceAdminStubSettings instanceAdminSettings = instanceAdminSettingsBuilder.build(); From 7c6472d0e1f8964c8dd90ef6b4524b886b78c4b3 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Tue, 14 Feb 2023 22:23:04 +0530 Subject: [PATCH 16/25] feat: lint formatting changes --- .../src/main/java/com/google/cloud/spanner/Type.java | 1 - 1 file changed, 1 deletion(-) 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 9ccdf82d4c8..e81f0c874ea 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 @@ -301,7 +301,6 @@ public String toString() { /** Describes an individual field in a {@code STRUCT type}. */ public static final class StructField implements Serializable { - private static final long serialVersionUID = 8640511292704408210L; private final String name; From 50b86666f2a0d95b7d63d3c09768b985b2d9baa7 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Tue, 14 Feb 2023 22:27:05 +0530 Subject: [PATCH 17/25] feat: lint formatting --- .../java/com/google/cloud/spanner/v1/SpannerSettings.java | 5 +---- .../google/cloud/spanner/v1/stub/SpannerStubSettings.java | 5 +---- .../google/cloud/spanner/DatabaseAdminClientImplTest.java | 1 - .../java/com/google/cloud/spanner/it/ITProtoColumnTest.java | 2 -- 4 files changed, 2 insertions(+), 11 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/SpannerSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/SpannerSettings.java index 6cec68b9a21..dd3d71d6396 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/SpannerSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/SpannerSettings.java @@ -86,10 +86,7 @@ * spannerSettingsBuilder * .createSessionSettings() * .setRetrySettings( - * spannerSettingsBuilder - * .createSessionSettings() - * .getRetrySettings() - * .toBuilder() + * spannerSettingsBuilder.createSessionSettings().getRetrySettings().toBuilder() * .setTotalTimeout(Duration.ofSeconds(30)) * .build()); * SpannerSettings spannerSettings = spannerSettingsBuilder.build(); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/stub/SpannerStubSettings.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/stub/SpannerStubSettings.java index ff5a6b9bb28..f244ce87f87 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/stub/SpannerStubSettings.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/v1/stub/SpannerStubSettings.java @@ -103,10 +103,7 @@ * spannerSettingsBuilder * .createSessionSettings() * .setRetrySettings( - * spannerSettingsBuilder - * .createSessionSettings() - * .getRetrySettings() - * .toBuilder() + * spannerSettingsBuilder.createSessionSettings().getRetrySettings().toBuilder() * .setTotalTimeout(Duration.ofSeconds(30)) * .build()); * SpannerStubSettings spannerSettings = spannerSettingsBuilder.build(); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java index 900e6948245..8a9144b0be6 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseAdminClientImplTest.java @@ -68,7 +68,6 @@ @RunWith(JUnit4.class) public class DatabaseAdminClientImplTest { - private static final String PROJECT_ID = "my-project"; private static final String INSTANCE_ID = "my-instance"; private static final String INSTANCE_NAME = "projects/my-project/instances/my-instance"; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java index 2edf35ae30c..57a76dc6483 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java @@ -63,8 +63,6 @@ public class ITProtoColumnTest { @ClassRule public static IntegrationTestEnv env = new IntegrationTestEnv(); private static DatabaseId databaseID; - // For reference of databaseClient and dbAdminClient usage check ITPgJsonbTest.java or - // ITWithGrpcGcpTest.java private static DatabaseAdminClient dbAdminClient; private static DatabaseClient databaseClient; From 72af9f31c63123ae8fd8a3d47f9b23fb7bc39caa Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Tue, 14 Feb 2023 22:31:17 +0530 Subject: [PATCH 18/25] feat: lint formatting --- .../java/com/google/cloud/spanner/DatabaseAdminClientImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java index f8adc278e38..125aa74cad1 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClientImpl.java @@ -40,7 +40,6 @@ /** Default implementation of {@link DatabaseAdminClient}. */ class DatabaseAdminClientImpl implements DatabaseAdminClient { - private static final class PolicyMarshaller extends DefaultMarshaller { @Override protected Policy fromPb(com.google.iam.v1.Policy policyPb) { From e355e4a295bdc9715c39ba6dd07573e922bb481b Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Wed, 15 Feb 2023 10:49:02 +0530 Subject: [PATCH 19/25] feat: test exception cases --- .../google/cloud/spanner/DatabaseTest.java | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java index 3e2ca094882..1cfcca7a8cd 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java @@ -223,7 +223,7 @@ public void testBuildWithProtoDescriptorsFromInputStream() throws IOException { } @Test - public void testBuildWithProtoDescriptorsFromByteArray() throws IOException { + public void testBuildWithProtoDescriptorsFromByteArray() { final Database database = dbClient .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) @@ -233,6 +233,37 @@ public void testBuildWithProtoDescriptorsFromByteArray() throws IOException { assertEquals(protoDescriptors, database.getProtoDescriptors()); } + @Test + public void testBuildWithProtoDescriptorsThrowsException() throws IOException { + InputStream in = + getClass().getClassLoader().getResourceAsStream(PROTO_DESCRIPTORS_RESOURCE_PATH); + in.close(); + // case1: Test empty file path + assertThrows( + IllegalStateException.class, + () -> + dbClient + .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) + .setProtoDescriptors("") + .build()); + // case2: Test invalid file path + assertThrows( + NullPointerException.class, + () -> + dbClient + .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) + .setProtoDescriptors("empty.pb") + .build()); + // case3: Test one of the IOException case, where InputStream is closed before read + assertThrows( + IOException.class, + () -> + dbClient + .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) + .setProtoDescriptors(in) + .build()); + } + @Test public void getIAMPolicy() { Database database = From eb938bc844ed8c052dec3005f1a552b15f5ceea5 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Mon, 27 Feb 2023 10:37:21 +0530 Subject: [PATCH 20/25] feat: code refactoring --- .../java/com/google/cloud/spanner/DatabaseInfo.java | 12 ++++++------ .../google/cloud/spanner/spi/v1/GapicSpannerRpc.java | 1 + .../java/com/google/cloud/spanner/DatabaseTest.java | 8 ++++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java index e1e65354f3d..018fc323d09 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java @@ -68,7 +68,7 @@ public Builder setDialect(Dialect dialect) { public abstract Builder setProtoDescriptors(@Nonnull InputStream inputStream) throws IOException; - public abstract Builder setProtoDescriptors(String filePath) throws IOException; + public abstract Builder setProtoDescriptors(@Nonnull String filePath) throws IOException; abstract Builder setProto(com.google.spanner.admin.database.v1.Database proto); @@ -165,16 +165,16 @@ public Builder setProtoDescriptors(@Nonnull byte[] protoDescriptors) { @Override public Builder setProtoDescriptors(@Nonnull InputStream inputStream) throws IOException { Preconditions.checkNotNull(inputStream); - byte[] byteArray = ByteStreams.toByteArray(inputStream); - this.protoDescriptors = ByteString.copyFrom(byteArray); + this.protoDescriptors = ByteString.readFrom(inputStream); return this; } @Override - public Builder setProtoDescriptors(String filePath) throws IOException { - Preconditions.checkState(filePath.length() != 0, "Input File Path cannot be empty."); + public Builder setProtoDescriptors(@Nonnull String filePath) throws IOException { + Preconditions.checkNotNull(filePath); + Preconditions.checkState(filePath.length() != 0, "Input Proto Descriptors File Path cannot be empty."); InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filePath); - Preconditions.checkNotNull(inputStream, "Input File path is invalid."); + Preconditions.checkNotNull(inputStream, "Input Proto Descriptors File path is invalid."); return setProtoDescriptors(inputStream); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java index 483314d4d34..9ccad743034 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GapicSpannerRpc.java @@ -1254,6 +1254,7 @@ public OperationFuture updateDatabaseDdl( @Nullable final String updateId) throws SpannerException { acquireAdministrativeRequestsRateLimiter(); + Preconditions.checkNotNull(databaseInfo.getId()); UpdateDatabaseDdlRequest.Builder requestBuilder = UpdateDatabaseDdlRequest.newBuilder() .setDatabase(databaseInfo.getId().getName()) diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java index 1cfcca7a8cd..220826d4f4d 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; @@ -72,7 +73,6 @@ public class DatabaseTest { private static final String DEFAULT_LEADER = "default-leader"; private static final DatabaseDialect DEFAULT_DIALECT = DatabaseDialect.GOOGLE_STANDARD_SQL; private static ByteString protoDescriptors; - private static InputStream protoDescriptorsInputStream; private static byte[] protoDescriptorsByteArray; private static final String PROTO_DESCRIPTORS_RESOURCE_PATH = "com/google/cloud/spanner/descriptors.pb"; @@ -90,12 +90,11 @@ public void setUp() { invocation -> new Database.Builder(dbClient, (DatabaseId) invocation.getArguments()[0])); try { - protoDescriptorsInputStream = + InputStream protoDescriptorsInputStream = getClass().getClassLoader().getResourceAsStream(PROTO_DESCRIPTORS_RESOURCE_PATH); + assertNotNull(protoDescriptorsInputStream); protoDescriptorsByteArray = ByteStreams.toByteArray(protoDescriptorsInputStream); protoDescriptors = ByteString.copyFrom(protoDescriptorsByteArray); - } catch (FileNotFoundException e) { - e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } @@ -213,6 +212,7 @@ public void testBuildWithProtoDescriptors() throws IOException { public void testBuildWithProtoDescriptorsFromInputStream() throws IOException { InputStream in = getClass().getClassLoader().getResourceAsStream(PROTO_DESCRIPTORS_RESOURCE_PATH); + assertNotNull(in); final Database database = dbClient .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) From f762e39b2a91f0b6229bfeefa056a7acac0cacb3 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Mon, 27 Feb 2023 12:19:08 +0530 Subject: [PATCH 21/25] feat: add java docs and refactoring --- .../google/cloud/spanner/DatabaseInfo.java | 32 +++++++++++++++++-- .../google/cloud/spanner/DatabaseTest.java | 3 +- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java index 018fc323d09..997a9f74bf8 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java @@ -19,7 +19,6 @@ import com.google.cloud.Timestamp; import com.google.cloud.spanner.encryption.CustomerManagedEncryption; import com.google.common.base.Preconditions; -import com.google.common.io.ByteStreams; import com.google.protobuf.ByteString; import java.io.IOException; import java.io.InputStream; @@ -63,11 +62,39 @@ public Builder setDialect(Dialect dialect) { throw new UnsupportedOperationException("Unimplemented"); } + /** + * Optional for creating a new database. + * + *

The proto descriptors input as byte[] to be used for the database. + * + *

It is used by CREATE/ALTER PROTO BUNDLE statements which are part of DDL statements. + * Contains a protobuf-serialized [google.protobuf.FileDescriptorSet]. To generate a proto + * descriptors file run `protoc` with --include_imports and --descriptor_set_out. + */ public abstract Builder setProtoDescriptors(@Nonnull byte[] protoDescriptors); + /** + * Optional for creating a new database. + * + *

The proto descriptors input as InputStream to be used for the database. + * + *

It is used by CREATE/ALTER PROTO BUNDLE statements which are part of DDL statements. + * Contains a protobuf-serialized [google.protobuf.FileDescriptorSet]. To generate a proto + * descriptors file run `protoc` with --include_imports and --descriptor_set_out. + */ public abstract Builder setProtoDescriptors(@Nonnull InputStream inputStream) throws IOException; + /** + * Optional for creating a new database. + * + *

The proto descriptors file path input as String to be used for the database. The proto + * descriptors file must be present with in the project resources directory. + * + *

It is used by CREATE/ALTER PROTO BUNDLE statements which are part of DDL statements. + * Contains a protobuf-serialized [google.protobuf.FileDescriptorSet]. To generate a proto + * descriptors file run `protoc` with --include_imports and --descriptor_set_out. + */ public abstract Builder setProtoDescriptors(@Nonnull String filePath) throws IOException; abstract Builder setProto(com.google.spanner.admin.database.v1.Database proto); @@ -172,7 +199,8 @@ public Builder setProtoDescriptors(@Nonnull InputStream inputStream) throws IOEx @Override public Builder setProtoDescriptors(@Nonnull String filePath) throws IOException { Preconditions.checkNotNull(filePath); - Preconditions.checkState(filePath.length() != 0, "Input Proto Descriptors File Path cannot be empty."); + Preconditions.checkState( + filePath.length() != 0, "Input Proto Descriptors File Path cannot be empty."); InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filePath); Preconditions.checkNotNull(inputStream, "Input Proto Descriptors File path is invalid."); return setProtoDescriptors(inputStream); diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java index 220826d4f4d..f623e8493f5 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java @@ -19,8 +19,8 @@ import static com.google.cloud.spanner.DatabaseInfo.State.CREATING; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; @@ -37,7 +37,6 @@ import com.google.rpc.Status; import com.google.spanner.admin.database.v1.DatabaseDialect; import com.google.spanner.admin.database.v1.EncryptionInfo; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Collections; From 30be84a126b37093878260772ead535b18979fbd Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Tue, 28 Feb 2023 18:11:10 +0530 Subject: [PATCH 22/25] feat: add java docs --- .../google/cloud/spanner/DatabaseInfo.java | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java index 997a9f74bf8..7cbf7214947 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java @@ -65,22 +65,27 @@ public Builder setDialect(Dialect dialect) { /** * Optional for creating a new database. * - *

The proto descriptors input as byte[] to be used for the database. - * *

It is used by CREATE/ALTER PROTO BUNDLE statements which are part of DDL statements. * Contains a protobuf-serialized [google.protobuf.FileDescriptorSet]. To generate a proto - * descriptors file run `protoc` with --include_imports and --descriptor_set_out. + * descriptors file run {@code protoc --include_imports + * --descriptor_set_out=DESCRIPTOR_OUTPUT_LOCATION LOCATION-OF-PROTO-FILES} + * + * @param protoDescriptors The proto descriptors input as byte[] to be used for the database. + * @return {@link Builder} */ public abstract Builder setProtoDescriptors(@Nonnull byte[] protoDescriptors); /** * Optional for creating a new database. * - *

The proto descriptors input as InputStream to be used for the database. - * *

It is used by CREATE/ALTER PROTO BUNDLE statements which are part of DDL statements. * Contains a protobuf-serialized [google.protobuf.FileDescriptorSet]. To generate a proto - * descriptors file run `protoc` with --include_imports and --descriptor_set_out. + * descriptors file run {@code protoc --include_imports + * --descriptor_set_out=DESCRIPTOR_OUTPUT_LOCATION LOCATION-OF-PROTO-FILES} + * + * @param inputStream The proto descriptors input as InputStream to be used for the database. + * @return {@link Builder} + * @throws IOException if there is a problem reading the underlying stream. */ public abstract Builder setProtoDescriptors(@Nonnull InputStream inputStream) throws IOException; @@ -88,12 +93,16 @@ public abstract Builder setProtoDescriptors(@Nonnull InputStream inputStream) /** * Optional for creating a new database. * - *

The proto descriptors file path input as String to be used for the database. The proto - * descriptors file must be present with in the project resources directory. - * *

It is used by CREATE/ALTER PROTO BUNDLE statements which are part of DDL statements. * Contains a protobuf-serialized [google.protobuf.FileDescriptorSet]. To generate a proto - * descriptors file run `protoc` with --include_imports and --descriptor_set_out. + * descriptors file run {@code protoc --include_imports + * --descriptor_set_out=DESCRIPTOR_OUTPUT_LOCATION LOCATION-OF-PROTO-FILES} + * + * @param filePath The proto descriptors file path input as String to be used for the database. + * The proto descriptors file must be present with in the project resources directory. + * @return {@link Builder} + * @throws IOException If the filePath is invalid or outside of project resources directory, or + * if file does not exist */ public abstract Builder setProtoDescriptors(@Nonnull String filePath) throws IOException; From 70acee6661b157b47df6ab0e63864ea0b280ab8f Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Wed, 15 Mar 2023 12:11:47 +0530 Subject: [PATCH 23/25] feat: java docs refactor --- .../src/main/java/com/google/cloud/spanner/Database.java | 2 +- .../java/com/google/cloud/spanner/DatabaseAdminClient.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java index 2a505f86cbd..2fa7e60ebf9 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java @@ -89,7 +89,7 @@ public OperationFuture updateDdl( } /** - * Updates a database in a Cloud Spanner instance + * Updates the schema of a database in a Cloud Spanner instance * * @param database Database object to set configuration options such as proto_descriptors. * @param statements DDL statements to run while updating the database. diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java index 4ec3edd45b6..e4c27ff4ef0 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseAdminClient.java @@ -410,8 +410,8 @@ OperationFuture updateDatabaseDdl( throws SpannerException; /** - * Updates a database in a Cloud Spanner instance. Few configuration options in the {@link - * Database} instance will be included in the {@link UpdateDatabaseDdlRequest}. + * Updates a database in a Cloud Spanner instance. Any proto descriptors that have been set for + * the {@link Database} instance will be included in the {@link UpdateDatabaseDdlRequest}. * *

If an operation already exists with the given operation id, the operation will be resumed * and the returned future will complete when the original operation finishes. See more From 51a4031d1be7d432fdde6766de8c20990bd11c94 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Wed, 15 Mar 2023 18:41:11 +0530 Subject: [PATCH 24/25] feat: remove overload method setProtoDescriptors that accepts file path as input to avoid unexpected issues --- .../google/cloud/spanner/DatabaseInfo.java | 26 ----------------- .../google/cloud/spanner/DatabaseTest.java | 29 +------------------ .../cloud/spanner/it/ITProtoColumnTest.java | 11 ++++--- 3 files changed, 8 insertions(+), 58 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java index 7cbf7214947..b992b23b0dc 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseInfo.java @@ -90,22 +90,6 @@ public Builder setDialect(Dialect dialect) { public abstract Builder setProtoDescriptors(@Nonnull InputStream inputStream) throws IOException; - /** - * Optional for creating a new database. - * - *

It is used by CREATE/ALTER PROTO BUNDLE statements which are part of DDL statements. - * Contains a protobuf-serialized [google.protobuf.FileDescriptorSet]. To generate a proto - * descriptors file run {@code protoc --include_imports - * --descriptor_set_out=DESCRIPTOR_OUTPUT_LOCATION LOCATION-OF-PROTO-FILES} - * - * @param filePath The proto descriptors file path input as String to be used for the database. - * The proto descriptors file must be present with in the project resources directory. - * @return {@link Builder} - * @throws IOException If the filePath is invalid or outside of project resources directory, or - * if file does not exist - */ - public abstract Builder setProtoDescriptors(@Nonnull String filePath) throws IOException; - abstract Builder setProto(com.google.spanner.admin.database.v1.Database proto); /** Builds the database from this builder. */ @@ -205,16 +189,6 @@ public Builder setProtoDescriptors(@Nonnull InputStream inputStream) throws IOEx return this; } - @Override - public Builder setProtoDescriptors(@Nonnull String filePath) throws IOException { - Preconditions.checkNotNull(filePath); - Preconditions.checkState( - filePath.length() != 0, "Input Proto Descriptors File Path cannot be empty."); - InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filePath); - Preconditions.checkNotNull(inputStream, "Input Proto Descriptors File path is invalid."); - return setProtoDescriptors(inputStream); - } - @Override Builder setProto(@Nullable com.google.spanner.admin.database.v1.Database proto) { this.proto = proto; diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java index f623e8493f5..ad799485a1b 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseTest.java @@ -196,17 +196,6 @@ public void testBuildWithDatabaseDialect() { assertEquals(Dialect.GOOGLE_STANDARD_SQL, database.getDialect()); } - @Test - public void testBuildWithProtoDescriptors() throws IOException { - final Database database = - dbClient - .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) - .setProtoDescriptors(PROTO_DESCRIPTORS_RESOURCE_PATH) - .build(); - - assertEquals(protoDescriptors, database.getProtoDescriptors()); - } - @Test public void testBuildWithProtoDescriptorsFromInputStream() throws IOException { InputStream in = @@ -237,23 +226,7 @@ public void testBuildWithProtoDescriptorsThrowsException() throws IOException { InputStream in = getClass().getClassLoader().getResourceAsStream(PROTO_DESCRIPTORS_RESOURCE_PATH); in.close(); - // case1: Test empty file path - assertThrows( - IllegalStateException.class, - () -> - dbClient - .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) - .setProtoDescriptors("") - .build()); - // case2: Test invalid file path - assertThrows( - NullPointerException.class, - () -> - dbClient - .newDatabaseBuilder(DatabaseId.of("my-project", "my-instance", "my-database")) - .setProtoDescriptors("empty.pb") - .build()); - // case3: Test one of the IOException case, where InputStream is closed before read + // case1: Test one of the IOException case, where InputStream is closed before read assertThrows( IOException.class, () -> diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java index 57a76dc6483..cbe00c1db4d 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/it/ITProtoColumnTest.java @@ -42,6 +42,7 @@ import com.google.protobuf.InvalidProtocolBufferException.InvalidWireTypeException; import com.google.protobuf.ProtocolMessageEnum; import com.google.spanner.admin.database.v1.Backup; +import java.io.InputStream; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -76,11 +77,12 @@ public static void setUpDatabase() throws Exception { } public static void createDatabase() throws Exception { + InputStream in = + ITProtoColumnTest.class + .getClassLoader() + .getResourceAsStream("com/google/cloud/spanner/descriptors.pb"); final Database databaseToCreate = - dbAdminClient - .newDatabaseBuilder(databaseID) - .setProtoDescriptors("com/google/cloud/spanner/descriptors.pb") - .build(); + dbAdminClient.newDatabaseBuilder(databaseID).setProtoDescriptors(in).build(); final Database createdDatabase = dbAdminClient .createDatabase( @@ -120,6 +122,7 @@ public static void createDatabase() throws Exception { // dbAdminClient.getDatabaseDdlResponse(databaseID.getInstanceId().getInstance(), // databaseID.getDatabase()); // assertNotNull(response.getProtoDescriptors()); + in.close(); } @AfterClass From bfae4adf8690f0e908377efed84ff0ada2b0c0e1 Mon Sep 17 00:00:00 2001 From: Sri Harsha CH Date: Wed, 15 Mar 2023 21:11:56 +0530 Subject: [PATCH 25/25] feat: remove updateDdl method overload to update proto descriptor --- .../java/com/google/cloud/spanner/Database.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java index 2fa7e60ebf9..94c30c9c702 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Database.java @@ -88,20 +88,6 @@ public OperationFuture updateDdl( return dbClient.updateDatabaseDdl(instance(), database(), statements, operationId); } - /** - * Updates the schema of a database in a Cloud Spanner instance - * - * @param database Database object to set configuration options such as proto_descriptors. - * @param statements DDL statements to run while updating the database. - * @param operationId Operation id assigned to this operation. If null, system will autogenerate - * one. This must be unique within a database abd must be a valid identifier - * [a-zA-Z][a-zA-Z0-9_]*. - */ - public OperationFuture updateDdl( - Database database, Iterable statements, String operationId) throws SpannerException { - return dbClient.updateDatabaseDdl(database, statements, operationId); - } - /** Drops this database. */ public void drop() throws SpannerException { dbClient.dropDatabase(instance(), database());