diff --git a/sqllogictest-bin/src/engines/postgres_extended.rs b/sqllogictest-bin/src/engines/postgres_extended.rs index cf0716e..71c6459 100644 --- a/sqllogictest-bin/src/engines/postgres_extended.rs +++ b/sqllogictest-bin/src/engines/postgres_extended.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use anyhow::Context; use async_trait::async_trait; -use chrono::{NaiveDate, NaiveDateTime, NaiveTime, DateTime}; +use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime}; use pg_interval::Interval; use postgres_types::Type; use rust_decimal::Decimal; @@ -74,6 +74,60 @@ macro_rules! array_process { } } }; + ($row:ident, $output:ident, $idx:ident, $t:ty, $convert:ident) => { + let value: Option>> = $row.get($idx); + match value { + Some(value) => { + write!($output, "{{").unwrap(); + for (i, v) in value.iter().enumerate() { + match v { + Some(v) => { + write!($output, "{}", $convert(v)).unwrap(); + } + None => { + write!($output, "NULL").unwrap(); + } + } + if i < value.len() - 1 { + write!($output, ",").unwrap(); + } + } + write!($output, "}}").unwrap(); + } + None => { + write!($output, "NULL").unwrap(); + } + } + }; + ($self:ident, $row:ident, $output:ident, $idx:ident, $t:ty, $ty_name:expr) => { + let value: Option>> = $row.get($idx); + match value { + Some(value) => { + write!($output, "{{").unwrap(); + for (i, v) in value.iter().enumerate() { + match v { + Some(v) => { + let sql = format!("select ($1::{})::varchar", stringify!($ty_name)); + let tmp_rows = $self.client.query(&sql, &[&v]).await.unwrap(); + let value: &str = tmp_rows.get(0).unwrap().get(0); + assert!(value.len() > 0); + write!($output, "{}", value).unwrap(); + } + None => { + write!($output, "NULL").unwrap(); + } + } + if i < value.len() - 1 { + write!($output, ",").unwrap(); + } + } + write!($output, "}}").unwrap(); + } + None => { + write!($output, "NULL").unwrap(); + } + } + }; } macro_rules! single_process { @@ -88,9 +142,17 @@ macro_rules! single_process { } } }; -} - -macro_rules! str_process { + ($row:ident, $output:ident, $idx:ident, $t:ty, $convert:ident) => { + let value: Option<$t> = $row.get($idx); + match value { + Some(value) => { + write!($output, "{}", $convert(&value)).unwrap(); + } + None => { + write!($output, "NULL").unwrap(); + } + } + }; ($self:ident, $row:ident, $output:ident, $idx:ident, $t:ty, $ty_name:expr) => { let value: Option<$t> = $row.get($idx); match value { @@ -98,7 +160,7 @@ macro_rules! str_process { let sql = format!("select ($1::{})::varchar", stringify!($ty_name)); let tmp_rows = $self.client.query(&sql, &[&value]).await.unwrap(); let value: &str = tmp_rows.get(0).unwrap().get(0); - assert!(value.len()>0); + assert!(value.len() > 0); write!($output, "{}", value).unwrap(); } None => { @@ -108,6 +170,46 @@ macro_rules! str_process { }; } +fn bool_to_str(value: &bool) -> &'static str { + if *value { + "t" + } else { + "f" + } +} + +fn varchar_to_str(value: &str) -> String { + if value.is_empty() { + "(empty)".to_string() + } else { + value.to_string() + } +} + +fn float4_to_str(value: &f32) -> String { + if value.is_nan() { + "NaN".to_string() + } else if *value == f32::INFINITY { + "Infinity".to_string() + } else if *value == f32::NEG_INFINITY { + "-Infinity".to_string() + } else { + value.to_string() + } +} + +fn float8_to_str(value: &f64) -> String { + if value.is_nan() { + "NaN".to_string() + } else if *value == f64::INFINITY { + "Infinity".to_string() + } else if *value == f64::NEG_INFINITY { + "-Infinity".to_string() + } else { + value.to_string() + } +} + #[async_trait] impl sqllogictest::AsyncDB for PostgresExtended { type Error = tokio_postgres::error::Error; @@ -154,6 +256,9 @@ impl sqllogictest::AsyncDB for PostgresExtended { Type::TIMESTAMP => { single_process!(row, output, idx, NaiveDateTime); } + Type::BOOL => { + single_process!(row, output, idx, bool, bool_to_str); + } Type::INT2_ARRAY => { array_process!(row, output, idx, i16); } @@ -163,84 +268,64 @@ impl sqllogictest::AsyncDB for PostgresExtended { Type::INT8_ARRAY => { array_process!(row, output, idx, i64); } + Type::BOOL_ARRAY => { + array_process!(row, output, idx, bool, bool_to_str); + } Type::FLOAT4_ARRAY => { - array_process!(row, output, idx, f32); + array_process!(row, output, idx, f32, float4_to_str); } Type::FLOAT8_ARRAY => { - array_process!(row, output, idx, f64); + array_process!(row, output, idx, f64, float8_to_str); } Type::NUMERIC_ARRAY => { array_process!(row, output, idx, Decimal); } - Type::VARCHAR | Type::TEXT => { - let value: Option<&str> = row.get(idx); - match value { - Some(value) => { - if value.is_empty() { - write!(output, "(empty)").unwrap(); - } else { - write!(output, "{}", value).unwrap(); - } - } - None => { - write!(output, "NULL").unwrap(); - } - } + Type::DATE_ARRAY => { + array_process!(row, output, idx, NaiveDate); } - Type::BOOL => { - let value: Option = row.get(idx); - match value { - Some(value) => { - if value { - write!(output, "t").unwrap(); - } else { - write!(output, "f").unwrap(); - } - } - None => { - write!(output, "NULL").unwrap(); - } - } + Type::TIME_ARRAY => { + array_process!(row, output, idx, NaiveTime); + } + Type::TIMESTAMP_ARRAY => { + array_process!(row, output, idx, NaiveDateTime); + } + Type::VARCHAR_ARRAY | Type::TEXT_ARRAY => { + array_process!(row, output, idx, String, varchar_to_str); + } + Type::VARCHAR | Type::TEXT => { + single_process!(row, output, idx, String, varchar_to_str); } Type::FLOAT4 => { - let value: Option = row.get(idx); - match value { - Some(value) => { - if value == f32::INFINITY { - write!(output, "Infinity").unwrap(); - } else if value == f32::NEG_INFINITY { - write!(output, "-Infinity").unwrap(); - } else { - write!(output, "{}", value).unwrap(); - } - } - None => { - write!(output, "NULL").unwrap(); - } - } + single_process!(row, output, idx, f32, float4_to_str); } Type::FLOAT8 => { - let value: Option = row.get(idx); - match value { - Some(value) => { - if value == f64::INFINITY { - write!(output, "Infinity").unwrap(); - } else if value == f64::NEG_INFINITY { - write!(output, "-Infinity").unwrap(); - } else { - write!(output, "{}", value).unwrap(); - } - } - None => { - write!(output, "NULL").unwrap(); - } - } + single_process!(row, output, idx, f64, float8_to_str); } Type::INTERVAL => { - str_process!(self,row, output, idx, Interval,INTERVAL); + single_process!(self, row, output, idx, Interval, INTERVAL); } Type::TIMESTAMPTZ => { - str_process!(self,row, output, idx, DateTime ,TIMESTAMPTZ); + single_process!( + self, + row, + output, + idx, + DateTime, + TIMESTAMPTZ + ); + } + Type::INTERVAL_ARRAY => { + array_process!(self, row, output, idx, Interval, INTERVAL); + } + Type::TIMESTAMPTZ_ARRAY => { + array_process!( + self, + row, + output, + idx, + DateTime, + TIMESTAMPTZ + ); } _ => { todo!("Don't support {} type now.", column.type_().name()) diff --git a/sqllogictest-bin/src/engines/postgres_extended_test.slt b/sqllogictest-bin/src/engines/postgres_extended_test.slt new file mode 100644 index 0000000..7722dc1 --- /dev/null +++ b/sqllogictest-bin/src/engines/postgres_extended_test.slt @@ -0,0 +1,107 @@ +# postgres_extended engine support following type: +# NOTE: array only support one dimension +# int2 +# int2 array +# int4 +# int4 array +# int8 +# int8 array +# float4 +# float4 array +# float8 +# float8 array +# numeric (not include: NaN,+Inf,-Inf) +# numeric array +# varchar +# varchar array +# date +# date array +# time +# time array +# timestamp +# timestamp array +# timestamptz +# timestamptz array +# interval +# interval array +# bool +# bool array + +# int2 && int2 array +query I +select 1::int2, '{1,2,3}'::int2[] +---- +1 {1,2,3} + +# int4 && int4 array +query I +select 1::int4, '{1,2,3}'::int4[] +---- +1 {1,2,3} + +# int8 && int8 array +query I +select 1::int8, '{1,2,3}'::int8[] +---- +1 {1,2,3} + +# float4 && float4 array +query I +select 1.0::float4, '{NaN,+Inf,-Inf}'::float4[] +---- +1 {NaN,Infinity,-Infinity} + +# float8 && float8 array +query I +select 1.0::float8, '{NaN,+Inf,-Inf}'::float8[] +---- +1 {NaN,Infinity,-Infinity} + +# numeric && numeric array +query I +select 1.0::numeric, '{2.0,3.0123,4.0123}'::numeric[] +---- +1.0 {2.0,3.0123,4.0123} + +# varchar && varchar array +query I +select 'a'::varchar, '{a,b,""}'::varchar[] +---- +a {a,b,(empty)} + +# date && date array +query I +select '2018-01-01'::date, '{2018-01-01,2018-01-02,2018-01-03}'::date[] +---- +2018-01-01 {2018-01-01,2018-01-02,2018-01-03} + +# time && time array +query I +select '12:00:00'::time, '{12:00:00,12:00:01,12:00:02}'::time[] +---- +12:00:00 {12:00:00,12:00:01,12:00:02} + +# timestamp && timestamp array +query I +select '2018-01-01 12:00:00'::timestamp, '{2018-01-01 12:00:00,2018-01-01 12:00:01,2018-01-01 12:00:02}'::timestamp[] +---- +2018-01-01 12:00:00 {2018-01-01 12:00:00,2018-01-01 12:00:01,2018-01-01 12:00:02} + +# timestamptz && timestamptz array +query I +select '2018-01-01 12:00:00+08'::timestamptz, '{2018-01-01 12:00:00+08,2018-01-01 12:00:01+08,2018-01-01 12:00:02+08}'::timestamptz[] +---- +2018-01-01 12:00:00+08 {2018-01-01 12:00:00+08,2018-01-01 12:00:01+08,2018-01-01 12:00:02+08} + +# interval && interval array +query I +select '1 day'::interval, '{1 day,2 mon,30 day}'::interval[] +---- +1 day {1 day,2 mons,30 days} + +# bool && bool array +query I +select true::bool, '{true,false}'::bool[] +---- +t {t,f} +