Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1813,6 +1813,12 @@ ColumnTypeInfo mapBigQueryTypeToJdbc(Field field) {
return new ColumnTypeInfo(Types.ARRAY, "ARRAY", null, null, null);
}

if (this.connection.isEnableTimestampPicos()
&& BigQueryTemporalUtility.isPicosecondTimestamp(field)) {
return new ColumnTypeInfo(
Types.VARCHAR, BigQueryTemporalUtility.TIMESTAMP_PICOSECONDS_TYPE_NAME, 32, 12, null);
}

StandardSQLTypeName bqType = null;
if (field.getType() != null && field.getType().getStandardType() != null) {
bqType = field.getType().getStandardType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,40 +21,50 @@
import com.google.cloud.bigquery.FieldList;
import com.google.cloud.bigquery.StandardSQLTypeName;
import com.google.cloud.bigquery.exception.BigQueryJdbcException;
import java.sql.Array;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;

/** This class returns ResultSetMetadata for the JSON and the Arrow ResultSets */
class BigQueryResultSetMetadata implements ResultSetMetaData {
private final BigQueryJdbcResultSetLogger LOG =
BigQueryJdbcResultSetLogger.getLogger(this.getClass());
private final FieldList schemaFieldList;
private final Statement statement;
private final BigQueryStatement statement;
private final int columnCount;
private final boolean enableTimestampPicos;

private static final int DEFAULT_DISPLAY_SIZE = 50;

private BigQueryResultSetMetadata(FieldList schemaFieldList, Statement statement) {
private BigQueryResultSetMetadata(FieldList schemaFieldList, BigQueryStatement statement) {
LOG.finestTrace("<init>");
this.schemaFieldList = schemaFieldList;
this.columnCount = schemaFieldList.size();
this.statement = statement;
this.enableTimestampPicos = statement != null && statement.isEnableTimestampPicos();
}

static BigQueryResultSetMetadata of(FieldList schemaFieldList, Statement statement) {
static BigQueryResultSetMetadata of(FieldList schemaFieldList, BigQueryStatement statement) {
return new BigQueryResultSetMetadata(schemaFieldList, statement);
}

Statement getStatement() {
BigQueryStatement getStatement() {
return this.statement;
}

private Field getField(int sqlColumn) {
return this.schemaFieldList.get(sqlColumn - 1);
}

private boolean isPicosecondTimestampColumn(int sqlColumn) {
if (!this.enableTimestampPicos) {
return false;
}
Field field = getField(sqlColumn);
return field.getMode() != Mode.REPEATED && BigQueryTemporalUtility.isPicosecondTimestamp(field);
Comment thread
keshavdandeva marked this conversation as resolved.
}

@Override
public int getColumnCount() {
return this.columnCount;
Expand Down Expand Up @@ -104,6 +114,9 @@ public boolean isSigned(int column) {

@Override
public int getColumnDisplaySize(int column) {
if (isPicosecondTimestampColumn(column)) {
return 32;
}
int colType = getColumnType(column);
switch (colType) {
case Types.BOOLEAN:
Expand All @@ -116,7 +129,7 @@ public int getColumnDisplaySize(int column) {
case Types.NUMERIC:
return 14;
case Types.TIMESTAMP:
return 16;
return 26;
default:
return DEFAULT_DISPLAY_SIZE;
}
Expand All @@ -138,6 +151,9 @@ public int getPrecision(int column) {
if (precision != null) {
return precision.intValue();
}
if (isPicosecondTimestampColumn(column)) {
return 32;
}
StandardSQLTypeName type = getStandardSQLTypeName(column);
BigQueryTypeRegistry.ColumnTypeInfo typeInfo = BigQueryTypeRegistry.getColumnTypeInfo(type);
if (typeInfo != null && typeInfo.columnSize != null) {
Expand All @@ -152,6 +168,9 @@ public int getScale(int column) {
if (scale != null) {
return scale.intValue();
}
if (isPicosecondTimestampColumn(column)) {
return 12;
}
StandardSQLTypeName type = getStandardSQLTypeName(column);
BigQueryTypeRegistry.ColumnTypeInfo typeInfo = BigQueryTypeRegistry.getColumnTypeInfo(type);
if (typeInfo != null && typeInfo.decimalDigits != null) {
Expand Down Expand Up @@ -187,11 +206,17 @@ private StandardSQLTypeName getStandardSQLTypeName(int column) {

@Override
public int getColumnType(int column) {
if (isPicosecondTimestampColumn(column)) {
return Types.VARCHAR;
}
return BigQueryTypeRegistry.toJdbcType(getStandardSQLTypeName(column));
}

@Override
public String getColumnTypeName(int column) {
if (isPicosecondTimestampColumn(column)) {
return BigQueryTemporalUtility.TIMESTAMP_PICOSECONDS_TYPE_NAME;
}
return getStandardSQLTypeName(column).name();
}

Expand All @@ -212,9 +237,12 @@ public boolean isDefinitelyWritable(int column) {

@Override
public String getColumnClassName(int column) throws SQLException {
if (isPicosecondTimestampColumn(column)) {
return String.class.getName();
}
Field field = getField(column);
if (field.getMode() == Mode.REPEATED) {
return java.sql.Array.class.getName();
return Array.class.getName();
}
return BigQueryTypeRegistry.toJavaClass(getStandardSQLTypeName(column)).getName();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ final class BigQueryTemporalUtility {
private static final BigDecimal MICROS_PER_SECOND = new BigDecimal("1000000");
private static final DateTimeFormatter BASE_FORMATTER =
DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.");
static final String TIMESTAMP_PICOSECONDS_TYPE_NAME = "TIMESTAMP_PICOSECONDS";

private BigQueryTemporalUtility() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,67 @@ public void testMapBigQueryTypeToJdbc_ArrayType() {
assertNull(infoArray.numPrecRadix);
}

@Test
public void testMapBigQueryTypeToJdbc_timestampPicos_whenEnabled() {
when(bigQueryConnection.isEnableTimestampPicos()).thenReturn(true);
Field fieldTimestampPicos =
Field.newBuilder("picos_ts", StandardSQLTypeName.TIMESTAMP)
.setTimestampPrecision(12L)
.build();
ColumnTypeInfo info = dbMetadata.mapBigQueryTypeToJdbc(fieldTimestampPicos);
assertEquals(Types.VARCHAR, info.jdbcType);
assertEquals(BigQueryTemporalUtility.TIMESTAMP_PICOSECONDS_TYPE_NAME, info.typeName);
assertEquals(Integer.valueOf(32), info.columnSize);
assertEquals(Integer.valueOf(12), info.decimalDigits);
assertNull(info.numPrecRadix);
}

@Test
public void testMapBigQueryTypeToJdbc_timestampPicos_whenDisabled() {
when(bigQueryConnection.isEnableTimestampPicos()).thenReturn(false);
Field fieldTimestampPicos =
Field.newBuilder("picos_ts", StandardSQLTypeName.TIMESTAMP)
.setTimestampPrecision(12L)
.build();
ColumnTypeInfo info = dbMetadata.mapBigQueryTypeToJdbc(fieldTimestampPicos);
assertEquals(Types.TIMESTAMP, info.jdbcType);
assertEquals("TIMESTAMP", info.typeName);
assertEquals(Integer.valueOf(26), info.columnSize);
assertEquals(Integer.valueOf(6), info.decimalDigits);
assertNull(info.numPrecRadix);
}

@Test
public void testMapBigQueryTypeToJdbc_repeatedTimestampPicos_remainsArray() {
when(bigQueryConnection.isEnableTimestampPicos()).thenReturn(true);
Field fieldRepeatedTimestampPicos =
Field.newBuilder("picos_array", StandardSQLTypeName.TIMESTAMP)
.setMode(Field.Mode.REPEATED)
.setTimestampPrecision(12L)
.build();
ColumnTypeInfo info = dbMetadata.mapBigQueryTypeToJdbc(fieldRepeatedTimestampPicos);
assertEquals(Types.ARRAY, info.jdbcType);
assertEquals("ARRAY", info.typeName);
assertNull(info.columnSize);
assertNull(info.decimalDigits);
assertNull(info.numPrecRadix);
}

@Test
public void testMapBigQueryTypeToJdbc_standardTimestamp_whenPicosEnabled() {
when(bigQueryConnection.isEnableTimestampPicos()).thenReturn(true);
Field fieldStandardTimestamp =
Field.newBuilder("standard_ts", StandardSQLTypeName.TIMESTAMP)
.setTimestampPrecision(6L)
.build();
ColumnTypeInfo info = dbMetadata.mapBigQueryTypeToJdbc(fieldStandardTimestamp);
assertEquals(Types.TIMESTAMP, info.jdbcType);
assertEquals("TIMESTAMP", info.typeName);
assertEquals(Integer.valueOf(26), info.columnSize);
assertEquals(Integer.valueOf(6), info.decimalDigits);
assertNull(info.numPrecRadix);
}

@Test
public void testCreateColumnRow() {
Field realField =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import com.google.cloud.bigquery.Field;
import com.google.cloud.bigquery.FieldList;
Expand All @@ -30,6 +31,7 @@
import java.sql.Array;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.concurrent.Future;
import java.util.stream.Stream;
Expand Down Expand Up @@ -196,7 +198,7 @@ public void testColumnDisplaySize() throws SQLException {
assertThat(resultSetMetaData.getColumnDisplaySize(2)).isEqualTo(10);
assertThat(resultSetMetaData.getColumnDisplaySize(3)).isEqualTo(14);
assertThat(resultSetMetaData.getColumnDisplaySize(12)).isEqualTo(50);
assertThat(resultSetMetaData.getColumnDisplaySize(5)).isEqualTo(16);
assertThat(resultSetMetaData.getColumnDisplaySize(5)).isEqualTo(26);
}

// Nested Types
Expand Down Expand Up @@ -295,4 +297,83 @@ public void testIsSearchableForAllTypes(StandardSQLTypeName type) throws SQLExce
ResultSetMetaData metaData = resultSet.getMetaData();
assertThat(metaData.isSearchable(1)).isTrue();
}

@Test
public void testTimestampPicosecondsMetadata_whenEnabled() throws SQLException {
Field picosTimestampField =
Field.newBuilder("picosTs", StandardSQLTypeName.TIMESTAMP)
.setTimestampPrecision(12L)
.build();
Schema schema = Schema.of(FieldList.of(picosTimestampField));
when(statement.isEnableTimestampPicos()).thenReturn(true);
BigQueryJsonResultSet jsonRs =
BigQueryJsonResultSet.of(schema, 1L, null, statement, (Future<?>[]) null);
ResultSetMetaData metadata = jsonRs.getMetaData();

assertThat(metadata.getColumnType(1)).isEqualTo(Types.VARCHAR);
assertThat(metadata.getColumnTypeName(1))
.isEqualTo(BigQueryTemporalUtility.TIMESTAMP_PICOSECONDS_TYPE_NAME);
assertThat(metadata.getColumnClassName(1)).isEqualTo(String.class.getName());
assertThat(metadata.getColumnDisplaySize(1)).isEqualTo(32);
assertThat(metadata.getPrecision(1)).isEqualTo(32);
assertThat(metadata.getScale(1)).isEqualTo(12);
}

@Test
public void testTimestampPicosecondsMetadata_whenDisabled() throws SQLException {
Field picosTimestampField =
Field.newBuilder("picosTs", StandardSQLTypeName.TIMESTAMP)
.setTimestampPrecision(12L)
.build();
Schema schema = Schema.of(FieldList.of(picosTimestampField));
when(statement.isEnableTimestampPicos()).thenReturn(false);
BigQueryJsonResultSet jsonRs =
BigQueryJsonResultSet.of(schema, 1L, null, statement, (Future<?>[]) null);
ResultSetMetaData metadata = jsonRs.getMetaData();

assertThat(metadata.getColumnType(1)).isEqualTo(Types.TIMESTAMP);
assertThat(metadata.getColumnTypeName(1)).isEqualTo("TIMESTAMP");
assertThat(metadata.getColumnClassName(1)).isEqualTo(Timestamp.class.getName());
assertThat(metadata.getColumnDisplaySize(1)).isEqualTo(26);
assertThat(metadata.getPrecision(1)).isEqualTo(26);
assertThat(metadata.getScale(1)).isEqualTo(6);
}

@Test
public void testRepeatedTimestampPicosecondsMetadata_remainsArray() throws SQLException {
Field repeatedPicosTimestampField =
Field.newBuilder("picosArray", StandardSQLTypeName.TIMESTAMP)
.setMode(Field.Mode.REPEATED)
.setTimestampPrecision(12L)
.build();
Schema schema = Schema.of(FieldList.of(repeatedPicosTimestampField));
when(statement.isEnableTimestampPicos()).thenReturn(true);
BigQueryJsonResultSet jsonRs =
BigQueryJsonResultSet.of(schema, 1L, null, statement, (Future<?>[]) null);
ResultSetMetaData metadata = jsonRs.getMetaData();

assertThat(metadata.getColumnType(1)).isEqualTo(Types.ARRAY);
assertThat(metadata.getColumnTypeName(1)).isEqualTo("ARRAY");
assertThat(metadata.getColumnClassName(1)).isEqualTo(Array.class.getName());
}

@Test
public void testStandardTimestampMetadata_whenPicosEnabled() throws SQLException {
Field standardTimestampField =
Field.newBuilder("standardTs", StandardSQLTypeName.TIMESTAMP)
.setTimestampPrecision(6L)
.build();
Schema schema = Schema.of(FieldList.of(standardTimestampField));
when(statement.isEnableTimestampPicos()).thenReturn(true);
BigQueryJsonResultSet jsonRs =
BigQueryJsonResultSet.of(schema, 1L, null, statement, (Future<?>[]) null);
ResultSetMetaData metadata = jsonRs.getMetaData();

assertThat(metadata.getColumnType(1)).isEqualTo(Types.TIMESTAMP);
assertThat(metadata.getColumnTypeName(1)).isEqualTo("TIMESTAMP");
assertThat(metadata.getColumnClassName(1)).isEqualTo(Timestamp.class.getName());
assertThat(metadata.getColumnDisplaySize(1)).isEqualTo(26);
assertThat(metadata.getPrecision(1)).isEqualTo(26);
assertThat(metadata.getScale(1)).isEqualTo(6);
}
}
Loading