Skip to content

Commit b0475cd

Browse files
authored
Merge pull request #18 from wangfenjin/time64
support time64
2 parents 9fafb50 + 9d67434 commit b0475cd

File tree

7 files changed

+69
-21
lines changed

7 files changed

+69
-21
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ name = "duckdb"
2121
members = ["libduckdb-sys"]
2222

2323
[features]
24-
default = ["modern-full"]
24+
default = []
2525
bundled = ["libduckdb-sys/bundled"]
2626
buildtime_bindgen = ["libduckdb-sys/buildtime_bindgen"]
2727
modern-full = [

src/row.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -532,22 +532,15 @@ impl<'stmt> Row<'stmt> {
532532
}
533533
ValueRef::Date32(array.value(row))
534534
}
535-
// NOTE: DataType::Date64 not supported by duckdb
536-
// DataType::Date64 => make_string_date!(array::Date64Array, column, row),
535+
DataType::Time64(TimeUnit::Microsecond) => {
536+
let array = column.as_any().downcast_ref::<array::Time64MicrosecondArray>().unwrap();
537537

538+
if array.is_null(row) {
539+
return ValueRef::Null;
540+
}
541+
ValueRef::Time64(types::TimeUnit::Microsecond, array.value(row))
542+
}
538543
// TODO: support more data types
539-
// DataType::Time32(unit) if *unit == TimeUnit::Second => {
540-
// make_string_time!(array::Time32SecondArray, column, row)
541-
// }
542-
// DataType::Time32(unit) if *unit == TimeUnit::Millisecond => {
543-
// make_string_time!(array::Time32MillisecondArray, column, row)
544-
// }
545-
// DataType::Time64(unit) if *unit == TimeUnit::Microsecond => {
546-
// make_string_time!(array::Time64MicrosecondArray, column, row)
547-
// }
548-
// DataType::Time64(unit) if *unit == TimeUnit::Nanosecond => {
549-
// make_string_time!(array::Time64NanosecondArray, column, row)
550-
// }
551544
// DataType::Interval(unit) => match unit {
552545
// IntervalUnit::DayTime => {
553546
// make_string_interval_day_time!(column, row)
@@ -571,6 +564,18 @@ impl<'stmt> Row<'stmt> {
571564
// column.data_type()
572565
// ))),
573566
// },
567+
568+
// NOTE: DataTypes not supported by duckdb
569+
// DataType::Date64 => make_string_date!(array::Date64Array, column, row),
570+
// DataType::Time32(unit) if *unit == TimeUnit::Second => {
571+
// make_string_time!(array::Time32SecondArray, column, row)
572+
// }
573+
// DataType::Time32(unit) if *unit == TimeUnit::Millisecond => {
574+
// make_string_time!(array::Time32MillisecondArray, column, row)
575+
// }
576+
// DataType::Time64(unit) if *unit == TimeUnit::Nanosecond => {
577+
// make_string_time!(array::Time64NanosecondArray, column, row)
578+
// }
574579
_ => unreachable!("invalid value: {}, {}", col, self.stmt.column_type(col)),
575580
}
576581
}

src/types/chrono.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ impl FromSql for NaiveDateTime {
6464
Ok(NaiveDateTime::from_timestamp(secs, nsecs as u32))
6565
}
6666
ValueRef::Date32(d) => Ok(NaiveDateTime::from_timestamp(24 * 3600 * (d as i64), 0)),
67+
ValueRef::Time64(TimeUnit::Microsecond, d) => Ok(NaiveDateTime::from_timestamp(
68+
d / 1_000_000,
69+
((d % 1_000_000) * 1_000) as u32,
70+
)),
6771
ValueRef::Text(s) => {
6872
let mut s = std::str::from_utf8(s).unwrap();
6973
let format = match s.len() {
@@ -128,10 +132,23 @@ mod test {
128132

129133
fn checked_memory_handle() -> Result<Connection> {
130134
let db = Connection::open_in_memory()?;
131-
db.execute_batch("CREATE TABLE foo (d DATE, t Text, i INTEGER, f FLOAT, b TIMESTAMP)")?;
135+
db.execute_batch("CREATE TABLE foo (d DATE, t Text, i INTEGER, f FLOAT, b TIMESTAMP, tt time)")?;
132136
Ok(db)
133137
}
134138

139+
#[test]
140+
fn test_naive_time() -> Result<()> {
141+
let db = checked_memory_handle()?;
142+
let time = NaiveTime::from_hms_micro(23, 56, 4, 12_345);
143+
db.execute("INSERT INTO foo (tt) VALUES (?)", [time])?;
144+
145+
let s: String = db.query_row("SELECT tt FROM foo", [], |r| r.get(0))?;
146+
assert_eq!("23:56:04.012345", s);
147+
let t: NaiveTime = db.query_row("SELECT tt FROM foo", [], |r| r.get(0))?;
148+
assert_eq!(time, t);
149+
Ok(())
150+
}
151+
135152
#[test]
136153
fn test_naive_date() -> Result<()> {
137154
let db = checked_memory_handle()?;
@@ -222,9 +239,8 @@ mod test {
222239
assert!(result.is_ok());
223240
let result: Result<DateTime<Utc>> = db.query_row("SELECT CURRENT_TIMESTAMP", [], |r| r.get(0));
224241
assert!(result.is_ok());
225-
// TODO(wangfenjin): time64
226-
// let result: Result<NaiveTime> = db.query_row("SELECT CURRENT_TIME", [], |r| r.get(0));
227-
// assert!(result.is_ok());
242+
let result: Result<NaiveTime> = db.query_row("SELECT CURRENT_TIME", [], |r| r.get(0));
243+
assert!(result.is_ok());
228244
Ok(())
229245
}
230246

src/types/from_sql.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
extern crate cast;
22

3-
use super::{Value, ValueRef};
3+
use super::{TimeUnit, Value, ValueRef};
44
use std::error::Error;
55
use std::fmt;
66

@@ -89,6 +89,7 @@ macro_rules! from_sql_integral(
8989

9090
ValueRef::Timestamp(_, i) => Ok(<$t as cast::From<i64>>::cast(i).unwrap()),
9191
ValueRef::Date32(i) => Ok(<$t as cast::From<i32>>::cast(i).unwrap()),
92+
ValueRef::Time64(TimeUnit::Microsecond, i) => Ok(<$t as cast::From<i64>>::cast(i).unwrap()),
9293
ValueRef::Text(_) => {
9394
let v = value.as_str()?.parse::<$t>();
9495
match v {
@@ -174,6 +175,8 @@ impl FromSql for String {
174175
#[cfg(feature = "chrono")]
175176
ValueRef::Date32(_) => Ok(chrono::NaiveDate::column_result(value)?.format("%F").to_string()),
176177
#[cfg(feature = "chrono")]
178+
ValueRef::Time64(..) => Ok(chrono::NaiveTime::column_result(value)?.format("%T%.f").to_string()),
179+
#[cfg(feature = "chrono")]
177180
ValueRef::Timestamp(..) => Ok(chrono::NaiveDateTime::column_result(value)?
178181
.format("%F %T%.f")
179182
.to_string()),
@@ -263,6 +266,19 @@ mod test {
263266
Ok(())
264267
}
265268

269+
#[test]
270+
fn test_time64_raw() -> Result<()> {
271+
let db = Connection::open_in_memory()?;
272+
let sql = "BEGIN;
273+
CREATE TABLE time64 (t time);
274+
INSERT INTO time64 VALUES ('20:08:10.998');
275+
END;";
276+
db.execute_batch(sql)?;
277+
let v = db.query_row("SELECT * FROM time64", [], |row| <(i64,)>::try_from(row))?;
278+
assert_eq!(v, (72490998000,));
279+
Ok(())
280+
}
281+
266282
#[test]
267283
fn test_date32_raw() -> Result<()> {
268284
let db = Connection::open_in_memory()?;

src/types/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ pub enum Type {
142142
Blob,
143143
/// DATE32
144144
Date32,
145+
/// TIME64
146+
Time64,
145147
/// Any
146148
Any,
147149
}
@@ -167,6 +169,7 @@ impl fmt::Display for Type {
167169
Type::Text => f.pad("Text"),
168170
Type::Blob => f.pad("Blob"),
169171
Type::Date32 => f.pad("Date32"),
172+
Type::Time64 => f.pad("Time64"),
170173
Type::Any => f.pad("Any"),
171174
}
172175
}

src/types/value.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ pub enum Value {
4444
Blob(Vec<u8>),
4545
/// The value is a date32
4646
Date32(i32),
47+
/// The value is a time64
48+
Time64(TimeUnit, i64),
4749
}
4850

4951
impl From<Null> for Value {
@@ -200,6 +202,7 @@ impl Value {
200202
Value::Text(_) => Type::Text,
201203
Value::Blob(_) => Type::Blob,
202204
Value::Date32(_) => Type::Date32,
205+
Value::Time64(..) => Type::Time64,
203206
}
204207
}
205208
}

src/types/value_ref.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ pub enum ValueRef<'a> {
5959
Blob(&'a [u8]),
6060
/// The value is a date32
6161
Date32(i32),
62+
/// The value is a time64
63+
Time64(TimeUnit, i64),
6264
}
6365

6466
impl ValueRef<'_> {
@@ -80,10 +82,11 @@ impl ValueRef<'_> {
8082
ValueRef::Float(_) => Type::Float,
8183
ValueRef::Double(_) => Type::Double,
8284
ValueRef::Decimal(_) => Type::Decimal,
83-
ValueRef::Timestamp(_, _) => Type::Timestamp,
85+
ValueRef::Timestamp(..) => Type::Timestamp,
8486
ValueRef::Text(_) => Type::Text,
8587
ValueRef::Blob(_) => Type::Blob,
8688
ValueRef::Date32(_) => Type::Date32,
89+
ValueRef::Time64(..) => Type::Time64,
8790
}
8891
}
8992
}
@@ -135,6 +138,7 @@ impl From<ValueRef<'_>> for Value {
135138
}
136139
ValueRef::Blob(b) => Value::Blob(b.to_vec()),
137140
ValueRef::Date32(d) => Value::Date32(d),
141+
ValueRef::Time64(t, d) => Value::Time64(t, d),
138142
}
139143
}
140144
}
@@ -175,6 +179,7 @@ impl<'a> From<&'a Value> for ValueRef<'a> {
175179
Value::Text(ref s) => ValueRef::Text(s.as_bytes()),
176180
Value::Blob(ref b) => ValueRef::Blob(b),
177181
Value::Date32(d) => ValueRef::Date32(d),
182+
Value::Time64(t, d) => ValueRef::Time64(t, d),
178183
}
179184
}
180185
}

0 commit comments

Comments
 (0)