Skip to content

Commit f7f14df

Browse files
authored
647 Adding all ansii character string types, parsing them, and differentiating between each one (#648)
1 parent 977cdb2 commit f7f14df

File tree

4 files changed

+110
-82
lines changed

4 files changed

+110
-82
lines changed

src/ast/data_type.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@ use super::value::escape_single_quote_string;
2525
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2626
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2727
pub enum DataType {
28-
/// Fixed-length character type e.g. CHAR(10)
28+
/// Fixed-length character type e.g. CHARACTER(10)
29+
Character(Option<u64>),
30+
/// Fixed-length char type e.g. CHAR(10)
2931
Char(Option<u64>),
32+
/// Character varying type e.g. CHARACTER VARYING(10)
33+
CharacterVarying(Option<u64>),
34+
/// Char varying type e.g. CHAR VARYING(10)
35+
CharVarying(Option<u64>),
3036
/// Variable-length character type e.g. VARCHAR(10)
3137
Varchar(Option<u64>),
3238
/// Variable-length character type e.g. NVARCHAR(10)
@@ -127,10 +133,17 @@ pub enum DataType {
127133
impl fmt::Display for DataType {
128134
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129135
match self {
136+
DataType::Character(size) => {
137+
format_type_with_optional_length(f, "CHARACTER", size, false)
138+
}
130139
DataType::Char(size) => format_type_with_optional_length(f, "CHAR", size, false),
131-
DataType::Varchar(size) => {
140+
DataType::CharacterVarying(size) => {
132141
format_type_with_optional_length(f, "CHARACTER VARYING", size, false)
133142
}
143+
DataType::CharVarying(size) => {
144+
format_type_with_optional_length(f, "CHAR VARYING", size, false)
145+
}
146+
DataType::Varchar(size) => format_type_with_optional_length(f, "VARCHAR", size, false),
134147
DataType::Nvarchar(size) => {
135148
format_type_with_optional_length(f, "NVARCHAR", size, false)
136149
}

src/parser.rs

+88-73
Original file line numberDiff line numberDiff line change
@@ -3414,9 +3414,16 @@ impl<'a> Parser<'a> {
34143414
}
34153415
Keyword::VARCHAR => Ok(DataType::Varchar(self.parse_optional_precision()?)),
34163416
Keyword::NVARCHAR => Ok(DataType::Nvarchar(self.parse_optional_precision()?)),
3417-
Keyword::CHAR | Keyword::CHARACTER => {
3417+
Keyword::CHARACTER => {
34183418
if self.parse_keyword(Keyword::VARYING) {
3419-
Ok(DataType::Varchar(self.parse_optional_precision()?))
3419+
Ok(DataType::CharacterVarying(self.parse_optional_precision()?))
3420+
} else {
3421+
Ok(DataType::Character(self.parse_optional_precision()?))
3422+
}
3423+
}
3424+
Keyword::CHAR => {
3425+
if self.parse_keyword(Keyword::VARYING) {
3426+
Ok(DataType::CharVarying(self.parse_optional_precision()?))
34203427
} else {
34213428
Ok(DataType::Char(self.parse_optional_precision()?))
34223429
}
@@ -5288,80 +5295,88 @@ mod tests {
52885295
});
52895296
}
52905297

5291-
// TODO add tests for all data types? https://github.com/sqlparser-rs/sqlparser-rs/issues/2
5292-
// TODO when we have dialect validation by data type parsing, split test
5293-
#[test]
5294-
fn test_parse_data_type() {
5295-
// BINARY data type
5296-
test_parse_data_type("BINARY", DataType::Binary(None), "BINARY");
5297-
test_parse_data_type("BINARY(20)", DataType::Binary(Some(20)), "BINARY(20)");
5298-
5299-
// BLOB data type
5300-
test_parse_data_type("BLOB", DataType::Blob(None), "BLOB");
5301-
test_parse_data_type("BLOB(50)", DataType::Blob(Some(50)), "BLOB(50)");
5302-
5303-
// CLOB data type
5304-
test_parse_data_type("CLOB", DataType::Clob(None), "CLOB");
5305-
test_parse_data_type("CLOB(50)", DataType::Clob(Some(50)), "CLOB(50)");
5306-
5307-
// Double data type
5308-
test_parse_data_type(
5309-
"DOUBLE PRECISION",
5310-
DataType::DoublePrecision,
5311-
"DOUBLE PRECISION",
5312-
);
5313-
test_parse_data_type("DOUBLE", DataType::Double, "DOUBLE");
5314-
5315-
// Time data type
5316-
test_parse_data_type("TIME", DataType::Time(TimezoneInfo::None), "TIME");
5317-
test_parse_data_type(
5318-
"TIME WITH TIME ZONE",
5319-
DataType::Time(TimezoneInfo::WithTimeZone),
5320-
"TIME WITH TIME ZONE",
5321-
);
5322-
test_parse_data_type(
5323-
"TIME WITHOUT TIME ZONE",
5324-
DataType::Time(TimezoneInfo::WithoutTimeZone),
5325-
"TIME WITHOUT TIME ZONE",
5326-
);
5327-
test_parse_data_type("TIMETZ", DataType::Time(TimezoneInfo::Tz), "TIMETZ");
5298+
#[cfg(test)]
5299+
mod test_parse_data_type {
5300+
use crate::ast::{DataType, TimezoneInfo};
5301+
use crate::dialect::{AnsiDialect, GenericDialect};
5302+
use crate::test_utils::TestedDialects;
53285303

5329-
// Timestamp data type
5330-
test_parse_data_type(
5331-
"TIMESTAMP",
5332-
DataType::Timestamp(TimezoneInfo::None),
5333-
"TIMESTAMP",
5334-
);
5335-
test_parse_data_type(
5336-
"TIMESTAMP WITH TIME ZONE",
5337-
DataType::Timestamp(TimezoneInfo::WithTimeZone),
5338-
"TIMESTAMP WITH TIME ZONE",
5339-
);
5340-
test_parse_data_type(
5341-
"TIMESTAMP WITHOUT TIME ZONE",
5342-
DataType::Timestamp(TimezoneInfo::WithoutTimeZone),
5343-
"TIMESTAMP WITHOUT TIME ZONE",
5344-
);
5345-
test_parse_data_type(
5346-
"TIMESTAMPTZ",
5347-
DataType::Timestamp(TimezoneInfo::Tz),
5348-
"TIMESTAMPTZ",
5349-
);
5304+
macro_rules! test_parse_data_type {
5305+
($dialect:expr, $input:expr, $expected_type:expr $(,)?) => {{
5306+
$dialect.run_parser_method(&*$input, |parser| {
5307+
let data_type = parser.parse_data_type().unwrap();
5308+
assert_eq!(data_type, $expected_type);
5309+
assert_eq!(data_type.to_string(), $input.to_string());
5310+
});
5311+
}};
5312+
}
53505313

5351-
// VARBINARY data type
5352-
test_parse_data_type("VARBINARY", DataType::Varbinary(None), "VARBINARY");
5353-
test_parse_data_type(
5354-
"VARBINARY(20)",
5355-
DataType::Varbinary(Some(20)),
5356-
"VARBINARY(20)",
5357-
);
5314+
#[test]
5315+
fn test_ansii_character_string_types() {
5316+
// Character string types: <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#character-string-type>
5317+
let dialect = TestedDialects {
5318+
dialects: vec![Box::new(GenericDialect {}), Box::new(AnsiDialect {})],
5319+
};
53585320

5359-
fn test_parse_data_type(input: &str, expected_type: DataType, expected_str: &str) {
5360-
all_dialects().run_parser_method(input, |parser| {
5361-
let data_type = parser.parse_data_type().unwrap();
5362-
assert_eq!(data_type, expected_type);
5363-
assert_eq!(expected_type.to_string(), expected_str.to_string());
5364-
});
5321+
test_parse_data_type!(dialect, "CHARACTER", DataType::Character(None));
5322+
5323+
test_parse_data_type!(dialect, "CHARACTER(20)", DataType::Character(Some(20)));
5324+
5325+
test_parse_data_type!(dialect, "CHAR", DataType::Char(None));
5326+
5327+
test_parse_data_type!(dialect, "CHAR(20)", DataType::Char(Some(20)));
5328+
5329+
test_parse_data_type!(
5330+
dialect,
5331+
"CHARACTER VARYING(20)",
5332+
DataType::CharacterVarying(Some(20))
5333+
);
5334+
5335+
test_parse_data_type!(dialect, "CHAR VARYING(20)", DataType::CharVarying(Some(20)));
5336+
5337+
test_parse_data_type!(dialect, "VARCHAR(20)", DataType::Varchar(Some(20)));
5338+
}
5339+
5340+
#[test]
5341+
fn test_ansii_datetime_types() {
5342+
// Datetime types: <https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#datetime-type>
5343+
let dialect = TestedDialects {
5344+
dialects: vec![Box::new(GenericDialect {}), Box::new(AnsiDialect {})],
5345+
};
5346+
5347+
test_parse_data_type!(dialect, "DATE", DataType::Date);
5348+
5349+
test_parse_data_type!(dialect, "TIME", DataType::Time(TimezoneInfo::None));
5350+
5351+
test_parse_data_type!(
5352+
dialect,
5353+
"TIME WITH TIME ZONE",
5354+
DataType::Time(TimezoneInfo::WithTimeZone)
5355+
);
5356+
5357+
test_parse_data_type!(
5358+
dialect,
5359+
"TIME WITHOUT TIME ZONE",
5360+
DataType::Time(TimezoneInfo::WithoutTimeZone)
5361+
);
5362+
5363+
test_parse_data_type!(
5364+
dialect,
5365+
"TIMESTAMP",
5366+
DataType::Timestamp(TimezoneInfo::None)
5367+
);
5368+
5369+
test_parse_data_type!(
5370+
dialect,
5371+
"TIMESTAMP WITH TIME ZONE",
5372+
DataType::Timestamp(TimezoneInfo::WithTimeZone)
5373+
);
5374+
5375+
test_parse_data_type!(
5376+
dialect,
5377+
"TIMESTAMP WITHOUT TIME ZONE",
5378+
DataType::Timestamp(TimezoneInfo::WithoutTimeZone)
5379+
);
53655380
}
53665381
}
53675382

tests/sqlparser_common.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1850,7 +1850,7 @@ fn parse_create_table() {
18501850
let ast = one_statement_parses_to(
18511851
sql,
18521852
"CREATE TABLE uk_cities (\
1853-
name CHARACTER VARYING(100) NOT NULL, \
1853+
name VARCHAR(100) NOT NULL, \
18541854
lat DOUBLE NULL, \
18551855
lng DOUBLE, \
18561856
constrained INT NULL CONSTRAINT pkey PRIMARY KEY NOT NULL UNIQUE CHECK (constrained > 0), \
@@ -2312,7 +2312,7 @@ fn parse_create_external_table() {
23122312
let ast = one_statement_parses_to(
23132313
sql,
23142314
"CREATE EXTERNAL TABLE uk_cities (\
2315-
name CHARACTER VARYING(100) NOT NULL, \
2315+
name VARCHAR(100) NOT NULL, \
23162316
lat DOUBLE NULL, \
23172317
lng DOUBLE) \
23182318
STORED AS TEXTFILE LOCATION '/tmp/example.csv'",
@@ -2382,7 +2382,7 @@ fn parse_create_or_replace_external_table() {
23822382
let ast = one_statement_parses_to(
23832383
sql,
23842384
"CREATE OR REPLACE EXTERNAL TABLE uk_cities (\
2385-
name CHARACTER VARYING(100) NOT NULL) \
2385+
name VARCHAR(100) NOT NULL) \
23862386
STORED AS TEXTFILE LOCATION '/tmp/example.csv'",
23872387
);
23882388
match ast {
@@ -2435,7 +2435,7 @@ fn parse_create_external_table_lowercase() {
24352435
let ast = one_statement_parses_to(
24362436
sql,
24372437
"CREATE EXTERNAL TABLE uk_cities (\
2438-
name CHARACTER VARYING(100) NOT NULL, \
2438+
name VARCHAR(100) NOT NULL, \
24392439
lat DOUBLE NULL, \
24402440
lng DOUBLE) \
24412441
STORED AS PARQUET LOCATION '/tmp/example.csv'",

tests/sqlparser_postgres.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ fn parse_create_table_with_defaults() {
7474
},
7575
ColumnDef {
7676
name: "first_name".into(),
77-
data_type: DataType::Varchar(Some(45)),
77+
data_type: DataType::CharacterVarying(Some(45)),
7878
collation: None,
7979
options: vec![ColumnOptionDef {
8080
name: None,
@@ -83,7 +83,7 @@ fn parse_create_table_with_defaults() {
8383
},
8484
ColumnDef {
8585
name: "last_name".into(),
86-
data_type: DataType::Varchar(Some(45)),
86+
data_type: DataType::CharacterVarying(Some(45)),
8787
collation: Some(ObjectName(vec![Ident::with_quote('"', "es_ES")])),
8888
options: vec![ColumnOptionDef {
8989
name: None,
@@ -92,7 +92,7 @@ fn parse_create_table_with_defaults() {
9292
},
9393
ColumnDef {
9494
name: "email".into(),
95-
data_type: DataType::Varchar(Some(50)),
95+
data_type: DataType::CharacterVarying(Some(50)),
9696
collation: None,
9797
options: vec![],
9898
},

0 commit comments

Comments
 (0)