Skip to content

Commit dee7cda

Browse files
authored
feat: allow DML batches in transactions to execute analyzeUpdate (#3114)
Executing analyzeUpdate in a DML Batch inside a transaction should be possible, as the parent transaction can be used for that.
1 parent dfd9c4b commit dee7cda

File tree

7 files changed

+45
-11
lines changed

7 files changed

+45
-11
lines changed

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractBaseUnitOfWork.java

-2
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,6 @@ private Void endUnitOfWorkSpan() {
176176
return null;
177177
}
178178

179-
abstract boolean isSingleUse();
180-
181179
/**
182180
* Returns a descriptive name for the type of transaction / unit of work. This is used in error
183181
* messages.

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/AbstractMultiUseTransaction.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public String toString() {
9696
}
9797

9898
@Override
99-
boolean isSingleUse() {
99+
public boolean isSingleUse() {
100100
return false;
101101
}
102102

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DdlBatch.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ private DdlBatch(Builder builder) {
9797
}
9898

9999
@Override
100-
boolean isSingleUse() {
100+
public boolean isSingleUse() {
101101
return false;
102102
}
103103

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DmlBatch.java

+7-4
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ static Builder newBuilder() {
7878

7979
private DmlBatch(Builder builder) {
8080
super(builder);
81-
this.transaction = builder.transaction;
81+
this.transaction = Preconditions.checkNotNull(builder.transaction);
8282
this.statementTag = builder.statementTag;
8383
}
8484

8585
@Override
86-
boolean isSingleUse() {
86+
public boolean isSingleUse() {
8787
return false;
8888
}
8989

@@ -174,8 +174,11 @@ public ApiFuture<Long> executeUpdateAsync(
174174
@Override
175175
public ApiFuture<ResultSet> analyzeUpdateAsync(
176176
CallType callType, ParsedStatement update, AnalyzeMode analyzeMode, UpdateOption... options) {
177-
throw SpannerExceptionFactory.newSpannerException(
178-
ErrorCode.FAILED_PRECONDITION, "Analyzing updates is not allowed for DML batches.");
177+
if (transaction.isSingleUse()) {
178+
throw SpannerExceptionFactory.newSpannerException(
179+
ErrorCode.FAILED_PRECONDITION, "Analyzing updates is not allowed for DML batches.");
180+
}
181+
return transaction.analyzeUpdateAsync(callType, update, analyzeMode, options);
179182
}
180183

181184
@Override

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/SingleUseTransaction.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ private SingleUseTransaction(Builder builder) {
180180
}
181181

182182
@Override
183-
boolean isSingleUse() {
183+
public boolean isSingleUse() {
184184
return true;
185185
}
186186

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/UnitOfWork.java

+3
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ public boolean isActive() {
7777
/** @return <code>true</code> if this unit of work is still active. */
7878
boolean isActive();
7979

80+
/** Returns true if this transaction can only be used for a single statement. */
81+
boolean isSingleUse();
82+
8083
/**
8184
* Commits the changes in this unit of work to the database. For read-only transactions, this only
8285
* closes the {@link ReadContext}. This method will throw a {@link SpannerException} if called for

google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/AnalyzeStatementsTest.java

+32-2
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,9 @@ public void testAnalyzeUpdateStatementDdlBatch() {
355355
}
356356

357357
@Test
358-
public void testAnalyzeUpdateDmlBatch() {
358+
public void testAnalyzeUpdateDmlBatch_AutoCommit() {
359359
try (Connection connection = createConnection()) {
360+
connection.setAutocommit(true);
360361
connection.startBatchDml();
361362

362363
SpannerException exception =
@@ -371,8 +372,23 @@ public void testAnalyzeUpdateDmlBatch() {
371372
}
372373

373374
@Test
374-
public void testAnalyzeUpdateStatementDmlBatch() {
375+
public void testAnalyzeUpdateDmlBatch_Transactional() {
375376
try (Connection connection = createConnection()) {
377+
connection.setAutocommit(false);
378+
connection.startBatchDml();
379+
380+
assertNotNull(connection.analyzeUpdate(PLAN_UPDATE, QueryAnalyzeMode.PLAN));
381+
assertEquals(-1L, connection.executeUpdate(INSERT_STATEMENT));
382+
connection.runBatch();
383+
384+
assertEquals(1, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
385+
}
386+
}
387+
388+
@Test
389+
public void testAnalyzeUpdateStatementDmlBatch_AutoCommit() {
390+
try (Connection connection = createConnection()) {
391+
connection.setAutocommit(true);
376392
connection.startBatchDml();
377393

378394
SpannerException exception =
@@ -385,4 +401,18 @@ public void testAnalyzeUpdateStatementDmlBatch() {
385401
assertEquals(0, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
386402
assertEquals(0, mockSpanner.countRequestsOfType(CommitRequest.class));
387403
}
404+
405+
@Test
406+
public void testAnalyzeUpdateStatementDmlBatch_Transactional() {
407+
try (Connection connection = createConnection()) {
408+
connection.setAutocommit(false);
409+
connection.startBatchDml();
410+
411+
connection.analyzeUpdateStatement(PLAN_UPDATE, QueryAnalyzeMode.PLAN);
412+
assertEquals(-1L, connection.executeUpdate(INSERT_STATEMENT));
413+
connection.runBatch();
414+
415+
assertEquals(1, mockSpanner.countRequestsOfType(ExecuteSqlRequest.class));
416+
}
417+
}
388418
}

0 commit comments

Comments
 (0)