|
1 | 1 | //! Utilities for converting between Arrow and Postgres formats. |
2 | 2 |
|
| 3 | +use std::str::FromStr; |
| 4 | + |
3 | 5 | use convergence::protocol::{DataTypeOid, ErrorResponse, FieldDescription, SqlState}; |
4 | 6 | use convergence::protocol_ext::DataRowBatch; |
| 7 | +use datafusion::arrow::array::timezone::Tz; |
5 | 8 | use datafusion::arrow::array::{ |
6 | | - BooleanArray, Date32Array, Date64Array, Decimal128Array, Float16Array, |
7 | | - Float32Array, Float64Array, Int16Array, Int32Array, Int64Array, Int8Array, StringArray, |
8 | | - StringViewArray, TimestampMicrosecondArray, TimestampMillisecondArray, TimestampNanosecondArray, |
9 | | - TimestampSecondArray, UInt16Array, UInt32Array, UInt64Array, UInt8Array |
| 9 | + BooleanArray, Date32Array, Date64Array, Decimal128Array, Float16Array, Float32Array, Float64Array, Int16Array, |
| 10 | + Int32Array, Int64Array, Int8Array, StringArray, StringViewArray, TimestampMicrosecondArray, |
| 11 | + TimestampMillisecondArray, TimestampNanosecondArray, TimestampSecondArray, UInt16Array, UInt32Array, UInt64Array, |
| 12 | + UInt8Array, |
10 | 13 | }; |
11 | 14 | use datafusion::arrow::datatypes::{DataType, Schema, TimeUnit}; |
12 | 15 | use datafusion::arrow::record_batch::RecordBatch; |
@@ -61,23 +64,52 @@ pub fn record_batch_to_rows(arrow_batch: &RecordBatch, pg_batch: &mut DataRowBat |
61 | 64 | ErrorResponse::error(SqlState::InvalidDatetimeFormat, "unsupported date type") |
62 | 65 | })?) |
63 | 66 | } |
64 | | - DataType::Timestamp(unit, None) => row.write_timestamp( |
65 | | - match unit { |
66 | | - TimeUnit::Second => array_val!(TimestampSecondArray, col, row_idx, value_as_datetime), |
67 | | - TimeUnit::Millisecond => { |
68 | | - array_val!(TimestampMillisecondArray, col, row_idx, value_as_datetime) |
69 | | - } |
70 | | - TimeUnit::Microsecond => { |
71 | | - array_val!(TimestampMicrosecondArray, col, row_idx, value_as_datetime) |
| 67 | + DataType::Timestamp(unit, tz) => { |
| 68 | + match tz { |
| 69 | + Some(tz) => { |
| 70 | + let tz = Tz::from_str(tz.as_ref()).map_err(|_| { |
| 71 | + ErrorResponse::error(SqlState::InvalidDatetimeFormat, "unsupported timezone") |
| 72 | + })?; |
| 73 | + let dt = match unit { |
| 74 | + TimeUnit::Second => array_cast!(TimestampSecondArray, col) |
| 75 | + .value_as_datetime_with_tz(row_idx, tz) |
| 76 | + .map(|d| d.fixed_offset()), |
| 77 | + TimeUnit::Millisecond => array_cast!(TimestampMillisecondArray, col) |
| 78 | + .value_as_datetime_with_tz(row_idx, tz) |
| 79 | + .map(|d| d.fixed_offset()), |
| 80 | + TimeUnit::Microsecond => array_cast!(TimestampMicrosecondArray, col) |
| 81 | + .value_as_datetime_with_tz(row_idx, tz) |
| 82 | + .map(|d| d.fixed_offset()), |
| 83 | + TimeUnit::Nanosecond => array_cast!(TimestampNanosecondArray, col) |
| 84 | + .value_as_datetime_with_tz(row_idx, tz) |
| 85 | + .map(|d| d.fixed_offset()), |
| 86 | + } |
| 87 | + .ok_or_else(|| { |
| 88 | + ErrorResponse::error(SqlState::InvalidDatetimeFormat, "unsupported timestamp type") |
| 89 | + })?; |
| 90 | + row.write_timestamp_with_tz(dt) |
72 | 91 | } |
73 | | - TimeUnit::Nanosecond => { |
74 | | - array_val!(TimestampNanosecondArray, col, row_idx, value_as_datetime) |
75 | | - } |
76 | | - } |
77 | | - .ok_or_else(|| { |
78 | | - ErrorResponse::error(SqlState::InvalidDatetimeFormat, "unsupported timestamp type") |
79 | | - })?, |
80 | | - ), |
| 92 | + None => row.write_timestamp( |
| 93 | + match unit { |
| 94 | + TimeUnit::Second => { |
| 95 | + array_val!(TimestampSecondArray, col, row_idx, value_as_datetime) |
| 96 | + } |
| 97 | + TimeUnit::Millisecond => { |
| 98 | + array_val!(TimestampMillisecondArray, col, row_idx, value_as_datetime) |
| 99 | + } |
| 100 | + TimeUnit::Microsecond => { |
| 101 | + array_val!(TimestampMicrosecondArray, col, row_idx, value_as_datetime) |
| 102 | + } |
| 103 | + TimeUnit::Nanosecond => { |
| 104 | + array_val!(TimestampNanosecondArray, col, row_idx, value_as_datetime) |
| 105 | + } |
| 106 | + } |
| 107 | + .ok_or_else(|| { |
| 108 | + ErrorResponse::error(SqlState::InvalidDatetimeFormat, "unsupported timestamp type") |
| 109 | + })?, |
| 110 | + ), |
| 111 | + }; |
| 112 | + } |
81 | 113 | other => { |
82 | 114 | return Err(ErrorResponse::error( |
83 | 115 | SqlState::FeatureNotSupported, |
@@ -108,7 +140,10 @@ pub fn data_type_to_oid(ty: &DataType) -> Result<DataTypeOid, ErrorResponse> { |
108 | 140 | DataType::Decimal128(_, _) => DataTypeOid::Numeric, |
109 | 141 | DataType::Utf8 | DataType::Utf8View => DataTypeOid::Text, |
110 | 142 | DataType::Date32 | DataType::Date64 => DataTypeOid::Date, |
111 | | - DataType::Timestamp(_, None) => DataTypeOid::Timestamp, |
| 143 | + DataType::Timestamp(_, tz) => match tz { |
| 144 | + Some(_) => DataTypeOid::Timestamptz, |
| 145 | + None => DataTypeOid::Timestamp, |
| 146 | + }, |
112 | 147 | other => { |
113 | 148 | return Err(ErrorResponse::error( |
114 | 149 | SqlState::FeatureNotSupported, |
|
0 commit comments