Skip to content

Commit 38191b1

Browse files
Fix: bigquery.create NullPointerException when job already exists (#3035)
* 3034: Reproduce and propose fix * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Louis-Maxime Crédeville <[email protected]> Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent f64326a commit 38191b1

File tree

3 files changed

+58
-61
lines changed

3 files changed

+58
-61
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,20 @@ If you are using Maven without the BOM, add this to your dependencies:
5353
If you are using Gradle 5.x or later, add this to your dependencies:
5454

5555
```Groovy
56-
implementation platform('com.google.cloud:libraries-bom:26.27.0')
56+
implementation platform('com.google.cloud:libraries-bom:26.29.0')
5757
5858
implementation 'com.google.cloud:google-cloud-bigquery'
5959
```
6060
If you are using Gradle without BOM, add this to your dependencies:
6161

6262
```Groovy
63-
implementation 'com.google.cloud:google-cloud-bigquery:2.34.2'
63+
implementation 'com.google.cloud:google-cloud-bigquery:2.35.0'
6464
```
6565

6666
If you are using SBT, add this to your dependencies:
6767

6868
```Scala
69-
libraryDependencies += "com.google.cloud" % "google-cloud-bigquery" % "2.34.2"
69+
libraryDependencies += "com.google.cloud" % "google-cloud-bigquery" % "2.35.0"
7070
```
7171
<!-- {x-version-update-end} -->
7272

@@ -351,7 +351,7 @@ Java is a registered trademark of Oracle and/or its affiliates.
351351
[kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-bigquery/java11.html
352352
[stability-image]: https://img.shields.io/badge/stability-stable-green
353353
[maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-bigquery.svg
354-
[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-bigquery/2.34.2
354+
[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-bigquery/2.35.0
355355
[authentication]: https://github.com/googleapis/google-cloud-java#authentication
356356
[auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes
357357
[predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles

google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ public com.google.api.services.bigquery.model.Job call() {
437437

438438
if (matcher.find()) {
439439
// If the Job ALREADY EXISTS, retrieve it.
440-
Job job = this.getJob(jobInfo.getJobId());
440+
Job job = this.getJob(jobInfo.getJobId(), JobOption.fields(JobField.STATISTICS));
441441

442442
long jobCreationTime = job.getStatistics().getCreationTime();
443443
long jobMinStaleTime = System.currentTimeMillis();

google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/BigQueryImplTest.java

Lines changed: 53 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,47 +16,27 @@
1616

1717
package com.google.cloud.bigquery;
1818

19+
import static com.google.cloud.bigquery.BigQuery.JobField.STATISTICS;
20+
import static com.google.cloud.bigquery.BigQuery.JobField.USER_EMAIL;
21+
import static com.google.cloud.bigquery.BigQueryImpl.optionMap;
1922
import static com.google.common.truth.Truth.assertThat;
20-
import static org.junit.Assert.assertArrayEquals;
21-
import static org.junit.Assert.assertEquals;
22-
import static org.junit.Assert.assertFalse;
23-
import static org.junit.Assert.assertNotNull;
24-
import static org.junit.Assert.assertNull;
25-
import static org.junit.Assert.assertSame;
26-
import static org.junit.Assert.assertTrue;
27-
import static org.junit.Assert.fail;
28-
import static org.mockito.Mockito.any;
29-
import static org.mockito.Mockito.doReturn;
30-
import static org.mockito.Mockito.eq;
31-
import static org.mockito.Mockito.mock;
32-
import static org.mockito.Mockito.times;
33-
import static org.mockito.Mockito.verify;
34-
import static org.mockito.Mockito.when;
23+
import static org.junit.Assert.*;
24+
import static org.mockito.Mockito.*;
3525

3626
import com.google.api.gax.paging.Page;
37-
import com.google.api.services.bigquery.model.ErrorProto;
38-
import com.google.api.services.bigquery.model.GetQueryResultsResponse;
39-
import com.google.api.services.bigquery.model.JobConfigurationQuery;
40-
import com.google.api.services.bigquery.model.QueryRequest;
41-
import com.google.api.services.bigquery.model.TableCell;
42-
import com.google.api.services.bigquery.model.TableDataInsertAllRequest;
43-
import com.google.api.services.bigquery.model.TableDataInsertAllResponse;
44-
import com.google.api.services.bigquery.model.TableDataList;
45-
import com.google.api.services.bigquery.model.TableRow;
27+
import com.google.api.services.bigquery.model.*;
28+
import com.google.api.services.bigquery.model.JobStatistics;
4629
import com.google.cloud.Policy;
4730
import com.google.cloud.ServiceOptions;
4831
import com.google.cloud.Tuple;
32+
import com.google.cloud.bigquery.BigQuery.JobOption;
4933
import com.google.cloud.bigquery.BigQuery.QueryResultsOption;
5034
import com.google.cloud.bigquery.InsertAllRequest.RowToInsert;
5135
import com.google.cloud.bigquery.spi.BigQueryRpcFactory;
5236
import com.google.cloud.bigquery.spi.v2.BigQueryRpc;
5337
import com.google.common.base.Function;
5438
import com.google.common.base.Supplier;
55-
import com.google.common.collect.ImmutableList;
56-
import com.google.common.collect.ImmutableMap;
57-
import com.google.common.collect.Iterables;
58-
import com.google.common.collect.Lists;
59-
import com.google.common.collect.Maps;
39+
import com.google.common.collect.*;
6040
import java.io.IOException;
6141
import java.math.BigInteger;
6242
import java.util.Collections;
@@ -422,12 +402,11 @@ public class BigQueryImplTest {
422402
BigQueryRpc.Option.START_INDEX, 0L);
423403

424404
// Job options
425-
private static final BigQuery.JobOption JOB_OPTION_FIELDS =
426-
BigQuery.JobOption.fields(BigQuery.JobField.USER_EMAIL);
405+
private static final JobOption JOB_OPTION_FIELDS = JobOption.fields(USER_EMAIL);
427406

428407
// Job list options
429408
private static final BigQuery.JobListOption JOB_LIST_OPTION_FIELD =
430-
BigQuery.JobListOption.fields(BigQuery.JobField.STATISTICS);
409+
BigQuery.JobListOption.fields(STATISTICS);
431410
private static final BigQuery.JobListOption JOB_LIST_ALL_USERS =
432411
BigQuery.JobListOption.allUsers();
433412
private static final BigQuery.JobListOption JOB_LIST_STATE_FILTER =
@@ -1615,7 +1594,7 @@ public void testCreateJobWithSelectedFields() {
16151594
any(com.google.api.services.bigquery.model.Job.class), capturedOptions.capture()))
16161595
.thenReturn(newJobPb());
16171596

1618-
BigQuery.JobOption jobOptions = BigQuery.JobOption.fields(BigQuery.JobField.USER_EMAIL);
1597+
JobOption jobOptions = JobOption.fields(USER_EMAIL);
16191598

16201599
bigquery = options.getService();
16211600
bigquery.create(JobInfo.of(QueryJobConfiguration.of("SOME QUERY")), jobOptions);
@@ -1674,6 +1653,35 @@ public JobId get() {
16741653
.getJob(any(String.class), eq(id), eq((String) null), eq(EMPTY_RPC_OPTIONS));
16751654
}
16761655

1656+
@Test
1657+
public void testCreateJobTryGetNotRandom() {
1658+
Map<BigQueryRpc.Option, ?> withStatisticOption = optionMap(JobOption.fields(STATISTICS));
1659+
final String id = "testCreateJobTryGet-id";
1660+
String query = "SELECT * in FOO";
1661+
1662+
when(bigqueryRpcMock.create(jobCapture.capture(), eq(EMPTY_RPC_OPTIONS)))
1663+
.thenThrow(
1664+
new BigQueryException(
1665+
409,
1666+
"already exists, for some reason",
1667+
new RuntimeException("Already Exists: Job")));
1668+
when(bigqueryRpcMock.getJob(
1669+
any(String.class), eq(id), eq((String) null), eq(withStatisticOption)))
1670+
.thenReturn(
1671+
newJobPb()
1672+
.setId(id)
1673+
.setStatistics(new JobStatistics().setCreationTime(System.currentTimeMillis())));
1674+
1675+
bigquery = options.getService();
1676+
Job job =
1677+
((BigQueryImpl) bigquery).create(JobInfo.of(JobId.of(id), QueryJobConfiguration.of(query)));
1678+
assertThat(job).isNotNull();
1679+
assertThat(jobCapture.getValue().getJobReference().getJobId()).isEqualTo(id);
1680+
verify(bigqueryRpcMock).create(jobCapture.capture(), eq(EMPTY_RPC_OPTIONS));
1681+
verify(bigqueryRpcMock)
1682+
.getJob(any(String.class), eq(id), eq((String) null), eq(withStatisticOption));
1683+
}
1684+
16771685
@Test
16781686
public void testCreateJobWithProjectId() {
16791687
JobInfo jobInfo =
@@ -1925,7 +1933,7 @@ public void testQueryRequestCompleted() throws InterruptedException {
19251933
JOB_INFO.toPb(), Collections.<BigQueryRpc.Option, Object>emptyMap()))
19261934
.thenReturn(jobResponsePb);
19271935
when(bigqueryRpcMock.getQueryResults(
1928-
PROJECT, JOB, null, BigQueryImpl.optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS)))
1936+
PROJECT, JOB, null, optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS)))
19291937
.thenReturn(responsePb);
19301938
when(bigqueryRpcMock.listTableData(
19311939
PROJECT, DATASET, TABLE, Collections.<BigQueryRpc.Option, Object>emptyMap()))
@@ -1946,8 +1954,7 @@ public void testQueryRequestCompleted() throws InterruptedException {
19461954
verify(bigqueryRpcMock)
19471955
.create(JOB_INFO.toPb(), Collections.<BigQueryRpc.Option, Object>emptyMap());
19481956
verify(bigqueryRpcMock)
1949-
.getQueryResults(
1950-
PROJECT, JOB, null, BigQueryImpl.optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS));
1957+
.getQueryResults(PROJECT, JOB, null, optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS));
19511958

19521959
verify(bigqueryRpcMock)
19531960
.listTableData(PROJECT, DATASET, TABLE, Collections.<BigQueryRpc.Option, Object>emptyMap());
@@ -2003,10 +2010,7 @@ public void testFastQueryMultiplePages() throws InterruptedException {
20032010
responseJob.getConfiguration().getQuery().setDestinationTable(TABLE_ID.toPb());
20042011
when(bigqueryRpcMock.getJob(PROJECT, JOB, null, EMPTY_RPC_OPTIONS)).thenReturn(responseJob);
20052012
when(bigqueryRpcMock.listTableData(
2006-
PROJECT,
2007-
DATASET,
2008-
TABLE,
2009-
BigQueryImpl.optionMap(BigQuery.TableDataListOption.pageToken(CURSOR))))
2013+
PROJECT, DATASET, TABLE, optionMap(BigQuery.TableDataListOption.pageToken(CURSOR))))
20102014
.thenReturn(
20112015
new TableDataList()
20122016
.setPageToken(CURSOR)
@@ -2044,10 +2048,7 @@ public void testFastQueryMultiplePages() throws InterruptedException {
20442048
verify(bigqueryRpcMock).getJob(PROJECT, JOB, null, EMPTY_RPC_OPTIONS);
20452049
verify(bigqueryRpcMock)
20462050
.listTableData(
2047-
PROJECT,
2048-
DATASET,
2049-
TABLE,
2050-
BigQueryImpl.optionMap(BigQuery.TableDataListOption.pageToken(CURSOR)));
2051+
PROJECT, DATASET, TABLE, optionMap(BigQuery.TableDataListOption.pageToken(CURSOR)));
20512052
verify(bigqueryRpcMock).queryRpc(eq(PROJECT), requestPbCapture.capture());
20522053
}
20532054

@@ -2084,7 +2085,7 @@ public void testFastQuerySlowDdl() throws InterruptedException {
20842085
responseJob.getConfiguration().getQuery().setDestinationTable(TABLE_ID.toPb());
20852086
when(bigqueryRpcMock.getJob(PROJECT, JOB, null, EMPTY_RPC_OPTIONS)).thenReturn(responseJob);
20862087
when(bigqueryRpcMock.getQueryResults(
2087-
PROJECT, JOB, null, BigQueryImpl.optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS)))
2088+
PROJECT, JOB, null, optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS)))
20882089
.thenReturn(queryResultsResponsePb);
20892090
when(bigqueryRpcMock.listTableData(PROJECT, DATASET, TABLE, EMPTY_RPC_OPTIONS))
20902091
.thenReturn(new TableDataList().setRows(ImmutableList.of(TABLE_ROW)).setTotalRows(1L));
@@ -2108,8 +2109,7 @@ public void testFastQuerySlowDdl() throws InterruptedException {
21082109
verify(bigqueryRpcMock).queryRpc(eq(PROJECT), requestPbCapture.capture());
21092110
verify(bigqueryRpcMock).getJob(PROJECT, JOB, null, EMPTY_RPC_OPTIONS);
21102111
verify(bigqueryRpcMock)
2111-
.getQueryResults(
2112-
PROJECT, JOB, null, BigQueryImpl.optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS));
2112+
.getQueryResults(PROJECT, JOB, null, optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS));
21132113
verify(bigqueryRpcMock).listTableData(PROJECT, DATASET, TABLE, EMPTY_RPC_OPTIONS);
21142114
}
21152115

@@ -2143,7 +2143,7 @@ public void testQueryRequestCompletedOptions() throws InterruptedException {
21432143
optionMap.put(pageSizeOption.getRpcOption(), pageSizeOption.getValue());
21442144

21452145
when(bigqueryRpcMock.getQueryResults(
2146-
PROJECT, JOB, null, BigQueryImpl.optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS)))
2146+
PROJECT, JOB, null, optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS)))
21472147
.thenReturn(responsePb);
21482148
when(bigqueryRpcMock.listTableData(PROJECT, DATASET, TABLE, optionMap))
21492149
.thenReturn(
@@ -2164,8 +2164,7 @@ public void testQueryRequestCompletedOptions() throws InterruptedException {
21642164
verify(bigqueryRpcMock)
21652165
.create(JOB_INFO.toPb(), Collections.<BigQueryRpc.Option, Object>emptyMap());
21662166
verify(bigqueryRpcMock)
2167-
.getQueryResults(
2168-
PROJECT, JOB, null, BigQueryImpl.optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS));
2167+
.getQueryResults(PROJECT, JOB, null, optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS));
21692168
verify(bigqueryRpcMock).listTableData(PROJECT, DATASET, TABLE, optionMap);
21702169
}
21712170

@@ -2199,10 +2198,10 @@ public void testQueryRequestCompletedOnSecondAttempt() throws InterruptedExcepti
21992198
JOB_INFO.toPb(), Collections.<BigQueryRpc.Option, Object>emptyMap()))
22002199
.thenReturn(jobResponsePb1);
22012200
when(bigqueryRpcMock.getQueryResults(
2202-
PROJECT, JOB, null, BigQueryImpl.optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS)))
2201+
PROJECT, JOB, null, optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS)))
22032202
.thenReturn(responsePb1);
22042203
when(bigqueryRpcMock.getQueryResults(
2205-
PROJECT, JOB, null, BigQueryImpl.optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS)))
2204+
PROJECT, JOB, null, optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS)))
22062205
.thenReturn(responsePb2);
22072206
when(bigqueryRpcMock.listTableData(
22082207
PROJECT, DATASET, TABLE, Collections.<BigQueryRpc.Option, Object>emptyMap()))
@@ -2223,11 +2222,9 @@ public void testQueryRequestCompletedOnSecondAttempt() throws InterruptedExcepti
22232222
verify(bigqueryRpcMock)
22242223
.create(JOB_INFO.toPb(), Collections.<BigQueryRpc.Option, Object>emptyMap());
22252224
verify(bigqueryRpcMock)
2226-
.getQueryResults(
2227-
PROJECT, JOB, null, BigQueryImpl.optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS));
2225+
.getQueryResults(PROJECT, JOB, null, optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS));
22282226
verify(bigqueryRpcMock)
2229-
.getQueryResults(
2230-
PROJECT, JOB, null, BigQueryImpl.optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS));
2227+
.getQueryResults(PROJECT, JOB, null, optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS));
22312228
verify(bigqueryRpcMock)
22322229
.listTableData(PROJECT, DATASET, TABLE, Collections.<BigQueryRpc.Option, Object>emptyMap());
22332230
}

0 commit comments

Comments
 (0)