Skip to content

Commit 9641cf3

Browse files
committed
chore: extract timestamp value to pg-srv
1 parent b668f3d commit 9641cf3

File tree

8 files changed

+223
-191
lines changed

8 files changed

+223
-191
lines changed

rust/cubesql/Cargo.lock

Lines changed: 47 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/cubesql/cubesql/src/sql/dataframe.rs

Lines changed: 5 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,4 @@
1-
use chrono::{
2-
format::{
3-
Fixed, Item,
4-
Numeric::{Day, Hour, Minute, Month, Second, Year},
5-
Pad::Zero,
6-
},
7-
prelude::*,
8-
};
9-
use chrono_tz::Tz;
1+
use chrono::prelude::*;
102
use comfy_table::{Cell, Table};
113
use datafusion::arrow::{
124
array::{
@@ -18,15 +10,13 @@ use datafusion::arrow::{
1810
},
1911
datatypes::{DataType, IntervalUnit, Schema, TimeUnit},
2012
record_batch::RecordBatch,
21-
temporal_conversions,
2213
};
23-
use pg_srv::IntervalValue;
14+
// Type aliases for compatibility - actual implementations are in pg-srv
15+
pub type IntervalValue = pg_srv::IntervalValue;
16+
pub type TimestampValue = pg_srv::TimestampValue;
2417
use rust_decimal::prelude::*;
2518
use serde::{Serialize, Serializer};
26-
use std::{
27-
fmt::{self, Debug, Formatter},
28-
io,
29-
};
19+
use std::fmt::Debug;
3020

3121
use super::{ColumnFlags, ColumnType};
3222
use crate::CubeError;
@@ -207,83 +197,6 @@ impl DataFrame {
207197
}
208198
}
209199

210-
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
211-
pub struct TimestampValue {
212-
unix_nano: i64,
213-
tz: Option<String>,
214-
}
215-
216-
impl TimestampValue {
217-
pub fn new(mut unix_nano: i64, tz: Option<String>) -> TimestampValue {
218-
// This is a hack to workaround a mismatch between on-disk and in-memory representations.
219-
// We use millisecond precision on-disk.
220-
unix_nano -= unix_nano % 1000;
221-
TimestampValue { unix_nano, tz }
222-
}
223-
224-
pub fn to_naive_datetime(&self) -> NaiveDateTime {
225-
assert!(self.tz.is_none());
226-
227-
temporal_conversions::timestamp_ns_to_datetime(self.unix_nano)
228-
}
229-
230-
pub fn to_fixed_datetime(&self) -> io::Result<DateTime<Tz>> {
231-
assert!(self.tz.is_some());
232-
233-
let tz = self
234-
.tz
235-
.as_ref()
236-
.unwrap()
237-
.parse::<Tz>()
238-
.map_err(|err| io::Error::new(io::ErrorKind::Other, err.to_string()))?;
239-
240-
let ndt = temporal_conversions::timestamp_ns_to_datetime(self.unix_nano);
241-
Ok(tz.from_utc_datetime(&ndt))
242-
}
243-
244-
pub fn tz_ref(&self) -> &Option<String> {
245-
&self.tz
246-
}
247-
248-
pub fn get_time_stamp(&self) -> i64 {
249-
self.unix_nano
250-
}
251-
}
252-
253-
impl Debug for TimestampValue {
254-
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
255-
f.debug_struct("TimestampValue")
256-
.field("unix_nano", &self.unix_nano)
257-
.field("tz", &self.tz)
258-
.field("str", &self.to_string())
259-
.finish()
260-
}
261-
}
262-
263-
impl ToString for TimestampValue {
264-
fn to_string(&self) -> String {
265-
Utc.timestamp_nanos(self.unix_nano)
266-
.format_with_items(
267-
[
268-
Item::Numeric(Year, Zero),
269-
Item::Literal("-"),
270-
Item::Numeric(Month, Zero),
271-
Item::Literal("-"),
272-
Item::Numeric(Day, Zero),
273-
Item::Literal("T"),
274-
Item::Numeric(Hour, Zero),
275-
Item::Literal(":"),
276-
Item::Numeric(Minute, Zero),
277-
Item::Literal(":"),
278-
Item::Numeric(Second, Zero),
279-
Item::Fixed(Fixed::Nanosecond3),
280-
]
281-
.iter(),
282-
)
283-
.to_string()
284-
}
285-
}
286-
287200
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
288201
pub struct Decimal128Value {
289202
n: i128,

rust/cubesql/cubesql/src/sql/postgres/writer.rs

Lines changed: 4 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
11
use crate::sql::{
2-
dataframe::{Decimal128Value, ListValue, TimestampValue},
2+
dataframe::{Decimal128Value, ListValue},
33
df_type_to_pg_tid,
44
};
55
use bytes::{BufMut, BytesMut};
6-
use chrono::{
7-
format::{
8-
Fixed, Item,
9-
Numeric::{Day, Hour, Minute, Month, Second, Year},
10-
Pad::Zero,
11-
},
12-
prelude::*,
13-
};
146
use datafusion::arrow::{
157
array::{
168
Array, BooleanArray, Float16Array, Float32Array, Float64Array, Int16Array, Int32Array,
@@ -24,87 +16,7 @@ use pg_srv::{
2416
PgTypeId, ProtocolError, ToProtocolValue,
2517
};
2618
use postgres_types::{ToSql, Type};
27-
use std::{convert::TryFrom, io, io::Error};
28-
29-
// POSTGRES_EPOCH_JDATE
30-
fn pg_base_date_epoch() -> NaiveDateTime {
31-
NaiveDate::from_ymd_opt(2000, 1, 1)
32-
.unwrap()
33-
.and_hms_opt(0, 0, 0)
34-
.unwrap()
35-
}
36-
37-
impl ToProtocolValue for TimestampValue {
38-
fn to_text(&self, buf: &mut BytesMut) -> Result<(), ProtocolError> {
39-
let ndt = match self.tz_ref() {
40-
None => self.to_naive_datetime(),
41-
Some(_) => self.to_fixed_datetime()?.naive_utc(),
42-
};
43-
44-
// 2022-04-25 15:36:49.39705+00
45-
let as_str = ndt
46-
.format_with_items(
47-
[
48-
Item::Numeric(Year, Zero),
49-
Item::Literal("-"),
50-
Item::Numeric(Month, Zero),
51-
Item::Literal("-"),
52-
Item::Numeric(Day, Zero),
53-
Item::Literal(" "),
54-
Item::Numeric(Hour, Zero),
55-
Item::Literal(":"),
56-
Item::Numeric(Minute, Zero),
57-
Item::Literal(":"),
58-
Item::Numeric(Second, Zero),
59-
Item::Fixed(Fixed::Nanosecond6),
60-
]
61-
.iter(),
62-
)
63-
.to_string();
64-
65-
match self.tz_ref() {
66-
None => as_str.to_text(buf),
67-
Some(_) => (as_str + "+00").to_text(buf),
68-
}
69-
}
70-
71-
fn to_binary(&self, buf: &mut BytesMut) -> Result<(), ProtocolError> {
72-
match self.tz_ref() {
73-
None => {
74-
let seconds = self
75-
.to_naive_datetime()
76-
.signed_duration_since(pg_base_date_epoch())
77-
.num_microseconds()
78-
.ok_or(Error::new(
79-
io::ErrorKind::Other,
80-
"Unable to extract number of seconds from timestamp",
81-
))?;
82-
83-
buf.put_i32(8_i32);
84-
buf.put_i64(seconds)
85-
}
86-
Some(tz) => {
87-
let seconds = self
88-
.to_fixed_datetime()?
89-
.naive_utc()
90-
.signed_duration_since(pg_base_date_epoch())
91-
.num_microseconds()
92-
.ok_or(Error::new(
93-
io::ErrorKind::Other,
94-
format!(
95-
"Unable to extract number of seconds from timestamp with tz: {}",
96-
tz
97-
),
98-
))?;
99-
100-
buf.put_i32(8_i32);
101-
buf.put_i64(seconds)
102-
}
103-
};
104-
105-
Ok(())
106-
}
107-
}
19+
use std::convert::TryFrom;
10820

10921
/// https://github.com/postgres/postgres/blob/REL_14_4/src/backend/utils/adt/numeric.c#L1022
11022
impl ToProtocolValue for Decimal128Value {
@@ -324,13 +236,13 @@ impl Serialize for BatchWriter {
324236
#[cfg(test)]
325237
mod tests {
326238
use crate::sql::{
327-
dataframe::{Decimal128Value, ListValue, TimestampValue},
239+
dataframe::{Decimal128Value, ListValue},
328240
shim::ConnectionError,
329241
writer::{BatchWriter, ToProtocolValue},
330242
};
331243
use bytes::BytesMut;
332244
use datafusion::arrow::array::{ArrayRef, Int64Builder};
333-
use pg_srv::{buffer, protocol::Format};
245+
use pg_srv::{buffer, protocol::Format, TimestampValue};
334246
use std::{io::Cursor, sync::Arc};
335247

336248
fn assert_text_encode<T: ToProtocolValue>(value: T, expected: &[u8]) {

rust/cubesql/pg-srv/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ thiserror = "2"
2222
chrono = { version = "0.4", package = "chrono", default-features = false, features = [
2323
"clock",
2424
], optional = true }
25+
chrono-tz = "0.8"
2526

2627
[dev-dependencies]
2728
hex = "0.4.3"

rust/cubesql/pg-srv/src/encoding.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ impl ToProtocolValue for NaiveDate {
146146
}
147147
}
148148

149-
150149
#[cfg(test)]
151150
mod tests {
152151
use crate::*;
@@ -182,5 +181,4 @@ mod tests {
182181

183182
Ok(())
184183
}
185-
186184
}

rust/cubesql/pg-srv/src/interval.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,4 +204,4 @@ mod tests {
204204

205205
Ok(())
206206
}
207-
}
207+
}

rust/cubesql/pg-srv/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ pub mod extended;
1010
pub mod interval;
1111
pub mod pg_type;
1212
pub mod protocol;
13+
pub mod timestamp;
1314

1415
pub use buffer::*;
1516
pub use decoding::*;
1617
pub use encoding::*;
1718
pub use extended::*;
1819
pub use interval::*;
1920
pub use pg_type::*;
21+
pub use timestamp::*;
2022

2123
use std::{backtrace::Backtrace, fmt::Formatter};
2224

0 commit comments

Comments
 (0)