1use std::fmt;
13
14use crate::error::{Error, Result};
15
16#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub struct Field {
19 pub name: String,
21 pub ty: LogicalType,
23 pub not_null: bool,
31}
32
33impl Field {
34 pub fn new(name: impl Into<String>, ty: LogicalType) -> Self {
36 Self { name: name.into(), ty, not_null: false }
37 }
38
39 pub fn required(name: impl Into<String>, ty: LogicalType) -> Self {
41 Self { name: name.into(), ty, not_null: true }
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Hash)]
52#[non_exhaustive]
53pub enum LogicalType {
54 Null,
56 Boolean,
58 TinyInt,
60 SmallInt,
62 Integer,
64 BigInt,
66 HugeInt,
68 UTinyInt,
70 USmallInt,
72 UInteger,
74 UBigInt,
76 UHugeInt,
78 Float,
80 Double,
82 Decimal {
84 width: u8,
86 scale: u8,
88 },
89 Varchar,
91 Blob,
93 Bit,
95 Uuid,
97 Date,
99 Time,
101 TimeTz,
103 Timestamp,
105 TimestampS,
107 TimestampMs,
109 TimestampNs,
111 TimestampTz,
113 Interval,
115 List(Box<LogicalType>),
117 Array(Box<LogicalType>, u32),
119 Struct(Vec<Field>),
121 Map(Box<LogicalType>, Box<LogicalType>),
123 Union(Vec<Field>),
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
132#[non_exhaustive]
133pub enum PhysicalType {
134 Bool,
136 Int8,
138 Int16,
140 Int32,
142 Int64,
144 Int128,
146 UInt8,
148 UInt16,
150 UInt32,
152 UInt64,
154 UInt128,
156 Float32,
158 Float64,
160 Interval,
162 Varlen,
164 List,
166 Array,
168 Struct,
170 Empty,
172}
173
174impl PhysicalType {
175 #[must_use]
188 pub const fn size(self) -> usize {
189 match self {
190 Self::Bool | Self::Int8 | Self::UInt8 => 1,
191 Self::Int16 | Self::UInt16 => 2,
192 Self::Int32 | Self::UInt32 | Self::Float32 => 4,
193 Self::Int64 | Self::UInt64 | Self::Float64 | Self::List => 8,
194 Self::Int128 | Self::UInt128 | Self::Interval | Self::Varlen => 16,
195 Self::Array | Self::Struct | Self::Empty => 0,
196 }
197 }
198}
199
200impl LogicalType {
201 pub fn decimal(width: u8, scale: u8) -> Result<Self> {
208 if width == 0 || width > MAX_DECIMAL_WIDTH {
209 return Err(Error::binder(format!("Width must be between 1 and {MAX_DECIMAL_WIDTH}!")));
210 }
211 if scale > width {
212 return Err(Error::binder(format!(
213 "Scale cannot be bigger than width, {scale} is bigger than {width}"
214 )));
215 }
216 Ok(Self::Decimal { width, scale })
217 }
218
219 #[must_use]
221 pub fn list(element: Self) -> Self {
222 Self::List(Box::new(element))
223 }
224
225 #[must_use]
227 pub fn array(element: Self, length: u32) -> Self {
228 Self::Array(Box::new(element), length)
229 }
230
231 #[must_use]
233 pub fn map(key: Self, value: Self) -> Self {
234 Self::Map(Box::new(key), Box::new(value))
235 }
236
237 #[must_use]
239 pub fn physical(&self) -> PhysicalType {
240 match self {
241 Self::Null => PhysicalType::Empty,
242 Self::Boolean => PhysicalType::Bool,
243 Self::TinyInt => PhysicalType::Int8,
244 Self::SmallInt => PhysicalType::Int16,
245 Self::Integer | Self::Date => PhysicalType::Int32,
246 Self::BigInt
247 | Self::Time
248 | Self::TimeTz
249 | Self::Timestamp
250 | Self::TimestampS
251 | Self::TimestampMs
252 | Self::TimestampNs
253 | Self::TimestampTz => PhysicalType::Int64,
254 Self::HugeInt | Self::Uuid => PhysicalType::Int128,
255 Self::UTinyInt => PhysicalType::UInt8,
256 Self::USmallInt => PhysicalType::UInt16,
257 Self::UInteger => PhysicalType::UInt32,
258 Self::UBigInt => PhysicalType::UInt64,
259 Self::UHugeInt => PhysicalType::UInt128,
260 Self::Float => PhysicalType::Float32,
261 Self::Double => PhysicalType::Float64,
262 Self::Decimal { width, .. } => match width {
266 0..=4 => PhysicalType::Int16,
267 5..=9 => PhysicalType::Int32,
268 10..=18 => PhysicalType::Int64,
269 _ => PhysicalType::Int128,
270 },
271 Self::Varchar | Self::Blob | Self::Bit => PhysicalType::Varlen,
272 Self::Interval => PhysicalType::Interval,
273 Self::List(_) | Self::Map(_, _) => PhysicalType::List,
276 Self::Array(_, _) => PhysicalType::Array,
277 Self::Struct(_) | Self::Union(_) => PhysicalType::Struct,
278 }
279 }
280
281 #[must_use]
289 pub fn physical_name(&self) -> String {
290 if let Some(width) = self.decimal_storage() {
291 return format!("DECIMAL({width})");
292 }
293 let name = match self {
294 Self::Boolean => "BOOL",
295 Self::TinyInt => "INT8",
296 Self::SmallInt => "INT16",
297 Self::Integer => "INT32",
298 Self::BigInt => "INT64",
299 Self::HugeInt => "INT128",
300 Self::UTinyInt => "UINT8",
301 Self::USmallInt => "UINT16",
302 Self::UInteger => "UINT32",
303 Self::UBigInt => "UINT64",
304 Self::UHugeInt => "UINT128",
305 other => return other.to_string(),
306 };
307 name.to_string()
308 }
309
310 #[must_use]
318 pub fn decimal_storage(&self) -> Option<u8> {
319 let Self::Decimal { width, .. } = self else {
320 return None;
321 };
322 Some(match width {
323 0..=4 => 4,
324 5..=9 => 9,
325 10..=18 => 18,
326 _ => MAX_DECIMAL_WIDTH,
327 })
328 }
329
330 #[must_use]
332 pub fn is_numeric(&self) -> bool {
333 self.is_integer() || matches!(self, Self::Float | Self::Double | Self::Decimal { .. })
334 }
335
336 #[must_use]
338 pub fn is_integer(&self) -> bool {
339 matches!(
340 self,
341 Self::TinyInt
342 | Self::SmallInt
343 | Self::Integer
344 | Self::BigInt
345 | Self::HugeInt
346 | Self::UTinyInt
347 | Self::USmallInt
348 | Self::UInteger
349 | Self::UBigInt
350 | Self::UHugeInt
351 )
352 }
353
354 #[must_use]
361 pub fn decimal_shape(&self) -> Option<(u8, u8)> {
362 match self {
363 Self::Decimal { width, scale } => Some((*width, *scale)),
364 other if other.is_integer() => Some((decimal_digits(other), 0)),
365 _ => None,
366 }
367 }
368
369 #[must_use]
371 pub fn is_temporal(&self) -> bool {
372 matches!(
373 self,
374 Self::Date
375 | Self::Time
376 | Self::TimeTz
377 | Self::Timestamp
378 | Self::TimestampS
379 | Self::TimestampMs
380 | Self::TimestampNs
381 | Self::TimestampTz
382 | Self::Interval
383 )
384 }
385
386 #[must_use]
391 pub fn is_nested(&self) -> bool {
392 matches!(
393 self,
394 Self::List(_) | Self::Array(_, _) | Self::Struct(_) | Self::Map(_, _) | Self::Union(_)
395 )
396 }
397
398 #[must_use]
412 pub fn is_keyed(&self) -> bool {
413 !self.is_nested() && !matches!(self, Self::Null)
414 }
415
416 #[must_use]
438 pub fn promote(&self, other: &Self) -> Option<Self> {
439 if self == other {
440 return Some(self.clone());
441 }
442 match (self, other) {
443 (Self::Null, ty) | (ty, Self::Null) => Some(ty.clone()),
444 (Self::List(left), Self::List(right)) => Some(Self::list(left.promote(right)?)),
445 _ if self.is_numeric() && other.is_numeric() => {
446 Some(promote_numeric(self.clone(), other.clone()))
447 }
448 _ if self.is_temporal() && other.is_temporal() => {
451 match (rank_temporal(self), rank_temporal(other)) {
452 (Some(left), Some(right)) => {
453 Some(if left >= right { self.clone() } else { other.clone() })
454 }
455 _ => None,
456 }
457 }
458 _ => None,
459 }
460 }
461
462 #[must_use]
464 pub fn children(&self) -> Vec<Self> {
465 match self {
466 Self::List(inner) | Self::Array(inner, _) => vec![inner.as_ref().clone()],
467 Self::Map(key, value) => vec![key.as_ref().clone(), value.as_ref().clone()],
468 Self::Struct(fields) | Self::Union(fields) => {
469 fields.iter().map(|f| f.ty.clone()).collect()
470 }
471 _ => Vec::new(),
472 }
473 }
474
475 pub fn parse(text: &str) -> Result<Self> {
482 let tokens = lex(text)?;
483 let mut parser = TypeParser { tokens: &tokens, position: 0 };
484 let ty = parser.parse_type()?;
485 if parser.position != parser.tokens.len() {
486 return Err(Error::parser(format!("Type \"{text}\" has trailing text")));
487 }
488 Ok(ty)
489 }
490}
491
492pub const MAX_DECIMAL_WIDTH: u8 = 38;
495
496impl fmt::Display for LogicalType {
497 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
498 match self {
499 Self::Null => f.write_str("\"NULL\""),
500 Self::Boolean => f.write_str("BOOLEAN"),
501 Self::TinyInt => f.write_str("TINYINT"),
502 Self::SmallInt => f.write_str("SMALLINT"),
503 Self::Integer => f.write_str("INTEGER"),
504 Self::BigInt => f.write_str("BIGINT"),
505 Self::HugeInt => f.write_str("HUGEINT"),
506 Self::UTinyInt => f.write_str("UTINYINT"),
507 Self::USmallInt => f.write_str("USMALLINT"),
508 Self::UInteger => f.write_str("UINTEGER"),
509 Self::UBigInt => f.write_str("UBIGINT"),
510 Self::UHugeInt => f.write_str("UHUGEINT"),
511 Self::Float => f.write_str("FLOAT"),
512 Self::Double => f.write_str("DOUBLE"),
513 Self::Decimal { width, scale } => write!(f, "DECIMAL({width},{scale})"),
514 Self::Varchar => f.write_str("VARCHAR"),
515 Self::Blob => f.write_str("BLOB"),
516 Self::Bit => f.write_str("BIT"),
517 Self::Uuid => f.write_str("UUID"),
518 Self::Date => f.write_str("DATE"),
519 Self::Time => f.write_str("TIME"),
520 Self::TimeTz => f.write_str("TIME WITH TIME ZONE"),
521 Self::Timestamp => f.write_str("TIMESTAMP"),
522 Self::TimestampS => f.write_str("TIMESTAMP_S"),
523 Self::TimestampMs => f.write_str("TIMESTAMP_MS"),
524 Self::TimestampNs => f.write_str("TIMESTAMP_NS"),
525 Self::TimestampTz => f.write_str("TIMESTAMP WITH TIME ZONE"),
526 Self::Interval => f.write_str("INTERVAL"),
527 Self::List(inner) => write!(f, "{inner}[]"),
528 Self::Array(inner, length) => write!(f, "{inner}[{length}]"),
529 Self::Map(key, value) => write!(f, "MAP({key}, {value})"),
530 Self::Struct(fields) => write_fields(f, "STRUCT", fields),
531 Self::Union(fields) => write_fields(f, "UNION", fields),
532 }
533 }
534}
535
536fn rank_numeric(ty: &LogicalType) -> u8 {
543 match ty {
544 LogicalType::TinyInt => 1,
545 LogicalType::UTinyInt => 2,
546 LogicalType::SmallInt => 3,
547 LogicalType::USmallInt => 4,
548 LogicalType::Integer => 5,
549 LogicalType::UInteger => 6,
550 LogicalType::BigInt => 7,
551 LogicalType::UBigInt => 8,
552 LogicalType::HugeInt => 9,
553 LogicalType::UHugeInt => 10,
554 LogicalType::Decimal { .. } => 11,
555 LogicalType::Float => 12,
556 LogicalType::Double => 13,
557 _ => 0,
558 }
559}
560
561fn integer_shape(ty: &LogicalType) -> (bool, u8) {
563 match ty {
564 LogicalType::TinyInt => (true, 8),
565 LogicalType::SmallInt => (true, 16),
566 LogicalType::Integer => (true, 32),
567 LogicalType::BigInt => (true, 64),
568 LogicalType::HugeInt => (true, 128),
569 LogicalType::UTinyInt => (false, 8),
570 LogicalType::USmallInt => (false, 16),
571 LogicalType::UInteger => (false, 32),
572 LogicalType::UBigInt => (false, 64),
573 _ => (false, 128),
574 }
575}
576
577fn integer_of(signed: bool, bits: u8) -> Option<LogicalType> {
579 Some(match (signed, bits) {
580 (true, 8) => LogicalType::TinyInt,
581 (true, 16) => LogicalType::SmallInt,
582 (true, 32) => LogicalType::Integer,
583 (true, 64) => LogicalType::BigInt,
584 (true, 128) => LogicalType::HugeInt,
585 (false, 8) => LogicalType::UTinyInt,
586 (false, 16) => LogicalType::USmallInt,
587 (false, 32) => LogicalType::UInteger,
588 (false, 64) => LogicalType::UBigInt,
589 (false, 128) => LogicalType::UHugeInt,
590 _ => return None,
591 })
592}
593
594fn promote_integers(left: &LogicalType, right: &LogicalType) -> LogicalType {
602 let (left_signed, left_bits) = integer_shape(left);
603 let (right_signed, right_bits) = integer_shape(right);
604 if left_signed == right_signed {
605 return if left_bits >= right_bits { left.clone() } else { right.clone() };
606 }
607 let (signed_bits, unsigned_bits) =
608 if left_signed { (left_bits, right_bits) } else { (right_bits, left_bits) };
609 let wanted = signed_bits.max(unsigned_bits.saturating_mul(2));
610 integer_of(true, wanted).unwrap_or(LogicalType::Double)
611}
612
613fn promote_numeric(left: LogicalType, right: LogicalType) -> LogicalType {
615 if let (
619 LogicalType::Decimal { width: left_width, scale: left_scale },
620 LogicalType::Decimal { width: right_width, scale: right_scale },
621 ) = (&left, &right)
622 {
623 let scale = (*left_scale).max(*right_scale);
624 let integral =
625 left_width.saturating_sub(*left_scale).max(right_width.saturating_sub(*right_scale));
626 let width = integral.saturating_add(scale).min(MAX_DECIMAL_WIDTH);
627 return LogicalType::Decimal { width, scale: scale.min(width) };
628 }
629 let widened = match (&left, &right) {
632 (LogicalType::Decimal { width, scale }, other)
633 | (other, LogicalType::Decimal { width, scale })
634 if other.is_integer() =>
635 {
636 let needed = decimal_digits(other).saturating_add(*scale).min(MAX_DECIMAL_WIDTH);
637 Some(LogicalType::Decimal { width: (*width).max(needed), scale: *scale })
638 }
639 _ => None,
640 };
641 if let Some(ty) = widened {
642 return ty;
643 }
644 if left.is_integer() && right.is_integer() {
645 return promote_integers(&left, &right);
646 }
647 if rank_numeric(&left) >= rank_numeric(&right) { left } else { right }
648}
649
650fn decimal_digits(ty: &LogicalType) -> u8 {
659 match ty {
660 LogicalType::TinyInt | LogicalType::UTinyInt => 3,
661 LogicalType::SmallInt | LogicalType::USmallInt => 5,
662 LogicalType::Integer | LogicalType::UInteger => 10,
663 LogicalType::BigInt => 19,
664 LogicalType::UBigInt => 20,
665 _ => MAX_DECIMAL_WIDTH,
666 }
667}
668
669fn rank_temporal(ty: &LogicalType) -> Option<u8> {
675 match ty {
676 LogicalType::Date => Some(1),
677 LogicalType::TimestampS => Some(2),
678 LogicalType::TimestampMs => Some(3),
679 LogicalType::Timestamp => Some(4),
680 LogicalType::TimestampNs => Some(5),
681 LogicalType::TimestampTz => Some(6),
682 _ => None,
683 }
684}
685
686fn write_fields(f: &mut fmt::Formatter<'_>, keyword: &str, fields: &[Field]) -> fmt::Result {
687 f.write_str(keyword)?;
688 f.write_str("(")?;
689 for (index, field) in fields.iter().enumerate() {
690 if index > 0 {
691 f.write_str(", ")?;
692 }
693 write_identifier(f, &field.name)?;
694 write!(f, " {}", field.ty)?;
695 }
696 f.write_str(")")
697}
698
699fn write_identifier(f: &mut fmt::Formatter<'_>, name: &str) -> fmt::Result {
701 let plain = !name.is_empty()
702 && name.chars().next().is_some_and(|c| c.is_ascii_alphabetic() || c == '_')
703 && name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_');
704 if plain {
705 f.write_str(name)
706 } else {
707 f.write_str("\"")?;
708 for c in name.chars() {
709 if c == '"' {
710 f.write_str("\"\"")?;
711 } else {
712 write!(f, "{c}")?;
713 }
714 }
715 f.write_str("\"")
716 }
717}
718
719#[derive(Debug, Clone, PartialEq, Eq)]
720enum Token {
721 Word(String),
722 Quoted(String),
723 Number(u32),
724 LeftParen,
725 RightParen,
726 LeftBracket,
727 RightBracket,
728 Comma,
729}
730
731fn lex(text: &str) -> Result<Vec<Token>> {
732 let mut tokens = Vec::new();
733 let chars: Vec<char> = text.chars().collect();
734 let mut i = 0;
735 while i < chars.len() {
736 let c = chars[i];
737 match c {
738 c if c.is_whitespace() => i += 1,
739 '(' => {
740 tokens.push(Token::LeftParen);
741 i += 1;
742 }
743 ')' => {
744 tokens.push(Token::RightParen);
745 i += 1;
746 }
747 '[' => {
748 tokens.push(Token::LeftBracket);
749 i += 1;
750 }
751 ']' => {
752 tokens.push(Token::RightBracket);
753 i += 1;
754 }
755 ',' => {
756 tokens.push(Token::Comma);
757 i += 1;
758 }
759 '"' => {
760 let mut name = String::new();
761 i += 1;
762 loop {
763 let Some(&c) = chars.get(i) else {
764 return Err(Error::parser(format!(
765 "Type \"{text}\" has an unterminated quoted name"
766 )));
767 };
768 i += 1;
769 if c == '"' {
770 if chars.get(i) == Some(&'"') {
771 name.push('"');
772 i += 1;
773 continue;
774 }
775 break;
776 }
777 name.push(c);
778 }
779 tokens.push(Token::Quoted(name));
780 }
781 c if c.is_ascii_digit() => {
782 let start = i;
783 while chars.get(i).is_some_and(char::is_ascii_digit) {
784 i += 1;
785 }
786 let digits: String = chars[start..i].iter().collect();
787 let number = digits.parse::<u32>().map_err(|_| {
788 Error::parser(format!("Type \"{text}\" has a number that is too large"))
789 })?;
790 tokens.push(Token::Number(number));
791 }
792 c if c.is_alphabetic() || c == '_' => {
793 let start = i;
794 while chars.get(i).is_some_and(|&c| c.is_alphanumeric() || c == '_') {
795 i += 1;
796 }
797 tokens.push(Token::Word(chars[start..i].iter().collect()));
798 }
799 other => {
800 return Err(Error::parser(format!(
801 "Type \"{text}\" has an unexpected character {other:?}"
802 )));
803 }
804 }
805 }
806 Ok(tokens)
807}
808
809struct TypeParser<'a> {
810 tokens: &'a [Token],
811 position: usize,
812}
813
814impl TypeParser<'_> {
815 fn peek(&self) -> Option<&Token> {
816 self.tokens.get(self.position)
817 }
818
819 fn eat(&mut self, token: &Token) -> bool {
820 if self.peek() == Some(token) {
821 self.position += 1;
822 true
823 } else {
824 false
825 }
826 }
827
828 fn eat_word(&mut self, word: &str) -> bool {
830 match self.peek() {
831 Some(Token::Word(found)) if found.eq_ignore_ascii_case(word) => {
832 self.position += 1;
833 true
834 }
835 _ => false,
836 }
837 }
838
839 fn parse_type(&mut self) -> Result<LogicalType> {
840 let mut ty = self.parse_base()?;
841 loop {
843 if !self.eat(&Token::LeftBracket) {
844 break;
845 }
846 if let Some(&Token::Number(length)) = self.peek() {
847 self.position += 1;
848 expect(self.eat(&Token::RightBracket), "]")?;
849 ty = LogicalType::array(ty, length);
850 } else {
851 expect(self.eat(&Token::RightBracket), "]")?;
852 ty = LogicalType::list(ty);
853 }
854 }
855 Ok(ty)
856 }
857
858 fn parse_base(&mut self) -> Result<LogicalType> {
859 let word = match self.peek().cloned() {
862 Some(Token::Word(word) | Token::Quoted(word)) => {
863 self.position += 1;
864 word
865 }
866 _ => return Err(Error::parser("Expected a type name".to_string())),
867 };
868 let upper = word.to_ascii_uppercase();
869
870 match upper.as_str() {
871 "STRUCT" | "ROW" => return self.parse_fields().map(LogicalType::Struct),
872 "UNION" => return self.parse_fields().map(LogicalType::Union),
873 "MAP" => {
874 expect(self.eat(&Token::LeftParen), "(")?;
875 let key = self.parse_type()?;
876 expect(self.eat(&Token::Comma), ",")?;
877 let value = self.parse_type()?;
878 expect(self.eat(&Token::RightParen), ")")?;
879 return Ok(LogicalType::map(key, value));
880 }
881 "DECIMAL" | "NUMERIC" | "DEC" => {
882 if !self.eat(&Token::LeftParen) {
883 return LogicalType::decimal(18, 3);
886 }
887 let width = self.parse_number()?;
888 let scale = if self.eat(&Token::Comma) { self.parse_number()? } else { 0 };
889 expect(self.eat(&Token::RightParen), ")")?;
890 let narrow = |n: u32| u8::try_from(n).unwrap_or(u8::MAX);
891 return LogicalType::decimal(narrow(width), narrow(scale));
892 }
893 "DOUBLE" => {
896 self.eat_word("PRECISION");
897 return Ok(LogicalType::Double);
898 }
899 "CHARACTER" => {
900 self.eat_word("VARYING");
901 self.eat_length_modifier()?;
902 return Ok(LogicalType::Varchar);
903 }
904 "TIME" | "TIMESTAMP" => {
905 let with_zone = self.eat_time_zone_suffix();
906 return Ok(match (upper.as_str(), with_zone) {
907 ("TIME", false) => LogicalType::Time,
908 ("TIME", true) => LogicalType::TimeTz,
909 (_, false) => LogicalType::Timestamp,
910 (_, true) => LogicalType::TimestampTz,
911 });
912 }
913 _ => {}
914 }
915
916 self.eat_length_modifier()?;
919 alias(&upper).ok_or_else(|| Error::parser(format!("Unrecognized type name \"{word}\"")))
920 }
921
922 fn eat_time_zone_suffix(&mut self) -> bool {
924 let start = self.position;
925 let with = if self.eat_word("WITH") {
926 true
927 } else if self.eat_word("WITHOUT") {
928 false
929 } else {
930 return false;
931 };
932 if self.eat_word("TIME") && self.eat_word("ZONE") {
933 with
934 } else {
935 self.position = start;
936 false
937 }
938 }
939
940 fn eat_length_modifier(&mut self) -> Result<()> {
941 if self.eat(&Token::LeftParen) {
942 self.parse_number()?;
943 expect(self.eat(&Token::RightParen), ")")?;
944 }
945 Ok(())
946 }
947
948 fn parse_fields(&mut self) -> Result<Vec<Field>> {
949 expect(self.eat(&Token::LeftParen), "(")?;
950 let mut fields = Vec::new();
951 if self.eat(&Token::RightParen) {
952 return Ok(fields);
953 }
954 loop {
955 let name = match self.peek().cloned() {
956 Some(Token::Word(name) | Token::Quoted(name)) => {
957 self.position += 1;
958 name
959 }
960 _ => return Err(Error::parser("Expected a field name".to_string())),
961 };
962 let ty = self.parse_type()?;
963 fields.push(Field::new(name, ty));
964 if self.eat(&Token::Comma) {
965 continue;
966 }
967 expect(self.eat(&Token::RightParen), ")")?;
968 return Ok(fields);
969 }
970 }
971
972 fn parse_number(&mut self) -> Result<u32> {
973 match self.peek() {
974 Some(&Token::Number(n)) => {
975 self.position += 1;
976 Ok(n)
977 }
978 _ => Err(Error::parser("Expected a number".to_string())),
979 }
980 }
981}
982
983fn expect(matched: bool, what: &str) -> Result<()> {
984 if matched { Ok(()) } else { Err(Error::parser(format!("Expected \"{what}\""))) }
985}
986
987fn alias(upper: &str) -> Option<LogicalType> {
1002 Some(match upper {
1003 "NULL" => LogicalType::Null,
1004 "BOOLEAN" | "BOOL" | "LOGICAL" => LogicalType::Boolean,
1005 "TINYINT" | "INT1" => LogicalType::TinyInt,
1006 "SMALLINT" | "INT2" | "INT16" | "SHORT" => LogicalType::SmallInt,
1007 "INTEGER" | "INT" | "INT4" | "INT32" | "SIGNED" | "INTEGRAL" => LogicalType::Integer,
1008 "BIGINT" | "INT8" | "INT64" | "LONG" | "OID" => LogicalType::BigInt,
1009 "HUGEINT" | "INT128" => LogicalType::HugeInt,
1010 "UTINYINT" | "UINT8" => LogicalType::UTinyInt,
1011 "USMALLINT" | "UINT16" => LogicalType::USmallInt,
1012 "UINTEGER" | "UINT32" => LogicalType::UInteger,
1013 "UBIGINT" | "UINT64" => LogicalType::UBigInt,
1014 "UHUGEINT" | "UINT128" => LogicalType::UHugeInt,
1015 "FLOAT" | "FLOAT4" | "REAL" => LogicalType::Float,
1016 "FLOAT8" => LogicalType::Double,
1017 "VARCHAR" | "CHAR" | "BPCHAR" | "TEXT" | "STRING" | "NVARCHAR" => LogicalType::Varchar,
1018 "BLOB" | "BYTEA" | "BINARY" | "VARBINARY" => LogicalType::Blob,
1019 "BIT" | "BITSTRING" => LogicalType::Bit,
1020 "UUID" | "GUID" => LogicalType::Uuid,
1021 "DATE" => LogicalType::Date,
1022 "TIMETZ" => LogicalType::TimeTz,
1023 "DATETIME" | "TIMESTAMP_US" => LogicalType::Timestamp,
1024 "TIMESTAMP_S" => LogicalType::TimestampS,
1025 "TIMESTAMP_MS" => LogicalType::TimestampMs,
1026 "TIMESTAMP_NS" => LogicalType::TimestampNs,
1027 "TIMESTAMPTZ" => LogicalType::TimestampTz,
1028 "INTERVAL" => LogicalType::Interval,
1029 _ => return None,
1030 })
1031}
1032
1033#[cfg(test)]
1034mod promotion_tests {
1035 use super::LogicalType;
1036
1037 #[test]
1038 fn a_type_promotes_with_itself_to_itself() {
1039 for ty in [
1040 LogicalType::Integer,
1041 LogicalType::Varchar,
1042 LogicalType::Boolean,
1043 LogicalType::Struct(vec![]),
1044 ] {
1045 assert_eq!(ty.promote(&ty), Some(ty.clone()), "{ty} does not promote with itself");
1046 }
1047 }
1048
1049 #[test]
1050 fn null_takes_the_other_type() {
1051 assert_eq!(LogicalType::Null.promote(&LogicalType::Varchar), Some(LogicalType::Varchar));
1052 assert_eq!(LogicalType::Date.promote(&LogicalType::Null), Some(LogicalType::Date));
1053 assert_eq!(LogicalType::Null.promote(&LogicalType::Null), Some(LogicalType::Null));
1054 }
1055
1056 #[test]
1057 fn the_wider_number_wins() {
1058 assert_eq!(
1059 LogicalType::Integer.promote(&LogicalType::SmallInt),
1060 Some(LogicalType::Integer)
1061 );
1062 assert_eq!(LogicalType::Integer.promote(&LogicalType::Double), Some(LogicalType::Double));
1063 assert_eq!(LogicalType::Float.promote(&LogicalType::Double), Some(LogicalType::Double));
1064 }
1065
1066 #[test]
1069 fn signed_and_unsigned_widen_rather_than_reinterpret() {
1070 assert_eq!(LogicalType::Integer.promote(&LogicalType::UInteger), Some(LogicalType::BigInt));
1071 assert_eq!(
1072 LogicalType::TinyInt.promote(&LogicalType::UTinyInt),
1073 Some(LogicalType::SmallInt)
1074 );
1075 assert_eq!(LogicalType::BigInt.promote(&LogicalType::UBigInt), Some(LogicalType::HugeInt));
1076 }
1077
1078 #[test]
1079 fn promotion_does_not_care_which_side_a_type_is_on() {
1080 let types = [
1081 LogicalType::TinyInt,
1082 LogicalType::UInteger,
1083 LogicalType::BigInt,
1084 LogicalType::Double,
1085 LogicalType::Decimal { width: 10, scale: 2 },
1086 LogicalType::Null,
1087 LogicalType::Varchar,
1088 LogicalType::Date,
1089 LogicalType::Timestamp,
1090 ];
1091 for left in &types {
1092 for right in &types {
1093 assert_eq!(
1094 left.promote(right),
1095 right.promote(left),
1096 "{left} and {right} promote differently depending on the order"
1097 );
1098 }
1099 }
1100 }
1101
1102 #[test]
1103 fn a_decimal_keeps_room_for_both_halves() {
1104 let left = LogicalType::Decimal { width: 5, scale: 4 };
1105 let right = LogicalType::Decimal { width: 5, scale: 1 };
1106 assert_eq!(left.promote(&right), Some(LogicalType::Decimal { width: 8, scale: 4 }));
1107 }
1108
1109 #[test]
1110 fn an_integer_next_to_a_decimal_widens_the_decimal() {
1111 let decimal = LogicalType::Decimal { width: 5, scale: 2 };
1112 assert_eq!(
1113 decimal.promote(&LogicalType::Integer),
1114 Some(LogicalType::Decimal { width: 12, scale: 2 })
1115 );
1116 }
1117
1118 #[test]
1123 fn a_bigint_leaves_room_for_one_digit_fewer_than_a_ubigint() {
1124 let decimal = LogicalType::Decimal { width: 4, scale: 2 };
1125 assert_eq!(
1126 decimal.promote(&LogicalType::BigInt),
1127 Some(LogicalType::Decimal { width: 21, scale: 2 })
1128 );
1129 assert_eq!(
1130 decimal.promote(&LogicalType::UBigInt),
1131 Some(LogicalType::Decimal { width: 22, scale: 2 })
1132 );
1133 assert_eq!(decimal.promote(&LogicalType::Integer), decimal.promote(&LogicalType::UInteger));
1134 }
1135
1136 #[test]
1137 fn a_date_and_a_timestamp_meet_at_the_timestamp() {
1138 assert_eq!(
1139 LogicalType::Date.promote(&LogicalType::Timestamp),
1140 Some(LogicalType::Timestamp)
1141 );
1142 assert_eq!(
1143 LogicalType::TimestampS.promote(&LogicalType::TimestampNs),
1144 Some(LogicalType::TimestampNs)
1145 );
1146 }
1147
1148 #[test]
1151 fn types_that_do_not_meet_say_so() {
1152 assert_eq!(LogicalType::Timestamp.promote(&LogicalType::Interval), None);
1153 assert_eq!(LogicalType::Integer.promote(&LogicalType::Varchar), None);
1154 assert_eq!(LogicalType::Boolean.promote(&LogicalType::Integer), None);
1155 }
1156
1157 #[test]
1158 fn a_list_promotes_by_its_element() {
1159 let left = LogicalType::list(LogicalType::Integer);
1160 let right = LogicalType::list(LogicalType::BigInt);
1161 assert_eq!(left.promote(&right), Some(LogicalType::list(LogicalType::BigInt)));
1162 assert_eq!(left.promote(&LogicalType::list(LogicalType::Varchar)), None);
1163 }
1164}
1165
1166#[cfg(test)]
1167mod tests {
1168 use super::{Field, LogicalType, PhysicalType};
1169
1170 fn every_type() -> Vec<LogicalType> {
1173 vec![
1174 LogicalType::Null,
1175 LogicalType::Boolean,
1176 LogicalType::TinyInt,
1177 LogicalType::SmallInt,
1178 LogicalType::Integer,
1179 LogicalType::BigInt,
1180 LogicalType::HugeInt,
1181 LogicalType::UTinyInt,
1182 LogicalType::USmallInt,
1183 LogicalType::UInteger,
1184 LogicalType::UBigInt,
1185 LogicalType::UHugeInt,
1186 LogicalType::Float,
1187 LogicalType::Double,
1188 LogicalType::Decimal { width: 18, scale: 3 },
1189 LogicalType::Decimal { width: 38, scale: 0 },
1190 LogicalType::Varchar,
1191 LogicalType::Blob,
1192 LogicalType::Bit,
1193 LogicalType::Uuid,
1194 LogicalType::Date,
1195 LogicalType::Time,
1196 LogicalType::TimeTz,
1197 LogicalType::Timestamp,
1198 LogicalType::TimestampS,
1199 LogicalType::TimestampMs,
1200 LogicalType::TimestampNs,
1201 LogicalType::TimestampTz,
1202 LogicalType::Interval,
1203 LogicalType::list(LogicalType::Integer),
1204 LogicalType::list(LogicalType::list(LogicalType::Varchar)),
1205 LogicalType::array(LogicalType::Double, 3),
1206 LogicalType::map(LogicalType::Varchar, LogicalType::Integer),
1207 LogicalType::Struct(vec![
1208 Field::new("a", LogicalType::Integer),
1209 Field::new("b", LogicalType::list(LogicalType::Varchar)),
1210 ]),
1211 LogicalType::Union(vec![
1212 Field::new("num", LogicalType::Integer),
1213 Field::new("str", LogicalType::Varchar),
1214 ]),
1215 ]
1216 }
1217
1218 #[test]
1219 fn every_type_survives_being_printed_and_read_back() {
1220 for ty in every_type() {
1224 let printed = ty.to_string();
1225 let parsed = LogicalType::parse(&printed)
1226 .unwrap_or_else(|e| panic!("{printed} did not parse back: {e}"));
1227 assert_eq!(parsed, ty, "{printed} parsed to something else");
1228 }
1229 }
1230
1231 #[test]
1232 fn a_field_name_that_needs_quoting_gets_quoted() {
1233 let ty = LogicalType::Struct(vec![
1234 Field::new("plain", LogicalType::Integer),
1235 Field::new("has space", LogicalType::Integer),
1236 Field::new("has\"quote", LogicalType::Integer),
1237 Field::new("2leading", LogicalType::Integer),
1238 ]);
1239 assert_eq!(
1240 ty.to_string(),
1241 "STRUCT(plain INTEGER, \"has space\" INTEGER, \"has\"\"quote\" INTEGER, \
1242 \"2leading\" INTEGER)"
1243 );
1244 assert_eq!(LogicalType::parse(&ty.to_string()).unwrap(), ty);
1245 }
1246
1247 #[test]
1248 fn the_duckdb_aliases_resolve() {
1249 let cases = [
1250 ("int4", LogicalType::Integer),
1251 ("INT", LogicalType::Integer),
1252 ("signed", LogicalType::Integer),
1253 ("int8", LogicalType::BigInt),
1254 ("float4", LogicalType::Float),
1255 ("float8", LogicalType::Double),
1256 ("double precision", LogicalType::Double),
1257 ("text", LogicalType::Varchar),
1258 ("varchar(10)", LogicalType::Varchar),
1259 ("character varying(255)", LogicalType::Varchar),
1260 ("bool", LogicalType::Boolean),
1261 ("datetime", LogicalType::Timestamp),
1262 ("numeric(9, 2)", LogicalType::Decimal { width: 9, scale: 2 }),
1263 ("decimal", LogicalType::Decimal { width: 18, scale: 3 }),
1264 ("timestamp without time zone", LogicalType::Timestamp),
1265 ("timestamp with time zone", LogicalType::TimestampTz),
1266 ("time with time zone", LogicalType::TimeTz),
1267 ];
1268 for (text, expected) in cases {
1269 assert_eq!(LogicalType::parse(text).unwrap(), expected, "{text}");
1270 }
1271 }
1272
1273 #[test]
1274 fn the_unsigned_names_count_bits_and_the_short_signed_ones_count_bytes() {
1275 let resolves = [
1280 ("int1", LogicalType::TinyInt),
1281 ("int2", LogicalType::SmallInt),
1282 ("int4", LogicalType::Integer),
1283 ("int8", LogicalType::BigInt),
1284 ("int16", LogicalType::SmallInt),
1285 ("int32", LogicalType::Integer),
1286 ("int64", LogicalType::BigInt),
1287 ("int128", LogicalType::HugeInt),
1288 ("uint8", LogicalType::UTinyInt),
1289 ("uint16", LogicalType::USmallInt),
1290 ("uint32", LogicalType::UInteger),
1291 ("uint64", LogicalType::UBigInt),
1292 ("uint128", LogicalType::UHugeInt),
1293 ];
1294 for (text, expected) in resolves {
1295 assert_eq!(LogicalType::parse(text).unwrap(), expected, "{text}");
1296 }
1297 for text in ["uint1", "uint2", "uint4"] {
1300 assert!(LogicalType::parse(text).is_err(), "{text} should not be a type name");
1301 }
1302 }
1303
1304 #[test]
1305 fn the_four_timestamp_units_are_the_only_four_spellings() {
1306 let resolves = [
1307 ("timestamp_s", LogicalType::TimestampS),
1308 ("timestamp_ms", LogicalType::TimestampMs),
1309 ("timestamp_us", LogicalType::Timestamp),
1310 ("timestamp_ns", LogicalType::TimestampNs),
1311 ];
1312 for (text, expected) in resolves {
1313 assert_eq!(LogicalType::parse(text).unwrap(), expected, "{text}");
1314 }
1315 for text in [
1319 "timestamp_sec",
1320 "timestamp_seconds",
1321 "timestamp_milliseconds",
1322 "timestamp_nanoseconds",
1323 ] {
1324 assert!(LogicalType::parse(text).is_err(), "{text} should not be a type name");
1325 }
1326 }
1327
1328 #[test]
1329 fn the_three_aliases_that_are_not_about_width_resolve() {
1330 assert_eq!(LogicalType::parse("integral").unwrap(), LogicalType::Integer);
1333 assert_eq!(LogicalType::parse("oid").unwrap(), LogicalType::BigInt);
1334 assert_eq!(LogicalType::parse("nvarchar").unwrap(), LogicalType::Varchar);
1335 }
1336
1337 #[test]
1338 fn list_and_array_suffixes_bind_left_to_right() {
1339 assert_eq!(
1340 LogicalType::parse("INTEGER[][3]").unwrap(),
1341 LogicalType::array(LogicalType::list(LogicalType::Integer), 3)
1342 );
1343 assert_eq!(
1344 LogicalType::parse("STRUCT(a INT)[]").unwrap(),
1345 LogicalType::list(LogicalType::Struct(vec![Field::new("a", LogicalType::Integer)]))
1346 );
1347 }
1348
1349 #[test]
1350 fn a_decimal_is_stored_in_the_narrowest_integer_that_holds_it() {
1351 assert_eq!(LogicalType::decimal(4, 2).unwrap().physical(), PhysicalType::Int16);
1352 assert_eq!(LogicalType::decimal(9, 2).unwrap().physical(), PhysicalType::Int32);
1353 assert_eq!(LogicalType::decimal(18, 2).unwrap().physical(), PhysicalType::Int64);
1354 assert_eq!(LogicalType::decimal(38, 2).unwrap().physical(), PhysicalType::Int128);
1355 }
1356
1357 #[test]
1361 fn a_message_names_the_type_by_what_it_is_stored_in() {
1362 assert_eq!(LogicalType::Boolean.physical_name(), "BOOL");
1363 assert_eq!(LogicalType::TinyInt.physical_name(), "INT8");
1364 assert_eq!(LogicalType::Integer.physical_name(), "INT32");
1365 assert_eq!(LogicalType::UBigInt.physical_name(), "UINT64");
1366 assert_eq!(LogicalType::HugeInt.physical_name(), "INT128");
1367 assert_eq!(LogicalType::Float.physical_name(), "FLOAT");
1368 assert_eq!(LogicalType::Varchar.physical_name(), "VARCHAR");
1369 assert_eq!(LogicalType::Date.physical_name(), "DATE");
1370 assert_eq!(LogicalType::decimal(4, 2).unwrap().physical_name(), "DECIMAL(4)");
1371 assert_eq!(LogicalType::decimal(11, 0).unwrap().physical_name(), "DECIMAL(18)");
1372 assert_eq!(LogicalType::decimal(18, 8).unwrap().physical_name(), "DECIMAL(18)");
1373 assert_eq!(LogicalType::decimal(38, 2).unwrap().physical_name(), "DECIMAL(38)");
1374 assert_eq!(LogicalType::Integer.decimal_storage(), None);
1375 }
1376
1377 #[test]
1378 fn a_decimal_outside_the_bounds_is_rejected_rather_than_clamped() {
1379 assert!(LogicalType::decimal(0, 0).is_err());
1380 assert!(LogicalType::decimal(39, 0).is_err());
1381 assert!(LogicalType::decimal(4, 5).is_err());
1382 assert!(LogicalType::parse("DECIMAL(39,0)").is_err());
1383 }
1384
1385 #[test]
1386 fn a_date_and_an_integer_share_a_layout_and_not_a_meaning() {
1387 assert_eq!(LogicalType::Date.physical(), LogicalType::Integer.physical());
1388 assert_ne!(LogicalType::Date, LogicalType::Integer);
1389 assert!(LogicalType::Date.is_temporal());
1390 assert!(!LogicalType::Date.is_numeric());
1391 }
1392
1393 #[test]
1394 fn nesting_reports_its_children_in_child_column_order() {
1395 let ty = LogicalType::map(LogicalType::Varchar, LogicalType::Integer);
1396 assert!(ty.is_nested());
1397 assert_eq!(ty.children(), vec![LogicalType::Varchar, LogicalType::Integer]);
1398 assert_eq!(LogicalType::Integer.children(), Vec::new());
1399 }
1400
1401 #[test]
1402 fn text_that_is_not_a_type_is_rejected_with_the_word_that_broke_it() {
1403 let error = LogicalType::parse("INTEGRE").unwrap_err();
1404 assert!(error.message().contains("INTEGRE"), "{error}");
1405 assert!(LogicalType::parse("INTEGER JUNK").is_err());
1406 assert!(LogicalType::parse("STRUCT(a)").is_err());
1407 assert!(LogicalType::parse("").is_err());
1408 }
1409}