You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by al...@apache.org on 2022/11/08 21:39:58 UTC
[arrow-datafusion] branch master updated: support `SET Timezone` (#4107)
This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-datafusion.git
The following commit(s) were added to refs/heads/master by this push:
new e8fe04256 support `SET Timezone` (#4107)
e8fe04256 is described below
commit e8fe0425685e68826521c5a4e78d15d35f4556c2
Author: Wei-Ting Kuo <wa...@gmail.com>
AuthorDate: Wed Nov 9 05:39:53 2022 +0800
support `SET Timezone` (#4107)
* poc
* fix test cases
* fix examples, add more test cases
* cargo fmt and clippy
* clippy
---
datafusion-examples/examples/rewrite_expr.rs | 7 +
datafusion/core/src/execution/context.rs | 4 +
datafusion/core/tests/sql/set_variable.rs | 247 ++++++++++++++++++++++---
datafusion/optimizer/tests/integration-test.rs | 7 +
datafusion/sql/examples/sql.rs | 7 +
datafusion/sql/src/planner.rs | 240 +++++++++++++-----------
6 files changed, 377 insertions(+), 135 deletions(-)
diff --git a/datafusion-examples/examples/rewrite_expr.rs b/datafusion-examples/examples/rewrite_expr.rs
index d4a34e199..7a2ee6d93 100644
--- a/datafusion-examples/examples/rewrite_expr.rs
+++ b/datafusion-examples/examples/rewrite_expr.rs
@@ -148,6 +148,13 @@ impl ContextProvider for MyContextProvider {
fn get_variable_type(&self, _variable_names: &[String]) -> Option<DataType> {
None
}
+
+ fn get_config_option(
+ &self,
+ _variable: &str,
+ ) -> Option<datafusion_common::ScalarValue> {
+ None
+ }
}
struct MyTableSource {
diff --git a/datafusion/core/src/execution/context.rs b/datafusion/core/src/execution/context.rs
index ec709f931..553a208b8 100644
--- a/datafusion/core/src/execution/context.rs
+++ b/datafusion/core/src/execution/context.rs
@@ -1818,6 +1818,10 @@ impl ContextProvider for SessionState {
.as_ref()
.and_then(|provider| provider.get(&provider_type)?.get_type(variable_names))
}
+
+ fn get_config_option(&self, variable: &str) -> Option<ScalarValue> {
+ self.config.config_options.read().get(variable)
+ }
}
impl FunctionRegistry for SessionState {
diff --git a/datafusion/core/tests/sql/set_variable.rs b/datafusion/core/tests/sql/set_variable.rs
index 2bbe49120..085e7b1f4 100644
--- a/datafusion/core/tests/sql/set_variable.rs
+++ b/datafusion/core/tests/sql/set_variable.rs
@@ -260,37 +260,238 @@ async fn set_u64_variable_bad_value() {
#[tokio::test]
async fn set_time_zone() {
- // we don't support changing time zone for now until all time zone issues fixed and related function completed
+ let ctx =
+ SessionContext::with_config(SessionConfig::new().with_information_schema(true));
- let ctx = SessionContext::new();
+ plan_and_collect(&ctx, "SET datafusion.execution.time_zone = '+08:00'")
+ .await
+ .unwrap();
- // for full variable name
- let err = plan_and_collect(&ctx, "set datafusion.execution.time_zone = '8'")
+ let result = plan_and_collect(&ctx, "SHOW datafusion.execution.time_zone")
.await
- .unwrap_err();
+ .unwrap();
+ let expected = vec![
+ "+--------------------------------+---------+",
+ "| name | setting |",
+ "+--------------------------------+---------+",
+ "| datafusion.execution.time_zone | +08:00 |",
+ "+--------------------------------+---------+",
+ ];
+ assert_batches_eq!(expected, &result);
+}
- assert_eq!(
- err.to_string(),
- "Error during planning: Changing Time Zone isn't supported yet"
- );
+#[tokio::test]
+async fn set_time_zone_with_alias_variable_name() {
+ let ctx =
+ SessionContext::with_config(SessionConfig::new().with_information_schema(true));
- // for alias time zone
- let err = plan_and_collect(&ctx, "set time zone = '8'")
+ // TIME ZONE with space
+ plan_and_collect(&ctx, "SET TIME ZONE = '+08:00'")
.await
- .unwrap_err();
+ .unwrap();
- assert_eq!(
- err.to_string(),
- "Error during planning: Changing Time Zone isn't supported yet"
- );
+ let result = plan_and_collect(&ctx, "SHOW TIME ZONE").await.unwrap();
+ let expected = vec![
+ "+--------------------------------+---------+",
+ "| name | setting |",
+ "+--------------------------------+---------+",
+ "| datafusion.execution.time_zone | +08:00 |",
+ "+--------------------------------+---------+",
+ ];
+ assert_batches_eq!(expected, &result);
- // for alias timezone
- let err = plan_and_collect(&ctx, "set timezone = '8'")
+ // TIMEZONE without space
+ plan_and_collect(&ctx, "SET TIMEZONE = '+07:00'")
.await
- .unwrap_err();
+ .unwrap();
- assert_eq!(
- err.to_string(),
- "Error during planning: Changing Time Zone isn't supported yet"
- );
+ let result = plan_and_collect(&ctx, "SHOW TIMEZONE").await.unwrap();
+ let expected = vec![
+ "+--------------------------------+---------+",
+ "| name | setting |",
+ "+--------------------------------+---------+",
+ "| datafusion.execution.time_zone | +07:00 |",
+ "+--------------------------------+---------+",
+ ];
+ assert_batches_eq!(expected, &result);
+}
+
+#[tokio::test]
+async fn set_time_zone_good_time_zone_format() {
+ let ctx =
+ SessionContext::with_config(SessionConfig::new().with_information_schema(true));
+
+ plan_and_collect(&ctx, "SET TIME ZONE = '+08:00'")
+ .await
+ .unwrap();
+
+ // casting UTF-8 to TimestampTZ isn't supported yet, add Timestamp as the middle layer for now
+ let result =
+ plan_and_collect(&ctx, "SELECT '2000-01-01T00:00:00'::TIMESTAMP::TIMESTAMPTZ")
+ .await
+ .unwrap();
+ let expected = vec![
+ "+-----------------------------+",
+ "| Utf8(\"2000-01-01T00:00:00\") |",
+ "+-----------------------------+",
+ "| 2000-01-01T08:00:00+08:00 |",
+ "+-----------------------------+",
+ ];
+ // this might break once https://github.com/apache/arrow-rs/issues/1936 fixed
+ assert_batches_eq!(expected, &result);
+
+ plan_and_collect(&ctx, "SET TIME ZONE = '-08:00'")
+ .await
+ .unwrap();
+
+ // casting UTF-8 to TimestampTZ isn't supported yet, add Timestamp as the middle layer for now
+ let result =
+ plan_and_collect(&ctx, "SELECT '2000-01-01T00:00:00'::TIMESTAMP::TIMESTAMPTZ")
+ .await
+ .unwrap();
+ let expected = vec![
+ "+-----------------------------+",
+ "| Utf8(\"2000-01-01T00:00:00\") |",
+ "+-----------------------------+",
+ "| 1999-12-31T16:00:00-08:00 |",
+ "+-----------------------------+",
+ ];
+ // this might break once https://github.com/apache/arrow-rs/issues/1936 fixed
+ assert_batches_eq!(expected, &result);
+
+ plan_and_collect(&ctx, "SET TIME ZONE = '+0800'")
+ .await
+ .unwrap();
+
+ // casting UTF-8 to TimestampTZ isn't supported yet, add Timestamp as the middle layer for now
+ let result =
+ plan_and_collect(&ctx, "SELECT '2000-01-01T00:00:00'::TIMESTAMP::TIMESTAMPTZ")
+ .await
+ .unwrap();
+ let expected = vec![
+ "+-----------------------------+",
+ "| Utf8(\"2000-01-01T00:00:00\") |",
+ "+-----------------------------+",
+ "| 2000-01-01T08:00:00+08:00 |",
+ "+-----------------------------+",
+ ];
+ // this might break once https://github.com/apache/arrow-rs/issues/1936 fixed
+ assert_batches_eq!(expected, &result);
+
+ plan_and_collect(&ctx, "SET TIME ZONE = '+08'")
+ .await
+ .unwrap();
+
+ // casting UTF-8 to TimestampTZ isn't supported yet, add Timestamp as the middle layer for now
+ let result =
+ plan_and_collect(&ctx, "SELECT '2000-01-01T00:00:00'::TIMESTAMP::TIMESTAMPTZ")
+ .await
+ .unwrap();
+ let expected = vec![
+ "+-----------------------------+",
+ "| Utf8(\"2000-01-01T00:00:00\") |",
+ "+-----------------------------+",
+ "| 2000-01-01T08:00:00+08:00 |",
+ "+-----------------------------+",
+ ];
+ // this might break once https://github.com/apache/arrow-rs/issues/1936 fixed
+ assert_batches_eq!(expected, &result);
+}
+
+#[tokio::test]
+async fn set_time_zone_bad_time_zone_format() {
+ let ctx =
+ SessionContext::with_config(SessionConfig::new().with_information_schema(true));
+
+ plan_and_collect(&ctx, "SET TIME ZONE = '+08:00:00'")
+ .await
+ .unwrap();
+
+ // casting UTF-8 to TimestampTZ isn't supported yet, add Timestamp as the middle layer for now
+ let result =
+ plan_and_collect(&ctx, "SELECT '2000-01-01T00:00:00'::TIMESTAMP::TIMESTAMPTZ")
+ .await
+ .unwrap();
+ let expected = vec![
+ "+-----------------------------------------------------+",
+ "| Utf8(\"2000-01-01T00:00:00\") |",
+ "+-----------------------------------------------------+",
+ "| 2000-01-01T00:00:00 (Unknown Time Zone '+08:00:00') |",
+ "+-----------------------------------------------------+",
+ ];
+ assert_batches_eq!(expected, &result);
+
+ plan_and_collect(&ctx, "SET TIME ZONE = '08:00'")
+ .await
+ .unwrap();
+
+ // casting UTF-8 to TimestampTZ isn't supported yet, add Timestamp as the middle layer for now
+ let result =
+ plan_and_collect(&ctx, "SELECT '2000-01-01T00:00:00'::TIMESTAMP::TIMESTAMPTZ")
+ .await
+ .unwrap();
+ let expected = vec![
+ "+-------------------------------------------------+",
+ "| Utf8(\"2000-01-01T00:00:00\") |",
+ "+-------------------------------------------------+",
+ "| 2000-01-01T00:00:00 (Unknown Time Zone '08:00') |",
+ "+-------------------------------------------------+",
+ ];
+ assert_batches_eq!(expected, &result);
+
+ plan_and_collect(&ctx, "SET TIME ZONE = '08'")
+ .await
+ .unwrap();
+
+ // casting UTF-8 to TimestampTZ isn't supported yet, add Timestamp as the middle layer for now
+ let result =
+ plan_and_collect(&ctx, "SELECT '2000-01-01T00:00:00'::TIMESTAMP::TIMESTAMPTZ")
+ .await
+ .unwrap();
+ let expected = vec![
+ "+----------------------------------------------+",
+ "| Utf8(\"2000-01-01T00:00:00\") |",
+ "+----------------------------------------------+",
+ "| 2000-01-01T00:00:00 (Unknown Time Zone '08') |",
+ "+----------------------------------------------+",
+ ];
+ assert_batches_eq!(expected, &result);
+
+ // we dont support named time zone yet
+ plan_and_collect(&ctx, "SET TIME ZONE = 'Asia/Taipei'")
+ .await
+ .unwrap();
+
+ // casting UTF-8 to TimestampTZ isn't supported yet, add Timestamp as the middle layer for now
+ let result =
+ plan_and_collect(&ctx, "SELECT '2000-01-01T00:00:00'::TIMESTAMP::TIMESTAMPTZ")
+ .await
+ .unwrap();
+ let expected = vec![
+ "+-------------------------------------------------------+",
+ "| Utf8(\"2000-01-01T00:00:00\") |",
+ "+-------------------------------------------------------+",
+ "| 2000-01-01T00:00:00 (Unknown Time Zone 'Asia/Taipei') |",
+ "+-------------------------------------------------------+",
+ ];
+ assert_batches_eq!(expected, &result);
+
+ // this is invalid even after we support named time zone
+ plan_and_collect(&ctx, "SET TIME ZONE = 'Asia/Taipei2'")
+ .await
+ .unwrap();
+
+ // casting UTF-8 to TimestampTZ isn't supported yet, add Timestamp as the middle layer for now
+ let result =
+ plan_and_collect(&ctx, "SELECT '2000-01-01T00:00:00'::TIMESTAMP::TIMESTAMPTZ")
+ .await
+ .unwrap();
+ let expected = vec![
+ "+--------------------------------------------------------+",
+ "| Utf8(\"2000-01-01T00:00:00\") |",
+ "+--------------------------------------------------------+",
+ "| 2000-01-01T00:00:00 (Unknown Time Zone 'Asia/Taipei2') |",
+ "+--------------------------------------------------------+",
+ ];
+ assert_batches_eq!(expected, &result);
}
diff --git a/datafusion/optimizer/tests/integration-test.rs b/datafusion/optimizer/tests/integration-test.rs
index b6931586e..be62ba2a5 100644
--- a/datafusion/optimizer/tests/integration-test.rs
+++ b/datafusion/optimizer/tests/integration-test.rs
@@ -330,6 +330,13 @@ impl ContextProvider for MySchemaProvider {
fn get_variable_type(&self, _variable_names: &[String]) -> Option<DataType> {
None
}
+
+ fn get_config_option(
+ &self,
+ _variable: &str,
+ ) -> Option<datafusion_common::ScalarValue> {
+ None
+ }
}
fn observe(_plan: &LogicalPlan, _rule: &dyn OptimizerRule) {}
diff --git a/datafusion/sql/examples/sql.rs b/datafusion/sql/examples/sql.rs
index f03cad0b6..bc47348d5 100644
--- a/datafusion/sql/examples/sql.rs
+++ b/datafusion/sql/examples/sql.rs
@@ -120,4 +120,11 @@ impl ContextProvider for MySchemaProvider {
fn get_variable_type(&self, _variable_names: &[String]) -> Option<DataType> {
None
}
+
+ fn get_config_option(
+ &self,
+ _variable: &str,
+ ) -> Option<datafusion_common::ScalarValue> {
+ None
+ }
}
diff --git a/datafusion/sql/src/planner.rs b/datafusion/sql/src/planner.rs
index 1ecd110c0..58b216240 100644
--- a/datafusion/sql/src/planner.rs
+++ b/datafusion/sql/src/planner.rs
@@ -55,6 +55,7 @@ use datafusion_expr::expr::{Between, BinaryExpr, Case, Cast, GroupingSet, Like};
use datafusion_expr::logical_plan::builder::project_with_alias;
use datafusion_expr::logical_plan::{Filter, Subquery};
use datafusion_expr::Expr::Alias;
+
use sqlparser::ast::TimezoneInfo;
use sqlparser::ast::{
BinaryOperator, DataType as SQLDataType, DateTimeField, Expr as SQLExpr, FunctionArg,
@@ -88,6 +89,8 @@ pub trait ContextProvider {
fn get_aggregate_meta(&self, name: &str) -> Option<Arc<AggregateUDF>>;
/// Getter for system/user-defined variable type
fn get_variable_type(&self, variable_names: &[String]) -> Option<DataType>;
+ /// Getter for config_options
+ fn get_config_option(&self, variable: &str) -> Option<ScalarValue>;
}
/// SQL query planner
@@ -558,7 +561,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
let mut fields = Vec::with_capacity(columns.len());
for column in columns {
- let data_type = convert_simple_data_type(&column.data_type)?;
+ let data_type = self.convert_simple_data_type(&column.data_type)?;
let allow_null = column
.options
.iter()
@@ -1721,7 +1724,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
SQLExpr::TypedString { data_type, value } => {
Ok(Expr::Cast(Cast::new(
Box::new(lit(value)),
- convert_data_type(&data_type)?,
+ self.convert_data_type(&data_type)?,
)))
}
SQLExpr::Cast { expr, data_type } => Ok(Expr::Cast(Cast::new(
@@ -1730,7 +1733,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
&schema,
&mut HashMap::new(),
)?),
- convert_data_type(&data_type)?,
+ self.convert_data_type(&data_type)?,
))),
other => Err(DataFusionError::NotImplemented(format!(
"Unsupported value {:?} in a values list expression",
@@ -1909,7 +1912,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
data_type,
} => Ok(Expr::Cast(Cast::new(
Box::new(self.sql_expr_to_logical_expr(*expr, schema, ctes)?),
- convert_data_type(&data_type)?,
+ self.convert_data_type(&data_type)?,
))),
SQLExpr::TryCast {
@@ -1917,7 +1920,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
data_type,
} => Ok(Expr::TryCast {
expr: Box::new(self.sql_expr_to_logical_expr(*expr, schema, ctes)?),
- data_type: convert_data_type(&data_type)?,
+ data_type: self.convert_data_type(&data_type)?,
}),
SQLExpr::TypedString {
@@ -1925,7 +1928,7 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
value,
} => Ok(Expr::Cast(Cast::new(
Box::new(lit(value)),
- convert_data_type(&data_type)?,
+ self.convert_data_type(&data_type)?,
))),
SQLExpr::IsNull(expr) => Ok(Expr::IsNull(Box::new(
@@ -2481,13 +2484,6 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
variable_lower = "datafusion.execution.time_zone".to_string();
}
- // we don't support change time zone until we complete time zone related implementation
- if variable_lower == "datafusion.execution.time_zone" {
- return Err(DataFusionError::Plan(
- "Changing Time Zone isn't supported yet".to_string(),
- ));
- }
-
// parse value string from Expr
let value_string = match &value[0] {
SQLExpr::Identifier(i) => i.to_string(),
@@ -2671,6 +2667,121 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
Ok(lit(ScalarValue::new_list(Some(values), data_type)))
}
}
+
+ fn convert_data_type(&self, sql_type: &SQLDataType) -> Result<DataType> {
+ match sql_type {
+ SQLDataType::Array(inner_sql_type) => {
+ let data_type = self.convert_simple_data_type(inner_sql_type)?;
+
+ Ok(DataType::List(Box::new(Field::new(
+ "field", data_type, true,
+ ))))
+ }
+ other => self.convert_simple_data_type(other),
+ }
+ }
+ fn convert_simple_data_type(&self, sql_type: &SQLDataType) -> Result<DataType> {
+ match sql_type {
+ SQLDataType::Boolean => Ok(DataType::Boolean),
+ SQLDataType::TinyInt(_) => Ok(DataType::Int8),
+ SQLDataType::SmallInt(_) => Ok(DataType::Int16),
+ SQLDataType::Int(_) | SQLDataType::Integer(_) => Ok(DataType::Int32),
+ SQLDataType::BigInt(_) => Ok(DataType::Int64),
+ SQLDataType::UnsignedTinyInt(_) => Ok(DataType::UInt8),
+ SQLDataType::UnsignedSmallInt(_) => Ok(DataType::UInt16),
+ SQLDataType::UnsignedInt(_) | SQLDataType::UnsignedInteger(_) => {
+ Ok(DataType::UInt32)
+ }
+ SQLDataType::UnsignedBigInt(_) => Ok(DataType::UInt64),
+ SQLDataType::Float(_) => Ok(DataType::Float32),
+ SQLDataType::Real => Ok(DataType::Float32),
+ SQLDataType::Double | SQLDataType::DoublePrecision => Ok(DataType::Float64),
+ SQLDataType::Char(_)
+ | SQLDataType::Varchar(_)
+ | SQLDataType::Text
+ | SQLDataType::String => Ok(DataType::Utf8),
+ SQLDataType::Timestamp(tz_info) => {
+ let tz = if matches!(tz_info, TimezoneInfo::Tz)
+ || matches!(tz_info, TimezoneInfo::WithTimeZone)
+ {
+ // Timestamp With Time Zone
+ // INPUT : [SQLDataType] TimestampTz + [RuntimeConfig] Time Zone
+ // OUTPUT: [ArrowDataType] Timestamp<TimeUnit, Some(Time Zone)>
+ match self
+ .schema_provider
+ .get_config_option("datafusion.execution.time_zone")
+ {
+ Some(ScalarValue::Utf8(s)) => s,
+ Some(v) => {
+ return Err(DataFusionError::Internal(format!(
+ "Incorrect data type for time_zone: {}",
+ v.get_datatype(),
+ )))
+ }
+ None => return Err(DataFusionError::Internal(
+ "Config Option datafusion.execution.time_zone doesn't exist"
+ .to_string(),
+ )),
+ }
+ } else {
+ // Timestamp Without Time zone
+ None
+ };
+ Ok(DataType::Timestamp(TimeUnit::Nanosecond, tz))
+ }
+ SQLDataType::Date => Ok(DataType::Date32),
+ SQLDataType::Time(tz_info) => {
+ if matches!(tz_info, TimezoneInfo::None)
+ || matches!(tz_info, TimezoneInfo::WithoutTimeZone)
+ {
+ Ok(DataType::Time64(TimeUnit::Nanosecond))
+ } else {
+ // We dont support TIMETZ and TIME WITH TIME ZONE for now
+ Err(DataFusionError::NotImplemented(format!(
+ "Unsupported SQL type {:?}",
+ sql_type
+ )))
+ }
+ }
+ SQLDataType::Decimal(exact_number_info) => {
+ let (precision, scale) = match *exact_number_info {
+ ExactNumberInfo::None => (None, None),
+ ExactNumberInfo::Precision(precision) => (Some(precision), None),
+ ExactNumberInfo::PrecisionAndScale(precision, scale) => {
+ (Some(precision), Some(scale))
+ }
+ };
+ make_decimal_type(precision, scale)
+ }
+ SQLDataType::Bytea => Ok(DataType::Binary),
+ // Explicitly list all other types so that if sqlparser
+ // adds/changes the `SQLDataType` the compiler will tell us on upgrade
+ // and avoid bugs like https://github.com/apache/arrow-datafusion/issues/3059
+ SQLDataType::Nvarchar(_)
+ | SQLDataType::Uuid
+ | SQLDataType::Binary(_)
+ | SQLDataType::Varbinary(_)
+ | SQLDataType::Blob(_)
+ | SQLDataType::Datetime
+ | SQLDataType::Interval
+ | SQLDataType::Regclass
+ | SQLDataType::Custom(_)
+ | SQLDataType::Array(_)
+ | SQLDataType::Enum(_)
+ | SQLDataType::Set(_)
+ | SQLDataType::MediumInt(_)
+ | SQLDataType::UnsignedMediumInt(_)
+ | SQLDataType::Character(_)
+ | SQLDataType::CharacterVarying(_)
+ | SQLDataType::CharVarying(_)
+ | SQLDataType::CharacterLargeObject(_)
+ | SQLDataType::CharLargeObject(_)
+ | SQLDataType::Clob(_) => Err(DataFusionError::NotImplemented(format!(
+ "Unsupported SQL type {:?}",
+ sql_type
+ ))),
+ }
+ }
}
/// Normalize a SQL object name
@@ -2808,105 +2919,6 @@ fn extract_possible_join_keys(
}
}
-/// Convert SQL simple data type to relational representation of data type
-pub fn convert_simple_data_type(sql_type: &SQLDataType) -> Result<DataType> {
- match sql_type {
- SQLDataType::Boolean => Ok(DataType::Boolean),
- SQLDataType::TinyInt(_) => Ok(DataType::Int8),
- SQLDataType::SmallInt(_) => Ok(DataType::Int16),
- SQLDataType::Int(_) | SQLDataType::Integer(_) => Ok(DataType::Int32),
- SQLDataType::BigInt(_) => Ok(DataType::Int64),
- SQLDataType::UnsignedTinyInt(_) => Ok(DataType::UInt8),
- SQLDataType::UnsignedSmallInt(_) => Ok(DataType::UInt16),
- SQLDataType::UnsignedInt(_) | SQLDataType::UnsignedInteger(_) => {
- Ok(DataType::UInt32)
- }
- SQLDataType::UnsignedBigInt(_) => Ok(DataType::UInt64),
- SQLDataType::Float(_) => Ok(DataType::Float32),
- SQLDataType::Real => Ok(DataType::Float32),
- SQLDataType::Double | SQLDataType::DoublePrecision => Ok(DataType::Float64),
- SQLDataType::Char(_)
- | SQLDataType::Varchar(_)
- | SQLDataType::Text
- | SQLDataType::String => Ok(DataType::Utf8),
- SQLDataType::Timestamp(tz_info) => {
- let tz = if matches!(tz_info, TimezoneInfo::Tz)
- || matches!(tz_info, TimezoneInfo::WithTimeZone)
- {
- Some("+00:00".to_string())
- } else {
- None
- };
- Ok(DataType::Timestamp(TimeUnit::Nanosecond, tz))
- }
- SQLDataType::Date => Ok(DataType::Date32),
- SQLDataType::Time(tz_info) => {
- if matches!(tz_info, TimezoneInfo::None)
- || matches!(tz_info, TimezoneInfo::WithoutTimeZone)
- {
- Ok(DataType::Time64(TimeUnit::Nanosecond))
- } else {
- // We dont support TIMETZ and TIME WITH TIME ZONE for now
- Err(DataFusionError::NotImplemented(format!(
- "Unsupported SQL type {:?}",
- sql_type
- )))
- }
- }
- SQLDataType::Decimal(exact_number_info) => {
- let (precision, scale) = match *exact_number_info {
- ExactNumberInfo::None => (None, None),
- ExactNumberInfo::Precision(precision) => (Some(precision), None),
- ExactNumberInfo::PrecisionAndScale(precision, scale) => {
- (Some(precision), Some(scale))
- }
- };
- make_decimal_type(precision, scale)
- }
- SQLDataType::Bytea => Ok(DataType::Binary),
- // Explicitly list all other types so that if sqlparser
- // adds/changes the `SQLDataType` the compiler will tell us on upgrade
- // and avoid bugs like https://github.com/apache/arrow-datafusion/issues/3059
- SQLDataType::Nvarchar(_)
- | SQLDataType::Uuid
- | SQLDataType::Binary(_)
- | SQLDataType::Varbinary(_)
- | SQLDataType::Blob(_)
- | SQLDataType::Datetime
- | SQLDataType::Interval
- | SQLDataType::Regclass
- | SQLDataType::Custom(_)
- | SQLDataType::Array(_)
- | SQLDataType::Enum(_)
- | SQLDataType::Set(_)
- | SQLDataType::MediumInt(_)
- | SQLDataType::UnsignedMediumInt(_)
- | SQLDataType::Character(_)
- | SQLDataType::CharacterVarying(_)
- | SQLDataType::CharVarying(_)
- | SQLDataType::CharacterLargeObject(_)
- | SQLDataType::CharLargeObject(_)
- | SQLDataType::Clob(_) => Err(DataFusionError::NotImplemented(format!(
- "Unsupported SQL type {:?}",
- sql_type
- ))),
- }
-}
-
-/// Convert SQL data type to relational representation of data type
-pub fn convert_data_type(sql_type: &SQLDataType) -> Result<DataType> {
- match sql_type {
- SQLDataType::Array(inner_sql_type) => {
- let data_type = convert_simple_data_type(inner_sql_type)?;
-
- Ok(DataType::List(Box::new(Field::new(
- "field", data_type, true,
- ))))
- }
- other => convert_simple_data_type(other),
- }
-}
-
// Parse number in sql string, convert to Expr::Literal
fn parse_sql_number(n: &str) -> Result<Expr> {
// parse first as i64
@@ -5014,6 +5026,10 @@ mod tests {
fn get_variable_type(&self, _: &[String]) -> Option<DataType> {
unimplemented!()
}
+
+ fn get_config_option(&self, _: &str) -> Option<ScalarValue> {
+ unimplemented!()
+ }
}
#[test]