diff --git a/google-cloud-jar-parent/pom.xml b/google-cloud-jar-parent/pom.xml index 7ab2d6e857a0..acb8610974d9 100644 --- a/google-cloud-jar-parent/pom.xml +++ b/google-cloud-jar-parent/pom.xml @@ -142,7 +142,7 @@ com.google.apis google-api-services-bigquery - v2-rev20260612-2.0.0 + v2-rev20260707-2.0.0 diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java new file mode 100644 index 000000000000..457ea4917daf --- /dev/null +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java @@ -0,0 +1,118 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.bigquery; + +import com.google.api.core.BetaApi; +import java.io.Serializable; +import java.util.Objects; + +/** Options specific to the Apache Arrow output format. */ +@BetaApi +public final class ArrowSerializationOptions implements Serializable { + + private static final long serialVersionUID = 1L; + + private final String bufferCompression; + private final String picosTimestampPrecision; + + private ArrowSerializationOptions(Builder builder) { + this.bufferCompression = builder.bufferCompression; + this.picosTimestampPrecision = builder.picosTimestampPrecision; + } + + public String getBufferCompression() { + return bufferCompression; + } + + public String getPicosTimestampPrecision() { + return picosTimestampPrecision; + } + + public static Builder newBuilder() { + return new Builder(); + } + + @Override + public String toString() { + return com.google.common.base.MoreObjects.toStringHelper(this) + .add("bufferCompression", bufferCompression) + .add("picosTimestampPrecision", picosTimestampPrecision) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ArrowSerializationOptions that = (ArrowSerializationOptions) o; + return Objects.equals(bufferCompression, that.bufferCompression) + && Objects.equals(picosTimestampPrecision, that.picosTimestampPrecision); + } + + @Override + public int hashCode() { + return Objects.hash(bufferCompression, picosTimestampPrecision); + } + + com.google.api.services.bigquery.model.ArrowSerializationOptions toPb() { + com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb = + new com.google.api.services.bigquery.model.ArrowSerializationOptions(); + if (bufferCompression != null) { + optionsPb.setBufferCompression(bufferCompression); + } + if (picosTimestampPrecision != null) { + optionsPb.setPicosTimestampPrecision(picosTimestampPrecision); + } + return optionsPb; + } + + static ArrowSerializationOptions fromPb( + com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb) { + if (optionsPb == null) { + return null; + } + return newBuilder() + .setBufferCompression(optionsPb.getBufferCompression()) + .setPicosTimestampPrecision(optionsPb.getPicosTimestampPrecision()) + .build(); + } + + public static final class Builder { + private String bufferCompression; + private String picosTimestampPrecision; + + private Builder() {} + + public Builder setBufferCompression(String bufferCompression) { + this.bufferCompression = bufferCompression; + return this; + } + + public Builder setPicosTimestampPrecision(String picosTimestampPrecision) { + this.picosTimestampPrecision = picosTimestampPrecision; + return this; + } + + public ArrowSerializationOptions build() { + return new ArrowSerializationOptions(this); + } + } +} diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java index a62fbb5008d4..0d75d509d1a3 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java @@ -75,6 +75,8 @@ public final class QueryJobConfiguration extends JobConfiguration { private final Long maxResults; private final JobCreationMode jobCreationMode; private final String reservation; + private final QueryResultsFormat queryResultsFormat; + private final ArrowSerializationOptions arrowSerializationOptions; /** * Priority levels for a query. If not specified the priority is assumed to be {@link @@ -144,6 +146,8 @@ public static final class Builder private Long maxResults; private JobCreationMode jobCreationMode; private String reservation; + private QueryResultsFormat queryResultsFormat; + private ArrowSerializationOptions arrowSerializationOptions; private Builder() { super(Type.QUERY); @@ -181,6 +185,8 @@ private Builder(QueryJobConfiguration jobConfiguration) { this.maxResults = jobConfiguration.maxResults; this.jobCreationMode = jobConfiguration.jobCreationMode; this.reservation = jobConfiguration.reservation; + this.queryResultsFormat = jobConfiguration.queryResultsFormat; + this.arrowSerializationOptions = jobConfiguration.arrowSerializationOptions; } private Builder(com.google.api.services.bigquery.model.JobConfiguration configurationPb) { @@ -701,6 +707,17 @@ public Builder setReservation(String reservation) { return this; } + public Builder setQueryResultsFormat(QueryResultsFormat queryResultsFormat) { + this.queryResultsFormat = queryResultsFormat; + return this; + } + + public Builder setArrowSerializationOptions( + ArrowSerializationOptions arrowSerializationOptions) { + this.arrowSerializationOptions = arrowSerializationOptions; + return this; + } + public QueryJobConfiguration build() { return new QueryJobConfiguration(this); } @@ -747,6 +764,8 @@ private QueryJobConfiguration(Builder builder) { this.maxResults = builder.maxResults; this.jobCreationMode = builder.jobCreationMode; this.reservation = builder.reservation; + this.queryResultsFormat = builder.queryResultsFormat; + this.arrowSerializationOptions = builder.arrowSerializationOptions; } /** @@ -973,6 +992,14 @@ public Builder toBuilder() { return new Builder(this); } + public QueryResultsFormat getQueryResultsFormat() { + return queryResultsFormat; + } + + public ArrowSerializationOptions getArrowSerializationOptions() { + return arrowSerializationOptions; + } + @Override ToStringHelper toStringHelper() { return super.toStringHelper() @@ -1004,13 +1031,23 @@ ToStringHelper toStringHelper() { .add("rangePartitioning", rangePartitioning) .add("connectionProperties", connectionProperties) .add("jobCreationMode", jobCreationMode) - .add("reservation", reservation); + .add("reservation", reservation) + .add("queryResultsFormat", queryResultsFormat) + .add("arrowSerializationOptions", arrowSerializationOptions); } @Override public boolean equals(Object obj) { - return obj == this - || obj instanceof QueryJobConfiguration && baseEquals((QueryJobConfiguration) obj); + if (obj == this) { + return true; + } + if (obj == null || !(obj instanceof QueryJobConfiguration)) { + return false; + } + QueryJobConfiguration other = (QueryJobConfiguration) obj; + return baseEquals(other) + && Objects.equals(queryResultsFormat, other.queryResultsFormat) + && Objects.equals(arrowSerializationOptions, other.arrowSerializationOptions); } @Override @@ -1043,7 +1080,9 @@ public int hashCode() { labels, rangePartitioning, connectionProperties, - reservation); + reservation, + queryResultsFormat, + arrowSerializationOptions); } @Override diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java new file mode 100644 index 000000000000..61c12d34e326 --- /dev/null +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java @@ -0,0 +1,29 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.bigquery; + +import com.google.api.core.BetaApi; + +/** The format of the query results. */ +@BetaApi +public enum QueryResultsFormat { + /** Serialized row data in Apache Arrow format. */ + ARROW, + + /** Default encoding of results as JSON struct array. */ + STRUCT_ENCODING +} diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java index 7fe41daa0608..1d60d904bfab 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java @@ -241,6 +241,35 @@ public void testJobCreationMode() { QUERY_JOB_CONFIGURATION_SET_JOB_CREATION_MODE.toBuilder().build()); } + @Test + public void testArrowConfigurations() { + QueryResultsFormat format = QueryResultsFormat.ARROW; + ArrowSerializationOptions options = + ArrowSerializationOptions.newBuilder() + .setBufferCompression("LZ4") + .setPicosTimestampPrecision("PRECISION_MILLIS") + .build(); + QueryJobConfiguration job = + QueryJobConfiguration.newBuilder(QUERY) + .setQueryResultsFormat(format) + .setArrowSerializationOptions(options) + .build(); + + assertEquals(format, job.getQueryResultsFormat()); + assertEquals(options, job.getArrowSerializationOptions()); + + // Test toBuilder + QueryJobConfiguration copiedJob = job.toBuilder().build(); + assertEquals(job, copiedJob); + assertEquals(format, copiedJob.getQueryResultsFormat()); + assertEquals(options, copiedJob.getArrowSerializationOptions()); + + // Test toPb/fromPb (not preserved) + QueryJobConfiguration jobFromPb = QueryJobConfiguration.fromPb(job.toPb()); + assertNull(jobFromPb.getQueryResultsFormat()); + assertNull(jobFromPb.getArrowSerializationOptions()); + } + private void compareQueryJobConfiguration( QueryJobConfiguration expected, QueryJobConfiguration value) { assertEquals(expected, value);