You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by lu...@apache.org on 2026/09/23 01:55:26 UTC

(datafusion-sqlparser-rs) branch custom-type-modifier-quoting updated (53680aaba -> df270147a)

This is an automated email from the ASF dual-hosted git repository.

LucaCappelletti94 pushed a change to branch custom-type-modifier-quoting
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git


 discard 53680aaba Keep custom data type modifiers re-parseable with a typed list
     new df270147a Keep custom data type modifiers re-parseable with a typed list

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (53680aaba)
            \
             N -- N -- N   refs/heads/custom-type-modifier-quoting (df270147a)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 tests/sqlparser_common.rs | 1 +
 1 file changed, 1 insertion(+)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org


(datafusion-sqlparser-rs) 01/01: Keep custom data type modifiers re-parseable with a typed list

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

LucaCappelletti94 pushed a commit to branch custom-type-modifier-quoting
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git

commit df270147aa7422c8d8e0b7c62e875f6c400679d9
Author: LucaCappelletti94 <ca...@gmail.com>
AuthorDate: Wed Sep 23 03:49:59 2026 +0200

    Keep custom data type modifiers re-parseable with a typed list
---
 src/ast/data_type.rs      | 31 +++++++++++++++++++++++++++----
 src/ast/mod.rs            |  2 +-
 src/parser/mod.rs         | 22 +++++++++++++++-------
 tests/sqlparser_common.rs | 32 +++++++++++++++++++++++++++++++-
 4 files changed, 74 insertions(+), 13 deletions(-)

diff --git a/src/ast/data_type.rs b/src/ast/data_type.rs
index be1acd1a7..ea55244d4 100644
--- a/src/ast/data_type.rs
+++ b/src/ast/data_type.rs
@@ -25,7 +25,7 @@ use serde::{Deserialize, Serialize};
 #[cfg(feature = "visitor")]
 use sqlparser_derive::{Visit, VisitMut};
 
-use crate::ast::{display_comma_separated, Expr, ObjectName, StructField, UnionField};
+use crate::ast::{display_comma_separated, Expr, Ident, ObjectName, StructField, UnionField};
 
 use super::{value::escape_single_quote_string, ColumnDef};
 
@@ -42,6 +42,29 @@ pub enum EnumMember {
     NamedValue(String, Expr),
 }
 
+/// One entry of a custom data type's parenthesized modifier list.
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum TypeModifier {
+    /// Identifier or keyword segment, quotes carried by `Ident`.
+    Identifier(Ident),
+    /// Numeric literal, the `bool` carries the `L` long suffix like `Value::Number`.
+    Number(String, bool),
+    /// Single quoted string literal.
+    String(String),
+}
+
+impl fmt::Display for TypeModifier {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Identifier(id) => write!(f, "{id}"),
+            Self::Number(n, long) => write!(f, "{}{long}", n, long = if *long { "L" } else { "" }),
+            Self::String(s) => write!(f, "'{}'", escape_single_quote_string(s)),
+        }
+    }
+}
+
 /// SQL data types
 #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -435,8 +458,8 @@ pub enum DataType {
     ///
     /// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html
     VarBit(Option<u64>),
-    /// Custom types.
-    Custom(ObjectName, Vec<String>),
+    /// Custom type with a modifier list, e.g. `GEOMETRY(POINT, 4326)`.
+    Custom(ObjectName, Vec<TypeModifier>),
     /// Arrays.
     Array(ArrayElemTypeDef),
     /// Map, see [ClickHouse], [Hive].
@@ -727,7 +750,7 @@ impl fmt::Display for DataType {
                 if modifiers.is_empty() {
                     write!(f, "{ty}")
                 } else {
-                    write!(f, "{}({})", ty, modifiers.join(", "))
+                    write!(f, "{ty}({})", display_comma_separated(modifiers))
                 }
             }
             DataType::Enum(vals, bits) => {
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index dcde4fc38..8aa571490 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -55,7 +55,7 @@ use crate::{
 
 pub use self::data_type::{
     ArrayElemTypeDef, BinaryLength, CharLengthUnits, CharacterLength, DataType, EnumMember,
-    ExactNumberInfo, IntervalFields, MapBracketKind, StructBracketKind, TimezoneInfo,
+    ExactNumberInfo, IntervalFields, MapBracketKind, StructBracketKind, TimezoneInfo, TypeModifier,
 };
 pub use self::dcl::{
     AlterRoleOperation, CreateRole, Grant, ResetConfig, Revoke, RoleOption, SecondaryRoles,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index eb435f153..2f52d9b6f 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -14326,15 +14326,19 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse optional type modifiers appearing in parentheses e.g. `(UNSIGNED, ZEROFILL)`.
-    pub fn parse_optional_type_modifiers(&mut self) -> Result<Option<Vec<String>>, ParserError> {
+    pub fn parse_optional_type_modifiers(
+        &mut self,
+    ) -> Result<Option<Vec<TypeModifier>>, ParserError> {
         if self.consume_token(&Token::LParen) {
             let mut modifiers = Vec::new();
             loop {
                 let next_token = self.next_token();
                 match next_token.token {
-                    Token::Word(w) => modifiers.push(w.to_string()),
-                    Token::Number(n, _) => modifiers.push(n),
-                    Token::SingleQuotedString(s) => modifiers.push(s),
+                    Token::Word(w) => {
+                        modifiers.push(TypeModifier::Identifier(w.to_ident(next_token.span)))
+                    }
+                    Token::Number(n, negative) => modifiers.push(TypeModifier::Number(n, negative)),
+                    Token::SingleQuotedString(s) => modifiers.push(TypeModifier::String(s)),
 
                     Token::Comma => {
                         continue;
@@ -21338,7 +21342,8 @@ mod tests {
     #[cfg(test)]
     mod test_parse_data_type {
         use crate::ast::{
-            CharLengthUnits, CharacterLength, DataType, ExactNumberInfo, ObjectName, TimezoneInfo,
+            CharLengthUnits, CharacterLength, DataType, ExactNumberInfo, Ident, ObjectName,
+            TimezoneInfo, TypeModifier,
         };
         use crate::dialect::{AnsiDialect, GenericDialect, PostgreSqlDialect};
         use crate::test_utils::TestedDialects;
@@ -21529,7 +21534,7 @@ mod tests {
                 "GEOMETRY(POINT)",
                 DataType::Custom(
                     ObjectName::from(vec!["GEOMETRY".into()]),
-                    vec!["POINT".to_string()]
+                    vec![TypeModifier::Identifier(Ident::new("POINT"))]
                 )
             );
 
@@ -21538,7 +21543,10 @@ mod tests {
                 "GEOMETRY(POINT, 4326)",
                 DataType::Custom(
                     ObjectName::from(vec!["GEOMETRY".into()]),
-                    vec!["POINT".to_string(), "4326".to_string()]
+                    vec![
+                        TypeModifier::Identifier(Ident::new("POINT")),
+                        TypeModifier::Number("4326".to_string(), false),
+                    ]
                 )
             );
         }
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 9fb208bd5..b718d8434 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -6944,7 +6944,7 @@ fn parse_text_type_modifier_double_colon_cast() {
             expr: Box::new(Expr::Identifier(Ident::new("ID"))),
             data_type: DataType::Custom(
                 ObjectName::from(vec![Ident::new("TEXT")]),
-                vec!["16777216".to_string()]
+                vec![TypeModifier::Number("16777216".to_string(), false)]
             ),
             format: None,
         }
@@ -20143,3 +20143,33 @@ fn parse_stage_table_factor() {
         ParserError::ParserError("Expected: identifier, found: @".to_string()),
     );
 }
+
+#[test]
+fn parse_custom_type_modifier_spellings() {
+    for sql in [
+        r#"CREATE TABLE t (c foo('a b'))"#,
+        r#"CREATE TABLE t (c foo(')'))"#,
+        r#"CREATE TABLE t (c foo('it''s'))"#,
+        "CREATE TABLE t (c foo(bar, 9))",
+    ] {
+        all_dialects().verified_stmt(sql);
+    }
+    let generic = TestedDialects::new(vec![Box::new(GenericDialect {})]);
+    generic.verified_stmt(r#"CREATE TABLE t (c foo("quoted"))"#);
+
+    let statements = generic
+        .parse_sql_statements("CREATE TABLE t (c foo(bar, 9, 'z'))")
+        .unwrap();
+    let Statement::CreateTable(create_table) = &statements[0] else {
+        panic!("expected CREATE TABLE")
+    };
+    let DataType::Custom(_, modifiers) = &create_table.columns[0].data_type else {
+        panic!("expected a custom type")
+    };
+    let expected = vec![
+        TypeModifier::Identifier(Ident::new("bar")),
+        TypeModifier::Number("9".to_string(), false),
+        TypeModifier::String("z".to_string()),
+    ];
+    assert_eq!(modifiers, &expected);
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org