diff --git a/CHANGELOG.md b/CHANGELOG.md index ee3da44d653..b43cabe3b12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [6.63.0](https://github.com/googleapis/java-spanner/compare/v6.62.1...v6.63.0) (2024-03-30) + + +### Features + +* Add support for transaction-level exclusion from change streams ([#2959](https://github.com/googleapis/java-spanner/issues/2959)) ([7ae376a](https://github.com/googleapis/java-spanner/commit/7ae376acea4dce7a0bb4565d6c9bfdbbb75146c6)) + + +### Dependencies + +* Update dependency com.google.cloud:google-cloud-monitoring to v3.40.0 ([#2987](https://github.com/googleapis/java-spanner/issues/2987)) ([0a1ffcb](https://github.com/googleapis/java-spanner/commit/0a1ffcb371bdee6e478e3aa53b0a4591055134e3)) +* Update dependency com.google.cloud:google-cloud-trace to v2.39.0 ([#2988](https://github.com/googleapis/java-spanner/issues/2988)) ([cf11641](https://github.com/googleapis/java-spanner/commit/cf116412d46c5047167d4dd60ef9c88c3d9c754b)) +* Update dependency commons-io:commons-io to v2.16.0 ([#2986](https://github.com/googleapis/java-spanner/issues/2986)) ([4697261](https://github.com/googleapis/java-spanner/commit/46972619f88018bad1b4e05526a618d38e2e0897)) + ## [6.62.1](https://github.com/googleapis/java-spanner/compare/v6.62.0...v6.62.1) (2024-03-28) diff --git a/README.md b/README.md index 56d91c89705..723b796a9e6 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file: com.google.cloud libraries-bom - 26.34.0 + 26.35.0 pom import @@ -50,7 +50,7 @@ If you are using Maven without the 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.34.0') +implementation platform('com.google.cloud:libraries-bom:26.35.0') implementation 'com.google.cloud:google-cloud-spanner' ``` diff --git a/google-cloud-spanner-bom/pom.xml b/google-cloud-spanner-bom/pom.xml index 939adc492ea..0e156cdde0d 100644 --- a/google-cloud-spanner-bom/pom.xml +++ b/google-cloud-spanner-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner-bom - 6.62.1 + 6.63.0 pom com.google.cloud @@ -53,43 +53,43 @@ com.google.cloud google-cloud-spanner - 6.62.1 + 6.63.0 com.google.cloud google-cloud-spanner test-jar - 6.62.1 + 6.63.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.62.1 + 6.63.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.62.1 + 6.63.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.62.1 + 6.63.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.62.1 + 6.63.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 6.62.1 + 6.63.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.62.1 + 6.63.0 diff --git a/google-cloud-spanner-executor/pom.xml b/google-cloud-spanner-executor/pom.xml index 2ddb93b5371..64b606e5a96 100644 --- a/google-cloud-spanner-executor/pom.xml +++ b/google-cloud-spanner-executor/pom.xml @@ -5,14 +5,14 @@ 4.0.0 com.google.cloud google-cloud-spanner-executor - 6.62.1 + 6.63.0 jar Google Cloud Spanner Executor com.google.cloud google-cloud-spanner-parent - 6.62.1 + 6.63.0 @@ -134,7 +134,7 @@ commons-io commons-io - 2.15.1 + 2.16.0 diff --git a/google-cloud-spanner/pom.xml b/google-cloud-spanner/pom.xml index c6959c55fd7..d471f46ae17 100644 --- a/google-cloud-spanner/pom.xml +++ b/google-cloud-spanner/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-spanner - 6.62.1 + 6.63.0 jar Google Cloud Spanner https://github.com/googleapis/java-spanner @@ -11,7 +11,7 @@ com.google.cloud google-cloud-spanner-parent - 6.62.1 + 6.63.0 google-cloud-spanner diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java index d5c95d0a5a5..3dbd0c1cda3 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Options.java @@ -61,6 +61,9 @@ public interface ReadOption {} public interface ReadQueryUpdateTransactionOption extends ReadOption, QueryOption, UpdateOption, TransactionOption {} + /** Marker interface to mark options applicable to Update and Write operations */ + public interface UpdateTransactionOption extends UpdateOption, TransactionOption {} + /** * Marker interface to mark options applicable to Create, Update and Delete operations in admin * API. @@ -108,6 +111,17 @@ public static TransactionOption commitStats() { public static TransactionOption optimisticLock() { return OPTIMISTIC_LOCK_OPTION; } + + /** + * Specifying this instructs the transaction to be excluded from being recorded in change streams + * with the DDL option `allow_txn_exclusion=true`. This does not exclude the transaction from + * being recorded in the change streams with the DDL option `allow_txn_exclusion` being false or + * unset. + */ + public static UpdateTransactionOption excludeTxnFromChangeStreams() { + return EXCLUDE_TXN_FROM_CHANGE_STREAMS_OPTION; + } + /** * Specifying this will cause the read to yield at most this many rows. This should be greater * than 0. @@ -281,6 +295,18 @@ void appendToOptions(Options options) { static final OptimisticLockOption OPTIMISTIC_LOCK_OPTION = new OptimisticLockOption(); + /** Option to request the transaction to be excluded from change streams. */ + static final class ExcludeTxnFromChangeStreamsOption extends InternalOption + implements UpdateTransactionOption { + @Override + void appendToOptions(Options options) { + options.withExcludeTxnFromChangeStreams = true; + } + } + + static final ExcludeTxnFromChangeStreamsOption EXCLUDE_TXN_FROM_CHANGE_STREAMS_OPTION = + new ExcludeTxnFromChangeStreamsOption(); + /** Option pertaining to flow control. */ static final class FlowControlOption extends InternalOption implements ReadAndQueryOption { final int prefetchChunks; @@ -405,6 +431,7 @@ void appendToOptions(Options options) { private String etag; private Boolean validateOnly; private Boolean withOptimisticLock; + private Boolean withExcludeTxnFromChangeStreams; private Boolean dataBoostEnabled; private DirectedReadOptions directedReadOptions; private DecodeMode decodeMode; @@ -508,6 +535,10 @@ Boolean withOptimisticLock() { return withOptimisticLock; } + Boolean withExcludeTxnFromChangeStreams() { + return withExcludeTxnFromChangeStreams; + } + boolean hasDataBoostEnabled() { return dataBoostEnabled != null; } @@ -571,6 +602,11 @@ public String toString() { if (withOptimisticLock != null) { b.append("withOptimisticLock: ").append(withOptimisticLock).append(' '); } + if (withExcludeTxnFromChangeStreams != null) { + b.append("withExcludeTxnFromChangeStreams: ") + .append(withExcludeTxnFromChangeStreams) + .append(' '); + } if (dataBoostEnabled != null) { b.append("dataBoostEnabled: ").append(dataBoostEnabled).append(' '); } @@ -616,6 +652,7 @@ public boolean equals(Object o) { && Objects.equals(etag(), that.etag()) && Objects.equals(validateOnly(), that.validateOnly()) && Objects.equals(withOptimisticLock(), that.withOptimisticLock()) + && Objects.equals(withExcludeTxnFromChangeStreams(), that.withExcludeTxnFromChangeStreams()) && Objects.equals(dataBoostEnabled(), that.dataBoostEnabled()) && Objects.equals(directedReadOptions(), that.directedReadOptions()); } @@ -662,6 +699,9 @@ public int hashCode() { if (withOptimisticLock != null) { result = 31 * result + withOptimisticLock.hashCode(); } + if (withExcludeTxnFromChangeStreams != null) { + result = 31 * result + withExcludeTxnFromChangeStreams.hashCode(); + } if (dataBoostEnabled != null) { result = 31 * result + dataBoostEnabled.hashCode(); } diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDmlTransaction.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDmlTransaction.java index cabc270566c..d498bb232a1 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDmlTransaction.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/PartitionedDmlTransaction.java @@ -167,7 +167,7 @@ private ExecuteSqlRequest resumeOrRestartRequest( @VisibleForTesting ExecuteSqlRequest newTransactionRequestFrom(final Statement statement, final Options options) { - ByteString transactionId = initTransaction(); + ByteString transactionId = initTransaction(options); final TransactionSelector transactionSelector = TransactionSelector.newBuilder().setId(transactionId).build(); @@ -195,13 +195,15 @@ ExecuteSqlRequest newTransactionRequestFrom(final Statement statement, final Opt return builder.build(); } - private ByteString initTransaction() { + private ByteString initTransaction(final Options options) { final BeginTransactionRequest request = BeginTransactionRequest.newBuilder() .setSession(session.getName()) .setOptions( TransactionOptions.newBuilder() - .setPartitionedDml(TransactionOptions.PartitionedDml.getDefaultInstance())) + .setPartitionedDml(TransactionOptions.PartitionedDml.getDefaultInstance()) + .setExcludeTxnFromChangeStreams( + options.withExcludeTxnFromChangeStreams() == Boolean.TRUE)) .build(); Transaction tx = rpc.beginTransaction(request, session.getOptions(), true); if (tx.getId().isEmpty()) { diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java index bea44abab3e..8c4a0068599 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SessionImpl.java @@ -69,11 +69,16 @@ static void throwIfTransactionsPending() { } static TransactionOptions createReadWriteTransactionOptions(Options options) { + TransactionOptions.Builder transactionOptions = TransactionOptions.newBuilder(); + if (options.withExcludeTxnFromChangeStreams() == Boolean.TRUE) { + transactionOptions.setExcludeTxnFromChangeStreams(true); + } TransactionOptions.ReadWrite.Builder readWrite = TransactionOptions.ReadWrite.newBuilder(); if (options.withOptimisticLock() == Boolean.TRUE) { readWrite.setReadLockMode(TransactionOptions.ReadWrite.ReadLockMode.OPTIMISTIC); } - return TransactionOptions.newBuilder().setReadWrite(readWrite).build(); + transactionOptions.setReadWrite(readWrite); + return transactionOptions.build(); } /** @@ -209,10 +214,16 @@ public CommitResponse writeAtLeastOnceWithOptions( CommitRequest.newBuilder() .setSession(name) .setReturnCommitStats(options.withCommitStats()) - .addAllMutations(mutationsProto) - .setSingleUseTransaction( - TransactionOptions.newBuilder() - .setReadWrite(TransactionOptions.ReadWrite.getDefaultInstance())); + .addAllMutations(mutationsProto); + + TransactionOptions.Builder transactionOptionsBuilder = + TransactionOptions.newBuilder() + .setReadWrite(TransactionOptions.ReadWrite.getDefaultInstance()); + if (options.withExcludeTxnFromChangeStreams() == Boolean.TRUE) { + transactionOptionsBuilder.setExcludeTxnFromChangeStreams(true); + } + requestBuilder.setSingleUseTransaction(transactionOptionsBuilder); + if (options.hasMaxCommitDelay()) { requestBuilder.setMaxCommitDelay( Duration.newBuilder() @@ -266,6 +277,10 @@ public ServerStream batchWriteAtLeastOnce( if (batchWriteRequestOptions != null) { requestBuilder.setRequestOptions(batchWriteRequestOptions); } + if (Options.fromTransactionOptions(transactionOptions).withExcludeTxnFromChangeStreams() + == Boolean.TRUE) { + requestBuilder.setExcludeTxnFromChangeStreams(true); + } ISpan span = tracer.spanBuilder(SpannerImpl.BATCH_WRITE); try (IScope s = tracer.withSpan(span)) { return spanner.getRpc().batchWriteAtLeastOnce(requestBuilder.build(), this.options); diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java index 3249be1bdb3..370d2f662f5 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/TransactionRunnerImpl.java @@ -76,6 +76,10 @@ class TransactionRunnerImpl implements SessionTransaction, TransactionRunner { private static final String TRANSACTION_ALREADY_COMMITTED_MESSAGE = "Transaction has already committed"; + private static final String DML_INVALID_EXCLUDE_CHANGE_STREAMS_OPTION_MESSAGE = + "Options.excludeTxnFromChangeStreams() cannot be specified for individual DML requests. " + + "This option should be set at the transaction level."; + @VisibleForTesting static class TransactionContextImpl extends AbstractReadContext implements TransactionContext { @@ -371,7 +375,9 @@ public void run() { if (transactionId == null && transactionIdFuture == null) { requestBuilder.setSingleUseTransaction( TransactionOptions.newBuilder() - .setReadWrite(TransactionOptions.ReadWrite.getDefaultInstance())); + .setReadWrite(TransactionOptions.ReadWrite.getDefaultInstance()) + .setExcludeTxnFromChangeStreams( + options.withExcludeTxnFromChangeStreams() == Boolean.TRUE)); } else { requestBuilder.setTransactionId( transactionId == null @@ -725,14 +731,16 @@ public long executeUpdate(Statement statement, UpdateOption... options) { } private ResultSet internalExecuteUpdate( - Statement statement, QueryMode queryMode, UpdateOption... options) { + Statement statement, QueryMode queryMode, UpdateOption... updateOptions) { beforeReadOrQuery(); + final Options options = Options.fromUpdateOptions(updateOptions); + if (options.withExcludeTxnFromChangeStreams() != null) { + throw newSpannerException( + ErrorCode.INVALID_ARGUMENT, DML_INVALID_EXCLUDE_CHANGE_STREAMS_OPTION_MESSAGE); + } final ExecuteSqlRequest.Builder builder = getExecuteSqlRequestBuilder( - statement, - queryMode, - Options.fromUpdateOptions(options), - /* withTransactionSelector = */ true); + statement, queryMode, options, /* withTransactionSelector = */ true); try { com.google.spanner.v1.ResultSet resultSet = rpc.executeQuery(builder.build(), session.getOptions(), isRouteToLeader()); @@ -753,14 +761,16 @@ private ResultSet internalExecuteUpdate( } @Override - public ApiFuture executeUpdateAsync(Statement statement, UpdateOption... options) { + public ApiFuture executeUpdateAsync(Statement statement, UpdateOption... updateOptions) { beforeReadOrQuery(); + final Options options = Options.fromUpdateOptions(updateOptions); + if (options.withExcludeTxnFromChangeStreams() != null) { + throw newSpannerException( + ErrorCode.INVALID_ARGUMENT, DML_INVALID_EXCLUDE_CHANGE_STREAMS_OPTION_MESSAGE); + } final ExecuteSqlRequest.Builder builder = getExecuteSqlRequestBuilder( - statement, - QueryMode.NORMAL, - Options.fromUpdateOptions(options), - /* withTransactionSelector = */ true); + statement, QueryMode.NORMAL, options, /* withTransactionSelector = */ true); final ApiFuture resultSet; try { // Register the update as an async operation that must finish before the transaction may @@ -832,10 +842,15 @@ private SpannerException createAbortedExceptionForBatchDml(ExecuteBatchDmlRespon } @Override - public long[] batchUpdate(Iterable statements, UpdateOption... options) { + public long[] batchUpdate(Iterable statements, UpdateOption... updateOptions) { beforeReadOrQuery(); + final Options options = Options.fromUpdateOptions(updateOptions); + if (options.withExcludeTxnFromChangeStreams() != null) { + throw newSpannerException( + ErrorCode.INVALID_ARGUMENT, DML_INVALID_EXCLUDE_CHANGE_STREAMS_OPTION_MESSAGE); + } final ExecuteBatchDmlRequest.Builder builder = - getExecuteBatchDmlRequestBuilder(statements, Options.fromUpdateOptions(options)); + getExecuteBatchDmlRequestBuilder(statements, options); try { com.google.spanner.v1.ExecuteBatchDmlResponse response = rpc.executeBatchDml(builder.build(), session.getOptions()); @@ -869,10 +884,15 @@ public long[] batchUpdate(Iterable statements, UpdateOption... option @Override public ApiFuture batchUpdateAsync( - Iterable statements, UpdateOption... options) { + Iterable statements, UpdateOption... updateOptions) { beforeReadOrQuery(); + final Options options = Options.fromUpdateOptions(updateOptions); + if (options.withExcludeTxnFromChangeStreams() != null) { + throw newSpannerException( + ErrorCode.INVALID_ARGUMENT, DML_INVALID_EXCLUDE_CHANGE_STREAMS_OPTION_MESSAGE); + } final ExecuteBatchDmlRequest.Builder builder = - getExecuteBatchDmlRequestBuilder(statements, Options.fromUpdateOptions(options)); + getExecuteBatchDmlRequestBuilder(statements, options); ApiFuture response; try { // Register the update as an async operation that must finish before the transaction may diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java index 7cba80edd8d..4ab6829a327 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/DatabaseClientImplTest.java @@ -75,6 +75,7 @@ import com.google.rpc.RetryInfo; import com.google.spanner.v1.BatchWriteRequest; import com.google.spanner.v1.BatchWriteResponse; +import com.google.spanner.v1.BeginTransactionRequest; import com.google.spanner.v1.CommitRequest; import com.google.spanner.v1.DeleteSessionRequest; import com.google.spanner.v1.DirectedReadOptions; @@ -1334,6 +1335,14 @@ public void testWrite() { Mutation.newInsertBuilder("FOO").set("ID").to(1L).set("NAME").to("Bar").build())); assertNotNull(timestamp); + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasReadWrite()); + assertFalse(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + List commitRequests = mockSpanner.getRequestsOfType(CommitRequest.class); assertThat(commitRequests).hasSize(1); CommitRequest commit = commitRequests.get(0); @@ -1388,6 +1397,14 @@ public void testWriteWithOptions() { Mutation.newInsertBuilder("FOO").set("ID").to(1L).set("NAME").to("Bar").build()), Options.priority(RpcPriority.HIGH)); + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasReadWrite()); + assertFalse(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + List commits = mockSpanner.getRequestsOfType(CommitRequest.class); assertThat(commits).hasSize(1); CommitRequest commit = commits.get(0); @@ -1409,6 +1426,24 @@ public void testWriteWithCommitStats() { assertNotNull(response.getCommitStats()); } + @Test + public void testWriteWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + client.writeWithOptions( + Collections.singletonList( + Mutation.newInsertBuilder("FOO").set("ID").to(1L).set("NAME").to("Bar").build()), + Options.excludeTxnFromChangeStreams()); + + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasReadWrite()); + assertTrue(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + } + @Test public void testWriteAtLeastOnce() { DatabaseClient client = @@ -1418,6 +1453,15 @@ public void testWriteAtLeastOnce() { Collections.singletonList( Mutation.newInsertBuilder("FOO").set("ID").to(1L).set("NAME").to("Bar").build())); assertNotNull(timestamp); + + List commitRequests = mockSpanner.getRequestsOfType(CommitRequest.class); + assertThat(commitRequests).hasSize(1); + CommitRequest commit = commitRequests.get(0); + assertNotNull(commit.getSingleUseTransaction()); + assertTrue(commit.getSingleUseTransaction().hasReadWrite()); + assertFalse(commit.getSingleUseTransaction().getExcludeTxnFromChangeStreams()); + assertNotNull(commit.getRequestOptions()); + assertEquals(Priority.PRIORITY_UNSPECIFIED, commit.getRequestOptions().getPriority()); } @Test @@ -1438,6 +1482,7 @@ public void testWriteAtLeastOnceWithCommitStats() { CommitRequest commit = commitRequests.get(0); assertNotNull(commit.getSingleUseTransaction()); assertTrue(commit.getSingleUseTransaction().hasReadWrite()); + assertFalse(commit.getSingleUseTransaction().getExcludeTxnFromChangeStreams()); assertNotNull(commit.getRequestOptions()); assertEquals(Priority.PRIORITY_UNSPECIFIED, commit.getRequestOptions().getPriority()); } @@ -1456,6 +1501,7 @@ public void testWriteAtLeastOnceWithOptions() { CommitRequest commit = commitRequests.get(0); assertNotNull(commit.getSingleUseTransaction()); assertTrue(commit.getSingleUseTransaction().hasReadWrite()); + assertFalse(commit.getSingleUseTransaction().getExcludeTxnFromChangeStreams()); assertNotNull(commit.getRequestOptions()); assertEquals(Priority.PRIORITY_LOW, commit.getRequestOptions().getPriority()); } @@ -1474,11 +1520,29 @@ public void testWriteAtLeastOnceWithTagOptions() { CommitRequest commit = commitRequests.get(0); assertNotNull(commit.getSingleUseTransaction()); assertTrue(commit.getSingleUseTransaction().hasReadWrite()); + assertFalse(commit.getSingleUseTransaction().getExcludeTxnFromChangeStreams()); assertNotNull(commit.getRequestOptions()); assertThat(commit.getRequestOptions().getTransactionTag()).isEqualTo("app=spanner,env=test"); assertThat(commit.getRequestOptions().getRequestTag()).isEmpty(); } + @Test + public void testWriteAtLeastOnceWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + client.writeAtLeastOnceWithOptions( + Collections.singletonList( + Mutation.newInsertBuilder("FOO").set("ID").to(1L).set("NAME").to("Bar").build()), + Options.excludeTxnFromChangeStreams()); + + List commitRequests = mockSpanner.getRequestsOfType(CommitRequest.class); + assertThat(commitRequests).hasSize(1); + CommitRequest commit = commitRequests.get(0); + assertNotNull(commit.getSingleUseTransaction()); + assertTrue(commit.getSingleUseTransaction().hasReadWrite()); + assertTrue(commit.getSingleUseTransaction().getExcludeTxnFromChangeStreams()); + } + @Test public void testBatchWriteAtLeastOnceWithoutOptions() { DatabaseClient client = @@ -1500,6 +1564,7 @@ public void testBatchWriteAtLeastOnceWithoutOptions() { BatchWriteRequest request = requests.get(0); assertEquals(request.getMutationGroupsCount(), 4); assertEquals(request.getRequestOptions().getPriority(), Priority.PRIORITY_UNSPECIFIED); + assertFalse(request.getExcludeTxnFromChangeStreams()); } @Test @@ -1514,6 +1579,7 @@ public void testBatchWriteAtLeastOnceWithOptions() { BatchWriteRequest request = requests.get(0); assertEquals(request.getMutationGroupsCount(), 4); assertEquals(request.getRequestOptions().getPriority(), Priority.PRIORITY_LOW); + assertFalse(request.getExcludeTxnFromChangeStreams()); } @Test @@ -1529,6 +1595,21 @@ public void testBatchWriteAtLeastOnceWithTagOptions() { assertEquals(request.getMutationGroupsCount(), 4); assertEquals(request.getRequestOptions().getTransactionTag(), "app=spanner,env=test"); assertThat(request.getRequestOptions().getRequestTag()).isEmpty(); + assertFalse(request.getExcludeTxnFromChangeStreams()); + } + + @Test + public void testBatchWriteAtLeastOnceWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + consumeBatchWriteStream( + client.batchWriteAtLeastOnce(MUTATION_GROUPS, Options.excludeTxnFromChangeStreams())); + + List requests = mockSpanner.getRequestsOfType(BatchWriteRequest.class); + assertEquals(requests.size(), 1); + BatchWriteRequest request = requests.get(0); + assertEquals(request.getMutationGroupsCount(), 4); + assertTrue(request.getExcludeTxnFromChangeStreams()); } @Test @@ -1782,6 +1863,9 @@ public void testExecuteUpdateWithTag() { assertThat(request.getRequestOptions().getRequestTag()) .isEqualTo("app=spanner,env=test,action=update"); assertThat(request.getRequestOptions().getTransactionTag()).isEmpty(); + assertNotNull(request.getTransaction().getBegin()); + assertTrue(request.getTransaction().getBegin().hasReadWrite()); + assertFalse(request.getTransaction().getBegin().getExcludeTxnFromChangeStreams()); } @Test @@ -1805,6 +1889,9 @@ public void testBatchUpdateWithTag() { .isEqualTo("app=spanner,env=test,action=batch"); assertThat(request.getRequestOptions().getTransactionTag()) .isEqualTo("app=spanner,env=test,action=txn"); + assertNotNull(request.getTransaction().getBegin()); + assertTrue(request.getTransaction().getBegin().hasReadWrite()); + assertFalse(request.getTransaction().getBegin().getExcludeTxnFromChangeStreams()); } @Test @@ -1814,6 +1901,14 @@ public void testPartitionedDMLWithTag() { client.executePartitionedUpdate( UPDATE_STATEMENT, Options.tag("app=spanner,env=test,action=dml")); + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasPartitionedDml()); + assertFalse(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + List requests = mockSpanner.getRequestsOfType(ExecuteSqlRequest.class); assertThat(requests).hasSize(1); ExecuteSqlRequest request = requests.get(0); @@ -1835,6 +1930,14 @@ public void testCommitWithTag() { return null; }); + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasReadWrite()); + assertFalse(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + List requests = mockSpanner.getRequestsOfType(CommitRequest.class); assertThat(requests).hasSize(1); CommitRequest request = requests.get(0); @@ -1855,6 +1958,14 @@ public void testTransactionManagerCommitWithTag() { manager.commit(); } + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasReadWrite()); + assertFalse(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + List requests = mockSpanner.getRequestsOfType(CommitRequest.class); assertThat(requests).hasSize(1); CommitRequest request = requests.get(0); @@ -1877,6 +1988,14 @@ public void testAsyncRunnerCommitWithTag() { }, executor)); + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasReadWrite()); + assertFalse(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + List requests = mockSpanner.getRequestsOfType(CommitRequest.class); assertThat(requests).hasSize(1); CommitRequest request = requests.get(0); @@ -1904,6 +2023,14 @@ public void testAsyncTransactionManagerCommitWithTag() { .commitAsync()); } + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasReadWrite()); + assertFalse(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + List requests = mockSpanner.getRequestsOfType(CommitRequest.class); assertThat(requests).hasSize(1); CommitRequest request = requests.get(0); @@ -1913,6 +2040,275 @@ public void testAsyncTransactionManagerCommitWithTag() { .isEqualTo("app=spanner,env=test,action=manager"); } + @Test + public void testReadWriteTxnWithExcludeTxnFromChangeStreams_executeUpdate() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + TransactionRunner runner = client.readWriteTransaction(Options.excludeTxnFromChangeStreams()); + runner.run(transaction -> transaction.executeUpdate(UPDATE_STATEMENT)); + + List requests = mockSpanner.getRequestsOfType(ExecuteSqlRequest.class); + assertThat(requests).hasSize(1); + ExecuteSqlRequest request = requests.get(0); + assertNotNull(request.getTransaction().getBegin()); + assertTrue(request.getTransaction().getBegin().hasReadWrite()); + assertTrue(request.getTransaction().getBegin().getExcludeTxnFromChangeStreams()); + } + + @Test + public void testReadWriteTxnWithExcludeTxnFromChangeStreams_batchUpdate() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + TransactionRunner runner = client.readWriteTransaction(Options.excludeTxnFromChangeStreams()); + runner.run(transaction -> transaction.batchUpdate(Collections.singletonList(UPDATE_STATEMENT))); + + List requests = + mockSpanner.getRequestsOfType(ExecuteBatchDmlRequest.class); + assertThat(requests).hasSize(1); + ExecuteBatchDmlRequest request = requests.get(0); + assertNotNull(request.getTransaction().getBegin()); + assertTrue(request.getTransaction().getBegin().hasReadWrite()); + assertTrue(request.getTransaction().getBegin().getExcludeTxnFromChangeStreams()); + } + + @Test + public void testPartitionedDMLWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + client.executePartitionedUpdate(UPDATE_STATEMENT, Options.excludeTxnFromChangeStreams()); + + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasPartitionedDml()); + assertTrue(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + } + + @Test + public void testCommitWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + TransactionRunner runner = client.readWriteTransaction(Options.excludeTxnFromChangeStreams()); + runner.run( + transaction -> { + transaction.buffer(Mutation.delete("TEST", KeySet.all())); + return null; + }); + + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasReadWrite()); + assertTrue(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + } + + @Test + public void testTransactionManagerCommitWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (TransactionManager manager = + client.transactionManager(Options.excludeTxnFromChangeStreams())) { + TransactionContext transaction = manager.begin(); + transaction.buffer(Mutation.delete("TEST", KeySet.all())); + manager.commit(); + } + + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasReadWrite()); + assertTrue(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + } + + @Test + public void testAsyncRunnerCommitWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + AsyncRunner runner = client.runAsync(Options.excludeTxnFromChangeStreams()); + get( + runner.runAsync( + txn -> { + txn.buffer(Mutation.delete("TEST", KeySet.all())); + return ApiFutures.immediateFuture(null); + }, + executor)); + + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasReadWrite()); + assertTrue(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + } + + @Test + public void testAsyncTransactionManagerCommitWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + try (AsyncTransactionManager manager = + client.transactionManagerAsync(Options.excludeTxnFromChangeStreams())) { + TransactionContextFuture transaction = manager.beginAsync(); + get( + transaction + .then( + (txn, input) -> { + txn.buffer(Mutation.delete("TEST", KeySet.all())); + return ApiFutures.immediateFuture(null); + }, + executor) + .commitAsync()); + } + + List beginTransactions = + mockSpanner.getRequestsOfType(BeginTransactionRequest.class); + assertThat(beginTransactions).hasSize(1); + BeginTransactionRequest beginTransaction = beginTransactions.get(0); + assertNotNull(beginTransaction.getOptions()); + assertTrue(beginTransaction.getOptions().hasReadWrite()); + assertTrue(beginTransaction.getOptions().getExcludeTxnFromChangeStreams()); + } + + @Test + public void testExecuteUpdateWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + TransactionRunner runner = client.readWriteTransaction(); + SpannerException e = + assertThrows( + SpannerException.class, + () -> + runner.run( + transaction -> + transaction.executeUpdate( + UPDATE_STATEMENT, Options.excludeTxnFromChangeStreams()))); + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(e.getMessage()) + .contains( + "Options.excludeTxnFromChangeStreams() cannot be specified for individual DML requests." + + " This option should be set at the transaction level."); + } + + @Test + public void testExecuteUpdateAsyncWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + AsyncRunner runner = client.runAsync(); + SpannerException e = + assertThrows( + SpannerException.class, + () -> + get( + runner.runAsync( + txn -> { + txn.executeUpdateAsync( + UPDATE_STATEMENT, Options.excludeTxnFromChangeStreams()); + return ApiFutures.immediateFuture(null); + }, + executor))); + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(e.getMessage()) + .contains( + "Options.excludeTxnFromChangeStreams() cannot be specified for individual DML requests." + + " This option should be set at the transaction level."); + } + + @Test + public void testAnalyzeUpdateWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + TransactionRunner runner = client.readWriteTransaction(); + SpannerException e = + assertThrows( + SpannerException.class, + () -> + runner.run( + transaction -> + transaction.analyzeUpdate( + UPDATE_STATEMENT, + QueryAnalyzeMode.PROFILE, + Options.excludeTxnFromChangeStreams()))); + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(e.getMessage()) + .contains( + "Options.excludeTxnFromChangeStreams() cannot be specified for individual DML requests." + + " This option should be set at the transaction level."); + } + + @Test + public void testAnalyzeUpdateStatementWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + TransactionRunner runner = client.readWriteTransaction(); + SpannerException e = + assertThrows( + SpannerException.class, + () -> + runner.run( + transaction -> + transaction.analyzeUpdateStatement( + UPDATE_STATEMENT, + QueryAnalyzeMode.PROFILE, + Options.excludeTxnFromChangeStreams()))); + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(e.getMessage()) + .contains( + "Options.excludeTxnFromChangeStreams() cannot be specified for individual DML requests." + + " This option should be set at the transaction level."); + } + + @Test + public void testBatchUpdateWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + TransactionRunner runner = client.readWriteTransaction(); + SpannerException e = + assertThrows( + SpannerException.class, + () -> + runner.run( + transaction -> + transaction.batchUpdate( + Collections.singletonList(UPDATE_STATEMENT), + Options.excludeTxnFromChangeStreams()))); + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(e.getMessage()) + .contains( + "Options.excludeTxnFromChangeStreams() cannot be specified for individual DML requests." + + " This option should be set at the transaction level."); + } + + @Test + public void testBatchUpdateAsyncWithExcludeTxnFromChangeStreams() { + DatabaseClient client = + spanner.getDatabaseClient(DatabaseId.of(TEST_PROJECT, TEST_INSTANCE, TEST_DATABASE)); + AsyncRunner runner = client.runAsync(); + SpannerException e = + assertThrows( + SpannerException.class, + () -> + get( + runner.runAsync( + txn -> { + txn.batchUpdateAsync( + Collections.singletonList(UPDATE_STATEMENT), + Options.excludeTxnFromChangeStreams()); + return ApiFutures.immediateFuture(null); + }, + executor))); + assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT); + assertThat(e.getMessage()) + .contains( + "Options.excludeTxnFromChangeStreams() cannot be specified for individual DML requests." + + " This option should be set at the transaction level."); + } + @Test public void singleUse() { DatabaseClientImpl client = diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java index e0bbf81f297..8c9a5d957e8 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/OptionsTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; @@ -100,6 +101,7 @@ public void allOptionsAbsent() { assertThat(options.hasTag()).isFalse(); assertThat(options.hasDataBoostEnabled()).isFalse(); assertThat(options.hasDirectedReadOptions()).isFalse(); + assertNull(options.withExcludeTxnFromChangeStreams()); assertThat(options.toString()).isEqualTo(""); assertThat(options.equals(options)).isTrue(); assertThat(options.equals(null)).isFalse(); @@ -691,4 +693,40 @@ public void directedReadHashCode() { public void directedReadsNullNotAllowed() { assertThrows(NullPointerException.class, () -> Options.directedRead(null)); } + + @Test + public void transactionOptionsExcludeTxnFromChangeStreams() { + Options option1 = Options.fromTransactionOptions(Options.excludeTxnFromChangeStreams()); + Options option2 = Options.fromTransactionOptions(Options.excludeTxnFromChangeStreams()); + Options option3 = Options.fromTransactionOptions(); + + assertEquals(option1, option2); + assertEquals(option1.hashCode(), option2.hashCode()); + assertNotEquals(option1, option3); + assertNotEquals(option1.hashCode(), option3.hashCode()); + + assertTrue(option1.withExcludeTxnFromChangeStreams()); + assertThat(option1.toString()).contains("withExcludeTxnFromChangeStreams: true"); + + assertNull(option3.withExcludeTxnFromChangeStreams()); + assertThat(option3.toString()).doesNotContain("withExcludeTxnFromChangeStreams: true"); + } + + @Test + public void updateOptionsExcludeTxnFromChangeStreams() { + Options option1 = Options.fromUpdateOptions(Options.excludeTxnFromChangeStreams()); + Options option2 = Options.fromUpdateOptions(Options.excludeTxnFromChangeStreams()); + Options option3 = Options.fromUpdateOptions(); + + assertEquals(option1, option2); + assertEquals(option1.hashCode(), option2.hashCode()); + assertNotEquals(option1, option3); + assertNotEquals(option1.hashCode(), option3.hashCode()); + + assertTrue(option1.withExcludeTxnFromChangeStreams()); + assertThat(option1.toString()).contains("withExcludeTxnFromChangeStreams: true"); + + assertNull(option3.withExcludeTxnFromChangeStreams()); + assertThat(option3.toString()).doesNotContain("withExcludeTxnFromChangeStreams: true"); + } } diff --git a/grpc-google-cloud-spanner-admin-database-v1/pom.xml b/grpc-google-cloud-spanner-admin-database-v1/pom.xml index 97f85ab5fdc..5c1af8f41b9 100644 --- a/grpc-google-cloud-spanner-admin-database-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.62.1 + 6.63.0 grpc-google-cloud-spanner-admin-database-v1 GRPC library for grpc-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 6.62.1 + 6.63.0 diff --git a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml index 0ab8b79b3e5..17fb51703b8 100644 --- a/grpc-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/grpc-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.62.1 + 6.63.0 grpc-google-cloud-spanner-admin-instance-v1 GRPC library for grpc-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 6.62.1 + 6.63.0 diff --git a/grpc-google-cloud-spanner-executor-v1/pom.xml b/grpc-google-cloud-spanner-executor-v1/pom.xml index f04c003621b..8f2a3b37db1 100644 --- a/grpc-google-cloud-spanner-executor-v1/pom.xml +++ b/grpc-google-cloud-spanner-executor-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-executor-v1 - 6.62.1 + 6.63.0 grpc-google-cloud-spanner-executor-v1 GRPC library for google-cloud-spanner com.google.cloud google-cloud-spanner-parent - 6.62.1 + 6.63.0 diff --git a/grpc-google-cloud-spanner-v1/pom.xml b/grpc-google-cloud-spanner-v1/pom.xml index fe934386b0d..892eaa734c9 100644 --- a/grpc-google-cloud-spanner-v1/pom.xml +++ b/grpc-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.62.1 + 6.63.0 grpc-google-cloud-spanner-v1 GRPC library for grpc-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 6.62.1 + 6.63.0 diff --git a/pom.xml b/pom.xml index 4ff60c2b9e2..cf1115a93fa 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-spanner-parent pom - 6.62.1 + 6.63.0 Google Cloud Spanner Parent https://github.com/googleapis/java-spanner @@ -61,47 +61,47 @@ com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.62.1 + 6.63.0 com.google.api.grpc proto-google-cloud-spanner-executor-v1 - 6.62.1 + 6.63.0 com.google.api.grpc grpc-google-cloud-spanner-executor-v1 - 6.62.1 + 6.63.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 6.62.1 + 6.63.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.62.1 + 6.63.0 com.google.api.grpc grpc-google-cloud-spanner-v1 - 6.62.1 + 6.63.0 com.google.api.grpc grpc-google-cloud-spanner-admin-instance-v1 - 6.62.1 + 6.63.0 com.google.api.grpc grpc-google-cloud-spanner-admin-database-v1 - 6.62.1 + 6.63.0 com.google.cloud google-cloud-spanner - 6.62.1 + 6.63.0 diff --git a/proto-google-cloud-spanner-admin-database-v1/pom.xml b/proto-google-cloud-spanner-admin-database-v1/pom.xml index 3770eebaad2..d434fe8202c 100644 --- a/proto-google-cloud-spanner-admin-database-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-database-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-database-v1 - 6.62.1 + 6.63.0 proto-google-cloud-spanner-admin-database-v1 PROTO library for proto-google-cloud-spanner-admin-database-v1 com.google.cloud google-cloud-spanner-parent - 6.62.1 + 6.63.0 diff --git a/proto-google-cloud-spanner-admin-instance-v1/pom.xml b/proto-google-cloud-spanner-admin-instance-v1/pom.xml index 1ab3f6ec5d8..0ea8a45b2d7 100644 --- a/proto-google-cloud-spanner-admin-instance-v1/pom.xml +++ b/proto-google-cloud-spanner-admin-instance-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-admin-instance-v1 - 6.62.1 + 6.63.0 proto-google-cloud-spanner-admin-instance-v1 PROTO library for proto-google-cloud-spanner-admin-instance-v1 com.google.cloud google-cloud-spanner-parent - 6.62.1 + 6.63.0 diff --git a/proto-google-cloud-spanner-executor-v1/pom.xml b/proto-google-cloud-spanner-executor-v1/pom.xml index ed63e21ea3c..24c5fac07b1 100644 --- a/proto-google-cloud-spanner-executor-v1/pom.xml +++ b/proto-google-cloud-spanner-executor-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-executor-v1 - 6.62.1 + 6.63.0 proto-google-cloud-spanner-executor-v1 Proto library for google-cloud-spanner com.google.cloud google-cloud-spanner-parent - 6.62.1 + 6.63.0 diff --git a/proto-google-cloud-spanner-v1/pom.xml b/proto-google-cloud-spanner-v1/pom.xml index 086d1659b70..ceb0c5bf614 100644 --- a/proto-google-cloud-spanner-v1/pom.xml +++ b/proto-google-cloud-spanner-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-spanner-v1 - 6.62.1 + 6.63.0 proto-google-cloud-spanner-v1 PROTO library for proto-google-cloud-spanner-v1 com.google.cloud google-cloud-spanner-parent - 6.62.1 + 6.63.0 diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index 7cb098895e1..b3647430cac 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -23,8 +23,8 @@ 1.8 UTF-8 0.31.1 - 2.38.0 - 3.39.0 + 2.39.0 + 3.40.0 diff --git a/samples/native-image/pom.xml b/samples/native-image/pom.xml index b009be4637d..c40930a15a8 100644 --- a/samples/native-image/pom.xml +++ b/samples/native-image/pom.xml @@ -29,7 +29,7 @@ com.google.cloud libraries-bom - 26.34.0 + 26.35.0 pom import diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 4dfae5bcd5c..cb8ad86b626 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -23,8 +23,8 @@ 1.8 UTF-8 0.31.1 - 2.38.0 - 3.39.0 + 2.39.0 + 3.40.0 @@ -32,7 +32,7 @@ com.google.cloud google-cloud-spanner - 6.62.1 + 6.63.0 diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index 655c9195864..1698a1207aa 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -34,7 +34,7 @@ com.google.cloud libraries-bom - 26.34.0 + 26.35.0 pom import diff --git a/versions.txt b/versions.txt index 8f703336abb..35f3118a473 100644 --- a/versions.txt +++ b/versions.txt @@ -1,13 +1,13 @@ # Format: # module:released-version:current-version -proto-google-cloud-spanner-admin-instance-v1:6.62.1:6.62.1 -proto-google-cloud-spanner-v1:6.62.1:6.62.1 -proto-google-cloud-spanner-admin-database-v1:6.62.1:6.62.1 -grpc-google-cloud-spanner-v1:6.62.1:6.62.1 -grpc-google-cloud-spanner-admin-instance-v1:6.62.1:6.62.1 -grpc-google-cloud-spanner-admin-database-v1:6.62.1:6.62.1 -google-cloud-spanner:6.62.1:6.62.1 -google-cloud-spanner-executor:6.62.1:6.62.1 -proto-google-cloud-spanner-executor-v1:6.62.1:6.62.1 -grpc-google-cloud-spanner-executor-v1:6.62.1:6.62.1 +proto-google-cloud-spanner-admin-instance-v1:6.63.0:6.63.0 +proto-google-cloud-spanner-v1:6.63.0:6.63.0 +proto-google-cloud-spanner-admin-database-v1:6.63.0:6.63.0 +grpc-google-cloud-spanner-v1:6.63.0:6.63.0 +grpc-google-cloud-spanner-admin-instance-v1:6.63.0:6.63.0 +grpc-google-cloud-spanner-admin-database-v1:6.63.0:6.63.0 +google-cloud-spanner:6.63.0:6.63.0 +google-cloud-spanner-executor:6.63.0:6.63.0 +proto-google-cloud-spanner-executor-v1:6.63.0:6.63.0 +grpc-google-cloud-spanner-executor-v1:6.63.0:6.63.0