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 @@ -35,6 +35,7 @@
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
Expand Down Expand Up @@ -369,6 +370,11 @@ private Object getObjectInternal(int columnIndex) throws SQLException {

@Override
public Object getObject(int columnIndex) throws SQLException {
return getObject(columnIndex, (ZoneId) null);
}

@Override
protected Object getObject(int columnIndex, ZoneId zone) throws SQLException {

// columnIndex is SQL index starting at 1
LOG.finestTrace("getObject");
Expand Down Expand Up @@ -398,7 +404,7 @@ public Object getObject(int columnIndex) throws SQLException {
if (this.enableTimestampPicos && BigQueryTemporalUtility.isPicosecondTimestamp(arrayField)) {
return BigQueryTemporalUtility.formatTimestampValue(value, true);
}
return BigQueryTypeRegistry.convert(value, arrayField.getType().getStandardType(), null);
return BigQueryTypeRegistry.convert(value, arrayField.getType().getStandardType(), zone);
}

int fieldIndex = this.isNested ? 0 : columnIndex - 1;
Expand Down Expand Up @@ -478,7 +484,7 @@ public Object getObject(int columnIndex) throws SQLException {
if (this.enableTimestampPicos && BigQueryTemporalUtility.isPicosecondTimestamp(fieldSchema)) {
return BigQueryTemporalUtility.formatTimestampValue(value, true);
}
return BigQueryTypeRegistry.convert(value, fieldSchema.getType().getStandardType(), null);
return BigQueryTypeRegistry.convert(value, fieldSchema.getType().getStandardType(), zone);
}

private StandardSQLTypeName getRangeElementType(Field field, Object representativeElement) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,10 @@ public boolean isClosed() {

public abstract Object getObject(int columnIndex) throws SQLException;

protected Object getObject(int columnIndex, ZoneId zone) throws SQLException {
return getObject(columnIndex);
}

@Override
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
LOG.finestTrace("getObject");
Expand All @@ -304,6 +308,12 @@ public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
if (value == null) {
return null;
}
if (type != null && !type.isInstance(value)) {
StandardSQLTypeName bqType = getStandardSQLTypeName(columnIndex);
if (bqType == StandardSQLTypeName.TIMESTAMP) {
return BigQueryTypeRegistry.convert(value, bqType, type, null);
}
}
return BigQueryTypeRegistry.convert(value, type);
} catch (RuntimeException e) {
throw createCoercionException(columnIndex, type, e);
Expand Down Expand Up @@ -454,43 +464,17 @@ public byte[] getBytes(int columnIndex) throws SQLException {

@Override
public Date getDate(int columnIndex) throws SQLException {
LOG.finestTrace("getDate");
try {
Object value = getObject(columnIndex);
return BigQueryTypeRegistry.convert(value, Date.class);
} catch (BigQueryJdbcException e) {
throw createCoercionException(columnIndex, Date.class, e);
}
return getDate(columnIndex, null);
}

@Override
public Time getTime(int columnIndex) throws SQLException {
LOG.finestTrace("getTime");
StandardSQLTypeName type = getStandardSQLTypeName(columnIndex);
if (type == StandardSQLTypeName.INT64) {
throw createCoercionException(columnIndex, Time.class, null);
}
try {
Object value = getObject(columnIndex);
return BigQueryTypeRegistry.convert(value, Time.class);
} catch (BigQueryJdbcException e) {
throw createCoercionException(columnIndex, Time.class, e);
}
return getTime(columnIndex, null);
}

@Override
public Timestamp getTimestamp(int columnIndex) throws SQLException {
LOG.finestTrace("getTimestamp");
StandardSQLTypeName type = getStandardSQLTypeName(columnIndex);
if (type == StandardSQLTypeName.INT64) {
throw createCoercionException(columnIndex, Timestamp.class, null);
}
try {
Object value = getObject(columnIndex);
return BigQueryTypeRegistry.convert(value, Timestamp.class);
} catch (BigQueryJdbcException e) {
throw createCoercionException(columnIndex, Timestamp.class, e);
}
return getTimestamp(columnIndex, null);
}

@Override
Expand Down Expand Up @@ -564,13 +548,19 @@ public InputStream getBinaryStream(int columnIndex) throws SQLException {
return bytes == null ? null : new ByteArrayInputStream(bytes);
}

private static ZoneId getEffectiveZone(StandardSQLTypeName bqType, Calendar cal) {
return (cal == null || bqType == StandardSQLTypeName.TIMESTAMP)
? null
: cal.getTimeZone().toZoneId();
}
Comment thread
keshavdandeva marked this conversation as resolved.

@Override
public Date getDate(int columnIndex, Calendar cal) throws SQLException {
LOG.finestTrace("getDate");
StandardSQLTypeName bqType = getStandardSQLTypeName(columnIndex);
ZoneId zone = getEffectiveZone(bqType, cal);
try {
Object value = getObject(columnIndex);
StandardSQLTypeName bqType = getStandardSQLTypeName(columnIndex);
ZoneId zone = (cal == null) ? null : cal.getTimeZone().toZoneId();
Object value = getObject(columnIndex, zone);
return BigQueryTypeRegistry.convert(value, bqType, Date.class, zone);
} catch (BigQueryJdbcException e) {
throw createCoercionException(columnIndex, Date.class, e);
Expand All @@ -580,10 +570,13 @@ public Date getDate(int columnIndex, Calendar cal) throws SQLException {
@Override
public Time getTime(int columnIndex, Calendar cal) throws SQLException {
LOG.finestTrace("getTime");
StandardSQLTypeName bqType = getStandardSQLTypeName(columnIndex);
if (bqType == StandardSQLTypeName.INT64) {
throw createCoercionException(columnIndex, Time.class, null);
}
ZoneId zone = getEffectiveZone(bqType, cal);
Comment thread
keshavdandeva marked this conversation as resolved.
try {
Object value = getObject(columnIndex);
StandardSQLTypeName bqType = getStandardSQLTypeName(columnIndex);
ZoneId zone = (cal == null) ? null : cal.getTimeZone().toZoneId();
Object value = getObject(columnIndex, zone);
return BigQueryTypeRegistry.convert(value, bqType, Time.class, zone);
} catch (BigQueryJdbcException e) {
throw createCoercionException(columnIndex, Time.class, e);
Expand All @@ -593,10 +586,13 @@ public Time getTime(int columnIndex, Calendar cal) throws SQLException {
@Override
public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {
LOG.finestTrace("getTimestamp");
StandardSQLTypeName bqType = getStandardSQLTypeName(columnIndex);
if (bqType == StandardSQLTypeName.INT64) {
throw createCoercionException(columnIndex, Timestamp.class, null);
}
ZoneId zone = getEffectiveZone(bqType, cal);
Comment thread
keshavdandeva marked this conversation as resolved.
try {
Object value = getObject(columnIndex);
StandardSQLTypeName bqType = getStandardSQLTypeName(columnIndex);
ZoneId zone = (cal == null) ? null : cal.getTimeZone().toZoneId();
Object value = getObject(columnIndex, zone);
return BigQueryTypeRegistry.convert(value, bqType, Timestamp.class, zone);
} catch (BigQueryJdbcException e) {
throw createCoercionException(columnIndex, Timestamp.class, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.google.cloud.bigquery.exception.BigQueryJdbcException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.ZoneId;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;

Expand Down Expand Up @@ -250,6 +251,11 @@ public boolean next() throws SQLException {

@Override
public Object getObject(int columnIndex) throws SQLException {
return getObject(columnIndex, (ZoneId) null);
}

@Override
protected Object getObject(int columnIndex, ZoneId zone) throws SQLException {
// columnIndex is SQL index starting at 1
checkClosed();
LOG.finestTrace("getObject");
Expand Down Expand Up @@ -277,7 +283,7 @@ public Object getObject(int columnIndex) throws SQLException {
if (this.enableTimestampPicos && isRangeTimestamp(arrayField)) {
return formatRangeTimestamp(value);
}
return BigQueryTypeRegistry.convert(value, arrayField.getType().getStandardType(), null);
return BigQueryTypeRegistry.convert(value, arrayField.getType().getStandardType(), zone);
}

Field fieldSchema = this.schemaFieldList.get(columnIndex - 1);
Expand All @@ -298,7 +304,7 @@ public Object getObject(int columnIndex) throws SQLException {
if (this.enableTimestampPicos && BigQueryTemporalUtility.isPicosecondTimestamp(fieldSchema)) {
return BigQueryTemporalUtility.formatTimestampValue(value.getStringValue(), true);
}
return BigQueryTypeRegistry.convert(value, fieldSchema.getType().getStandardType(), null);
return BigQueryTypeRegistry.convert(value, fieldSchema.getType().getStandardType(), zone);
}

static String formatRangeTimestamp(FieldValue value) throws SQLException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,46 @@ private BigQueryTemporalUtility() {}
* provided timezone (or JVM default if null).
*/
public static Timestamp boxDateTime(String val, ZoneId zoneId) {
ZoneId targetZone = zoneId != null ? zoneId : ZoneId.systemDefault();
String isoString = truncateFractionalSeconds(val.replace(' ', 'T'), 9);
return Timestamp.from(LocalDateTime.parse(isoString).atZone(targetZone).toInstant());
return boxDateTime(LocalDateTime.parse(isoString), zoneId);
}

/**
* Converts a civil {@link LocalDateTime} into a {@link Timestamp} by anchoring it to the provided
* timezone (or JVM default if null).
*/
static Timestamp boxDateTime(LocalDateTime localDateTime, ZoneId zoneId) {
ZoneId targetZone = zoneId != null ? zoneId : ZoneId.systemDefault();
return Timestamp.from(localDateTime.atZone(targetZone).toInstant());
}

/**
* Converts a BigQuery civil DATE string into an absolute Date by anchoring it to midnight of the
* provided timezone (or JVM default if null).
*/
public static Date boxDate(String val, ZoneId zoneId) {
return boxDate(LocalDate.parse(val), zoneId);
}

/**
* Converts a civil {@link LocalDate} into a {@link Date} by anchoring it to midnight of the
* provided timezone (or JVM default if null).
*/
static Date boxDate(LocalDate localDate, ZoneId zoneId) {
ZoneId targetZone = zoneId != null ? zoneId : ZoneId.systemDefault();
return new Date(LocalDate.parse(val).atStartOfDay(targetZone).toInstant().toEpochMilli());
return new Date(localDate.atStartOfDay(targetZone).toInstant().toEpochMilli());
}

/**
* Converts a civil {@link LocalTime} into a {@link Time} anchored to 1970-01-01 in the provided
* timezone (or JVM default if null).
*/
static Time boxTime(LocalTime localTime, ZoneId zoneId) {
if (zoneId == null) {
return Time.valueOf(localTime);
}
long millisOfDay = localTime.toNanoOfDay() / 1_000_000;
return new Time(getLocalMillis(millisOfDay, zoneId));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,17 +253,20 @@ static TypeDescriptor<?> createDateDescriptor() {
if (val instanceof Date) {
sqlDate = (Date) val;
} else if (val instanceof Timestamp) {
sqlDate = Date.valueOf(((Timestamp) val).toLocalDateTime().toLocalDate());
ZoneId targetZone = zone != null ? zone : ZoneId.systemDefault();
LocalDate localDate = ((Timestamp) val).toInstant().atZone(targetZone).toLocalDate();
sqlDate = BigQueryTemporalUtility.boxDate(localDate, zone);
} else if (val instanceof java.sql.Time) {
throw new BigQueryJdbcException("Cannot convert to DATE: " + val);
} else if (val instanceof java.util.Date) {
sqlDate = new Date(((java.util.Date) val).getTime());
} else if (val instanceof LocalDate) {
sqlDate = Date.valueOf((LocalDate) val);
sqlDate = BigQueryTemporalUtility.boxDate((LocalDate) val, zone);
} else if (val instanceof LocalDateTime) {
sqlDate = Date.valueOf(((LocalDateTime) val).toLocalDate());
sqlDate = BigQueryTemporalUtility.boxDate(((LocalDateTime) val).toLocalDate(), zone);
} else if (val instanceof Integer) {
sqlDate = Date.valueOf(LocalDate.ofEpochDay(((Integer) val).longValue()));
LocalDate localDate = LocalDate.ofEpochDay(((Integer) val).longValue());
sqlDate = BigQueryTemporalUtility.boxDate(localDate, zone);
} else if (val instanceof String) {
sqlDate = BigQueryTemporalUtility.boxDate((String) val, zone);
} else {
Expand All @@ -290,7 +293,10 @@ static TypeDescriptor<?> createDatetimeDescriptor() {
} else if (val instanceof java.util.Date) {
return new Timestamp(((java.util.Date) val).getTime()).toLocalDateTime();
} else if (val instanceof String) {
return LocalDateTime.parse(((String) val).replace(' ', 'T'));
String isoString =
BigQueryTemporalUtility.truncateFractionalSeconds(
((String) val).replace(' ', 'T'), 9);
return LocalDateTime.parse(isoString);
} else {
throw new BigQueryJdbcException("Cannot convert to DATETIME: " + val);
}
Expand All @@ -303,7 +309,7 @@ static TypeDescriptor<?> createDatetimeDescriptor() {
} else if (val instanceof java.util.Date) {
ts = new Timestamp(((java.util.Date) val).getTime());
} else if (val instanceof LocalDateTime) {
ts = Timestamp.valueOf((LocalDateTime) val);
ts = BigQueryTemporalUtility.boxDateTime((LocalDateTime) val, zone);
} else if (val instanceof String) {
ts = BigQueryTemporalUtility.boxDateTime((String) val, zone);
} else {
Expand Down Expand Up @@ -408,13 +414,16 @@ static TypeDescriptor<?> createTimeDescriptor() {
Time sqlTime;
if (val instanceof Time) sqlTime = (Time) val;
else if (val instanceof Timestamp) {
sqlTime = Time.valueOf(((Timestamp) val).toLocalDateTime().toLocalTime());
ZoneId targetZone = zone != null ? zone : ZoneId.systemDefault();
LocalTime localTime = ((Timestamp) val).toInstant().atZone(targetZone).toLocalTime();
sqlTime = BigQueryTemporalUtility.boxTime(localTime, zone);
} else if (val instanceof java.sql.Date) {
throw new BigQueryJdbcException("Cannot convert to TIME: " + val);
} else if (val instanceof java.util.Date)
sqlTime = new Time(((java.util.Date) val).getTime());
else if (val instanceof LocalTime) sqlTime = Time.valueOf((LocalTime) val);
else if (val instanceof LocalDateTime) {
else if (val instanceof LocalTime) {
sqlTime = BigQueryTemporalUtility.boxTime((LocalTime) val, zone);
} else if (val instanceof LocalDateTime) {
long millisOfDay = ((LocalDateTime) val).toLocalTime().toNanoOfDay() / 1_000_000;
sqlTime = new Time(BigQueryTemporalUtility.getLocalMillis(millisOfDay, zone));
} else if (val instanceof Long) {
Expand Down Expand Up @@ -772,12 +781,28 @@ public static <T> T convert(
if (input == null) {
return null;
}
if (input instanceof FieldValue) {
FieldValue fv = (FieldValue) input;
if (fv.isNull()) {
return null;
}
input = fv.getValue();
}
int ordinal = bqType.ordinal();
if (ordinal >= DESCRIPTORS_BY_ORDINAL.length || DESCRIPTORS_BY_ORDINAL[ordinal] == null) {
throw new BigQueryJdbcException("No type descriptor registered for BigQuery type: " + bqType);
}
ZoneId effectiveZone = (bqType == StandardSQLTypeName.TIMESTAMP) ? null : zoneId;
Comment thread
keshavdandeva marked this conversation as resolved.
try {
return (T) DESCRIPTORS_BY_ORDINAL[ordinal].convert(input, targetClass, zoneId);
Object result = DESCRIPTORS_BY_ORDINAL[ordinal].convert(input, targetClass, effectiveZone);
if (!targetClass.isInstance(result)) {
Comment thread
keshavdandeva marked this conversation as resolved.
TypeDescriptor<?> targetDescriptor = getDescriptorForClass(targetClass);
if (targetDescriptor == null) {
throw new BigQueryJdbcException("Unsupported target class: " + targetClass.getName());
}
result = targetDescriptor.convert(result, targetClass, effectiveZone);
}
return (T) result;
} catch (Exception e) {
throw new BigQueryJdbcException(
String.format(
Expand Down
Loading
Loading