From d41451df1de4a272a0ea3eb709ac39de5f2d4951 Mon Sep 17 00:00:00 2001 From: Keshav Dandeva Date: Wed, 9 Sep 2026 17:50:43 +0000 Subject: [PATCH 1/2] feat(bigquery-jdbc): support picosecond in REST JSON path and nested types --- .../bigquery/jdbc/BigQueryArrowResultSet.java | 1 + .../bigquery/jdbc/BigQueryJsonArray.java | 53 ++++- .../bigquery/jdbc/BigQueryJsonResultSet.java | 89 +++++++-- .../bigquery/jdbc/BigQueryJsonStruct.java | 35 +++- .../jdbc/BigQueryJdbcCustomLoggerTest.java | 10 +- .../BigQueryJsonArrayOfPrimitivesTest.java | 75 +++++++ .../jdbc/BigQueryJsonResultSetTest.java | 189 +++++++++++++++++- .../bigquery/jdbc/BigQueryJsonStructTest.java | 37 ++++ .../jdbc/BigQueryResultSetMetadataTest.java | 2 +- 9 files changed, 456 insertions(+), 35 deletions(-) diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryArrowResultSet.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryArrowResultSet.java index f76cfaba4d5e..68d857c4a516 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryArrowResultSet.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryArrowResultSet.java @@ -363,6 +363,7 @@ private Object getObjectInternal(int columnIndex) throws SQLException { return value; } + @Override public Object getObject(int columnIndex) throws SQLException { diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArray.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArray.java index 029a36e73c5b..cd28db97bb20 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArray.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArray.java @@ -33,14 +33,20 @@ class BigQueryJsonArray extends BigQueryBaseArray { private List values; + private final boolean enableTimestampPicos; BigQueryJsonArray(Field schema, FieldValue values) { - this(schema, values, BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonArray.class)); + this(schema, values, BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonArray.class), false); } - BigQueryJsonArray(Field schema, FieldValue values, BigQueryJdbcResultSetLogger log) { + BigQueryJsonArray( + Field schema, + FieldValue values, + BigQueryJdbcResultSetLogger log, + boolean enableTimestampPicos) { super(schema, log); this.values = (values == null || values.isNull()) ? null : values.getRepeatedValue(); + this.enableTimestampPicos = enableTimestampPicos; } @Override @@ -74,7 +80,11 @@ public ResultSet getResultSet() { BigQueryFieldValueListWrapper bigQueryFieldValueListWrapper = getNestedFieldValueListWrapper(FieldList.of(singleElementSchema()), this.values); return BigQueryJsonResultSet.getNestedResultSet( - Schema.of(this.schema), bigQueryFieldValueListWrapper, 0, this.values.size()); + Schema.of(this.schema), + bigQueryFieldValueListWrapper, + 0, + this.values.size(), + this.enableTimestampPicos); } @Override @@ -88,7 +98,11 @@ public ResultSet getResultSet(long index, int count) { BigQueryFieldValueListWrapper bigQueryFieldValueListWrapper = getNestedFieldValueListWrapper(FieldList.of(singleElementSchema()), this.values); return BigQueryJsonResultSet.getNestedResultSet( - Schema.of(this.schema), bigQueryFieldValueListWrapper, range.x(), range.y()); + Schema.of(this.schema), + bigQueryFieldValueListWrapper, + range.x(), + range.y(), + this.enableTimestampPicos); } @Override @@ -97,12 +111,35 @@ public void free() { markInvalid(); } + @Override + protected Class getTargetClass() { + LOG.finestTrace("getTargetClass"); + if (this.enableTimestampPicos && BigQueryTemporalUtility.isPicosecondTimestamp(this.schema)) { + return String.class; + } + return super.getTargetClass(); + } + @Override Object getCoercedValue(int index) throws SQLException { + LOG.finestTrace("getCoercedValue"); FieldValue fieldValue = this.values.get(index); - return this.arrayOfStruct - ? new BigQueryJsonStruct( - this.schema.getSubFields(), fieldValue, this.LOG.getJsonStructLogger()) - : BigQueryTypeRegistry.convert(fieldValue, this.schema.getType().getStandardType(), null); + if (fieldValue == null || fieldValue.isNull()) { + return null; + } + if (this.arrayOfStruct) { + return new BigQueryJsonStruct( + this.schema.getSubFields(), + fieldValue, + this.LOG.getJsonStructLogger(), + this.enableTimestampPicos); + } + if (this.enableTimestampPicos && BigQueryTemporalUtility.isPicosecondTimestamp(this.schema)) { + return BigQueryTemporalUtility.formatTimestampValue(fieldValue.getStringValue(), true); + } + if (this.enableTimestampPicos && BigQueryJsonResultSet.isRangeTimestamp(this.schema)) { + return BigQueryJsonResultSet.formatRangeTimestamp(fieldValue); + } + return BigQueryTypeRegistry.convert(fieldValue, this.schema.getType().getStandardType(), null); } } diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonResultSet.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonResultSet.java index e08b87751fbb..4b8d52cb1364 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonResultSet.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonResultSet.java @@ -24,7 +24,9 @@ import com.google.cloud.bigquery.FieldValue; import com.google.cloud.bigquery.FieldValue.Attribute; import com.google.cloud.bigquery.Job; +import com.google.cloud.bigquery.Range; import com.google.cloud.bigquery.Schema; +import com.google.cloud.bigquery.StandardSQLTypeName; import com.google.cloud.bigquery.exception.BigQueryJdbcRuntimeException; import java.sql.ResultSet; import java.sql.SQLException; @@ -45,6 +47,7 @@ class BigQueryJsonResultSet extends BigQueryBaseResultSet { private final int fromIndex; private final int toIndexExclusive; private final Future[] ownedTasks; + private final boolean enableTimestampPicos; private BigQueryJsonResultSet( Schema schema, @@ -57,7 +60,8 @@ private BigQueryJsonResultSet( int toIndexExclusive, Future[] ownedTasks, BigQuery bigQuery, - Job job) { + Job job, + boolean enableTimestampPicos) { super(bigQuery, statement, schema, isNested, job); this.totalRows = totalRows; this.buffer = buffer; @@ -66,6 +70,8 @@ private BigQueryJsonResultSet( this.toIndexExclusive = toIndexExclusive; this.nestedRowIndex = fromIndex - 1; this.ownedTasks = ownedTasks; + this.enableTimestampPicos = + statement != null ? statement.isEnableTimestampPicos() : enableTimestampPicos; } /** @@ -95,7 +101,18 @@ static BigQueryJsonResultSet of( Job job) { return new BigQueryJsonResultSet( - schema, totalRows, buffer, statement, false, null, -1, -1, ownedTasks, bigQuery, job); + schema, + totalRows, + buffer, + statement, + false, + null, + -1, + -1, + ownedTasks, + bigQuery, + job, + false); } static BigQueryJsonResultSet of( @@ -106,7 +123,7 @@ static BigQueryJsonResultSet of( Future[] ownedTasks) { return new BigQueryJsonResultSet( - schema, totalRows, buffer, statement, false, null, -1, -1, ownedTasks, null, null); + schema, totalRows, buffer, statement, false, null, -1, -1, ownedTasks, null, null, false); } static BigQueryJsonResultSet of( @@ -133,6 +150,7 @@ static BigQueryJsonResultSet of( fromIndex = 0; ownedTasks = new Future[0]; toIndexExclusive = 0; + this.enableTimestampPicos = false; } // @@ -145,10 +163,15 @@ static BigQueryJsonResultSet of( * @param cursor Points to the current record * @param fromIndex starting index under consideration * @param toIndexExclusive last index under consideration + * @param enableTimestampPicos whether picosecond timestamp precision is enabled * @return The BigQueryJsonResultSet */ static BigQueryJsonResultSet getNestedResultSet( - Schema schema, BigQueryFieldValueListWrapper cursor, int fromIndex, int toIndexExclusive) { + Schema schema, + BigQueryFieldValueListWrapper cursor, + int fromIndex, + int toIndexExclusive, + boolean enableTimestampPicos) { return new BigQueryJsonResultSet( schema, -1, @@ -160,7 +183,8 @@ static BigQueryJsonResultSet getNestedResultSet( toIndexExclusive, null, null, - null); + null, + enableTimestampPicos); } /* Advances the result set to the next row, returning false if no such row exists. Potentially blocking operation */ @@ -232,21 +256,60 @@ public Object getObject(int columnIndex) throws SQLException { Field arrayField = this.schema.getFields().get(0); if (isStruct(arrayField)) { return new BigQueryJsonStruct( - arrayField.getSubFields(), value, this.LOG.getJsonStructLogger()); + arrayField.getSubFields(), + value, + this.LOG.getJsonStructLogger(), + this.enableTimestampPicos); + } + if (this.enableTimestampPicos && BigQueryTemporalUtility.isPicosecondTimestamp(arrayField)) { + return BigQueryTemporalUtility.formatTimestampValue(value.getStringValue(), true); + } + if (this.enableTimestampPicos && isRangeTimestamp(arrayField)) { + return formatRangeTimestamp(value); } return BigQueryTypeRegistry.convert(value, arrayField.getType().getStandardType(), null); } - int extraIndex = this.isNested ? 2 : 1; - Field fieldSchema = this.schemaFieldList.get(columnIndex - extraIndex); + Field fieldSchema = this.schemaFieldList.get(columnIndex - 1); if (isArray(fieldSchema)) { - return new BigQueryJsonArray(fieldSchema, value, this.LOG.getJsonArrayLogger()); - } else if (isStruct(fieldSchema)) { + return new BigQueryJsonArray( + fieldSchema, value, this.LOG.getJsonArrayLogger(), this.enableTimestampPicos); + } + if (isStruct(fieldSchema)) { return new BigQueryJsonStruct( - fieldSchema.getSubFields(), value, this.LOG.getJsonStructLogger()); - } else { - return BigQueryTypeRegistry.convert(value, fieldSchema.getType().getStandardType(), null); + fieldSchema.getSubFields(), + value, + this.LOG.getJsonStructLogger(), + this.enableTimestampPicos); + } + if (this.enableTimestampPicos && isRangeTimestamp(fieldSchema)) { + return formatRangeTimestamp(value); } + if (this.enableTimestampPicos && BigQueryTemporalUtility.isPicosecondTimestamp(fieldSchema)) { + return BigQueryTemporalUtility.formatTimestampValue(value.getStringValue(), true); + } + return BigQueryTypeRegistry.convert(value, fieldSchema.getType().getStandardType(), null); + } + + static String formatRangeTimestamp(FieldValue value) throws SQLException { + Range range = value.getRangeValue(); + String start = + range.getStart().isNull() + ? "UNBOUNDED" + : BigQueryTemporalUtility.formatTimestampValue(range.getStart().getStringValue(), true); + String end = + range.getEnd().isNull() + ? "UNBOUNDED" + : BigQueryTemporalUtility.formatTimestampValue(range.getEnd().getStringValue(), true); + return String.format("[%s, %s)", start, end); + } + + static boolean isRangeTimestamp(Field field) { + return field != null + && field.getRangeElementType() != null + && StandardSQLTypeName.TIMESTAMP + .name() + .equalsIgnoreCase(field.getRangeElementType().getType()); } /** diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStruct.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStruct.java index c8129f41b88b..59c3d21a50ef 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStruct.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStruct.java @@ -34,15 +34,21 @@ class BigQueryJsonStruct extends BigQueryBaseStruct { private final FieldList schema; private final List values; + private final boolean enableTimestampPicos; public BigQueryJsonStruct(FieldList schema, FieldValue values) { - this(schema, values, BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonStruct.class)); + this(schema, values, BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonStruct.class), false); } - public BigQueryJsonStruct(FieldList schema, FieldValue values, BigQueryJdbcResultSetLogger log) { + public BigQueryJsonStruct( + FieldList schema, + FieldValue values, + BigQueryJdbcResultSetLogger log, + boolean enableTimestampPicos) { super(log); this.schema = schema; this.values = (values == null || values.isNull()) ? null : values.getRecordValue(); + this.enableTimestampPicos = enableTimestampPicos; } @Override @@ -67,14 +73,27 @@ public Object[] getAttributes() throws SQLException { private Object getValue(Field currentSchema, FieldValue currentValue) throws SQLException { LOG.finestTrace("getValue"); + if (currentValue == null || currentValue.isNull()) { + return null; + } if (isArray(currentSchema)) { - return new BigQueryJsonArray(currentSchema, currentValue, this.LOG.getJsonArrayLogger()); - } else if (isStruct(currentSchema)) { + return new BigQueryJsonArray( + currentSchema, currentValue, this.LOG.getJsonArrayLogger(), this.enableTimestampPicos); + } + if (isStruct(currentSchema)) { return new BigQueryJsonStruct( - currentSchema.getSubFields(), currentValue, this.LOG.getJsonStructLogger()); - } else { - return BigQueryTypeRegistry.convert( - currentValue, currentSchema.getType().getStandardType(), null); + currentSchema.getSubFields(), + currentValue, + this.LOG.getJsonStructLogger(), + this.enableTimestampPicos); + } + if (this.enableTimestampPicos && BigQueryTemporalUtility.isPicosecondTimestamp(currentSchema)) { + return BigQueryTemporalUtility.formatTimestampValue(currentValue.getStringValue(), true); + } + if (this.enableTimestampPicos && BigQueryJsonResultSet.isRangeTimestamp(currentSchema)) { + return BigQueryJsonResultSet.formatRangeTimestamp(currentValue); } + return BigQueryTypeRegistry.convert( + currentValue, currentSchema.getType().getStandardType(), null); } } diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLoggerTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLoggerTest.java index 7ce5e6fba529..c75f66fa11bd 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLoggerTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLoggerTest.java @@ -486,7 +486,7 @@ public void testJsonArrayConnectionIdPropagation() { Attribute.REPEATED, FieldValueList.of( Collections.singletonList(FieldValue.of(Attribute.PRIMITIVE, "123")))); - BigQueryJsonArray array = new BigQueryJsonArray(arraySchema, arrayValue, logger); + BigQueryJsonArray array = new BigQueryJsonArray(arraySchema, arrayValue, logger, false); assertConnectionIdPropagated( logger, connectionId, "Log from JSON Array", () -> array.LOG.fine("Log from JSON Array")); @@ -504,7 +504,8 @@ public void testJsonStructConnectionIdPropagation() { Attribute.RECORD, FieldValueList.of( Collections.singletonList(FieldValue.of(Attribute.PRIMITIVE, "456")))); - BigQueryJsonStruct struct = new BigQueryJsonStruct(structSchema, structValue, structLogger); + BigQueryJsonStruct struct = + new BigQueryJsonStruct(structSchema, structValue, structLogger, false); assertConnectionIdPropagated( structLogger, @@ -531,7 +532,8 @@ public void testNestedStructInJsonArrayConnectionIdPropagation() throws Exceptio Collections.singletonList(FieldValue.of(Attribute.PRIMITIVE, "789")))); FieldValue listVal = FieldValue.of(Attribute.REPEATED, FieldValueList.of(Collections.singletonList(recordVal))); - BigQueryJsonArray arrayWithNested = new BigQueryJsonArray(arrayNestedSchema, listVal, logger); + BigQueryJsonArray arrayWithNested = + new BigQueryJsonArray(arrayNestedSchema, listVal, logger, false); Object[] result = (Object[]) arrayWithNested.getArray(); BigQueryJsonStruct nestedStruct = (BigQueryJsonStruct) result[0]; @@ -565,7 +567,7 @@ public void testNestedArrayInJsonStructConnectionIdPropagation() throws Exceptio FieldValue.of(Attribute.RECORD, FieldValueList.of(Collections.singletonList(arrayVal))); BigQueryJsonStruct structWithNestedArray = - new BigQueryJsonStruct(nestedSchema, rootVal, structLogger); + new BigQueryJsonStruct(nestedSchema, rootVal, structLogger, false); Object[] attributes = structWithNestedArray.getAttributes(); BigQueryJsonArray nestedArray = (BigQueryJsonArray) attributes[0]; diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArrayOfPrimitivesTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArrayOfPrimitivesTest.java index 30a66a2bf5fd..b4f153973d98 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArrayOfPrimitivesTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArrayOfPrimitivesTest.java @@ -41,6 +41,7 @@ import com.google.cloud.Tuple; import com.google.cloud.bigquery.Field; import com.google.cloud.bigquery.FieldValue; +import com.google.cloud.bigquery.FieldValueList; import com.google.cloud.bigquery.StandardSQLTypeName; import com.google.cloud.bigquery.jdbc.rules.TimeZoneRule; import com.google.common.io.BaseEncoding; @@ -59,8 +60,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.function.Executable; import org.junit.jupiter.params.ParameterizedTest; @@ -383,4 +386,76 @@ private void ensureArrayIsInvalid(Executable block) { Exception exception = assertThrows(IllegalStateException.class, block); assertThat(exception.getMessage()).isEqualTo(INVALID_ARRAY); } + + @Test + public void testJsonArrayTimestampPicosEnabled() throws SQLException { + Field field = + Field.newBuilder("picosArray", StandardSQLTypeName.TIMESTAMP) + .setMode(Field.Mode.REPEATED) + .setTimestampPrecision(12L) + .build(); + FieldValue val1 = FieldValue.of(FieldValue.Attribute.PRIMITIVE, "1680174859.123456789123"); + FieldValue val2 = + FieldValue.of(FieldValue.Attribute.PRIMITIVE, "2026-04-08T11:00:00.987654321012Z"); + FieldValue arrayValue = + FieldValue.of(FieldValue.Attribute.REPEATED, FieldValueList.of(Arrays.asList(val1, val2))); + + BigQueryJsonArray array = + new BigQueryJsonArray( + field, + arrayValue, + BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonArray.class), + true); + + assertThat(array.getBaseTypeName()).isEqualTo("TIMESTAMP"); + assertThat(array.getBaseType()).isEqualTo(Types.TIMESTAMP); + + Object result = array.getArray(); + assertThat(result).isInstanceOf(String[].class); + assertThat((String[]) result) + .asList() + .containsExactly("2023-03-30 11:14:19.123456789123", "2026-04-08 11:00:00.987654321012") + .inOrder(); + + ResultSet rs = array.getResultSet(); + assertThat(rs.next()).isTrue(); + assertThat(rs.getInt(1)).isEqualTo(1); + assertThat(rs.getString(2)).isEqualTo("2023-03-30 11:14:19.123456789123"); + assertThat(rs.getObject(2)).isEqualTo("2023-03-30 11:14:19.123456789123"); + + assertThat(rs.next()).isTrue(); + assertThat(rs.getInt(1)).isEqualTo(2); + assertThat(rs.getString(2)).isEqualTo("2026-04-08 11:00:00.987654321012"); + assertThat(rs.getObject(2)).isEqualTo("2026-04-08 11:00:00.987654321012"); + } + + @Test + public void testJsonArrayTimestampPicosDisabled() throws SQLException { + Field field = + Field.newBuilder("picosArray", StandardSQLTypeName.TIMESTAMP) + .setMode(Field.Mode.REPEATED) + .setTimestampPrecision(12L) + .build(); + FieldValue val1 = FieldValue.of(FieldValue.Attribute.PRIMITIVE, "1680174859.123456789123"); + FieldValue arrayValue = + FieldValue.of( + FieldValue.Attribute.REPEATED, FieldValueList.of(Collections.singletonList(val1))); + + BigQueryJsonArray array = + new BigQueryJsonArray( + field, + arrayValue, + BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonArray.class), + false); + + Object result = array.getArray(); + assertThat(result).isInstanceOf(Timestamp[].class); + Timestamp expectedTs = Timestamp.valueOf("2023-03-30 11:14:19.123456789"); + assertThat((Timestamp[]) result).asList().containsExactly(expectedTs); + + ResultSet rs = array.getResultSet(); + assertThat(rs.next()).isTrue(); + assertThat(rs.getString(2)).isEqualTo("2023-03-30 11:14:19.123456"); + assertThat(rs.getObject(2)).isEqualTo(expectedTs); + } } diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonResultSetTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonResultSetTest.java index 06af37010d25..f44e42595a1b 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonResultSetTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonResultSetTest.java @@ -19,14 +19,17 @@ import static com.google.common.truth.Truth.assertThat; import static java.time.Month.MARCH; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import com.google.cloud.bigquery.Field; +import com.google.cloud.bigquery.FieldElementType; import com.google.cloud.bigquery.FieldList; import com.google.cloud.bigquery.FieldValue; import com.google.cloud.bigquery.FieldValue.Attribute; import com.google.cloud.bigquery.FieldValueList; import com.google.cloud.bigquery.LegacySQLTypeName; +import com.google.cloud.bigquery.Range; import com.google.cloud.bigquery.Schema; import com.google.cloud.bigquery.StandardSQLTypeName; import com.google.cloud.bigquery.jdbc.rules.TimeZoneRule; @@ -195,7 +198,8 @@ public void setUp() { Schema.of(fieldEight), bigQueryFieldValueListWrapperNested, 0, - fieldEightValue.getRepeatedValue().size()); + fieldEightValue.getRepeatedValue().size(), + false); } private boolean resetResultSet() @@ -513,4 +517,187 @@ private int resultSetRowCount(BigQueryJsonResultSet resultSet) throws SQLExcepti } return rowCount; } + + private BigQueryJsonResultSet createJsonResultSet( + FieldList schemaFields, FieldValueList values, boolean enableTimestampPicos) { + Schema schema = Schema.of(schemaFields); + boolean[] isComplex = BigQueryFieldValueListWrapper.createComplexColumnFlags(schemaFields); + BlockingQueue picosBuffer = new LinkedBlockingDeque<>(2); + picosBuffer.add(BigQueryFieldValueListWrapper.of(schemaFields, values, isComplex)); + picosBuffer.add(BigQueryFieldValueListWrapper.ofEndOfStream(null)); + BigQueryStatement stmt = mock(BigQueryStatement.class); + doReturn(enableTimestampPicos).when(stmt).isEnableTimestampPicos(); + return BigQueryJsonResultSet.of( + schema, 1L, picosBuffer, stmt, new Future[] {mock(Future.class)}); + } + + @Test + public void testTimestampPicosEnabledWithDecimalEpoch() throws SQLException { + Field picosField = + Field.newBuilder("picosTs", StandardSQLTypeName.TIMESTAMP) + .setTimestampPrecision(12L) + .build(); + FieldList fields = FieldList.of(picosField); + FieldValueList row = + FieldValueList.of( + ImmutableList.of(FieldValue.of(Attribute.PRIMITIVE, "1680174859.123456789123")), + fields); + BigQueryJsonResultSet rs = createJsonResultSet(fields, row, true); + assertThat(rs.next()).isTrue(); + assertThat(rs.getString("picosTs")).isEqualTo("2023-03-30 11:14:19.123456789123"); + assertThat(rs.getString(1)).isEqualTo("2023-03-30 11:14:19.123456789123"); + assertThat(rs.getObject("picosTs")).isEqualTo("2023-03-30 11:14:19.123456789123"); + assertThat(rs.getObject(1)).isEqualTo("2023-03-30 11:14:19.123456789123"); + assertThat(rs.getObject("picosTs", String.class)).isEqualTo("2023-03-30 11:14:19.123456789123"); + + Timestamp expectedTs = Timestamp.valueOf("2023-03-30 11:14:19.123456789"); + assertThat(rs.getTimestamp("picosTs")).isEqualTo(expectedTs); + assertThat(rs.getObject("picosTs", Timestamp.class)).isEqualTo(expectedTs); + } + + @Test + public void testTimestampPicosEnabledWithIsoString() throws SQLException { + Field picosField = + Field.newBuilder("picosTs", StandardSQLTypeName.TIMESTAMP) + .setTimestampPrecision(12L) + .build(); + FieldList fields = FieldList.of(picosField); + FieldValueList row = + FieldValueList.of( + ImmutableList.of( + FieldValue.of(Attribute.PRIMITIVE, "2026-04-08T10:00:00.123456789123Z")), + fields); + BigQueryJsonResultSet rs = createJsonResultSet(fields, row, true); + assertThat(rs.next()).isTrue(); + assertThat(rs.getString("picosTs")).isEqualTo("2026-04-08 10:00:00.123456789123"); + assertThat(rs.getObject("picosTs")).isEqualTo("2026-04-08 10:00:00.123456789123"); + assertThat(rs.getObject(1)).isEqualTo("2026-04-08 10:00:00.123456789123"); + } + + @Test + public void testTimestampPicosEnabledWithScientificNotation() throws SQLException { + Field picosField = + Field.newBuilder("picosTs", StandardSQLTypeName.TIMESTAMP) + .setTimestampPrecision(12L) + .build(); + FieldList fields = FieldList.of(picosField); + FieldValueList row = + FieldValueList.of( + ImmutableList.of(FieldValue.of(Attribute.PRIMITIVE, "1.6905474E9")), fields); + BigQueryJsonResultSet rs = createJsonResultSet(fields, row, true); + assertThat(rs.next()).isTrue(); + assertThat(rs.getString("picosTs")).isEqualTo("2023-07-28 12:30:00.000000000000"); + } + + @Test + public void testTimestampPicosEnabledWithNegativeEpoch() throws SQLException { + Field picosField = + Field.newBuilder("picosTs", StandardSQLTypeName.TIMESTAMP) + .setTimestampPrecision(12L) + .build(); + FieldList fields = FieldList.of(picosField); + FieldValueList row = + FieldValueList.of( + ImmutableList.of(FieldValue.of(Attribute.PRIMITIVE, "-0.123456789123")), fields); + BigQueryJsonResultSet rs = createJsonResultSet(fields, row, true); + assertThat(rs.next()).isTrue(); + assertThat(rs.getString("picosTs")).isEqualTo("1969-12-31 23:59:59.876543210877"); + } + + @Test + public void testTimestampPicosDisabledWith12DigitField() throws SQLException { + Field picosField = + Field.newBuilder("picosTs", StandardSQLTypeName.TIMESTAMP) + .setTimestampPrecision(12L) + .build(); + FieldList fields = FieldList.of(picosField); + FieldValueList row = + FieldValueList.of( + ImmutableList.of(FieldValue.of(Attribute.PRIMITIVE, "1680174859.123456789123")), + fields); + BigQueryJsonResultSet rs = createJsonResultSet(fields, row, false); + assertThat(rs.next()).isTrue(); + assertThat(rs.getString("picosTs")).isEqualTo("2023-03-30 11:14:19.123456"); + Timestamp expectedTs = Timestamp.valueOf("2023-03-30 11:14:19.123456789"); + assertThat(rs.getObject("picosTs")).isEqualTo(expectedTs); + assertThat(rs.getTimestamp("picosTs")).isEqualTo(expectedTs); + } + + @Test + public void testStandardTimestampWithPicosEnabled() throws SQLException { + Field stdField = Field.of("stdTs", StandardSQLTypeName.TIMESTAMP); + FieldList fields = FieldList.of(stdField); + FieldValueList row = + FieldValueList.of( + ImmutableList.of(FieldValue.of(Attribute.PRIMITIVE, "1680174859.820000")), fields); + BigQueryJsonResultSet rs = createJsonResultSet(fields, row, true); + assertThat(rs.next()).isTrue(); + assertThat(rs.getString("stdTs")).isEqualTo("2023-03-30 11:14:19.820000"); + Timestamp expectedTs = Timestamp.valueOf("2023-03-30 11:14:19.820"); + assertThat(rs.getObject("stdTs")).isEqualTo(expectedTs); + } + + @Test + public void testRangeTimestampPicosEnabled() throws SQLException { + Field rangeField = + Field.newBuilder("rangeTs", StandardSQLTypeName.RANGE) + .setRangeElementType(FieldElementType.newBuilder().setType("TIMESTAMP").build()) + .build(); + FieldList fields = FieldList.of(rangeField); + Range range = Range.of("[1680174859.123456789123, 1680174860.123456789123)"); + FieldValueList row = + FieldValueList.of(ImmutableList.of(FieldValue.of(Attribute.RANGE, range)), fields); + BigQueryJsonResultSet rs = createJsonResultSet(fields, row, true); + assertThat(rs.next()).isTrue(); + assertThat(rs.getString("rangeTs")) + .isEqualTo("[2023-03-30 11:14:19.123456789123, 2023-03-30 11:14:20.123456789123)"); + assertThat(rs.getObject("rangeTs")) + .isEqualTo("[2023-03-30 11:14:19.123456789123, 2023-03-30 11:14:20.123456789123)"); + } + + @Test + public void testRangeTimestampPicosDisabled() throws SQLException { + Field rangeField = + Field.newBuilder("rangeTs", StandardSQLTypeName.RANGE) + .setRangeElementType(FieldElementType.newBuilder().setType("TIMESTAMP").build()) + .build(); + FieldList fields = FieldList.of(rangeField); + Range range = Range.of("[1680174859.123456789123, 1680174860.123456789123)"); + FieldValueList row = + FieldValueList.of(ImmutableList.of(FieldValue.of(Attribute.RANGE, range)), fields); + BigQueryJsonResultSet rs = createJsonResultSet(fields, row, false); + assertThat(rs.next()).isTrue(); + assertThat(rs.getString("rangeTs")) + .isEqualTo("[1680174859.123456789123, 1680174860.123456789123)"); + } + + @Test + public void testRangeTimestampUnbounded() throws SQLException { + Field rangeField = + Field.newBuilder("rangeTs", StandardSQLTypeName.RANGE) + .setRangeElementType(FieldElementType.newBuilder().setType("TIMESTAMP").build()) + .build(); + FieldList fields = FieldList.of(rangeField); + Range range = Range.of("[UNBOUNDED, 1680174860.123456789123)"); + FieldValueList row = + FieldValueList.of(ImmutableList.of(FieldValue.of(Attribute.RANGE, range)), fields); + BigQueryJsonResultSet rs = createJsonResultSet(fields, row, true); + assertThat(rs.next()).isTrue(); + assertThat(rs.getString("rangeTs")).isEqualTo("[UNBOUNDED, 2023-03-30 11:14:20.123456789123)"); + } + + @Test + public void testRangeDate() throws SQLException { + Field rangeField = + Field.newBuilder("rangeDate", StandardSQLTypeName.RANGE) + .setRangeElementType(FieldElementType.newBuilder().setType("DATE").build()) + .build(); + FieldList fields = FieldList.of(rangeField); + Range range = Range.of("[2023-01-01, 2023-01-31)"); + FieldValueList row = + FieldValueList.of(ImmutableList.of(FieldValue.of(Attribute.RANGE, range)), fields); + BigQueryJsonResultSet rs = createJsonResultSet(fields, row, true); + assertThat(rs.next()).isTrue(); + assertThat(rs.getString("rangeDate")).isEqualTo("[2023-01-01, 2023-01-31)"); + } } diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStructTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStructTest.java index 5c8deeab85e3..58aa84e451ce 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStructTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStructTest.java @@ -258,4 +258,41 @@ public void getAttributesWithCustomTypeMappingsIsNotSupported() { () -> structWithPrimitiveValues.getAttributes(emptyMap())); assertThat(exception.getMessage()).isEqualTo(CUSTOMER_TYPE_MAPPING_NOT_SUPPORTED); } + + @Test + public void testJsonStructTimestampPicosEnabled() throws SQLException { + Field picosField = Field.newBuilder("picosTs", TIMESTAMP).setTimestampPrecision(12L).build(); + FieldList schema = FieldList.of(picosField); + FieldValue val = FieldValue.of(PRIMITIVE, "1680174859.123456789123"); + FieldValue structValue = FieldValue.of(RECORD, FieldValueList.of(asList(val))); + + BigQueryJsonStruct struct = + new BigQueryJsonStruct( + schema, + structValue, + BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonStruct.class), + true); + + Object[] attributes = struct.getAttributes(); + assertThat(attributes).isEqualTo(new Object[] {"2023-03-30 11:14:19.123456789123"}); + } + + @Test + public void testJsonStructTimestampPicosDisabled() throws SQLException { + Field picosField = Field.newBuilder("picosTs", TIMESTAMP).setTimestampPrecision(12L).build(); + FieldList schema = FieldList.of(picosField); + FieldValue val = FieldValue.of(PRIMITIVE, "1680174859.123456789123"); + FieldValue structValue = FieldValue.of(RECORD, FieldValueList.of(asList(val))); + + BigQueryJsonStruct struct = + new BigQueryJsonStruct( + schema, + structValue, + BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonStruct.class), + false); + + Object[] attributes = struct.getAttributes(); + Timestamp expectedTs = Timestamp.valueOf("2023-03-30 11:14:19.123456789"); + assertThat(attributes).isEqualTo(new Object[] {expectedTs}); + } } diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryResultSetMetadataTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryResultSetMetadataTest.java index 8261a14dc981..f124901ca80c 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryResultSetMetadataTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryResultSetMetadataTest.java @@ -100,7 +100,7 @@ public void setUp() throws SQLException { BigQueryFieldValueListWrapper.getNestedFieldValueListWrapper(nestedFieldList, null); BigQueryJsonResultSet bigQueryJsonResultSetNested = BigQueryJsonResultSet.getNestedResultSet( - Schema.of(nestedFieldList), bigQueryFieldValueListWrapperNested, -1, -1); + Schema.of(nestedFieldList), bigQueryFieldValueListWrapperNested, -1, -1, false); resultSetMetaDataNested = bigQueryJsonResultSetNested.getMetaData(); } From 48b38509273d44df6c9d0cede0bde3fa65debb96 Mon Sep 17 00:00:00 2001 From: Keshav Dandeva Date: Fri, 11 Sep 2026 14:56:34 +0000 Subject: [PATCH 2/2] refactor --- .../bigquery/jdbc/BigQueryArrowResultSet.java | 1 - .../bigquery/jdbc/BigQueryJsonArray.java | 23 ++++-------- .../bigquery/jdbc/BigQueryJsonResultSet.java | 36 ++++++++++++------- .../bigquery/jdbc/BigQueryJsonStruct.java | 16 ++++----- .../jdbc/BigQueryJdbcCustomLoggerTest.java | 8 ++--- .../BigQueryJsonArrayOfPrimitivesTest.java | 8 ++--- .../bigquery/jdbc/BigQueryJsonStructTest.java | 8 ++--- 7 files changed, 49 insertions(+), 51 deletions(-) diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryArrowResultSet.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryArrowResultSet.java index 68d857c4a516..f76cfaba4d5e 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryArrowResultSet.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryArrowResultSet.java @@ -363,7 +363,6 @@ private Object getObjectInternal(int columnIndex) throws SQLException { return value; } - @Override public Object getObject(int columnIndex) throws SQLException { diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArray.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArray.java index cd28db97bb20..cbe237a996fa 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArray.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArray.java @@ -33,20 +33,18 @@ class BigQueryJsonArray extends BigQueryBaseArray { private List values; - private final boolean enableTimestampPicos; BigQueryJsonArray(Field schema, FieldValue values) { - this(schema, values, BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonArray.class), false); + this(schema, values, false, BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonArray.class)); } BigQueryJsonArray( Field schema, FieldValue values, - BigQueryJdbcResultSetLogger log, - boolean enableTimestampPicos) { - super(schema, log); + boolean enableTimestampPicos, + BigQueryJdbcResultSetLogger log) { + super(schema, enableTimestampPicos, log); this.values = (values == null || values.isNull()) ? null : values.getRepeatedValue(); - this.enableTimestampPicos = enableTimestampPicos; } @Override @@ -111,15 +109,6 @@ public void free() { markInvalid(); } - @Override - protected Class getTargetClass() { - LOG.finestTrace("getTargetClass"); - if (this.enableTimestampPicos && BigQueryTemporalUtility.isPicosecondTimestamp(this.schema)) { - return String.class; - } - return super.getTargetClass(); - } - @Override Object getCoercedValue(int index) throws SQLException { LOG.finestTrace("getCoercedValue"); @@ -131,8 +120,8 @@ Object getCoercedValue(int index) throws SQLException { return new BigQueryJsonStruct( this.schema.getSubFields(), fieldValue, - this.LOG.getJsonStructLogger(), - this.enableTimestampPicos); + this.enableTimestampPicos, + this.LOG.getJsonStructLogger()); } if (this.enableTimestampPicos && BigQueryTemporalUtility.isPicosecondTimestamp(this.schema)) { return BigQueryTemporalUtility.formatTimestampValue(fieldValue.getStringValue(), true); diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonResultSet.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonResultSet.java index 4b8d52cb1364..7aac998b0cc8 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonResultSet.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonResultSet.java @@ -70,8 +70,7 @@ private BigQueryJsonResultSet( this.toIndexExclusive = toIndexExclusive; this.nestedRowIndex = fromIndex - 1; this.ownedTasks = ownedTasks; - this.enableTimestampPicos = - statement != null ? statement.isEnableTimestampPicos() : enableTimestampPicos; + this.enableTimestampPicos = enableTimestampPicos; } /** @@ -112,7 +111,7 @@ static BigQueryJsonResultSet of( ownedTasks, bigQuery, job, - false); + statement != null && statement.isEnableTimestampPicos()); } static BigQueryJsonResultSet of( @@ -123,7 +122,18 @@ static BigQueryJsonResultSet of( Future[] ownedTasks) { return new BigQueryJsonResultSet( - schema, totalRows, buffer, statement, false, null, -1, -1, ownedTasks, null, null, false); + schema, + totalRows, + buffer, + statement, + false, + null, + -1, + -1, + ownedTasks, + null, + null, + statement != null && statement.isEnableTimestampPicos()); } static BigQueryJsonResultSet of( @@ -258,8 +268,8 @@ public Object getObject(int columnIndex) throws SQLException { return new BigQueryJsonStruct( arrayField.getSubFields(), value, - this.LOG.getJsonStructLogger(), - this.enableTimestampPicos); + this.enableTimestampPicos, + this.LOG.getJsonStructLogger()); } if (this.enableTimestampPicos && BigQueryTemporalUtility.isPicosecondTimestamp(arrayField)) { return BigQueryTemporalUtility.formatTimestampValue(value.getStringValue(), true); @@ -273,14 +283,14 @@ public Object getObject(int columnIndex) throws SQLException { Field fieldSchema = this.schemaFieldList.get(columnIndex - 1); if (isArray(fieldSchema)) { return new BigQueryJsonArray( - fieldSchema, value, this.LOG.getJsonArrayLogger(), this.enableTimestampPicos); + fieldSchema, value, this.enableTimestampPicos, this.LOG.getJsonArrayLogger()); } if (isStruct(fieldSchema)) { return new BigQueryJsonStruct( fieldSchema.getSubFields(), value, - this.LOG.getJsonStructLogger(), - this.enableTimestampPicos); + this.enableTimestampPicos, + this.LOG.getJsonStructLogger()); } if (this.enableTimestampPicos && isRangeTimestamp(fieldSchema)) { return formatRangeTimestamp(value); @@ -307,9 +317,11 @@ static String formatRangeTimestamp(FieldValue value) throws SQLException { static boolean isRangeTimestamp(Field field) { return field != null && field.getRangeElementType() != null - && StandardSQLTypeName.TIMESTAMP - .name() - .equalsIgnoreCase(field.getRangeElementType().getType()); + && field.getRangeElementType().getType() != null + && field + .getRangeElementType() + .getType() + .equalsIgnoreCase(StandardSQLTypeName.TIMESTAMP.name()); } /** diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStruct.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStruct.java index 59c3d21a50ef..041d45650222 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStruct.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStruct.java @@ -34,21 +34,19 @@ class BigQueryJsonStruct extends BigQueryBaseStruct { private final FieldList schema; private final List values; - private final boolean enableTimestampPicos; public BigQueryJsonStruct(FieldList schema, FieldValue values) { - this(schema, values, BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonStruct.class), false); + this(schema, values, false, BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonStruct.class)); } public BigQueryJsonStruct( FieldList schema, FieldValue values, - BigQueryJdbcResultSetLogger log, - boolean enableTimestampPicos) { - super(log); + boolean enableTimestampPicos, + BigQueryJdbcResultSetLogger log) { + super(enableTimestampPicos, log); this.schema = schema; this.values = (values == null || values.isNull()) ? null : values.getRecordValue(); - this.enableTimestampPicos = enableTimestampPicos; } @Override @@ -78,14 +76,14 @@ private Object getValue(Field currentSchema, FieldValue currentValue) throws SQL } if (isArray(currentSchema)) { return new BigQueryJsonArray( - currentSchema, currentValue, this.LOG.getJsonArrayLogger(), this.enableTimestampPicos); + currentSchema, currentValue, this.enableTimestampPicos, this.LOG.getJsonArrayLogger()); } if (isStruct(currentSchema)) { return new BigQueryJsonStruct( currentSchema.getSubFields(), currentValue, - this.LOG.getJsonStructLogger(), - this.enableTimestampPicos); + this.enableTimestampPicos, + this.LOG.getJsonStructLogger()); } if (this.enableTimestampPicos && BigQueryTemporalUtility.isPicosecondTimestamp(currentSchema)) { return BigQueryTemporalUtility.formatTimestampValue(currentValue.getStringValue(), true); diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLoggerTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLoggerTest.java index c75f66fa11bd..38a5df969406 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLoggerTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLoggerTest.java @@ -486,7 +486,7 @@ public void testJsonArrayConnectionIdPropagation() { Attribute.REPEATED, FieldValueList.of( Collections.singletonList(FieldValue.of(Attribute.PRIMITIVE, "123")))); - BigQueryJsonArray array = new BigQueryJsonArray(arraySchema, arrayValue, logger, false); + BigQueryJsonArray array = new BigQueryJsonArray(arraySchema, arrayValue, false, logger); assertConnectionIdPropagated( logger, connectionId, "Log from JSON Array", () -> array.LOG.fine("Log from JSON Array")); @@ -505,7 +505,7 @@ public void testJsonStructConnectionIdPropagation() { FieldValueList.of( Collections.singletonList(FieldValue.of(Attribute.PRIMITIVE, "456")))); BigQueryJsonStruct struct = - new BigQueryJsonStruct(structSchema, structValue, structLogger, false); + new BigQueryJsonStruct(structSchema, structValue, false, structLogger); assertConnectionIdPropagated( structLogger, @@ -533,7 +533,7 @@ public void testNestedStructInJsonArrayConnectionIdPropagation() throws Exceptio FieldValue listVal = FieldValue.of(Attribute.REPEATED, FieldValueList.of(Collections.singletonList(recordVal))); BigQueryJsonArray arrayWithNested = - new BigQueryJsonArray(arrayNestedSchema, listVal, logger, false); + new BigQueryJsonArray(arrayNestedSchema, listVal, false, logger); Object[] result = (Object[]) arrayWithNested.getArray(); BigQueryJsonStruct nestedStruct = (BigQueryJsonStruct) result[0]; @@ -567,7 +567,7 @@ public void testNestedArrayInJsonStructConnectionIdPropagation() throws Exceptio FieldValue.of(Attribute.RECORD, FieldValueList.of(Collections.singletonList(arrayVal))); BigQueryJsonStruct structWithNestedArray = - new BigQueryJsonStruct(nestedSchema, rootVal, structLogger, false); + new BigQueryJsonStruct(nestedSchema, rootVal, false, structLogger); Object[] attributes = structWithNestedArray.getAttributes(); BigQueryJsonArray nestedArray = (BigQueryJsonArray) attributes[0]; diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArrayOfPrimitivesTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArrayOfPrimitivesTest.java index b4f153973d98..f2127a552077 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArrayOfPrimitivesTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonArrayOfPrimitivesTest.java @@ -404,8 +404,8 @@ public void testJsonArrayTimestampPicosEnabled() throws SQLException { new BigQueryJsonArray( field, arrayValue, - BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonArray.class), - true); + true, + BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonArray.class)); assertThat(array.getBaseTypeName()).isEqualTo("TIMESTAMP"); assertThat(array.getBaseType()).isEqualTo(Types.TIMESTAMP); @@ -445,8 +445,8 @@ public void testJsonArrayTimestampPicosDisabled() throws SQLException { new BigQueryJsonArray( field, arrayValue, - BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonArray.class), - false); + false, + BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonArray.class)); Object result = array.getArray(); assertThat(result).isInstanceOf(Timestamp[].class); diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStructTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStructTest.java index 58aa84e451ce..6620cab2ca5c 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStructTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJsonStructTest.java @@ -270,8 +270,8 @@ public void testJsonStructTimestampPicosEnabled() throws SQLException { new BigQueryJsonStruct( schema, structValue, - BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonStruct.class), - true); + true, + BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonStruct.class)); Object[] attributes = struct.getAttributes(); assertThat(attributes).isEqualTo(new Object[] {"2023-03-30 11:14:19.123456789123"}); @@ -288,8 +288,8 @@ public void testJsonStructTimestampPicosDisabled() throws SQLException { new BigQueryJsonStruct( schema, structValue, - BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonStruct.class), - false); + false, + BigQueryJdbcResultSetLogger.getLogger(BigQueryJsonStruct.class)); Object[] attributes = struct.getAttributes(); Timestamp expectedTs = Timestamp.valueOf("2023-03-30 11:14:19.123456789");