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]
420 pub fn promote(&self, other: &Self) -> Option<Self> {
421 if self == other {
422 return Some(self.clone());
423 }
424 match (self, other) {
425 (Self::Null, ty) | (ty, Self::Null) => Some(ty.clone()),
426 (Self::List(left), Self::List(right)) => Some(Self::list(left.promote(right)?)),
427 _ if self.is_numeric() && other.is_numeric() => {
428 Some(promote_numeric(self.clone(), other.clone()))
429 }
430 _ if self.is_temporal() && other.is_temporal() => {
433 match (rank_temporal(self), rank_temporal(other)) {
434 (Some(left), Some(right)) => {
435 Some(if left >= right { self.clone() } else { other.clone() })
436 }
437 _ => None,
438 }
439 }
440 _ => None,
441 }
442 }
443
444 #[must_use]
446 pub fn children(&self) -> Vec<Self> {
447 match self {
448 Self::List(inner) | Self::Array(inner, _) => vec![inner.as_ref().clone()],
449 Self::Map(key, value) => vec![key.as_ref().clone(), value.as_ref().clone()],
450 Self::Struct(fields) | Self::Union(fields) => {
451 fields.iter().map(|f| f.ty.clone()).collect()
452 }
453 _ => Vec::new(),
454 }
455 }
456
457 pub fn parse(text: &str) -> Result<Self> {
464 let tokens = lex(text)?;
465 let mut parser = TypeParser { tokens: &tokens, position: 0 };
466 let ty = parser.parse_type()?;
467 if parser.position != parser.tokens.len() {
468 return Err(Error::parser(format!("Type \"{text}\" has trailing text")));
469 }
470 Ok(ty)
471 }
472}
473
474pub const MAX_DECIMAL_WIDTH: u8 = 38;
477
478impl fmt::Display for LogicalType {
479 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
480 match self {
481 Self::Null => f.write_str("\"NULL\""),
482 Self::Boolean => f.write_str("BOOLEAN"),
483 Self::TinyInt => f.write_str("TINYINT"),
484 Self::SmallInt => f.write_str("SMALLINT"),
485 Self::Integer => f.write_str("INTEGER"),
486 Self::BigInt => f.write_str("BIGINT"),
487 Self::HugeInt => f.write_str("HUGEINT"),
488 Self::UTinyInt => f.write_str("UTINYINT"),
489 Self::USmallInt => f.write_str("USMALLINT"),
490 Self::UInteger => f.write_str("UINTEGER"),
491 Self::UBigInt => f.write_str("UBIGINT"),
492 Self::UHugeInt => f.write_str("UHUGEINT"),
493 Self::Float => f.write_str("FLOAT"),
494 Self::Double => f.write_str("DOUBLE"),
495 Self::Decimal { width, scale } => write!(f, "DECIMAL({width},{scale})"),
496 Self::Varchar => f.write_str("VARCHAR"),
497 Self::Blob => f.write_str("BLOB"),
498 Self::Bit => f.write_str("BIT"),
499 Self::Uuid => f.write_str("UUID"),
500 Self::Date => f.write_str("DATE"),
501 Self::Time => f.write_str("TIME"),
502 Self::TimeTz => f.write_str("TIME WITH TIME ZONE"),
503 Self::Timestamp => f.write_str("TIMESTAMP"),
504 Self::TimestampS => f.write_str("TIMESTAMP_S"),
505 Self::TimestampMs => f.write_str("TIMESTAMP_MS"),
506 Self::TimestampNs => f.write_str("TIMESTAMP_NS"),
507 Self::TimestampTz => f.write_str("TIMESTAMP WITH TIME ZONE"),
508 Self::Interval => f.write_str("INTERVAL"),
509 Self::List(inner) => write!(f, "{inner}[]"),
510 Self::Array(inner, length) => write!(f, "{inner}[{length}]"),
511 Self::Map(key, value) => write!(f, "MAP({key}, {value})"),
512 Self::Struct(fields) => write_fields(f, "STRUCT", fields),
513 Self::Union(fields) => write_fields(f, "UNION", fields),
514 }
515 }
516}
517
518fn rank_numeric(ty: &LogicalType) -> u8 {
525 match ty {
526 LogicalType::TinyInt => 1,
527 LogicalType::UTinyInt => 2,
528 LogicalType::SmallInt => 3,
529 LogicalType::USmallInt => 4,
530 LogicalType::Integer => 5,
531 LogicalType::UInteger => 6,
532 LogicalType::BigInt => 7,
533 LogicalType::UBigInt => 8,
534 LogicalType::HugeInt => 9,
535 LogicalType::UHugeInt => 10,
536 LogicalType::Decimal { .. } => 11,
537 LogicalType::Float => 12,
538 LogicalType::Double => 13,
539 _ => 0,
540 }
541}
542
543fn integer_shape(ty: &LogicalType) -> (bool, u8) {
545 match ty {
546 LogicalType::TinyInt => (true, 8),
547 LogicalType::SmallInt => (true, 16),
548 LogicalType::Integer => (true, 32),
549 LogicalType::BigInt => (true, 64),
550 LogicalType::HugeInt => (true, 128),
551 LogicalType::UTinyInt => (false, 8),
552 LogicalType::USmallInt => (false, 16),
553 LogicalType::UInteger => (false, 32),
554 LogicalType::UBigInt => (false, 64),
555 _ => (false, 128),
556 }
557}
558
559fn integer_of(signed: bool, bits: u8) -> Option<LogicalType> {
561 Some(match (signed, bits) {
562 (true, 8) => LogicalType::TinyInt,
563 (true, 16) => LogicalType::SmallInt,
564 (true, 32) => LogicalType::Integer,
565 (true, 64) => LogicalType::BigInt,
566 (true, 128) => LogicalType::HugeInt,
567 (false, 8) => LogicalType::UTinyInt,
568 (false, 16) => LogicalType::USmallInt,
569 (false, 32) => LogicalType::UInteger,
570 (false, 64) => LogicalType::UBigInt,
571 (false, 128) => LogicalType::UHugeInt,
572 _ => return None,
573 })
574}
575
576fn promote_integers(left: &LogicalType, right: &LogicalType) -> LogicalType {
584 let (left_signed, left_bits) = integer_shape(left);
585 let (right_signed, right_bits) = integer_shape(right);
586 if left_signed == right_signed {
587 return if left_bits >= right_bits { left.clone() } else { right.clone() };
588 }
589 let (signed_bits, unsigned_bits) =
590 if left_signed { (left_bits, right_bits) } else { (right_bits, left_bits) };
591 let wanted = signed_bits.max(unsigned_bits.saturating_mul(2));
592 integer_of(true, wanted).unwrap_or(LogicalType::Double)
593}
594
595fn promote_numeric(left: LogicalType, right: LogicalType) -> LogicalType {
597 if let (
601 LogicalType::Decimal { width: left_width, scale: left_scale },
602 LogicalType::Decimal { width: right_width, scale: right_scale },
603 ) = (&left, &right)
604 {
605 let scale = (*left_scale).max(*right_scale);
606 let integral =
607 left_width.saturating_sub(*left_scale).max(right_width.saturating_sub(*right_scale));
608 let width = integral.saturating_add(scale).min(MAX_DECIMAL_WIDTH);
609 return LogicalType::Decimal { width, scale: scale.min(width) };
610 }
611 let widened = match (&left, &right) {
614 (LogicalType::Decimal { width, scale }, other)
615 | (other, LogicalType::Decimal { width, scale })
616 if other.is_integer() =>
617 {
618 let needed = decimal_digits(other).saturating_add(*scale).min(MAX_DECIMAL_WIDTH);
619 Some(LogicalType::Decimal { width: (*width).max(needed), scale: *scale })
620 }
621 _ => None,
622 };
623 if let Some(ty) = widened {
624 return ty;
625 }
626 if left.is_integer() && right.is_integer() {
627 return promote_integers(&left, &right);
628 }
629 if rank_numeric(&left) >= rank_numeric(&right) { left } else { right }
630}
631
632fn decimal_digits(ty: &LogicalType) -> u8 {
641 match ty {
642 LogicalType::TinyInt | LogicalType::UTinyInt => 3,
643 LogicalType::SmallInt | LogicalType::USmallInt => 5,
644 LogicalType::Integer | LogicalType::UInteger => 10,
645 LogicalType::BigInt => 19,
646 LogicalType::UBigInt => 20,
647 _ => MAX_DECIMAL_WIDTH,
648 }
649}
650
651fn rank_temporal(ty: &LogicalType) -> Option<u8> {
657 match ty {
658 LogicalType::Date => Some(1),
659 LogicalType::TimestampS => Some(2),
660 LogicalType::TimestampMs => Some(3),
661 LogicalType::Timestamp => Some(4),
662 LogicalType::TimestampNs => Some(5),
663 LogicalType::TimestampTz => Some(6),
664 _ => None,
665 }
666}
667
668fn write_fields(f: &mut fmt::Formatter<'_>, keyword: &str, fields: &[Field]) -> fmt::Result {
669 f.write_str(keyword)?;
670 f.write_str("(")?;
671 for (index, field) in fields.iter().enumerate() {
672 if index > 0 {
673 f.write_str(", ")?;
674 }
675 write_identifier(f, &field.name)?;
676 write!(f, " {}", field.ty)?;
677 }
678 f.write_str(")")
679}
680
681fn write_identifier(f: &mut fmt::Formatter<'_>, name: &str) -> fmt::Result {
683 let plain = !name.is_empty()
684 && name.chars().next().is_some_and(|c| c.is_ascii_alphabetic() || c == '_')
685 && name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_');
686 if plain {
687 f.write_str(name)
688 } else {
689 f.write_str("\"")?;
690 for c in name.chars() {
691 if c == '"' {
692 f.write_str("\"\"")?;
693 } else {
694 write!(f, "{c}")?;
695 }
696 }
697 f.write_str("\"")
698 }
699}
700
701#[derive(Debug, Clone, PartialEq, Eq)]
702enum Token {
703 Word(String),
704 Quoted(String),
705 Number(u32),
706 LeftParen,
707 RightParen,
708 LeftBracket,
709 RightBracket,
710 Comma,
711}
712
713fn lex(text: &str) -> Result<Vec<Token>> {
714 let mut tokens = Vec::new();
715 let chars: Vec<char> = text.chars().collect();
716 let mut i = 0;
717 while i < chars.len() {
718 let c = chars[i];
719 match c {
720 c if c.is_whitespace() => i += 1,
721 '(' => {
722 tokens.push(Token::LeftParen);
723 i += 1;
724 }
725 ')' => {
726 tokens.push(Token::RightParen);
727 i += 1;
728 }
729 '[' => {
730 tokens.push(Token::LeftBracket);
731 i += 1;
732 }
733 ']' => {
734 tokens.push(Token::RightBracket);
735 i += 1;
736 }
737 ',' => {
738 tokens.push(Token::Comma);
739 i += 1;
740 }
741 '"' => {
742 let mut name = String::new();
743 i += 1;
744 loop {
745 let Some(&c) = chars.get(i) else {
746 return Err(Error::parser(format!(
747 "Type \"{text}\" has an unterminated quoted name"
748 )));
749 };
750 i += 1;
751 if c == '"' {
752 if chars.get(i) == Some(&'"') {
753 name.push('"');
754 i += 1;
755 continue;
756 }
757 break;
758 }
759 name.push(c);
760 }
761 tokens.push(Token::Quoted(name));
762 }
763 c if c.is_ascii_digit() => {
764 let start = i;
765 while chars.get(i).is_some_and(char::is_ascii_digit) {
766 i += 1;
767 }
768 let digits: String = chars[start..i].iter().collect();
769 let number = digits.parse::<u32>().map_err(|_| {
770 Error::parser(format!("Type \"{text}\" has a number that is too large"))
771 })?;
772 tokens.push(Token::Number(number));
773 }
774 c if c.is_alphabetic() || c == '_' => {
775 let start = i;
776 while chars.get(i).is_some_and(|&c| c.is_alphanumeric() || c == '_') {
777 i += 1;
778 }
779 tokens.push(Token::Word(chars[start..i].iter().collect()));
780 }
781 other => {
782 return Err(Error::parser(format!(
783 "Type \"{text}\" has an unexpected character {other:?}"
784 )));
785 }
786 }
787 }
788 Ok(tokens)
789}
790
791struct TypeParser<'a> {
792 tokens: &'a [Token],
793 position: usize,
794}
795
796impl TypeParser<'_> {
797 fn peek(&self) -> Option<&Token> {
798 self.tokens.get(self.position)
799 }
800
801 fn eat(&mut self, token: &Token) -> bool {
802 if self.peek() == Some(token) {
803 self.position += 1;
804 true
805 } else {
806 false
807 }
808 }
809
810 fn eat_word(&mut self, word: &str) -> bool {
812 match self.peek() {
813 Some(Token::Word(found)) if found.eq_ignore_ascii_case(word) => {
814 self.position += 1;
815 true
816 }
817 _ => false,
818 }
819 }
820
821 fn parse_type(&mut self) -> Result<LogicalType> {
822 let mut ty = self.parse_base()?;
823 loop {
825 if !self.eat(&Token::LeftBracket) {
826 break;
827 }
828 if let Some(&Token::Number(length)) = self.peek() {
829 self.position += 1;
830 expect(self.eat(&Token::RightBracket), "]")?;
831 ty = LogicalType::array(ty, length);
832 } else {
833 expect(self.eat(&Token::RightBracket), "]")?;
834 ty = LogicalType::list(ty);
835 }
836 }
837 Ok(ty)
838 }
839
840 fn parse_base(&mut self) -> Result<LogicalType> {
841 let word = match self.peek().cloned() {
844 Some(Token::Word(word) | Token::Quoted(word)) => {
845 self.position += 1;
846 word
847 }
848 _ => return Err(Error::parser("Expected a type name".to_string())),
849 };
850 let upper = word.to_ascii_uppercase();
851
852 match upper.as_str() {
853 "STRUCT" | "ROW" => return self.parse_fields().map(LogicalType::Struct),
854 "UNION" => return self.parse_fields().map(LogicalType::Union),
855 "MAP" => {
856 expect(self.eat(&Token::LeftParen), "(")?;
857 let key = self.parse_type()?;
858 expect(self.eat(&Token::Comma), ",")?;
859 let value = self.parse_type()?;
860 expect(self.eat(&Token::RightParen), ")")?;
861 return Ok(LogicalType::map(key, value));
862 }
863 "DECIMAL" | "NUMERIC" | "DEC" => {
864 if !self.eat(&Token::LeftParen) {
865 return LogicalType::decimal(18, 3);
868 }
869 let width = self.parse_number()?;
870 let scale = if self.eat(&Token::Comma) { self.parse_number()? } else { 0 };
871 expect(self.eat(&Token::RightParen), ")")?;
872 let narrow = |n: u32| u8::try_from(n).unwrap_or(u8::MAX);
873 return LogicalType::decimal(narrow(width), narrow(scale));
874 }
875 "DOUBLE" => {
878 self.eat_word("PRECISION");
879 return Ok(LogicalType::Double);
880 }
881 "CHARACTER" => {
882 self.eat_word("VARYING");
883 self.eat_length_modifier()?;
884 return Ok(LogicalType::Varchar);
885 }
886 "TIME" | "TIMESTAMP" => {
887 let with_zone = self.eat_time_zone_suffix();
888 return Ok(match (upper.as_str(), with_zone) {
889 ("TIME", false) => LogicalType::Time,
890 ("TIME", true) => LogicalType::TimeTz,
891 (_, false) => LogicalType::Timestamp,
892 (_, true) => LogicalType::TimestampTz,
893 });
894 }
895 _ => {}
896 }
897
898 self.eat_length_modifier()?;
901 alias(&upper).ok_or_else(|| Error::parser(format!("Unrecognized type name \"{word}\"")))
902 }
903
904 fn eat_time_zone_suffix(&mut self) -> bool {
906 let start = self.position;
907 let with = if self.eat_word("WITH") {
908 true
909 } else if self.eat_word("WITHOUT") {
910 false
911 } else {
912 return false;
913 };
914 if self.eat_word("TIME") && self.eat_word("ZONE") {
915 with
916 } else {
917 self.position = start;
918 false
919 }
920 }
921
922 fn eat_length_modifier(&mut self) -> Result<()> {
923 if self.eat(&Token::LeftParen) {
924 self.parse_number()?;
925 expect(self.eat(&Token::RightParen), ")")?;
926 }
927 Ok(())
928 }
929
930 fn parse_fields(&mut self) -> Result<Vec<Field>> {
931 expect(self.eat(&Token::LeftParen), "(")?;
932 let mut fields = Vec::new();
933 if self.eat(&Token::RightParen) {
934 return Ok(fields);
935 }
936 loop {
937 let name = match self.peek().cloned() {
938 Some(Token::Word(name) | Token::Quoted(name)) => {
939 self.position += 1;
940 name
941 }
942 _ => return Err(Error::parser("Expected a field name".to_string())),
943 };
944 let ty = self.parse_type()?;
945 fields.push(Field::new(name, ty));
946 if self.eat(&Token::Comma) {
947 continue;
948 }
949 expect(self.eat(&Token::RightParen), ")")?;
950 return Ok(fields);
951 }
952 }
953
954 fn parse_number(&mut self) -> Result<u32> {
955 match self.peek() {
956 Some(&Token::Number(n)) => {
957 self.position += 1;
958 Ok(n)
959 }
960 _ => Err(Error::parser("Expected a number".to_string())),
961 }
962 }
963}
964
965fn expect(matched: bool, what: &str) -> Result<()> {
966 if matched { Ok(()) } else { Err(Error::parser(format!("Expected \"{what}\""))) }
967}
968
969fn alias(upper: &str) -> Option<LogicalType> {
984 Some(match upper {
985 "NULL" => LogicalType::Null,
986 "BOOLEAN" | "BOOL" | "LOGICAL" => LogicalType::Boolean,
987 "TINYINT" | "INT1" => LogicalType::TinyInt,
988 "SMALLINT" | "INT2" | "INT16" | "SHORT" => LogicalType::SmallInt,
989 "INTEGER" | "INT" | "INT4" | "INT32" | "SIGNED" | "INTEGRAL" => LogicalType::Integer,
990 "BIGINT" | "INT8" | "INT64" | "LONG" | "OID" => LogicalType::BigInt,
991 "HUGEINT" | "INT128" => LogicalType::HugeInt,
992 "UTINYINT" | "UINT8" => LogicalType::UTinyInt,
993 "USMALLINT" | "UINT16" => LogicalType::USmallInt,
994 "UINTEGER" | "UINT32" => LogicalType::UInteger,
995 "UBIGINT" | "UINT64" => LogicalType::UBigInt,
996 "UHUGEINT" | "UINT128" => LogicalType::UHugeInt,
997 "FLOAT" | "FLOAT4" | "REAL" => LogicalType::Float,
998 "FLOAT8" => LogicalType::Double,
999 "VARCHAR" | "CHAR" | "BPCHAR" | "TEXT" | "STRING" | "NVARCHAR" => LogicalType::Varchar,
1000 "BLOB" | "BYTEA" | "BINARY" | "VARBINARY" => LogicalType::Blob,
1001 "BIT" | "BITSTRING" => LogicalType::Bit,
1002 "UUID" | "GUID" => LogicalType::Uuid,
1003 "DATE" => LogicalType::Date,
1004 "TIMETZ" => LogicalType::TimeTz,
1005 "DATETIME" | "TIMESTAMP_US" => LogicalType::Timestamp,
1006 "TIMESTAMP_S" => LogicalType::TimestampS,
1007 "TIMESTAMP_MS" => LogicalType::TimestampMs,
1008 "TIMESTAMP_NS" => LogicalType::TimestampNs,
1009 "TIMESTAMPTZ" => LogicalType::TimestampTz,
1010 "INTERVAL" => LogicalType::Interval,
1011 _ => return None,
1012 })
1013}
1014
1015#[cfg(test)]
1016mod promotion_tests {
1017 use super::LogicalType;
1018
1019 #[test]
1020 fn a_type_promotes_with_itself_to_itself() {
1021 for ty in [
1022 LogicalType::Integer,
1023 LogicalType::Varchar,
1024 LogicalType::Boolean,
1025 LogicalType::Struct(vec![]),
1026 ] {
1027 assert_eq!(ty.promote(&ty), Some(ty.clone()), "{ty} does not promote with itself");
1028 }
1029 }
1030
1031 #[test]
1032 fn null_takes_the_other_type() {
1033 assert_eq!(LogicalType::Null.promote(&LogicalType::Varchar), Some(LogicalType::Varchar));
1034 assert_eq!(LogicalType::Date.promote(&LogicalType::Null), Some(LogicalType::Date));
1035 assert_eq!(LogicalType::Null.promote(&LogicalType::Null), Some(LogicalType::Null));
1036 }
1037
1038 #[test]
1039 fn the_wider_number_wins() {
1040 assert_eq!(
1041 LogicalType::Integer.promote(&LogicalType::SmallInt),
1042 Some(LogicalType::Integer)
1043 );
1044 assert_eq!(LogicalType::Integer.promote(&LogicalType::Double), Some(LogicalType::Double));
1045 assert_eq!(LogicalType::Float.promote(&LogicalType::Double), Some(LogicalType::Double));
1046 }
1047
1048 #[test]
1051 fn signed_and_unsigned_widen_rather_than_reinterpret() {
1052 assert_eq!(LogicalType::Integer.promote(&LogicalType::UInteger), Some(LogicalType::BigInt));
1053 assert_eq!(
1054 LogicalType::TinyInt.promote(&LogicalType::UTinyInt),
1055 Some(LogicalType::SmallInt)
1056 );
1057 assert_eq!(LogicalType::BigInt.promote(&LogicalType::UBigInt), Some(LogicalType::HugeInt));
1058 }
1059
1060 #[test]
1061 fn promotion_does_not_care_which_side_a_type_is_on() {
1062 let types = [
1063 LogicalType::TinyInt,
1064 LogicalType::UInteger,
1065 LogicalType::BigInt,
1066 LogicalType::Double,
1067 LogicalType::Decimal { width: 10, scale: 2 },
1068 LogicalType::Null,
1069 LogicalType::Varchar,
1070 LogicalType::Date,
1071 LogicalType::Timestamp,
1072 ];
1073 for left in &types {
1074 for right in &types {
1075 assert_eq!(
1076 left.promote(right),
1077 right.promote(left),
1078 "{left} and {right} promote differently depending on the order"
1079 );
1080 }
1081 }
1082 }
1083
1084 #[test]
1085 fn a_decimal_keeps_room_for_both_halves() {
1086 let left = LogicalType::Decimal { width: 5, scale: 4 };
1087 let right = LogicalType::Decimal { width: 5, scale: 1 };
1088 assert_eq!(left.promote(&right), Some(LogicalType::Decimal { width: 8, scale: 4 }));
1089 }
1090
1091 #[test]
1092 fn an_integer_next_to_a_decimal_widens_the_decimal() {
1093 let decimal = LogicalType::Decimal { width: 5, scale: 2 };
1094 assert_eq!(
1095 decimal.promote(&LogicalType::Integer),
1096 Some(LogicalType::Decimal { width: 12, scale: 2 })
1097 );
1098 }
1099
1100 #[test]
1105 fn a_bigint_leaves_room_for_one_digit_fewer_than_a_ubigint() {
1106 let decimal = LogicalType::Decimal { width: 4, scale: 2 };
1107 assert_eq!(
1108 decimal.promote(&LogicalType::BigInt),
1109 Some(LogicalType::Decimal { width: 21, scale: 2 })
1110 );
1111 assert_eq!(
1112 decimal.promote(&LogicalType::UBigInt),
1113 Some(LogicalType::Decimal { width: 22, scale: 2 })
1114 );
1115 assert_eq!(decimal.promote(&LogicalType::Integer), decimal.promote(&LogicalType::UInteger));
1116 }
1117
1118 #[test]
1119 fn a_date_and_a_timestamp_meet_at_the_timestamp() {
1120 assert_eq!(
1121 LogicalType::Date.promote(&LogicalType::Timestamp),
1122 Some(LogicalType::Timestamp)
1123 );
1124 assert_eq!(
1125 LogicalType::TimestampS.promote(&LogicalType::TimestampNs),
1126 Some(LogicalType::TimestampNs)
1127 );
1128 }
1129
1130 #[test]
1133 fn types_that_do_not_meet_say_so() {
1134 assert_eq!(LogicalType::Timestamp.promote(&LogicalType::Interval), None);
1135 assert_eq!(LogicalType::Integer.promote(&LogicalType::Varchar), None);
1136 assert_eq!(LogicalType::Boolean.promote(&LogicalType::Integer), None);
1137 }
1138
1139 #[test]
1140 fn a_list_promotes_by_its_element() {
1141 let left = LogicalType::list(LogicalType::Integer);
1142 let right = LogicalType::list(LogicalType::BigInt);
1143 assert_eq!(left.promote(&right), Some(LogicalType::list(LogicalType::BigInt)));
1144 assert_eq!(left.promote(&LogicalType::list(LogicalType::Varchar)), None);
1145 }
1146}
1147
1148#[cfg(test)]
1149mod tests {
1150 use super::{Field, LogicalType, PhysicalType};
1151
1152 fn every_type() -> Vec<LogicalType> {
1155 vec![
1156 LogicalType::Null,
1157 LogicalType::Boolean,
1158 LogicalType::TinyInt,
1159 LogicalType::SmallInt,
1160 LogicalType::Integer,
1161 LogicalType::BigInt,
1162 LogicalType::HugeInt,
1163 LogicalType::UTinyInt,
1164 LogicalType::USmallInt,
1165 LogicalType::UInteger,
1166 LogicalType::UBigInt,
1167 LogicalType::UHugeInt,
1168 LogicalType::Float,
1169 LogicalType::Double,
1170 LogicalType::Decimal { width: 18, scale: 3 },
1171 LogicalType::Decimal { width: 38, scale: 0 },
1172 LogicalType::Varchar,
1173 LogicalType::Blob,
1174 LogicalType::Bit,
1175 LogicalType::Uuid,
1176 LogicalType::Date,
1177 LogicalType::Time,
1178 LogicalType::TimeTz,
1179 LogicalType::Timestamp,
1180 LogicalType::TimestampS,
1181 LogicalType::TimestampMs,
1182 LogicalType::TimestampNs,
1183 LogicalType::TimestampTz,
1184 LogicalType::Interval,
1185 LogicalType::list(LogicalType::Integer),
1186 LogicalType::list(LogicalType::list(LogicalType::Varchar)),
1187 LogicalType::array(LogicalType::Double, 3),
1188 LogicalType::map(LogicalType::Varchar, LogicalType::Integer),
1189 LogicalType::Struct(vec![
1190 Field::new("a", LogicalType::Integer),
1191 Field::new("b", LogicalType::list(LogicalType::Varchar)),
1192 ]),
1193 LogicalType::Union(vec![
1194 Field::new("num", LogicalType::Integer),
1195 Field::new("str", LogicalType::Varchar),
1196 ]),
1197 ]
1198 }
1199
1200 #[test]
1201 fn every_type_survives_being_printed_and_read_back() {
1202 for ty in every_type() {
1206 let printed = ty.to_string();
1207 let parsed = LogicalType::parse(&printed)
1208 .unwrap_or_else(|e| panic!("{printed} did not parse back: {e}"));
1209 assert_eq!(parsed, ty, "{printed} parsed to something else");
1210 }
1211 }
1212
1213 #[test]
1214 fn a_field_name_that_needs_quoting_gets_quoted() {
1215 let ty = LogicalType::Struct(vec![
1216 Field::new("plain", LogicalType::Integer),
1217 Field::new("has space", LogicalType::Integer),
1218 Field::new("has\"quote", LogicalType::Integer),
1219 Field::new("2leading", LogicalType::Integer),
1220 ]);
1221 assert_eq!(
1222 ty.to_string(),
1223 "STRUCT(plain INTEGER, \"has space\" INTEGER, \"has\"\"quote\" INTEGER, \
1224 \"2leading\" INTEGER)"
1225 );
1226 assert_eq!(LogicalType::parse(&ty.to_string()).unwrap(), ty);
1227 }
1228
1229 #[test]
1230 fn the_duckdb_aliases_resolve() {
1231 let cases = [
1232 ("int4", LogicalType::Integer),
1233 ("INT", LogicalType::Integer),
1234 ("signed", LogicalType::Integer),
1235 ("int8", LogicalType::BigInt),
1236 ("float4", LogicalType::Float),
1237 ("float8", LogicalType::Double),
1238 ("double precision", LogicalType::Double),
1239 ("text", LogicalType::Varchar),
1240 ("varchar(10)", LogicalType::Varchar),
1241 ("character varying(255)", LogicalType::Varchar),
1242 ("bool", LogicalType::Boolean),
1243 ("datetime", LogicalType::Timestamp),
1244 ("numeric(9, 2)", LogicalType::Decimal { width: 9, scale: 2 }),
1245 ("decimal", LogicalType::Decimal { width: 18, scale: 3 }),
1246 ("timestamp without time zone", LogicalType::Timestamp),
1247 ("timestamp with time zone", LogicalType::TimestampTz),
1248 ("time with time zone", LogicalType::TimeTz),
1249 ];
1250 for (text, expected) in cases {
1251 assert_eq!(LogicalType::parse(text).unwrap(), expected, "{text}");
1252 }
1253 }
1254
1255 #[test]
1256 fn the_unsigned_names_count_bits_and_the_short_signed_ones_count_bytes() {
1257 let resolves = [
1262 ("int1", LogicalType::TinyInt),
1263 ("int2", LogicalType::SmallInt),
1264 ("int4", LogicalType::Integer),
1265 ("int8", LogicalType::BigInt),
1266 ("int16", LogicalType::SmallInt),
1267 ("int32", LogicalType::Integer),
1268 ("int64", LogicalType::BigInt),
1269 ("int128", LogicalType::HugeInt),
1270 ("uint8", LogicalType::UTinyInt),
1271 ("uint16", LogicalType::USmallInt),
1272 ("uint32", LogicalType::UInteger),
1273 ("uint64", LogicalType::UBigInt),
1274 ("uint128", LogicalType::UHugeInt),
1275 ];
1276 for (text, expected) in resolves {
1277 assert_eq!(LogicalType::parse(text).unwrap(), expected, "{text}");
1278 }
1279 for text in ["uint1", "uint2", "uint4"] {
1282 assert!(LogicalType::parse(text).is_err(), "{text} should not be a type name");
1283 }
1284 }
1285
1286 #[test]
1287 fn the_four_timestamp_units_are_the_only_four_spellings() {
1288 let resolves = [
1289 ("timestamp_s", LogicalType::TimestampS),
1290 ("timestamp_ms", LogicalType::TimestampMs),
1291 ("timestamp_us", LogicalType::Timestamp),
1292 ("timestamp_ns", LogicalType::TimestampNs),
1293 ];
1294 for (text, expected) in resolves {
1295 assert_eq!(LogicalType::parse(text).unwrap(), expected, "{text}");
1296 }
1297 for text in [
1301 "timestamp_sec",
1302 "timestamp_seconds",
1303 "timestamp_milliseconds",
1304 "timestamp_nanoseconds",
1305 ] {
1306 assert!(LogicalType::parse(text).is_err(), "{text} should not be a type name");
1307 }
1308 }
1309
1310 #[test]
1311 fn the_three_aliases_that_are_not_about_width_resolve() {
1312 assert_eq!(LogicalType::parse("integral").unwrap(), LogicalType::Integer);
1315 assert_eq!(LogicalType::parse("oid").unwrap(), LogicalType::BigInt);
1316 assert_eq!(LogicalType::parse("nvarchar").unwrap(), LogicalType::Varchar);
1317 }
1318
1319 #[test]
1320 fn list_and_array_suffixes_bind_left_to_right() {
1321 assert_eq!(
1322 LogicalType::parse("INTEGER[][3]").unwrap(),
1323 LogicalType::array(LogicalType::list(LogicalType::Integer), 3)
1324 );
1325 assert_eq!(
1326 LogicalType::parse("STRUCT(a INT)[]").unwrap(),
1327 LogicalType::list(LogicalType::Struct(vec![Field::new("a", LogicalType::Integer)]))
1328 );
1329 }
1330
1331 #[test]
1332 fn a_decimal_is_stored_in_the_narrowest_integer_that_holds_it() {
1333 assert_eq!(LogicalType::decimal(4, 2).unwrap().physical(), PhysicalType::Int16);
1334 assert_eq!(LogicalType::decimal(9, 2).unwrap().physical(), PhysicalType::Int32);
1335 assert_eq!(LogicalType::decimal(18, 2).unwrap().physical(), PhysicalType::Int64);
1336 assert_eq!(LogicalType::decimal(38, 2).unwrap().physical(), PhysicalType::Int128);
1337 }
1338
1339 #[test]
1343 fn a_message_names_the_type_by_what_it_is_stored_in() {
1344 assert_eq!(LogicalType::Boolean.physical_name(), "BOOL");
1345 assert_eq!(LogicalType::TinyInt.physical_name(), "INT8");
1346 assert_eq!(LogicalType::Integer.physical_name(), "INT32");
1347 assert_eq!(LogicalType::UBigInt.physical_name(), "UINT64");
1348 assert_eq!(LogicalType::HugeInt.physical_name(), "INT128");
1349 assert_eq!(LogicalType::Float.physical_name(), "FLOAT");
1350 assert_eq!(LogicalType::Varchar.physical_name(), "VARCHAR");
1351 assert_eq!(LogicalType::Date.physical_name(), "DATE");
1352 assert_eq!(LogicalType::decimal(4, 2).unwrap().physical_name(), "DECIMAL(4)");
1353 assert_eq!(LogicalType::decimal(11, 0).unwrap().physical_name(), "DECIMAL(18)");
1354 assert_eq!(LogicalType::decimal(18, 8).unwrap().physical_name(), "DECIMAL(18)");
1355 assert_eq!(LogicalType::decimal(38, 2).unwrap().physical_name(), "DECIMAL(38)");
1356 assert_eq!(LogicalType::Integer.decimal_storage(), None);
1357 }
1358
1359 #[test]
1360 fn a_decimal_outside_the_bounds_is_rejected_rather_than_clamped() {
1361 assert!(LogicalType::decimal(0, 0).is_err());
1362 assert!(LogicalType::decimal(39, 0).is_err());
1363 assert!(LogicalType::decimal(4, 5).is_err());
1364 assert!(LogicalType::parse("DECIMAL(39,0)").is_err());
1365 }
1366
1367 #[test]
1368 fn a_date_and_an_integer_share_a_layout_and_not_a_meaning() {
1369 assert_eq!(LogicalType::Date.physical(), LogicalType::Integer.physical());
1370 assert_ne!(LogicalType::Date, LogicalType::Integer);
1371 assert!(LogicalType::Date.is_temporal());
1372 assert!(!LogicalType::Date.is_numeric());
1373 }
1374
1375 #[test]
1376 fn nesting_reports_its_children_in_child_column_order() {
1377 let ty = LogicalType::map(LogicalType::Varchar, LogicalType::Integer);
1378 assert!(ty.is_nested());
1379 assert_eq!(ty.children(), vec![LogicalType::Varchar, LogicalType::Integer]);
1380 assert_eq!(LogicalType::Integer.children(), Vec::new());
1381 }
1382
1383 #[test]
1384 fn text_that_is_not_a_type_is_rejected_with_the_word_that_broke_it() {
1385 let error = LogicalType::parse("INTEGRE").unwrap_err();
1386 assert!(error.message().contains("INTEGRE"), "{error}");
1387 assert!(LogicalType::parse("INTEGER JUNK").is_err());
1388 assert!(LogicalType::parse("STRUCT(a)").is_err());
1389 assert!(LogicalType::parse("").is_err());
1390 }
1391}