From 6ba2126da9c80b14f32123c98247f7e2332b1ada Mon Sep 17 00:00:00 2001
From: "release-please[bot]"
<55107282+release-please[bot]@users.noreply.github.com>
Date: Wed, 25 Jun 2025 17:56:27 -0400
Subject: [PATCH 01/16] chore(main): release 2.52.1-SNAPSHOT (#3864)
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
---
benchmark/pom.xml | 2 +-
google-cloud-bigquery-bom/pom.xml | 4 ++--
google-cloud-bigquery/pom.xml | 4 ++--
pom.xml | 4 ++--
samples/snapshot/pom.xml | 2 +-
versions.txt | 2 +-
6 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/benchmark/pom.xml b/benchmark/pom.xml
index bb58ca1e1..8fcf7ca00 100644
--- a/benchmark/pom.xml
+++ b/benchmark/pom.xml
@@ -6,7 +6,7 @@
google-cloud-bigquery-parent
com.google.cloud
- 2.52.0
+ 2.52.1-SNAPSHOT
diff --git a/google-cloud-bigquery-bom/pom.xml b/google-cloud-bigquery-bom/pom.xml
index 836073eb4..1194e1b0e 100644
--- a/google-cloud-bigquery-bom/pom.xml
+++ b/google-cloud-bigquery-bom/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.google.cloud
google-cloud-bigquery-bom
- 2.52.0
+ 2.52.1-SNAPSHOT
pom
com.google.cloud
@@ -54,7 +54,7 @@
com.google.cloud
google-cloud-bigquery
- 2.52.0
+ 2.52.1-SNAPSHOT
diff --git a/google-cloud-bigquery/pom.xml b/google-cloud-bigquery/pom.xml
index 644fe0ef5..6c7e1aed1 100644
--- a/google-cloud-bigquery/pom.xml
+++ b/google-cloud-bigquery/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.google.cloud
google-cloud-bigquery
- 2.52.0
+ 2.52.1-SNAPSHOT
jar
BigQuery
https://github.com/googleapis/java-bigquery
@@ -11,7 +11,7 @@
com.google.cloud
google-cloud-bigquery-parent
- 2.52.0
+ 2.52.1-SNAPSHOT
google-cloud-bigquery
diff --git a/pom.xml b/pom.xml
index b265c66e3..6d9674e6f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.google.cloud
google-cloud-bigquery-parent
pom
- 2.52.0
+ 2.52.1-SNAPSHOT
BigQuery Parent
https://github.com/googleapis/java-bigquery
@@ -93,7 +93,7 @@
com.google.cloud
google-cloud-bigquery
- 2.52.0
+ 2.52.1-SNAPSHOT
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index 1a1655234..9e5136361 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -44,7 +44,7 @@
com.google.cloud
google-cloud-bigquery
- 2.52.0
+ 2.52.1-SNAPSHOT
diff --git a/versions.txt b/versions.txt
index 2b5922874..5e931b82a 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,4 +1,4 @@
# Format:
# module:released-version:current-version
-google-cloud-bigquery:2.52.0:2.52.0
\ No newline at end of file
+google-cloud-bigquery:2.52.0:2.52.1-SNAPSHOT
\ No newline at end of file
From e2d23c1b15f2c48a4113f82b920f5c29c4b5dfea Mon Sep 17 00:00:00 2001
From: Liam Huffman <44932470+whuffman36@users.noreply.github.com>
Date: Wed, 25 Jun 2025 23:14:57 -0700
Subject: [PATCH 02/16] feat(bigquery): Add OpenTelemetry support to BQ rpcs
(#3860)
* feat(bigquery): Add OpenTelemetry support to BQ rpcs
* remove oauth and access token attributes
* Capture repsponse ids in attributes
* Fix attribute name scoping typos
---
.../bigquery/spi/v2/HttpBigQueryRpc.java | 1062 ++++++++++++++---
.../cloud/bigquery/it/ITBigQueryTest.java | 20 +
2 files changed, 914 insertions(+), 168 deletions(-)
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpc.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpc.java
index 03e1fb586..9d89435ea 100644
--- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpc.java
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/spi/v2/HttpBigQueryRpc.java
@@ -69,6 +69,9 @@
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.SpanKind;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
@@ -155,7 +158,28 @@ public Dataset getDatasetSkipExceptionTranslation(
if (options.containsKey(Option.DATASET_VIEW)) {
bqGetRequest.setDatasetView(options.get(Option.DATASET_VIEW).toString());
}
- return bqGetRequest.execute();
+
+ Span getDataset = null;
+ if (this.options.isOpenTelemetryTracingEnabled()
+ && this.options.getOpenTelemetryTracer() != null) {
+ getDataset =
+ this.options
+ .getOpenTelemetryTracer()
+ .spanBuilder("com.google.cloud.bigquery.BigQueryRpc.getDataset")
+ .setSpanKind(SpanKind.CLIENT)
+ .setAttribute("bq.rpc.service", "DatasetService")
+ .setAttribute("bq.rpc.method", "GetDataset")
+ .setAttribute("bq.rpc.system", "http")
+ .setAllAttributes(otelAttributesFromOptions(options))
+ .startSpan();
+ }
+
+ Dataset dataset = bqGetRequest.execute();
+ if (getDataset != null) {
+ getDataset.setAttribute("bq.rpc.response.dataset.id", dataset.getId());
+ getDataset.end();
+ }
+ return dataset;
}
@Override
@@ -171,7 +195,7 @@ public Tuple> listDatasets(String projectId, Map> listDatasetsSkipExceptionTranslation(
String projectId, Map
From e5467c917c63ac066edcbcd902cc2093a39971a3 Mon Sep 17 00:00:00 2001
From: Liam Huffman <44932470+whuffman36@users.noreply.github.com>
Date: Mon, 30 Jun 2025 16:27:08 -0700
Subject: [PATCH 09/16] feat(bigquery): Add support for custom timezones and
timestamps (#3859)
* feat(bigquery): Add support for custom timezones and timestamps
* update ignored-diff
* fix data -> date typo
* Add enums for SourceColumnMatch
* Change null markers test names
* change enums to StringEnumValue
---
.../clirr-ignored-differences.xml | 70 ++++++
.../bigquery/ExternalTableDefinition.java | 186 +++++++++++++++
.../cloud/bigquery/LoadJobConfiguration.java | 219 +++++++++++++++++-
.../bigquery/ExternalTableDefinitionTest.java | 29 +++
.../bigquery/LoadJobConfigurationTest.java | 22 ++
5 files changed, 525 insertions(+), 1 deletion(-)
diff --git a/google-cloud-bigquery/clirr-ignored-differences.xml b/google-cloud-bigquery/clirr-ignored-differences.xml
index e048f4ce8..bd455d2d4 100644
--- a/google-cloud-bigquery/clirr-ignored-differences.xml
+++ b/google-cloud-bigquery/clirr-ignored-differences.xml
@@ -2,6 +2,76 @@
+
+ 7013
+ com/google/cloud/bigquery/ExternalTableDefinition*
+ *TimeZone(*)
+
+
+ 7013
+ com/google/cloud/bigquery/ExternalTableDefinition*
+ *DateFormat(*)
+
+
+ 7013
+ com/google/cloud/bigquery/ExternalTableDefinition*
+ *DatetimeFormat(*)
+
+
+ 7013
+ com/google/cloud/bigquery/ExternalTableDefinition*
+ *TimeFormat(*)
+
+
+ 7013
+ com/google/cloud/bigquery/ExternalTableDefinition*
+ *TimestampFormat(*)
+
+
+ 7013
+ com/google/cloud/bigquery/ExternalTableDefinition*
+ *SourceColumnMatch(*)
+
+
+ 7013
+ com/google/cloud/bigquery/ExternalTableDefinition*
+ *NullMarkers(*)
+
+
+ 7013
+ com/google/cloud/bigquery/LoadJobConfiguration*
+ *TimeZone(*)
+
+
+ 7013
+ com/google/cloud/bigquery/LoadJobConfiguration*
+ *DateFormat(*)
+
+
+ 7013
+ com/google/cloud/bigquery/LoadJobConfiguration*
+ *DatetimeFormat(*)
+
+
+ 7013
+ com/google/cloud/bigquery/LoadJobConfiguration*
+ *TimeFormat(*)
+
+
+ 7013
+ com/google/cloud/bigquery/LoadJobConfiguration*
+ *TimestampFormat(*)
+
+
+ 7013
+ com/google/cloud/bigquery/LoadJobConfiguration*
+ *SourceColumnMatch(*)
+
+
+ 7013
+ com/google/cloud/bigquery/LoadJobConfiguration*
+ *NullMarkers(*)
+
7004
com/google/cloud/bigquery/BigQueryRetryHelper
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ExternalTableDefinition.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ExternalTableDefinition.java
index ea4cceead..c1859c3f9 100644
--- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ExternalTableDefinition.java
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ExternalTableDefinition.java
@@ -19,9 +19,12 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
+import com.google.api.core.ApiFunction;
import com.google.api.services.bigquery.model.ExternalDataConfiguration;
import com.google.api.services.bigquery.model.Table;
import com.google.auto.value.AutoValue;
+import com.google.cloud.StringEnumType;
+import com.google.cloud.StringEnumValue;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import java.util.List;
@@ -57,6 +60,46 @@ public ExternalDataConfiguration apply(ExternalTableDefinition tableInfo) {
private static final long serialVersionUID = -5951580238459622025L;
+ public static final class SourceColumnMatch extends StringEnumValue {
+ private static final long serialVersionUID = 818920627219751207L;
+ private static final ApiFunction CONSTRUCTOR =
+ new ApiFunction() {
+ @Override
+ public SourceColumnMatch apply(String constant) {
+ return new SourceColumnMatch(constant);
+ }
+ };
+
+ private static final StringEnumType type =
+ new StringEnumType(SourceColumnMatch.class, CONSTRUCTOR);
+
+ public static final SourceColumnMatch POSITION = type.createAndRegister("POSITION");
+
+ public static final SourceColumnMatch NAME = type.createAndRegister("NAME");
+
+ private SourceColumnMatch(String constant) {
+ super(constant);
+ }
+
+ /**
+ * Get the SourceColumnMatch for the given String constant, and throw an exception if the
+ * constant is not recognized.
+ */
+ public static SourceColumnMatch valueOfStrict(String constant) {
+ return type.valueOfStrict(constant);
+ }
+
+ /** Get the SourceColumnMatch for the given String constant, and allow unrecognized values. */
+ public static SourceColumnMatch valueOf(String constant) {
+ return type.valueOf(constant);
+ }
+
+ /** Return the known values for SourceColumnMatch. */
+ public static SourceColumnMatch[] values() {
+ return type.values();
+ }
+ }
+
@AutoValue.Builder
public abstract static class Builder
extends TableDefinition.Builder {
@@ -215,6 +258,45 @@ public Builder setMaxStaleness(String maxStaleness) {
abstract Builder setMaxStalenessInner(String maxStaleness);
+ /**
+ * Time zone used when parsing timestamp values that do not have specific time zone information
+ * (e.g. 2024-04-20 12:34:56). The expected format is a IANA timezone string (e.g.
+ * America/Los_Angeles).
+ */
+ public abstract Builder setTimeZone(String timeZone);
+
+ /** Format used to parse DATE values. Supports C-style and SQL-style values. */
+ public abstract Builder setDateFormat(String dateFormat);
+
+ /** Format used to parse DATETIME values. Supports C-style and SQL-style values. */
+ public abstract Builder setDatetimeFormat(String datetimeFormat);
+
+ /** Format used to parse TIME values. Supports C-style and SQL-style values. */
+ public abstract Builder setTimeFormat(String timeFormat);
+
+ /** Format used to parse TIMESTAMP values. Supports C-style and SQL-style values. */
+ public abstract Builder setTimestampFormat(String timestampFormat);
+
+ /**
+ * Controls the strategy used to match loaded columns to the schema. If not set, a sensible
+ * default is chosen based on how the schema is provided. If autodetect is used, then columns
+ * are matched by name. Otherwise, columns are matched by position. This is done to keep the
+ * behavior backward-compatible. Acceptable values are: POSITION - matches by position. This
+ * assumes that the columns are ordered the same way as the schema. NAME - matches by name. This
+ * reads the header row as column names and reorders columns to match the field names in the
+ * schema.
+ */
+ public abstract Builder setSourceColumnMatch(SourceColumnMatch sourceColumnMatch);
+
+ /**
+ * A list of strings represented as SQL NULL value in a CSV file. null_marker and null_markers
+ * can't be set at the same time. If null_marker is set, null_markers has to be not set. If
+ * null_markers is set, null_marker has to be not set. If both null_marker and null_markers are
+ * set at the same time, a user error would be thrown. Any strings listed in null_markers,
+ * including empty string would be interpreted as SQL NULL. This applies to all column types.
+ */
+ public abstract Builder setNullMarkers(List nullMarkers);
+
/** Creates an {@code ExternalTableDefinition} object. */
@Override
public abstract ExternalTableDefinition build();
@@ -373,6 +455,37 @@ public HivePartitioningOptions getHivePartitioningOptions() {
return getHivePartitioningOptionsInner();
}
+ /**
+ * Returns the time zone used when parsing timestamp values that don't have specific time zone
+ * information.
+ */
+ @Nullable
+ public abstract String getTimeZone();
+
+ /** Returns the format used to parse DATE values. */
+ @Nullable
+ public abstract String getDateFormat();
+
+ /** Returns the format used to parse DATETIME values. */
+ @Nullable
+ public abstract String getDatetimeFormat();
+
+ /** Returns the format used to parse TIME values. */
+ @Nullable
+ public abstract String getTimeFormat();
+
+ /** Returns the format used to parse TIMESTAMP values. */
+ @Nullable
+ public abstract String getTimestampFormat();
+
+ /** Returns the strategy used to match loaded columns to the schema, either POSITION or NAME. */
+ @Nullable
+ public abstract SourceColumnMatch getSourceColumnMatch();
+
+ /** Returns a list of strings represented as SQL NULL value in a CSV file. */
+ @Nullable
+ public abstract List getNullMarkers();
+
@Nullable
abstract HivePartitioningOptions getHivePartitioningOptionsInner();
@@ -454,6 +567,29 @@ com.google.api.services.bigquery.model.ExternalDataConfiguration toExternalDataC
if (getMetadataCacheMode() != null) {
externalConfigurationPb.setMetadataCacheMode(getMetadataCacheMode());
}
+ if (getTimeZone() != null) {
+ externalConfigurationPb.setTimeZone(getTimeZone());
+ }
+ if (getDateFormat() != null) {
+ externalConfigurationPb.setDateFormat(getDateFormat());
+ }
+ if (getDatetimeFormat() != null) {
+ externalConfigurationPb.setDatetimeFormat(getDatetimeFormat());
+ }
+ if (getTimeFormat() != null) {
+ externalConfigurationPb.setTimeFormat(getTimeFormat());
+ }
+ if (getTimestampFormat() != null) {
+ externalConfigurationPb.setTimestampFormat(getTimestampFormat());
+ }
+ if (getSourceColumnMatch() != null) {
+ externalConfigurationPb
+ .getCsvOptions()
+ .setSourceColumnMatch(getSourceColumnMatch().toString());
+ }
+ if (getNullMarkers() != null) {
+ externalConfigurationPb.getCsvOptions().setNullMarkers(getNullMarkers());
+ }
return externalConfigurationPb;
}
@@ -654,6 +790,31 @@ static ExternalTableDefinition fromPb(Table tablePb) {
if (tablePb.getMaxStaleness() != null) {
builder.setMaxStaleness(tablePb.getMaxStaleness());
}
+ if (externalDataConfiguration.getTimeZone() != null) {
+ builder.setTimeZone(externalDataConfiguration.getTimeZone());
+ }
+ if (externalDataConfiguration.getDateFormat() != null) {
+ builder.setDateFormat(externalDataConfiguration.getDateFormat());
+ }
+ if (externalDataConfiguration.getDatetimeFormat() != null) {
+ builder.setDatetimeFormat(externalDataConfiguration.getDatetimeFormat());
+ }
+ if (externalDataConfiguration.getTimeFormat() != null) {
+ builder.setTimeFormat(externalDataConfiguration.getTimeFormat());
+ }
+ if (externalDataConfiguration.getTimestampFormat() != null) {
+ builder.setTimestampFormat(externalDataConfiguration.getTimestampFormat());
+ }
+ if (externalDataConfiguration.getCsvOptions() != null) {
+ if (externalDataConfiguration.getCsvOptions().getSourceColumnMatch() != null) {
+ builder.setSourceColumnMatch(
+ SourceColumnMatch.valueOf(
+ externalDataConfiguration.getCsvOptions().getSourceColumnMatch()));
+ }
+ if (externalDataConfiguration.getCsvOptions().getNullMarkers() != null) {
+ builder.setNullMarkers(externalDataConfiguration.getCsvOptions().getNullMarkers());
+ }
+ }
}
return builder.build();
}
@@ -724,6 +885,31 @@ static ExternalTableDefinition fromExternalDataConfiguration(
if (externalDataConfiguration.getMetadataCacheMode() != null) {
builder.setMetadataCacheMode(externalDataConfiguration.getMetadataCacheMode());
}
+ if (externalDataConfiguration.getTimeZone() != null) {
+ builder.setTimeZone(externalDataConfiguration.getTimeZone());
+ }
+ if (externalDataConfiguration.getDateFormat() != null) {
+ builder.setDateFormat(externalDataConfiguration.getDateFormat());
+ }
+ if (externalDataConfiguration.getDatetimeFormat() != null) {
+ builder.setDatetimeFormat(externalDataConfiguration.getDatetimeFormat());
+ }
+ if (externalDataConfiguration.getTimeFormat() != null) {
+ builder.setTimeFormat(externalDataConfiguration.getTimeFormat());
+ }
+ if (externalDataConfiguration.getTimestampFormat() != null) {
+ builder.setTimestampFormat(externalDataConfiguration.getTimeFormat());
+ }
+ if (externalDataConfiguration.getCsvOptions() != null) {
+ if (externalDataConfiguration.getCsvOptions().getSourceColumnMatch() != null) {
+ builder.setSourceColumnMatch(
+ SourceColumnMatch.valueOf(
+ externalDataConfiguration.getCsvOptions().getSourceColumnMatch()));
+ }
+ if (externalDataConfiguration.getCsvOptions().getNullMarkers() != null) {
+ builder.setNullMarkers(externalDataConfiguration.getCsvOptions().getNullMarkers());
+ }
+ }
return builder.build();
}
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/LoadJobConfiguration.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/LoadJobConfiguration.java
index 5d1755459..0d1eb7245 100644
--- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/LoadJobConfiguration.java
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/LoadJobConfiguration.java
@@ -18,7 +18,10 @@
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.api.core.ApiFunction;
import com.google.api.services.bigquery.model.JobConfigurationLoad;
+import com.google.cloud.StringEnumType;
+import com.google.cloud.StringEnumValue;
import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
@@ -63,6 +66,55 @@ public final class LoadJobConfiguration extends JobConfiguration implements Load
private final List connectionProperties;
private final Boolean createSession;
private final String reservation;
+ private final String timeZone;
+ private final String dateFormat;
+ private final String datetimeFormat;
+ private final String timeFormat;
+ private final String timestampFormat;
+ private final SourceColumnMatch sourceColumnMatch;
+ private final List nullMarkers;
+
+ public static final class SourceColumnMatch extends StringEnumValue {
+ private static final long serialVersionUID = 818920627219751207L;
+ private static final ApiFunction CONSTRUCTOR =
+ new ApiFunction() {
+ @Override
+ public SourceColumnMatch apply(String constant) {
+ return new SourceColumnMatch(constant);
+ }
+ };
+
+ private static final StringEnumType type =
+ new StringEnumType(SourceColumnMatch.class, CONSTRUCTOR);
+
+ public static final SourceColumnMatch SOURCE_COLUMN_MATCH_UNSPECIFIED =
+ type.createAndRegister("SOURCE_COLUMN_MATCH_UNSPECIFIED");
+ public static final SourceColumnMatch POSITION = type.createAndRegister("POSITION");
+
+ public static final SourceColumnMatch NAME = type.createAndRegister("NAME");
+
+ private SourceColumnMatch(String constant) {
+ super(constant);
+ }
+
+ /**
+ * Get the SourceColumnMatch for the given String constant, and throw an exception if the
+ * constant is not recognized.
+ */
+ public static SourceColumnMatch valueOfStrict(String constant) {
+ return type.valueOfStrict(constant);
+ }
+
+ /** Get the SourceColumnMatch for the given String constant, and allow unrecognized values. */
+ public static SourceColumnMatch valueOf(String constant) {
+ return type.valueOf(constant);
+ }
+
+ /** Return the known values for SourceColumnMatch. */
+ public static SourceColumnMatch[] values() {
+ return type.values();
+ }
+ }
public static final class Builder extends JobConfiguration.Builder
implements LoadConfiguration.Builder {
@@ -95,6 +147,13 @@ public static final class Builder extends JobConfiguration.Builder connectionProperties;
private Boolean createSession;
private String reservation;
+ private String timeZone;
+ private String dateFormat;
+ private String datetimeFormat;
+ private String timeFormat;
+ private String timestampFormat;
+ private SourceColumnMatch sourceColumnMatch;
+ private List nullMarkers;
private Builder() {
super(Type.LOAD);
@@ -129,6 +188,13 @@ private Builder(LoadJobConfiguration loadConfiguration) {
this.connectionProperties = loadConfiguration.connectionProperties;
this.createSession = loadConfiguration.createSession;
this.reservation = loadConfiguration.reservation;
+ this.timeZone = loadConfiguration.timeZone;
+ this.dateFormat = loadConfiguration.dateFormat;
+ this.datetimeFormat = loadConfiguration.datetimeFormat;
+ this.timeFormat = loadConfiguration.timeFormat;
+ this.timestampFormat = loadConfiguration.timestampFormat;
+ this.sourceColumnMatch = loadConfiguration.sourceColumnMatch;
+ this.nullMarkers = loadConfiguration.nullMarkers;
}
private Builder(com.google.api.services.bigquery.model.JobConfiguration configurationPb) {
@@ -238,6 +304,28 @@ private Builder(com.google.api.services.bigquery.model.JobConfiguration configur
if (configurationPb.getReservation() != null) {
this.reservation = configurationPb.getReservation();
}
+ if (loadConfigurationPb.getTimeZone() != null) {
+ this.timeZone = loadConfigurationPb.getTimeZone();
+ }
+ if (loadConfigurationPb.getDateFormat() != null) {
+ this.dateFormat = loadConfigurationPb.getDateFormat();
+ }
+ if (loadConfigurationPb.getDatetimeFormat() != null) {
+ this.datetimeFormat = loadConfigurationPb.getDatetimeFormat();
+ }
+ if (loadConfigurationPb.getTimeFormat() != null) {
+ this.timeFormat = loadConfigurationPb.getTimeFormat();
+ }
+ if (loadConfigurationPb.getTimestampFormat() != null) {
+ this.timestampFormat = loadConfigurationPb.getTimestampFormat();
+ }
+ if (loadConfigurationPb.getSourceColumnMatch() != null) {
+ this.sourceColumnMatch =
+ SourceColumnMatch.valueOf(loadConfigurationPb.getSourceColumnMatch());
+ }
+ if (loadConfigurationPb.getNullMarkers() != null) {
+ this.nullMarkers = loadConfigurationPb.getNullMarkers();
+ }
}
@Override
@@ -449,6 +537,62 @@ public Builder setReservation(String reservation) {
return this;
}
+ /**
+ * [Experimental] Default time zone that will apply when parsing timestamp values that have no
+ * specific time zone.
+ */
+ public Builder setTimeZone(String timeZone) {
+ this.timeZone = timeZone;
+ return this;
+ }
+
+ /** Date format used for parsing DATE values. */
+ public Builder setDateFormat(String dateFormat) {
+ this.dateFormat = dateFormat;
+ return this;
+ }
+
+ /** Date format used for parsing DATETIME values. */
+ public Builder setDatetimeFormat(String datetimeFormat) {
+ this.datetimeFormat = datetimeFormat;
+ return this;
+ }
+
+ /** Date format used for parsing TIME values. */
+ public Builder setTimeFormat(String timeFormat) {
+ this.timeFormat = timeFormat;
+ return this;
+ }
+
+ /** Date format used for parsing TIMESTAMP values. */
+ public Builder setTimestampFormat(String timestampFormat) {
+ this.timestampFormat = timestampFormat;
+ return this;
+ }
+
+ /**
+ * Controls the strategy used to match loaded columns to the schema. If not set, a sensible
+ * default is chosen based on how the schema is provided. If autodetect is used, then columns
+ * are matched by name. Otherwise, columns are matched by position. This is done to keep the
+ * behavior backward-compatible.
+ */
+ public Builder setSourceColumnMatch(SourceColumnMatch sourceColumnMatch) {
+ this.sourceColumnMatch = sourceColumnMatch;
+ return this;
+ }
+
+ /**
+ * A list of strings represented as SQL NULL value in a CSV file. null_marker and null_markers
+ * can't be set at the same time. If null_marker is set, null_markers has to be not set. If
+ * null_markers is set, null_marker has to be not set. If both null_marker and null_markers are
+ * set at the same time, a user error would be thrown. Any strings listed in null_markers,
+ * including empty string would be interpreted as SQL NULL. This applies to all column types.
+ */
+ public Builder setNullMarkers(List nullMarkers) {
+ this.nullMarkers = nullMarkers;
+ return this;
+ }
+
@Override
public LoadJobConfiguration build() {
return new LoadJobConfiguration(this);
@@ -483,6 +627,13 @@ private LoadJobConfiguration(Builder builder) {
this.connectionProperties = builder.connectionProperties;
this.createSession = builder.createSession;
this.reservation = builder.reservation;
+ this.timeZone = builder.timeZone;
+ this.dateFormat = builder.dateFormat;
+ this.datetimeFormat = builder.datetimeFormat;
+ this.timeFormat = builder.timeFormat;
+ this.timestampFormat = builder.timestampFormat;
+ this.sourceColumnMatch = builder.sourceColumnMatch;
+ this.nullMarkers = builder.nullMarkers;
}
@Override
@@ -634,6 +785,44 @@ public String getReservation() {
return reservation;
}
+ /**
+ * Returns the time zone used when parsing timestamp values that don't have specific time zone
+ * information.
+ */
+ public String getTimeZone() {
+ return timeZone;
+ }
+
+ /** Returns the format used to parse DATE values. */
+ public String getDateFormat() {
+ return dateFormat;
+ }
+
+ /** Returns the format used to parse DATETIME values. */
+ public String getDatetimeFormat() {
+ return datetimeFormat;
+ }
+
+ /** Returns the format used to parse TIME values. */
+ public String getTimeFormat() {
+ return timeFormat;
+ }
+
+ /** Returns the format used to parse TIMESTAMP values. */
+ public String getTimestampFormat() {
+ return timestampFormat;
+ }
+
+ /** Returns the strategy used to match loaded columns to the schema, either POSITION or NAME. */
+ public SourceColumnMatch getSourceColumnMatch() {
+ return sourceColumnMatch;
+ }
+
+ /** Returns a list of strings represented as SQL NULL value in a CSV file. */
+ public List getNullMarkers() {
+ return nullMarkers;
+ }
+
@Override
public Builder toBuilder() {
return new Builder(this);
@@ -667,7 +856,14 @@ ToStringHelper toStringHelper() {
.add("referenceFileSchemaUri", referenceFileSchemaUri)
.add("connectionProperties", connectionProperties)
.add("createSession", createSession)
- .add("reservation", reservation);
+ .add("reservation", reservation)
+ .add("timeZone", timeZone)
+ .add("dateFormat", dateFormat)
+ .add("datetimeFormat", datetimeFormat)
+ .add("timeFormat", timeFormat)
+ .add("timestampFormat", timestampFormat)
+ .add("sourceColumnMatch", sourceColumnMatch)
+ .add("nullMarkers", nullMarkers);
}
@Override
@@ -789,6 +985,27 @@ com.google.api.services.bigquery.model.JobConfiguration toPb() {
if (reservation != null) {
jobConfiguration.setReservation(reservation);
}
+ if (timeZone != null) {
+ loadConfigurationPb.setTimeZone(timeZone);
+ }
+ if (dateFormat != null) {
+ loadConfigurationPb.setDateFormat(dateFormat);
+ }
+ if (datetimeFormat != null) {
+ loadConfigurationPb.setDatetimeFormat(datetimeFormat);
+ }
+ if (timeFormat != null) {
+ loadConfigurationPb.setTimeFormat(timeFormat);
+ }
+ if (timestampFormat != null) {
+ loadConfigurationPb.setTimestampFormat(timestampFormat);
+ }
+ if (sourceColumnMatch != null) {
+ loadConfigurationPb.setSourceColumnMatch(sourceColumnMatch.toString());
+ }
+ if (nullMarkers != null) {
+ loadConfigurationPb.setNullMarkers(nullMarkers);
+ }
jobConfiguration.setLoad(loadConfigurationPb);
return jobConfiguration;
diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ExternalTableDefinitionTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ExternalTableDefinitionTest.java
index 93a4425df..cb7578c75 100644
--- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ExternalTableDefinitionTest.java
+++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ExternalTableDefinitionTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
+import com.google.cloud.bigquery.ExternalTableDefinition.SourceColumnMatch;
import com.google.common.collect.ImmutableList;
import java.util.List;
import org.junit.Test;
@@ -61,6 +62,13 @@ public class ExternalTableDefinitionTest {
private static final String OBJECT_METADATA = "SIMPLE";
private static final String METADATA_CACHE_MODE = "AUTOMATIC";
private static final String MAX_STALENESS = "INTERVAL 15 MINUTE";
+ private static final String TIME_ZONE = "America/Los_Angeles";
+ private static final String DATE_FORMAT = "YYYY-MM-DD";
+ private static final String DATETIME_FORMAT = "YYYY-MM-DD HH:MI:SS";
+ private static final String TIME_FORMAT = "HH:MI:SS";
+ private static final String TIMESTAMP_FORMAT = "YYYY-MM-DD HH:MI:SS";
+ private static final SourceColumnMatch SOURCE_COLUMN_MATCH = SourceColumnMatch.POSITION;
+ private static final List NULL_MARKERS = ImmutableList.of("SQL NULL", "TEST_MARKER");
private static final ExternalTableDefinition EXTERNAL_TABLE_DEFINITION =
ExternalTableDefinition.newBuilder(SOURCE_URIS, TABLE_SCHEMA, CSV_OPTIONS)
.setFileSetSpecType("FILE_SET_SPEC_TYPE_FILE_SYSTEM_MATCH")
@@ -74,6 +82,13 @@ public class ExternalTableDefinitionTest {
.setObjectMetadata(OBJECT_METADATA)
.setMetadataCacheMode(METADATA_CACHE_MODE)
.setMaxStaleness(MAX_STALENESS)
+ .setTimeZone(TIME_ZONE)
+ .setDateFormat(DATE_FORMAT)
+ .setDatetimeFormat(DATETIME_FORMAT)
+ .setTimeFormat(TIME_FORMAT)
+ .setTimestampFormat(TIMESTAMP_FORMAT)
+ .setSourceColumnMatch(SOURCE_COLUMN_MATCH)
+ .setNullMarkers(NULL_MARKERS)
.build();
private static final ExternalTableDefinition EXTERNAL_TABLE_DEFINITION_AVRO =
@@ -131,6 +146,13 @@ public void testBuilder() {
assertEquals(DECIMAL_TARGET_TYPES, EXTERNAL_TABLE_DEFINITION.getDecimalTargetTypes());
assertEquals(AUTODETECT, EXTERNAL_TABLE_DEFINITION.getAutodetect());
assertEquals(HIVE_PARTITIONING_OPTIONS, EXTERNAL_TABLE_DEFINITION.getHivePartitioningOptions());
+ assertEquals(TIME_ZONE, EXTERNAL_TABLE_DEFINITION.getTimeZone());
+ assertEquals(DATE_FORMAT, EXTERNAL_TABLE_DEFINITION.getDateFormat());
+ assertEquals(DATETIME_FORMAT, EXTERNAL_TABLE_DEFINITION.getDatetimeFormat());
+ assertEquals(TIME_FORMAT, EXTERNAL_TABLE_DEFINITION.getTimeFormat());
+ assertEquals(TIMESTAMP_FORMAT, EXTERNAL_TABLE_DEFINITION.getTimestampFormat());
+ assertEquals(SOURCE_COLUMN_MATCH, EXTERNAL_TABLE_DEFINITION.getSourceColumnMatch());
+ assertEquals(NULL_MARKERS, EXTERNAL_TABLE_DEFINITION.getNullMarkers());
assertNotEquals(EXTERNAL_TABLE_DEFINITION, TableDefinition.Type.EXTERNAL);
}
@@ -174,5 +196,12 @@ private void compareExternalTableDefinition(
assertEquals(expected.getObjectMetadata(), value.getObjectMetadata());
assertEquals(expected.getMetadataCacheMode(), value.getMetadataCacheMode());
assertEquals(expected.getMaxStaleness(), value.getMaxStaleness());
+ assertEquals(expected.getTimeZone(), value.getTimeZone());
+ assertEquals(expected.getDateFormat(), value.getDateFormat());
+ assertEquals(expected.getDatetimeFormat(), value.getDatetimeFormat());
+ assertEquals(expected.getTimeFormat(), value.getTimeFormat());
+ assertEquals(expected.getTimestampFormat(), value.getTimestampFormat());
+ assertEquals(expected.getSourceColumnMatch(), value.getSourceColumnMatch());
+ assertEquals(expected.getNullMarkers(), value.getNullMarkers());
}
}
diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/LoadJobConfigurationTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/LoadJobConfigurationTest.java
index 6d181a328..b1a2f1af8 100644
--- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/LoadJobConfigurationTest.java
+++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/LoadJobConfigurationTest.java
@@ -21,6 +21,7 @@
import com.google.cloud.bigquery.JobInfo.CreateDisposition;
import com.google.cloud.bigquery.JobInfo.SchemaUpdateOption;
import com.google.cloud.bigquery.JobInfo.WriteDisposition;
+import com.google.cloud.bigquery.LoadJobConfiguration.SourceColumnMatch;
import com.google.cloud.bigquery.TimePartitioning.Type;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -77,6 +78,13 @@ public class LoadJobConfigurationTest {
private static final String KEY = "session_id";
private static final String VALUE = "session_id_1234567890";
+ private static final String TIME_ZONE = "America/Los_Angeles";
+ private static final String DATE_FORMAT = "YYYY-MM-DD";
+ private static final String DATETIME_FORMAT = "YYYY-MM-DD HH:MI:SS";
+ private static final String TIME_FORMAT = "HH:MI:SS";
+ private static final String TIMESTAMP_FORMAT = "YYYY-MM-DD HH:MI:SS";
+ private static final SourceColumnMatch SOURCE_COLUMN_MATCH = SourceColumnMatch.POSITION;
+ private static final List NULL_MARKERS = ImmutableList.of("SQL NULL", "TEST MARKER");
private static final ConnectionProperty CONNECTION_PROPERTY =
ConnectionProperty.newBuilder().setKey(KEY).setValue(VALUE).build();
private static final List CONNECTION_PROPERTIES =
@@ -110,6 +118,13 @@ public class LoadJobConfigurationTest {
.setConnectionProperties(CONNECTION_PROPERTIES)
.setCreateSession(CREATE_SESSION)
.setReservation(RESERVATION)
+ .setTimeZone(TIME_ZONE)
+ .setDateFormat(DATE_FORMAT)
+ .setDatetimeFormat(DATETIME_FORMAT)
+ .setTimeFormat(TIME_FORMAT)
+ .setTimestampFormat(TIMESTAMP_FORMAT)
+ .setSourceColumnMatch(SOURCE_COLUMN_MATCH)
+ .setNullMarkers(NULL_MARKERS)
.build();
private static final DatastoreBackupOptions BACKUP_OPTIONS =
@@ -271,5 +286,12 @@ private void compareLoadJobConfiguration(
assertEquals(expected.getConnectionProperties(), value.getConnectionProperties());
assertEquals(expected.getCreateSession(), value.getCreateSession());
assertEquals(expected.getReservation(), value.getReservation());
+ assertEquals(expected.getTimeZone(), value.getTimeZone());
+ assertEquals(expected.getDateFormat(), value.getDateFormat());
+ assertEquals(expected.getDatetimeFormat(), value.getDatetimeFormat());
+ assertEquals(expected.getTimeFormat(), value.getTimeFormat());
+ assertEquals(expected.getTimestampFormat(), value.getTimestampFormat());
+ assertEquals(expected.getSourceColumnMatch(), value.getSourceColumnMatch());
+ assertEquals(expected.getNullMarkers(), value.getNullMarkers());
}
}
From 8aabfa76ac8d55a6a3d49b76ac85abd011411fc6 Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Wed, 2 Jul 2025 15:54:42 +0200
Subject: [PATCH 10/16] chore(deps): update dependency
com.google.cloud:libraries-bom to v26.63.0 (#3874)
---
samples/snippets/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index 8b1e77bd3..62c7f22ec 100644
--- a/samples/snippets/pom.xml
+++ b/samples/snippets/pom.xml
@@ -47,7 +47,7 @@
com.google.cloud
libraries-bom
- 26.62.0
+ 26.63.0
pom
import
From d2918da844cd20ca1602c6fcf9fa1df685f261fc Mon Sep 17 00:00:00 2001
From: Phong Chuong <147636638+PhongChuong@users.noreply.github.com>
Date: Fri, 4 Jul 2025 13:16:25 -0400
Subject: [PATCH 11/16] docs: update maven format command (#3877)
---
CONTRIBUTING.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 0599033d7..5456fad05 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -88,7 +88,7 @@ Code in this repo is formatted with
[google-java-format](https://github.com/google/google-java-format).
To run formatting on your project, you can run:
```
-mvn com.coveo:fmt-maven-plugin:format
+mvn com.spotify.fmt:fmt-maven-plugin:format
```
[1]: https://cloud.google.com/docs/authentication/getting-started#creating_a_service_account
From 0e971b8ace013caa31b8a02a21038e94bebae2a5 Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Wed, 9 Jul 2025 16:57:01 +0200
Subject: [PATCH 12/16] deps: update dependency
com.google.cloud:sdk-platform-java-config to v3.50.1 (#3878)
---
.github/workflows/unmanaged_dependency_check.yaml | 2 +-
.kokoro/continuous/graalvm-native-a.cfg | 2 +-
.kokoro/continuous/graalvm-native-b.cfg | 2 +-
.kokoro/continuous/graalvm-native-c.cfg | 2 +-
.kokoro/presubmit/graalvm-native-a.cfg | 2 +-
.kokoro/presubmit/graalvm-native-b.cfg | 2 +-
.kokoro/presubmit/graalvm-native-c.cfg | 2 +-
google-cloud-bigquery-bom/pom.xml | 2 +-
pom.xml | 2 +-
9 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/.github/workflows/unmanaged_dependency_check.yaml b/.github/workflows/unmanaged_dependency_check.yaml
index 63543a40f..1795d3b24 100644
--- a/.github/workflows/unmanaged_dependency_check.yaml
+++ b/.github/workflows/unmanaged_dependency_check.yaml
@@ -17,7 +17,7 @@ jobs:
# repository
.kokoro/build.sh
- name: Unmanaged dependency check
- uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@google-cloud-shared-dependencies/v3.50.0
+ uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@google-cloud-shared-dependencies/v3.50.1
with:
# java-bigquery does not produce a BOM. Fortunately the root pom.xml
# defines google-cloud-bigquery in dependencyManagement section. So
diff --git a/.kokoro/continuous/graalvm-native-a.cfg b/.kokoro/continuous/graalvm-native-a.cfg
index dfa34060b..13d12ce34 100644
--- a/.kokoro/continuous/graalvm-native-a.cfg
+++ b/.kokoro/continuous/graalvm-native-a.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.50.0"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.50.1"
}
env_vars: {
diff --git a/.kokoro/continuous/graalvm-native-b.cfg b/.kokoro/continuous/graalvm-native-b.cfg
index 37dda4ab5..4696d04ef 100644
--- a/.kokoro/continuous/graalvm-native-b.cfg
+++ b/.kokoro/continuous/graalvm-native-b.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.50.0"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.50.1"
}
env_vars: {
diff --git a/.kokoro/continuous/graalvm-native-c.cfg b/.kokoro/continuous/graalvm-native-c.cfg
index a8ab97784..26d39a747 100644
--- a/.kokoro/continuous/graalvm-native-c.cfg
+++ b/.kokoro/continuous/graalvm-native-c.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_c:3.50.0"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_c:3.50.1"
}
env_vars: {
diff --git a/.kokoro/presubmit/graalvm-native-a.cfg b/.kokoro/presubmit/graalvm-native-a.cfg
index dfa34060b..13d12ce34 100644
--- a/.kokoro/presubmit/graalvm-native-a.cfg
+++ b/.kokoro/presubmit/graalvm-native-a.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.50.0"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.50.1"
}
env_vars: {
diff --git a/.kokoro/presubmit/graalvm-native-b.cfg b/.kokoro/presubmit/graalvm-native-b.cfg
index 37dda4ab5..4696d04ef 100644
--- a/.kokoro/presubmit/graalvm-native-b.cfg
+++ b/.kokoro/presubmit/graalvm-native-b.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.50.0"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.50.1"
}
env_vars: {
diff --git a/.kokoro/presubmit/graalvm-native-c.cfg b/.kokoro/presubmit/graalvm-native-c.cfg
index a8ab97784..26d39a747 100644
--- a/.kokoro/presubmit/graalvm-native-c.cfg
+++ b/.kokoro/presubmit/graalvm-native-c.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_c:3.50.0"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_c:3.50.1"
}
env_vars: {
diff --git a/google-cloud-bigquery-bom/pom.xml b/google-cloud-bigquery-bom/pom.xml
index 1194e1b0e..8af53ddad 100644
--- a/google-cloud-bigquery-bom/pom.xml
+++ b/google-cloud-bigquery-bom/pom.xml
@@ -8,7 +8,7 @@
com.google.cloud
sdk-platform-java-config
- 3.50.0
+ 3.50.1
diff --git a/pom.xml b/pom.xml
index 433cb320c..5c10cf019 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,7 +14,7 @@
com.google.cloud
sdk-platform-java-config
- 3.50.0
+ 3.50.1
From 5cfdf855fa0cf206660fd89743cbaabf3afa75a3 Mon Sep 17 00:00:00 2001
From: Phong Chuong <147636638+PhongChuong@users.noreply.github.com>
Date: Wed, 9 Jul 2025 21:01:49 -0400
Subject: [PATCH 13/16] fix: load jobs preserve ascii control characters
configuration (#3876)
* fix: load jobs preserve ascii control characters configuration
* fix lint
* fix NPE
* fix NPE
---
.../cloud/bigquery/LoadJobConfiguration.java | 6 ++++
.../bigquery/LoadJobConfigurationTest.java | 1 +
.../cloud/bigquery/it/ITBigQueryTest.java | 29 +++++++++++++++++--
3 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/LoadJobConfiguration.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/LoadJobConfiguration.java
index 0d1eb7245..381942cd0 100644
--- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/LoadJobConfiguration.java
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/LoadJobConfiguration.java
@@ -219,6 +219,7 @@ private Builder(com.google.api.services.bigquery.model.JobConfiguration configur
this.nullMarker = loadConfigurationPb.getNullMarker();
}
if (loadConfigurationPb.getAllowJaggedRows() != null
+ || loadConfigurationPb.getPreserveAsciiControlCharacters() != null
|| loadConfigurationPb.getAllowQuotedNewlines() != null
|| loadConfigurationPb.getEncoding() != null
|| loadConfigurationPb.getFieldDelimiter() != null
@@ -229,6 +230,10 @@ private Builder(com.google.api.services.bigquery.model.JobConfiguration configur
.setEncoding(loadConfigurationPb.getEncoding())
.setFieldDelimiter(loadConfigurationPb.getFieldDelimiter())
.setQuote(loadConfigurationPb.getQuote());
+ if (loadConfigurationPb.getPreserveAsciiControlCharacters() != null) {
+ builder.setPreserveAsciiControlCharacters(
+ loadConfigurationPb.getPreserveAsciiControlCharacters());
+ }
if (loadConfigurationPb.getAllowJaggedRows() != null) {
builder.setAllowJaggedRows(loadConfigurationPb.getAllowJaggedRows());
}
@@ -907,6 +912,7 @@ com.google.api.services.bigquery.model.JobConfiguration toPb() {
.setAllowJaggedRows(csvOptions.allowJaggedRows())
.setAllowQuotedNewlines(csvOptions.allowQuotedNewLines())
.setEncoding(csvOptions.getEncoding())
+ .setPreserveAsciiControlCharacters(csvOptions.getPreserveAsciiControlCharacters())
.setQuote(csvOptions.getQuote());
if (csvOptions.getSkipLeadingRows() != null) {
// todo(mziccard) remove checked cast or comment when #1044 is closed
diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/LoadJobConfigurationTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/LoadJobConfigurationTest.java
index b1a2f1af8..d987eb28e 100644
--- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/LoadJobConfigurationTest.java
+++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/LoadJobConfigurationTest.java
@@ -38,6 +38,7 @@ public class LoadJobConfigurationTest {
.setAllowJaggedRows(true)
.setAllowQuotedNewLines(false)
.setEncoding(StandardCharsets.UTF_8)
+ .setPreserveAsciiControlCharacters(true)
.build();
private static final TableId TABLE_ID = TableId.of("dataset", "table");
private static final CreateDisposition CREATE_DISPOSITION = CreateDisposition.CREATE_IF_NEEDED;
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 f188e7946..c9f6296cc 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
@@ -613,6 +613,7 @@ public class ITBigQueryTest {
private static final String LOAD_FILE_LARGE = "load_large.csv";
private static final String LOAD_FILE_FLEXIBLE_COLUMN_NAME = "load_flexible_column_name.csv";
+ private static final String LOAD_FILE_NULL = "load_null.csv";
private static final String JSON_LOAD_FILE = "load.json";
private static final String JSON_LOAD_FILE_BQ_RESULTSET = "load_bq_resultset.json";
private static final String JSON_LOAD_FILE_SIMPLE = "load_simple.json";
@@ -628,6 +629,7 @@ public class ITBigQueryTest {
private static final TableId TABLE_ID_FASTQUERY_BQ_RESULTSET =
TableId.of(DATASET, "fastquery_testing_bq_resultset");
private static final String CSV_CONTENT = "StringValue1\nStringValue2\n";
+ private static final String CSV_CONTENT_NULL = "String\0Value1\n";
private static final String CSV_CONTENT_FLEXIBLE_COLUMN = "name,&ersand\nrow_name,1";
private static final String JSON_CONTENT =
@@ -1080,6 +1082,9 @@ public static void beforeClass() throws InterruptedException, IOException {
storage.create(
BlobInfo.newBuilder(BUCKET, LOAD_FILE).setContentType("text/plain").build(),
CSV_CONTENT.getBytes(StandardCharsets.UTF_8));
+ storage.create(
+ BlobInfo.newBuilder(BUCKET, LOAD_FILE_NULL).setContentType("text/plain").build(),
+ CSV_CONTENT_NULL.getBytes(StandardCharsets.UTF_8));
storage.create(
BlobInfo.newBuilder(BUCKET, LOAD_FILE_FLEXIBLE_COLUMN_NAME)
.setContentType("text/plain")
@@ -6600,9 +6605,9 @@ public void testLocation() throws Exception {
}
@Test
- public void testPreserveAsciiControlCharacters()
+ public void testWriteChannelPreserveAsciiControlCharacters()
throws InterruptedException, IOException, TimeoutException {
- String destinationTableName = "test_preserve_ascii_control_characters";
+ String destinationTableName = "test_write_channel_preserve_ascii_control_characters";
TableId tableId = TableId.of(DATASET, destinationTableName);
WriteChannelConfiguration configuration =
WriteChannelConfiguration.newBuilder(tableId)
@@ -6625,6 +6630,26 @@ public void testPreserveAsciiControlCharacters()
assertTrue(bigquery.delete(tableId));
}
+ @Test
+ public void testLoadJobPreserveAsciiControlCharacters() throws InterruptedException {
+ String destinationTableName = "test_load_job_preserve_ascii_control_characters";
+ TableId destinationTable = TableId.of(DATASET, destinationTableName);
+
+ try {
+ LoadJobConfiguration configuration =
+ LoadJobConfiguration.newBuilder(destinationTable, "gs://" + BUCKET + "/" + LOAD_FILE_NULL)
+ .setFormatOptions(
+ CsvOptions.newBuilder().setPreserveAsciiControlCharacters(true).build())
+ .setSchema(SIMPLE_SCHEMA)
+ .build();
+ Job remoteLoadJob = bigquery.create(JobInfo.of(configuration));
+ remoteLoadJob = remoteLoadJob.waitFor();
+ assertNull(remoteLoadJob.getStatus().getError());
+ } finally {
+ assertTrue(bigquery.delete(destinationTable));
+ }
+ }
+
@Test
public void testReferenceFileSchemaUriForAvro() {
try {
From c47a062136fea4de91190cafb1f11bac6abbbe3a Mon Sep 17 00:00:00 2001
From: Jin Seop Kim
Date: Thu, 10 Jul 2025 11:38:38 -0700
Subject: [PATCH 14/16] feat: next release from main branch is 2.53.0 (#3879)
---
.github/release-please.yml | 4 ++++
.github/sync-repo-settings.yaml | 15 +++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/.github/release-please.yml b/.github/release-please.yml
index 48231f76e..d722d35a2 100644
--- a/.github/release-please.yml
+++ b/.github/release-please.yml
@@ -31,6 +31,10 @@ branches:
handleGHRelease: true
releaseType: java-backport
branch: 2.48.x
+ - bumpMinorPreMajor: true
+ handleGHRelease: true
+ releaseType: java-backport
+ branch: 2.52.x
bumpMinorPreMajor: true
handleGHRelease: true
releaseType: java-yoshi
diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml
index c3a3263dd..26f85cb16 100644
--- a/.github/sync-repo-settings.yaml
+++ b/.github/sync-repo-settings.yaml
@@ -132,6 +132,21 @@ branchProtectionRules:
- cla/google
- javadoc
- unmanaged_dependency_check
+ - pattern: 2.52.x
+ isAdminEnforced: true
+ requiredApprovingReviewCount: 1
+ requiresCodeOwnerReviews: true
+ requiresStrictStatusChecks: false
+ requiredStatusCheckContexts:
+ - dependencies (17)
+ - lint
+ - clirr
+ - units (8)
+ - units (11)
+ - 'Kokoro - Test: Integration'
+ - cla/google
+ - javadoc
+ - unmanaged_dependency_check
permissionRules:
- team: api-bigquery
permission: admin
From 3a17ec2c7e0e2f2c0960d07a92bc09cac9dc8ab7 Mon Sep 17 00:00:00 2001
From: Mend Renovate
Date: Mon, 14 Jul 2025 17:03:06 +0200
Subject: [PATCH 15/16] chore(deps): update dependency
com.google.cloud:google-cloud-bigquerystorage-bom to v3.16.0 (#3884)
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 5c10cf019..d44a03bef 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,7 +71,7 @@
com.google.cloud
google-cloud-bigquerystorage-bom
- 3.15.3
+ 3.16.0
pom
import
From ed331354e225d9340c6101b9e783a1b79eae2875 Mon Sep 17 00:00:00 2001
From: "release-please[bot]"
<55107282+release-please[bot]@users.noreply.github.com>
Date: Mon, 14 Jul 2025 12:59:52 -0400
Subject: [PATCH 16/16] chore(main): release 2.53.0 (#3866)
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
---
CHANGELOG.md | 26 ++++++++++++++++++++++++++
benchmark/pom.xml | 2 +-
google-cloud-bigquery-bom/pom.xml | 4 ++--
google-cloud-bigquery/pom.xml | 4 ++--
pom.xml | 4 ++--
samples/snapshot/pom.xml | 2 +-
versions.txt | 2 +-
7 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 71577758b..9336a4195 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,31 @@
# Changelog
+## [2.53.0](https://github.com/googleapis/java-bigquery/compare/v2.52.0...v2.53.0) (2025-07-14)
+
+
+### Features
+
+* **bigquery:** Add OpenTelemetry support to BQ rpcs ([#3860](https://github.com/googleapis/java-bigquery/issues/3860)) ([e2d23c1](https://github.com/googleapis/java-bigquery/commit/e2d23c1b15f2c48a4113f82b920f5c29c4b5dfea))
+* **bigquery:** Add support for custom timezones and timestamps ([#3859](https://github.com/googleapis/java-bigquery/issues/3859)) ([e5467c9](https://github.com/googleapis/java-bigquery/commit/e5467c917c63ac066edcbcd902cc2093a39971a3))
+* Next release from main branch is 2.53.0 ([#3879](https://github.com/googleapis/java-bigquery/issues/3879)) ([c47a062](https://github.com/googleapis/java-bigquery/commit/c47a062136fea4de91190cafb1f11bac6abbbe3a))
+
+
+### Bug Fixes
+
+* Load jobs preserve ascii control characters configuration ([#3876](https://github.com/googleapis/java-bigquery/issues/3876)) ([5cfdf85](https://github.com/googleapis/java-bigquery/commit/5cfdf855fa0cf206660fd89743cbaabf3afa75a3))
+
+
+### Dependencies
+
+* Update dependency com.google.api.grpc:proto-google-cloud-bigqueryconnection-v1 to v2.69.0 ([#3870](https://github.com/googleapis/java-bigquery/issues/3870)) ([a7f1007](https://github.com/googleapis/java-bigquery/commit/a7f1007b5242da2c0adebbb309a908d7d4db5974))
+* Update dependency com.google.apis:google-api-services-bigquery to v2-rev20250615-2.0.0 ([#3872](https://github.com/googleapis/java-bigquery/issues/3872)) ([f081589](https://github.com/googleapis/java-bigquery/commit/f08158955b7fec3c2ced6332b6e4d76cc13f2e90))
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.50.1 ([#3878](https://github.com/googleapis/java-bigquery/issues/3878)) ([0e971b8](https://github.com/googleapis/java-bigquery/commit/0e971b8ace013caa31b8a02a21038e94bebae2a5))
+
+
+### Documentation
+
+* Update maven format command ([#3877](https://github.com/googleapis/java-bigquery/issues/3877)) ([d2918da](https://github.com/googleapis/java-bigquery/commit/d2918da844cd20ca1602c6fcf9fa1df685f261fc))
+
## [2.52.0](https://github.com/googleapis/java-bigquery/compare/v2.51.0...v2.52.0) (2025-06-25)
diff --git a/benchmark/pom.xml b/benchmark/pom.xml
index 8fcf7ca00..8674b7102 100644
--- a/benchmark/pom.xml
+++ b/benchmark/pom.xml
@@ -6,7 +6,7 @@
google-cloud-bigquery-parent
com.google.cloud
- 2.52.1-SNAPSHOT
+ 2.53.0
diff --git a/google-cloud-bigquery-bom/pom.xml b/google-cloud-bigquery-bom/pom.xml
index 8af53ddad..bc3a9e0c3 100644
--- a/google-cloud-bigquery-bom/pom.xml
+++ b/google-cloud-bigquery-bom/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.google.cloud
google-cloud-bigquery-bom
- 2.52.1-SNAPSHOT
+ 2.53.0
pom
com.google.cloud
@@ -54,7 +54,7 @@
com.google.cloud
google-cloud-bigquery
- 2.52.1-SNAPSHOT
+ 2.53.0
diff --git a/google-cloud-bigquery/pom.xml b/google-cloud-bigquery/pom.xml
index 6c7e1aed1..ad20f607e 100644
--- a/google-cloud-bigquery/pom.xml
+++ b/google-cloud-bigquery/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.google.cloud
google-cloud-bigquery
- 2.52.1-SNAPSHOT
+ 2.53.0
jar
BigQuery
https://github.com/googleapis/java-bigquery
@@ -11,7 +11,7 @@
com.google.cloud
google-cloud-bigquery-parent
- 2.52.1-SNAPSHOT
+ 2.53.0
google-cloud-bigquery
diff --git a/pom.xml b/pom.xml
index d44a03bef..4bc7652ba 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.google.cloud
google-cloud-bigquery-parent
pom
- 2.52.1-SNAPSHOT
+ 2.53.0
BigQuery Parent
https://github.com/googleapis/java-bigquery
@@ -93,7 +93,7 @@
com.google.cloud
google-cloud-bigquery
- 2.52.1-SNAPSHOT
+ 2.53.0
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index d9d52314b..7e1bfd314 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -44,7 +44,7 @@
com.google.cloud
google-cloud-bigquery
- 2.52.1-SNAPSHOT
+ 2.53.0
diff --git a/versions.txt b/versions.txt
index 5e931b82a..5245c445b 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,4 +1,4 @@
# Format:
# module:released-version:current-version
-google-cloud-bigquery:2.52.0:2.52.1-SNAPSHOT
\ No newline at end of file
+google-cloud-bigquery:2.53.0:2.53.0
\ No newline at end of file