From 6f3d843b285830af99ac306464faa7aa9ff89eaa Mon Sep 17 00:00:00 2001 From: Kirill Logachev Date: Wed, 5 Nov 2025 22:51:50 +0000 Subject: [PATCH 1/7] feat: new queryNoWait method --- .../com/google/cloud/bigquery/BigQuery.java | 21 +++++++ .../google/cloud/bigquery/BigQueryImpl.java | 61 ++++++------------- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java index 2e0747f6be..f4095e1d46 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java @@ -1609,6 +1609,27 @@ TableResult query(QueryJobConfiguration configuration, JobOption... options) TableResult query(QueryJobConfiguration configuration, JobId jobId, JobOption... options) throws InterruptedException, JobException; + /** + * Starts the query associated with the request, using the given JobId. It returns either TableResult + * for quick queries or Job object for long-running queries. + * + *

If the location of the job is not "US" or "EU", the {@code jobId} must specify the job + * location. + * + *

This method cannot be used in conjunction with {@link QueryJobConfiguration#dryRun()} + * queries. Since dry-run queries are not actually executed, there's no way to retrieve results. + * + *

See {@link #query(QueryJobConfiguration, JobOption...)} for examples on populating a {@link + * QueryJobConfiguration}. + * + * @throws BigQueryException upon failure + * @throws InterruptedException if the current thread gets interrupted while waiting for the query + * to complete + * @throws JobException if the job completes unsuccessfully + */ + Object queryNoWait(QueryJobConfiguration configuration, JobId jobId, JobOption... options) + throws InterruptedException, JobException; + /** * Returns results of the query associated with the provided job. * diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java index 088d15c09c..4eafc81b53 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java @@ -1925,47 +1925,10 @@ public Boolean call() throws IOException { @Override public TableResult query(QueryJobConfiguration configuration, JobOption... options) throws InterruptedException, JobException { - Job.checkNotDryRun(configuration, "query"); - - configuration = - configuration.toBuilder() - .setJobCreationMode(getOptions().getDefaultJobCreationMode()) - .build(); - - Span querySpan = null; - if (getOptions().isOpenTelemetryTracingEnabled() - && getOptions().getOpenTelemetryTracer() != null) { - querySpan = - getOptions() - .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQuery.query") - .setAllAttributes(otelAttributesFromOptions(options)) - .startSpan(); - } - try (Scope queryScope = querySpan != null ? querySpan.makeCurrent() : null) { - // If all parameters passed in configuration are supported by the query() method on the - // backend, - // put on fast path - QueryRequestInfo requestInfo = - new QueryRequestInfo(configuration, getOptions().getUseInt64Timestamps()); - if (requestInfo.isFastQuerySupported(null)) { - String projectId = getOptions().getProjectId(); - QueryRequest content = requestInfo.toPb(); - if (getOptions().getLocation() != null) { - content.setLocation(getOptions().getLocation()); - } - return queryRpc(projectId, content, options); - } - // Otherwise, fall back to the existing create query job logic - return create(JobInfo.of(configuration), options).getQueryResults(); - } finally { - if (querySpan != null) { - querySpan.end(); - } - } + return query(configuration, null, options); } - private TableResult queryRpc( + private Object queryRpc( final String projectId, final QueryRequest content, JobOption... options) throws InterruptedException { com.google.api.services.bigquery.model.QueryResponse results; @@ -2030,7 +1993,7 @@ public com.google.api.services.bigquery.model.QueryResponse call() // here, but this is left as future work. JobId jobId = JobId.fromPb(results.getJobReference()); Job job = getJob(jobId, options); - return job.getQueryResults(); + return job; } if (results.getPageToken() != null) { @@ -2070,6 +2033,16 @@ public com.google.api.services.bigquery.model.QueryResponse call() @Override public TableResult query(QueryJobConfiguration configuration, JobId jobId, JobOption... options) throws InterruptedException, JobException { + Object result = queryNoWait(configuration, jobId, options); + if (result instanceof Job){ + return ((Job) result).getQueryResults(); + } + return (TableResult) result; + } + + @Override + public Object queryNoWait(QueryJobConfiguration configuration, JobId jobId, JobOption... options) + throws InterruptedException, JobException { Job.checkNotDryRun(configuration, "query"); Span querySpan = null; @@ -2078,8 +2051,8 @@ && getOptions().getOpenTelemetryTracer() != null) { querySpan = getOptions() .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQuery.query") - .setAllAttributes(jobId.getOtelAttributes()) + .spanBuilder("com.google.cloud.bigquery.BigQuery.queryNoWait") + .setAllAttributes(jobId != null ? jobId.getOtelAttributes() : null) .setAllAttributes(otelAttributesFromOptions(options)) .startSpan(); } @@ -2095,14 +2068,14 @@ && getOptions().getOpenTelemetryTracer() != null) { // fail with "Access denied" if the project do not have enough permissions to run the job. String projectId = - jobId.getProject() != null ? jobId.getProject() : getOptions().getProjectId(); + jobId != null && jobId.getProject() != null ? jobId.getProject() : getOptions().getProjectId(); QueryRequest content = requestInfo.toPb(); // Be careful when setting the location, if a location is specified in the BigQueryOption or // JobId the job created by the query method will be in that location, even if the table to // be // queried is in a different location. This may cause the query to fail with // "BigQueryException: Not found" - if (jobId.getLocation() != null) { + if (jobId != null && jobId.getLocation() != null) { content.setLocation(jobId.getLocation()); } else if (getOptions().getLocation() != null) { content.setLocation(getOptions().getLocation()); From 997e3ba1326ec5d7029cb2701a644d31a74816c9 Mon Sep 17 00:00:00 2001 From: Kirill Logachev Date: Thu, 6 Nov 2025 20:28:20 +0000 Subject: [PATCH 2/7] Rename method to queryWithTimeout --- .../src/main/java/com/google/cloud/bigquery/BigQuery.java | 2 +- .../main/java/com/google/cloud/bigquery/BigQueryImpl.java | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java index f4095e1d46..9b780b6678 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java @@ -1627,7 +1627,7 @@ TableResult query(QueryJobConfiguration configuration, JobId jobId, JobOption... * to complete * @throws JobException if the job completes unsuccessfully */ - Object queryNoWait(QueryJobConfiguration configuration, JobId jobId, JobOption... options) + Object queryWithTimeout(QueryJobConfiguration configuration, JobId jobId, Long timeoutMs, JobOption... options) throws InterruptedException, JobException; /** diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java index 4eafc81b53..b94af228f8 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java @@ -2033,7 +2033,7 @@ public com.google.api.services.bigquery.model.QueryResponse call() @Override public TableResult query(QueryJobConfiguration configuration, JobId jobId, JobOption... options) throws InterruptedException, JobException { - Object result = queryNoWait(configuration, jobId, options); + Object result = queryWithTimeout(configuration, jobId, null, options); if (result instanceof Job){ return ((Job) result).getQueryResults(); } @@ -2041,7 +2041,7 @@ public TableResult query(QueryJobConfiguration configuration, JobId jobId, JobOp } @Override - public Object queryNoWait(QueryJobConfiguration configuration, JobId jobId, JobOption... options) + public Object queryWithTimeout(QueryJobConfiguration configuration, JobId jobId, Long timeoutMs, JobOption... options) throws InterruptedException, JobException { Job.checkNotDryRun(configuration, "query"); @@ -2080,6 +2080,9 @@ && getOptions().getOpenTelemetryTracer() != null) { } else if (getOptions().getLocation() != null) { content.setLocation(getOptions().getLocation()); } + if (timeoutMs != null){ + content.setTimeoutMs(timeoutMs); + } return queryRpc(projectId, content, options); } From d543779f1be353dd9bf90e1b49fcbce093dea37a Mon Sep 17 00:00:00 2001 From: Kirill Logachev Date: Thu, 6 Nov 2025 21:03:19 +0000 Subject: [PATCH 3/7] rename to queryWithTimeout() --- .../java/com/google/cloud/bigquery/BigQuery.java | 12 +++++++----- .../java/com/google/cloud/bigquery/BigQueryImpl.java | 2 +- .../com/google/cloud/bigquery/it/ITBigQueryTest.java | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java index 9b780b6678..5fde35e0bb 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java @@ -18,6 +18,12 @@ import static com.google.common.base.Preconditions.checkArgument; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import org.checkerframework.checker.nullness.qual.NonNull; + import com.google.api.core.BetaApi; import com.google.api.core.InternalApi; import com.google.api.gax.paging.Page; @@ -30,10 +36,6 @@ import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import org.checkerframework.checker.nullness.qual.NonNull; /** * An interface for Google Cloud BigQuery. @@ -49,7 +51,7 @@ public interface BigQuery extends Service { * Resource */ enum DatasetField implements FieldSelector { - ACCESS("access"), + ACCESS("access"),testTableResultJobIdAndQueryId CREATION_TIME("creationTime"), DATASET_REFERENCE("datasetReference"), DEFAULT_TABLE_EXPIRATION_MS("defaultTableExpirationMsS"), diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java index b94af228f8..103ca991b8 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java @@ -2051,7 +2051,7 @@ && getOptions().getOpenTelemetryTracer() != null) { querySpan = getOptions() .getOpenTelemetryTracer() - .spanBuilder("com.google.cloud.bigquery.BigQuery.queryNoWait") + .spanBuilder("com.google.cloud.bigquery.BigQuery.queryWithTimeout") .setAllAttributes(jobId != null ? jobId.getOtelAttributes() : null) .setAllAttributes(otelAttributesFromOptions(options)) .startSpan(); diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java index c9f6296cc5..4b91a570a5 100644 --- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java +++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java @@ -7743,7 +7743,7 @@ public void testOpenTelemetryTracingQuery() throws InterruptedException { assertNotNull( OTEL_ATTRIBUTES.get("com.google.cloud.bigquery.BigQueryRetryHelper.runWithRetries")); assertNotNull(OTEL_ATTRIBUTES.get("com.google.cloud.bigquery.BigQueryRpc.queryRpc")); - assertTrue(OTEL_ATTRIBUTES.containsKey("com.google.cloud.bigquery.BigQuery.query")); + assertTrue(OTEL_ATTRIBUTES.containsKey("com.google.cloud.bigquery.BigQuery.queryWithTimeout")); // Query job String query = "SELECT TimestampField, StringField, BooleanField FROM " + TABLE_ID.getTable(); From a973a8dcbfcab608b2b7c79e784df6e6bb3cd784 Mon Sep 17 00:00:00 2001 From: Kirill Logachev Date: Thu, 6 Nov 2025 21:06:42 +0000 Subject: [PATCH 4/7] lint --- .../com/google/cloud/bigquery/BigQuery.java | 19 +++++++++---------- .../google/cloud/bigquery/BigQueryImpl.java | 16 +++++++++------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java index 5fde35e0bb..ab16ed40f7 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java @@ -18,12 +18,6 @@ import static com.google.common.base.Preconditions.checkArgument; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.checkerframework.checker.nullness.qual.NonNull; - import com.google.api.core.BetaApi; import com.google.api.core.InternalApi; import com.google.api.gax.paging.Page; @@ -36,6 +30,10 @@ import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import org.checkerframework.checker.nullness.qual.NonNull; /** * An interface for Google Cloud BigQuery. @@ -51,7 +49,7 @@ public interface BigQuery extends Service { * Resource */ enum DatasetField implements FieldSelector { - ACCESS("access"),testTableResultJobIdAndQueryId + ACCESS("access"), CREATION_TIME("creationTime"), DATASET_REFERENCE("datasetReference"), DEFAULT_TABLE_EXPIRATION_MS("defaultTableExpirationMsS"), @@ -1612,8 +1610,8 @@ TableResult query(QueryJobConfiguration configuration, JobId jobId, JobOption... throws InterruptedException, JobException; /** - * Starts the query associated with the request, using the given JobId. It returns either TableResult - * for quick queries or Job object for long-running queries. + * Starts the query associated with the request, using the given JobId. It returns either + * TableResult for quick queries or Job object for long-running queries. * *

If the location of the job is not "US" or "EU", the {@code jobId} must specify the job * location. @@ -1629,7 +1627,8 @@ TableResult query(QueryJobConfiguration configuration, JobId jobId, JobOption... * to complete * @throws JobException if the job completes unsuccessfully */ - Object queryWithTimeout(QueryJobConfiguration configuration, JobId jobId, Long timeoutMs, JobOption... options) + Object queryWithTimeout( + QueryJobConfiguration configuration, JobId jobId, Long timeoutMs, JobOption... options) throws InterruptedException, JobException; /** diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java index 103ca991b8..cd9c439004 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java @@ -1928,8 +1928,7 @@ public TableResult query(QueryJobConfiguration configuration, JobOption... optio return query(configuration, null, options); } - private Object queryRpc( - final String projectId, final QueryRequest content, JobOption... options) + private Object queryRpc(final String projectId, final QueryRequest content, JobOption... options) throws InterruptedException { com.google.api.services.bigquery.model.QueryResponse results; Span queryRpc = null; @@ -2034,14 +2033,15 @@ public com.google.api.services.bigquery.model.QueryResponse call() public TableResult query(QueryJobConfiguration configuration, JobId jobId, JobOption... options) throws InterruptedException, JobException { Object result = queryWithTimeout(configuration, jobId, null, options); - if (result instanceof Job){ + if (result instanceof Job) { return ((Job) result).getQueryResults(); - } + } return (TableResult) result; } @Override - public Object queryWithTimeout(QueryJobConfiguration configuration, JobId jobId, Long timeoutMs, JobOption... options) + public Object queryWithTimeout( + QueryJobConfiguration configuration, JobId jobId, Long timeoutMs, JobOption... options) throws InterruptedException, JobException { Job.checkNotDryRun(configuration, "query"); @@ -2068,7 +2068,9 @@ && getOptions().getOpenTelemetryTracer() != null) { // fail with "Access denied" if the project do not have enough permissions to run the job. String projectId = - jobId != null && jobId.getProject() != null ? jobId.getProject() : getOptions().getProjectId(); + jobId != null && jobId.getProject() != null + ? jobId.getProject() + : getOptions().getProjectId(); QueryRequest content = requestInfo.toPb(); // Be careful when setting the location, if a location is specified in the BigQueryOption or // JobId the job created by the query method will be in that location, even if the table to @@ -2080,7 +2082,7 @@ && getOptions().getOpenTelemetryTracer() != null) { } else if (getOptions().getLocation() != null) { content.setLocation(getOptions().getLocation()); } - if (timeoutMs != null){ + if (timeoutMs != null) { content.setTimeoutMs(timeoutMs); } From 736c2a1b083873352770b2c4c28d2bcaac2a1c35 Mon Sep 17 00:00:00 2001 From: Kirill Logachev Date: Thu, 6 Nov 2025 23:26:29 +0000 Subject: [PATCH 5/7] lint --- .../main/java/com/google/cloud/bigquery/BigQueryImpl.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java index cd9c439004..ac8fce7082 100644 --- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java +++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java @@ -2045,6 +2045,14 @@ public Object queryWithTimeout( throws InterruptedException, JobException { Job.checkNotDryRun(configuration, "query"); + // If JobCreationMode is not explicitly set, update it with default value; + if (configuration.getJobCreationMode() == null) { + configuration = + configuration.toBuilder() + .setJobCreationMode(getOptions().getDefaultJobCreationMode()) + .build(); + } + Span querySpan = null; if (getOptions().isOpenTelemetryTracingEnabled() && getOptions().getOpenTelemetryTracer() != null) { From 3896c7a88eca27abc328f17ddedd5cd4719be784 Mon Sep 17 00:00:00 2001 From: Kirill Logachev Date: Fri, 7 Nov 2025 02:31:43 +0000 Subject: [PATCH 6/7] add tests --- .../cloud/bigquery/BigQueryImplTest.java | 23 ++++++++ .../cloud/bigquery/it/ITBigQueryTest.java | 55 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/BigQueryImplTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/BigQueryImplTest.java index c0367beae4..393455e364 100644 --- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/BigQueryImplTest.java +++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/BigQueryImplTest.java @@ -2610,6 +2610,29 @@ PROJECT, JOB, null, optionMap(Job.DEFAULT_QUERY_WAIT_OPTIONS))) PROJECT, DATASET, TABLE, Collections.emptyMap()); } + @Test + public void testQueryWithTimeoutSetsTimeout() throws InterruptedException, IOException { + com.google.api.services.bigquery.model.QueryResponse queryResponsePb = + new com.google.api.services.bigquery.model.QueryResponse() + .setCacheHit(false) + .setJobComplete(true) + .setKind("bigquery#queryResponse") + .setPageToken(null) + .setRows(ImmutableList.of(TABLE_ROW)) + .setSchema(TABLE_SCHEMA.toPb()) + .setTotalBytesProcessed(42L) + .setTotalRows(BigInteger.valueOf(1L)); + + when(bigqueryRpcMock.queryRpcSkipExceptionTranslation(eq(PROJECT), requestPbCapture.capture())) + .thenReturn(queryResponsePb); + + bigquery = options.getService(); + Object result = bigquery.queryWithTimeout(QUERY_JOB_CONFIGURATION_FOR_QUERY, null, 1000L); + assertTrue(result instanceof TableResult); + QueryRequest requestPb = requestPbCapture.getValue(); + assertEquals((Long) 1000L, requestPb.getTimeoutMs()); + } + @Test public void testGetQueryResults() throws IOException { JobId queryJob = JobId.of(JOB); diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java index 4b91a570a5..ec1f7b5a09 100644 --- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java +++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java @@ -7215,6 +7215,7 @@ public void testTableResultJobIdAndQueryId() throws InterruptedException { // 2. For queries that fails the requirements to be stateless, then jobId is populated and // queryId is not. // 3. For explicitly created jobs, then jobId is populated and queryId is not populated. + // 4. If QueryJobConfiguration explicitly sets Job Creation Mode to Required. // Test scenario 1. // Create local BigQuery for test scenario 1 to not contaminate global test parameters. @@ -7241,6 +7242,16 @@ public void testTableResultJobIdAndQueryId() throws InterruptedException { result = job.getQueryResults(); assertNotNull(result.getJobId()); assertNull(result.getQueryId()); + + // Test scenario 4. + configWithJob = + QueryJobConfiguration.newBuilder(query) + .setJobCreationMode(JobCreationMode.JOB_CREATION_REQUIRED) + .build(); + result = bigQuery.query(configWithJob); + result = job.getQueryResults(); + assertNotNull(result.getJobId()); + assertNull(result.getQueryId()); } @Test @@ -7294,6 +7305,50 @@ public void testStatelessQueriesWithLocation() throws Exception { } } + @Test + public void testQueryWithTimeout() throws InterruptedException { + // Validate that queryWithTimeout returns either TableResult or Job object + + RemoteBigQueryHelper bigqueryHelper = RemoteBigQueryHelper.create(); + BigQuery bigQuery = bigqueryHelper.getOptions().getService(); + bigQuery.getOptions().setDefaultJobCreationMode(JobCreationMode.JOB_CREATION_OPTIONAL); + String largeQuery = + "SELECT * FROM UNNEST(GENERATE_ARRAY(1, 20000)) CROSS JOIN UNNEST(GENERATE_ARRAY(1, 20000))"; + String query = "SELECT 1 as one"; + // Test scenario 1. + // Stateless query returns TableResult + QueryJobConfiguration config = QueryJobConfiguration.newBuilder(query).build(); + Object result = bigQuery.queryWithTimeout(config, null, null); + assertTrue(result instanceof TableResult); + assertNull(((TableResult) result).getJobId()); + assertNotNull(((TableResult) result).getQueryId()); + + // Stateful query returns Job + // Test scenario 2 to ensure job is created if JobCreationMode is set, but for a small query + // it still returns results. + config = + QueryJobConfiguration.newBuilder(query) + .setJobCreationMode(JobCreationMode.JOB_CREATION_REQUIRED) + .build(); + result = bigQuery.queryWithTimeout(config, null, null); + assertTrue(result instanceof TableResult); + assertNotNull(((TableResult) result).getJobId()); + assertNull(((TableResult) result).getQueryId()); + + // Stateful query returns Job + // Test scenario 3 to ensure job is created if Query is long running. + // Explicitly disable cache to ensure it is long-running query; + config = QueryJobConfiguration.newBuilder(largeQuery).setUseQueryCache(false).build(); + long millis = System.currentTimeMillis(); + result = bigQuery.queryWithTimeout(config, null, 1000L); + millis = System.currentTimeMillis() - millis; + assertTrue(result instanceof Job); + // Cancel the job as we don't need results. + ((Job) result).cancel(); + // Allow 2 seconds of timeout value to account for random delays + assertTrue(millis < 1_000_000 * 2); + } + @Test public void testUniverseDomainWithInvalidUniverseDomain() { RemoteBigQueryHelper bigqueryHelper = RemoteBigQueryHelper.create(); From d35054a5e5ceef8da69209205ee763e13c57c98e Mon Sep 17 00:00:00 2001 From: Kirill Logachev Date: Wed, 12 Nov 2025 00:38:18 +0000 Subject: [PATCH 7/7] Update clirr ignore --- google-cloud-bigquery/clirr-ignored-differences.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/google-cloud-bigquery/clirr-ignored-differences.xml b/google-cloud-bigquery/clirr-ignored-differences.xml index bd455d2d4f..cef0f30f73 100644 --- a/google-cloud-bigquery/clirr-ignored-differences.xml +++ b/google-cloud-bigquery/clirr-ignored-differences.xml @@ -117,6 +117,11 @@ com/google/cloud/bigquery/TableInfo* *ResourceTags(*) + + 7012 + com/google/cloud/bigquery/BigQuery + java.lang.Object queryWithTimeout(com.google.cloud.bigquery.QueryJobConfiguration, com.google.cloud.bigquery.JobId, java.lang.Long, com.google.cloud.bigquery.BigQuery$JobOption[]) + 7012 com/google/cloud/bigquery/Connection