From 411b9922827a1ea5a994e4df7380c182fc7cd732 Mon Sep 17 00:00:00 2001 From: wugeer <1284057728@qq.com> Date: Thu, 21 May 2026 18:03:48 +0800 Subject: [PATCH 1/2] Hive: Support MAP column types --- src/dialect/hive.rs | 5 +++++ tests/sqlparser_hive.rs | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/dialect/hive.rs b/src/dialect/hive.rs index 085d1598cb..6cbaef5ca9 100644 --- a/src/dialect/hive.rs +++ b/src/dialect/hive.rs @@ -79,4 +79,9 @@ impl Dialect for HiveDialect { fn supports_from_first_insert(&self) -> bool { true } + + /// See + fn supports_map_literal_with_angle_brackets(&self) -> bool { + true + } } diff --git a/tests/sqlparser_hive.rs b/tests/sqlparser_hive.rs index c0a15d5b9a..e7d45ad86e 100644 --- a/tests/sqlparser_hive.rs +++ b/tests/sqlparser_hive.rs @@ -21,10 +21,10 @@ //! is also tested (on the inputs it can handle). use sqlparser::ast::{ - ClusteredBy, CommentDef, CreateFunction, CreateFunctionBody, CreateFunctionUsing, CreateTable, - Expr, Function, FunctionArgumentList, FunctionArguments, Ident, ObjectName, OrderByExpr, - OrderByOptions, OrderBySort, SelectItem, Set, Statement, TableFactor, UnaryOperator, Use, - Value, + ClusteredBy, ColumnOption, CommentDef, CreateFunction, CreateFunctionBody, CreateFunctionUsing, + CreateTable, DataType, Expr, Function, FunctionArgumentList, FunctionArguments, Ident, + ObjectName, OrderByExpr, OrderByOptions, OrderBySort, SelectItem, Set, Statement, TableFactor, + UnaryOperator, Use, Value, }; use sqlparser::dialect::{AnsiDialect, GenericDialect, HiveDialect}; use sqlparser::parser::ParserError; @@ -562,6 +562,38 @@ fn test_tample_sample() { hive().verified_stmt("SELECT * FROM source TABLESAMPLE (10 ROWS)"); } +#[test] +fn parse_create_table_with_map_column_comment() { + let sql = "create table tmp.xxx (kv_map map comment 'kv col comment');"; + let mut statements = hive().parse_sql_statements(sql).unwrap(); + assert_eq!(statements.len(), 1); + + match statements.pop().unwrap() { + Statement::CreateTable(CreateTable { name, columns, .. }) => { + assert_eq!( + name, + ObjectName::from(vec![Ident::new("tmp"), Ident::new("xxx")]) + ); + assert_eq!(columns.len(), 1); + let column = &columns[0]; + assert_eq!(column.name, Ident::new("kv_map")); + assert_eq!( + column.data_type, + DataType::Map( + Box::new(DataType::String(None)), + Box::new(DataType::String(None)) + ) + ); + assert_eq!(column.options.len(), 1); + assert_eq!( + column.options[0].option, + ColumnOption::Comment("kv col comment".to_string()) + ); + } + _ => unreachable!(), + } +} + fn hive() -> TestedDialects { TestedDialects::new(vec![Box::new(HiveDialect {})]) } From 339ce027b3981cd20e35e62458a4eafd62c92a59 Mon Sep 17 00:00:00 2001 From: wugeer <1284057728@qq.com> Date: Mon, 25 May 2026 14:25:25 +0800 Subject: [PATCH 2/2] =?UTF-8?q?Hive:=20Preserve=20MAP=20type=20angle=20bra?= =?UTF-8?q?cket=20display=EF=BC=8Cwhile=20Keeping=20the=20default=20MAP=20?= =?UTF-8?q?bracket=20style=20as=20the=20existing=20parenthesized=20=20=20f?= =?UTF-8?q?ormat=20for=20ClickHouse=20and=20generic=20parsing=20paths?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ast/data_type.rs | 27 +++++++++++++++++++----- src/ast/mod.rs | 2 +- src/parser/mod.rs | 2 ++ tests/sqlparser_clickhouse.rs | 3 ++- tests/sqlparser_hive.rs | 39 +++++++---------------------------- 5 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/ast/data_type.rs b/src/ast/data_type.rs index 285eec5054..f129a557cf 100644 --- a/src/ast/data_type.rs +++ b/src/ast/data_type.rs @@ -439,10 +439,11 @@ pub enum DataType { Custom(ObjectName, Vec), /// Arrays. Array(ArrayElemTypeDef), - /// Map, see [ClickHouse]. + /// Map, see [ClickHouse], [Hive]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/map - Map(Box, Box), + /// [Hive]: https://hive.apache.org/docs/latest/language/languagemanual-types/ + Map(Box, Box, MapBracketKind), /// Tuple, see [ClickHouse]. /// /// [ClickHouse]: https://clickhouse.com/docs/en/sql-reference/data-types/tuple @@ -785,9 +786,14 @@ impl fmt::Display for DataType { DataType::LowCardinality(data_type) => { write!(f, "LowCardinality({data_type})") } - DataType::Map(key_data_type, value_data_type) => { - write!(f, "Map({key_data_type}, {value_data_type})") - } + DataType::Map(key_data_type, value_data_type, bracket) => match bracket { + MapBracketKind::Parentheses => { + write!(f, "Map({key_data_type}, {value_data_type})") + } + MapBracketKind::AngleBrackets => { + write!(f, "MAP<{key_data_type}, {value_data_type}>") + } + }, DataType::Tuple(fields) => { write!(f, "Tuple({})", display_comma_separated(fields)) } @@ -904,6 +910,17 @@ pub enum StructBracketKind { AngleBrackets, } +/// Type of brackets used for `MAP` types. +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] +pub enum MapBracketKind { + /// Example: `Map(String, UInt16)` + Parentheses, + /// Example: `MAP` + AngleBrackets, +} + /// Timestamp and Time data types information about TimeZone formatting. /// /// This is more related to a display information than real differences between each variant. To diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 46826d7be0..7c3662e9fc 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -53,7 +53,7 @@ use crate::{ pub use self::data_type::{ ArrayElemTypeDef, BinaryLength, CharLengthUnits, CharacterLength, DataType, EnumMember, - ExactNumberInfo, IntervalFields, StructBracketKind, TimezoneInfo, + ExactNumberInfo, IntervalFields, MapBracketKind, StructBracketKind, TimezoneInfo, }; pub use self::dcl::{ AlterRoleOperation, CreateRole, Grant, ResetConfig, Revoke, RoleOption, SecondaryRoles, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 763b876dec..6b988eed7b 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -12746,6 +12746,7 @@ impl<'a> Parser<'a> { Ok(DataType::Map( Box::new(key_data_type), Box::new(value_data_type), + MapBracketKind::AngleBrackets, )) } Keyword::MAP if dialect_is!(dialect is ClickHouseDialect | GenericDialect) => { @@ -12754,6 +12755,7 @@ impl<'a> Parser<'a> { Ok(DataType::Map( Box::new(key_data_type), Box::new(value_data_type), + MapBracketKind::Parentheses, )) } Keyword::NESTED if dialect_is!(dialect is ClickHouseDialect | GenericDialect) => { diff --git a/tests/sqlparser_clickhouse.rs b/tests/sqlparser_clickhouse.rs index 716a3919fc..cb2df1ff6f 100644 --- a/tests/sqlparser_clickhouse.rs +++ b/tests/sqlparser_clickhouse.rs @@ -767,7 +767,8 @@ fn parse_create_table_with_nested_data_types() { name: Ident::new("m"), data_type: DataType::Map( Box::new(DataType::String(None)), - Box::new(DataType::UInt16) + Box::new(DataType::UInt16), + MapBracketKind::Parentheses ), options: vec![], }, diff --git a/tests/sqlparser_hive.rs b/tests/sqlparser_hive.rs index e7d45ad86e..21e76e23b6 100644 --- a/tests/sqlparser_hive.rs +++ b/tests/sqlparser_hive.rs @@ -21,10 +21,10 @@ //! is also tested (on the inputs it can handle). use sqlparser::ast::{ - ClusteredBy, ColumnOption, CommentDef, CreateFunction, CreateFunctionBody, CreateFunctionUsing, - CreateTable, DataType, Expr, Function, FunctionArgumentList, FunctionArguments, Ident, - ObjectName, OrderByExpr, OrderByOptions, OrderBySort, SelectItem, Set, Statement, TableFactor, - UnaryOperator, Use, Value, + ClusteredBy, CommentDef, CreateFunction, CreateFunctionBody, CreateFunctionUsing, CreateTable, + Expr, Function, FunctionArgumentList, FunctionArguments, Ident, ObjectName, OrderByExpr, + OrderByOptions, OrderBySort, SelectItem, Set, Statement, TableFactor, UnaryOperator, Use, + Value, }; use sqlparser::dialect::{AnsiDialect, GenericDialect, HiveDialect}; use sqlparser::parser::ParserError; @@ -564,34 +564,9 @@ fn test_tample_sample() { #[test] fn parse_create_table_with_map_column_comment() { - let sql = "create table tmp.xxx (kv_map map comment 'kv col comment');"; - let mut statements = hive().parse_sql_statements(sql).unwrap(); - assert_eq!(statements.len(), 1); - - match statements.pop().unwrap() { - Statement::CreateTable(CreateTable { name, columns, .. }) => { - assert_eq!( - name, - ObjectName::from(vec![Ident::new("tmp"), Ident::new("xxx")]) - ); - assert_eq!(columns.len(), 1); - let column = &columns[0]; - assert_eq!(column.name, Ident::new("kv_map")); - assert_eq!( - column.data_type, - DataType::Map( - Box::new(DataType::String(None)), - Box::new(DataType::String(None)) - ) - ); - assert_eq!(column.options.len(), 1); - assert_eq!( - column.options[0].option, - ColumnOption::Comment("kv col comment".to_string()) - ); - } - _ => unreachable!(), - } + hive().verified_stmt( + "CREATE TABLE target (kv_map MAP COMMENT 'kv col comment') COMMENT 'this is table comment'", + ); } fn hive() -> TestedDialects {