Skip to content

Commit

Permalink
fix(driver): parse null value for Nullable column
Browse files Browse the repository at this point in the history
  • Loading branch information
everpcpc committed Apr 21, 2023
1 parent cdf6de6 commit 5460213
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 2 deletions.
2 changes: 1 addition & 1 deletion driver/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "databend-driver"
version = "0.2.16"
version = "0.2.17"
edition = "2021"
license = "Apache-2.0"
description = "Databend Driver for Rust"
Expand Down
Empty file added driver/core
Empty file.
46 changes: 45 additions & 1 deletion driver/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::error::{ConvertError, Error, Result};

// Thu 1970-01-01 is R.D. 719163
const DAYS_FROM_CE: i32 = 719_163;
const NULL_VALUE: &str = "NULL";

#[cfg(feature = "flight-sql")]
use {
Expand Down Expand Up @@ -140,7 +141,13 @@ impl TryFrom<(&DataType, &str)> for Value {
DataType::Date => Ok(Self::Date(
chrono::NaiveDate::parse_from_str(v, "%Y-%m-%d")?.num_days_from_ce() - DAYS_FROM_CE,
)),
DataType::Nullable(inner) => Self::try_from((inner.as_ref(), v)),
DataType::Nullable(inner) => {
if v == NULL_VALUE {
Ok(Self::Null)
} else {
Self::try_from((inner.as_ref(), v))
}
}
// TODO:(everpcpc) handle complex types
_ => Ok(Self::String(v.to_string())),
}
Expand All @@ -153,6 +160,9 @@ impl TryFrom<(&ArrowField, &Arc<dyn ArrowArray>, usize)> for Value {
fn try_from(
(field, array, seq): (&ArrowField, &Arc<dyn ArrowArray>, usize),
) -> std::result::Result<Self, Self::Error> {
if field.is_nullable() && array.is_null(seq) {
return Ok(Value::Null);
}
match field.data_type() {
ArrowDataType::Null => Ok(Value::Null),
ArrowDataType::Boolean => match array.as_any().downcast_ref::<BooleanArray>() {
Expand Down Expand Up @@ -361,6 +371,40 @@ impl TryFrom<Value> for NaiveDate {
}
}

// This macro implements TryFrom to Option for Nullable column
macro_rules! impl_try_from_to_option {
($($t:ty),*) => {
$(
impl TryFrom<Value> for Option<$t> {
type Error = Error;
fn try_from(val: Value) -> Result<Self> {
match val {
Value::Null => Ok(None),
_ => {
let inner: $t = val.try_into()?;
Ok(Some(inner))
},
}

}
}
)*
};
}

impl_try_from_to_option!(String);
impl_try_from_to_option!(bool);
impl_try_from_to_option!(u8);
impl_try_from_to_option!(u16);
impl_try_from_to_option!(u32);
impl_try_from_to_option!(u64);
impl_try_from_to_option!(i8);
impl_try_from_to_option!(i16);
impl_try_from_to_option!(i32);
impl_try_from_to_option!(i64);
impl_try_from_to_option!(f32);
impl_try_from_to_option!(f64);

impl std::fmt::Display for NumberValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand Down
26 changes: 26 additions & 0 deletions driver/tests/driver/select_simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,32 @@ async fn select_datetime() {
}
}

#[tokio::test]
async fn select_null() {
let conn = prepare().await;
let row = conn
.query_row("select sum(number) from numbers(0)")
.await
.unwrap();
assert!(row.is_some());
let row = row.unwrap();
let (val,): (Option<u64>,) = row.try_into().unwrap();
assert_eq!(val, None);
}

#[tokio::test]
async fn select_nullable_u64() {
let conn = prepare().await;
let row = conn
.query_row("select sum(number) from numbers(100)")
.await
.unwrap();
assert!(row.is_some());
let row = row.unwrap();
let (val,): (Option<u64>,) = row.try_into().unwrap();
assert_eq!(val, Some(4950));
}

// TODO:(everpcoc) parse to real array
// #[tokio::test]
// async fn select_array() {
Expand Down

0 comments on commit 5460213

Please sign in to comment.