Skip to main content

parquet/schema/
parser.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Parquet schema parser.
19//! Provides methods to parse and validate string message type into Parquet
20//! [`Type`].
21//!
22//! # Example
23//!
24//! ```rust
25//! use parquet::schema::parser::parse_message_type;
26//!
27//! let message_type = "
28//!   message spark_schema {
29//!     OPTIONAL BYTE_ARRAY a (UTF8);
30//!     REQUIRED INT32 b;
31//!     REQUIRED DOUBLE c;
32//!     REQUIRED BOOLEAN d;
33//!     OPTIONAL group e (LIST) {
34//!       REPEATED group list {
35//!         REQUIRED INT32 element;
36//!       }
37//!     }
38//!   }
39//! ";
40//!
41//! let schema = parse_message_type(message_type).expect("Expected valid schema");
42//! println!("{:?}", schema);
43//! ```
44
45use std::sync::Arc;
46
47use crate::basic::{ConvertedType, LogicalType, Repetition, TimeUnit, Type as PhysicalType};
48use crate::errors::{ParquetError, Result};
49use crate::schema::types::{Type, TypePtr};
50
51/// Parses message type as string into a Parquet [`Type`]
52/// which, for example, could be used to extract individual columns. Returns Parquet
53/// general error when parsing or validation fails.
54pub fn parse_message_type(message_type: &str) -> Result<Type> {
55    let mut parser = Parser {
56        tokenizer: &mut Tokenizer::from_str(message_type),
57    };
58    parser.parse_message_type()
59}
60
61/// Tokenizer to split message type string into tokens that are separated using characters
62/// defined in `is_schema_delim` method. Tokenizer also preserves delimiters as tokens.
63/// Tokenizer provides Iterator interface to process tokens; it also allows to step back
64/// to reprocess previous tokens.
65struct Tokenizer<'a> {
66    // List of all tokens for a string
67    tokens: Vec<&'a str>,
68    // Current index of vector
69    index: usize,
70}
71
72impl<'a> Tokenizer<'a> {
73    // Create tokenizer from message type string
74    pub fn from_str(string: &'a str) -> Self {
75        let vec = string
76            .split_whitespace()
77            .flat_map(Self::split_token)
78            .collect();
79        Tokenizer {
80            tokens: vec,
81            index: 0,
82        }
83    }
84
85    // List of all special characters in schema
86    fn is_schema_delim(c: char) -> bool {
87        c == ';' || c == '{' || c == '}' || c == '(' || c == ')' || c == '=' || c == ','
88    }
89
90    /// Splits string into tokens; input string can already be token or can contain
91    /// delimiters, e.g. required" -> Vec("required") and
92    /// "(UTF8);" -> Vec("(", "UTF8", ")", ";")
93    fn split_token(string: &str) -> Vec<&str> {
94        let mut buffer: Vec<&str> = Vec::new();
95        let mut tail = string;
96        while let Some(index) = tail.find(Self::is_schema_delim) {
97            let (h, t) = tail.split_at(index);
98            if !h.is_empty() {
99                buffer.push(h);
100            }
101            buffer.push(&t[0..1]);
102            tail = &t[1..];
103        }
104        if !tail.is_empty() {
105            buffer.push(tail);
106        }
107        buffer
108    }
109
110    // Move pointer to a previous element
111    fn backtrack(&mut self) {
112        self.index -= 1;
113    }
114}
115
116impl<'a> Iterator for Tokenizer<'a> {
117    type Item = &'a str;
118
119    fn next(&mut self) -> Option<&'a str> {
120        if self.index < self.tokens.len() {
121            self.index += 1;
122            Some(self.tokens[self.index - 1])
123        } else {
124            None
125        }
126    }
127}
128
129/// Internal Schema parser.
130/// Traverses message type using tokenizer and parses each group/primitive type
131/// recursively.
132struct Parser<'a> {
133    tokenizer: &'a mut Tokenizer<'a>,
134}
135
136// Utility function to assert token on validity.
137fn assert_token(token: Option<&str>, expected: &str) -> Result<()> {
138    match token {
139        Some(value) if value == expected => Ok(()),
140        Some(other) => Err(general_err!(
141            "Expected '{}', found token '{}'",
142            expected,
143            other
144        )),
145        None => Err(general_err!(
146            "Expected '{}', but no token found (None)",
147            expected
148        )),
149    }
150}
151
152// Utility function to parse i32 or return general error.
153#[inline]
154fn parse_i32(value: Option<&str>, not_found_msg: &str, parse_fail_msg: &str) -> Result<i32> {
155    value
156        .ok_or_else(|| general_err!(not_found_msg))?
157        .parse::<i32>()
158        .map_err(|_| general_err!(parse_fail_msg))
159}
160
161// Utility function to parse boolean or return general error.
162#[inline]
163fn parse_bool(value: Option<&str>, not_found_msg: &str, parse_fail_msg: &str) -> Result<bool> {
164    value
165        .ok_or_else(|| general_err!(not_found_msg))?
166        .to_lowercase()
167        .parse::<bool>()
168        .map_err(|_| general_err!(parse_fail_msg))
169}
170
171// Utility function to parse TimeUnit or return general error.
172fn parse_timeunit(
173    value: Option<&str>,
174    not_found_msg: &str,
175    parse_fail_msg: &str,
176) -> Result<TimeUnit> {
177    let v = value.ok_or_else(|| general_err!(not_found_msg))?;
178    match v.to_uppercase().as_str() {
179        "MILLIS" => Ok(TimeUnit::MILLIS),
180        "MICROS" => Ok(TimeUnit::MICROS),
181        "NANOS" => Ok(TimeUnit::NANOS),
182        _ => Err(general_err!(parse_fail_msg)),
183    }
184}
185
186impl Parser<'_> {
187    // Entry function to parse message type, uses internal tokenizer.
188    fn parse_message_type(&mut self) -> Result<Type> {
189        // Check that message type starts with "message".
190        match self.tokenizer.next() {
191            Some("message") => {
192                let name = self
193                    .tokenizer
194                    .next()
195                    .ok_or_else(|| general_err!("Expected name, found None"))?;
196                Type::group_type_builder(name)
197                    .with_fields(self.parse_child_types()?)
198                    .build()
199            }
200            _ => Err(general_err!("Message type does not start with 'message'")),
201        }
202    }
203
204    // Parses child types for a current group type.
205    // This is only invoked on root and group types.
206    fn parse_child_types(&mut self) -> Result<Vec<TypePtr>> {
207        assert_token(self.tokenizer.next(), "{")?;
208        let mut vec = Vec::new();
209        while let Some(value) = self.tokenizer.next() {
210            if value == "}" {
211                break;
212            }
213            self.tokenizer.backtrack();
214            vec.push(Arc::new(self.add_type()?));
215        }
216        Ok(vec)
217    }
218
219    fn add_type(&mut self) -> Result<Type> {
220        // Parse repetition
221        let repetition = self
222            .tokenizer
223            .next()
224            .ok_or_else(|| general_err!("Expected repetition, found None"))
225            .and_then(|v| v.to_uppercase().parse::<Repetition>())?;
226
227        match self.tokenizer.next() {
228            Some(group) if group.to_uppercase() == "GROUP" => self.add_group_type(Some(repetition)),
229            Some(type_string) => {
230                let physical_type = type_string.to_uppercase().parse::<PhysicalType>()?;
231                self.add_primitive_type(repetition, physical_type)
232            }
233            None => Err(general_err!("Invalid type, could not extract next token")),
234        }
235    }
236
237    fn add_group_type(&mut self, repetition: Option<Repetition>) -> Result<Type> {
238        // Parse name of the group type
239        let name = self
240            .tokenizer
241            .next()
242            .ok_or_else(|| general_err!("Expected name, found None"))?;
243
244        // Parse logical or converted type if exists
245        let (logical_type, converted_type) = if self.tokenizer.next() == Some("(") {
246            let tpe = self
247                .tokenizer
248                .next()
249                .ok_or_else(|| general_err!("Expected converted type, found None"))
250                .and_then(|v| {
251                    // Try logical type first
252                    let upper = v.to_uppercase();
253                    let logical = upper.parse::<LogicalType>();
254                    match logical {
255                        Ok(logical) => {
256                            Ok((Some(logical.clone()), ConvertedType::from(Some(logical))))
257                        }
258                        Err(_) => Ok((None, upper.parse::<ConvertedType>()?)),
259                    }
260                })?;
261            assert_token(self.tokenizer.next(), ")")?;
262            tpe
263        } else {
264            self.tokenizer.backtrack();
265            (None, ConvertedType::NONE)
266        };
267
268        // Parse optional id
269        let id = if self.tokenizer.next() == Some("=") {
270            self.tokenizer.next().and_then(|v| v.parse::<i32>().ok())
271        } else {
272            self.tokenizer.backtrack();
273            None
274        };
275
276        let mut builder = Type::group_type_builder(name)
277            .with_logical_type(logical_type)
278            .with_converted_type(converted_type)
279            .with_fields(self.parse_child_types()?)
280            .with_id(id);
281        if let Some(rep) = repetition {
282            builder = builder.with_repetition(rep);
283        }
284        builder.build()
285    }
286
287    fn add_primitive_type(
288        &mut self,
289        repetition: Repetition,
290        physical_type: PhysicalType,
291    ) -> Result<Type> {
292        // Read type length if the type is FIXED_LEN_BYTE_ARRAY.
293        let mut length: i32 = -1;
294        if physical_type == PhysicalType::FIXED_LEN_BYTE_ARRAY {
295            assert_token(self.tokenizer.next(), "(")?;
296            length = parse_i32(
297                self.tokenizer.next(),
298                "Expected length for FIXED_LEN_BYTE_ARRAY, found None",
299                "Failed to parse length for FIXED_LEN_BYTE_ARRAY",
300            )?;
301            assert_token(self.tokenizer.next(), ")")?;
302        }
303
304        // Parse name of the primitive type
305        let name = self
306            .tokenizer
307            .next()
308            .ok_or_else(|| general_err!("Expected name, found None"))?;
309
310        // Parse converted type
311        let (logical_type, converted_type, precision, scale) = if self.tokenizer.next() == Some("(")
312        {
313            let (mut logical, mut converted) = self
314                .tokenizer
315                .next()
316                .ok_or_else(|| general_err!("Expected logical or converted type, found None"))
317                .and_then(|v| {
318                    let upper = v.to_uppercase();
319                    let logical = upper.parse::<LogicalType>();
320                    match logical {
321                        Ok(logical) => {
322                            Ok((Some(logical.clone()), ConvertedType::from(Some(logical))))
323                        }
324                        Err(_) => Ok((None, upper.parse::<ConvertedType>()?)),
325                    }
326                })?;
327
328            // Parse precision and scale for decimals
329            let mut precision: i32 = -1;
330            let mut scale: i32 = -1;
331
332            // Parse the concrete logical type
333            if let Some(tpe) = &logical {
334                match tpe {
335                    LogicalType::Decimal { .. } => {
336                        if self.tokenizer.next() == Some("(") {
337                            precision = parse_i32(
338                                self.tokenizer.next(),
339                                "Expected precision, found None",
340                                "Failed to parse precision for DECIMAL type",
341                            )?;
342                            if self.tokenizer.next() == Some(",") {
343                                scale = parse_i32(
344                                    self.tokenizer.next(),
345                                    "Expected scale, found None",
346                                    "Failed to parse scale for DECIMAL type",
347                                )?;
348                                assert_token(self.tokenizer.next(), ")")?;
349                            } else {
350                                scale = 0
351                            }
352                            logical = Some(LogicalType::decimal(scale, precision));
353                            converted = ConvertedType::from(logical.clone());
354                        }
355                    }
356                    LogicalType::Time { .. } => {
357                        if self.tokenizer.next() == Some("(") {
358                            let unit = parse_timeunit(
359                                self.tokenizer.next(),
360                                "Invalid timeunit found",
361                                "Failed to parse timeunit for TIME type",
362                            )?;
363                            if self.tokenizer.next() == Some(",") {
364                                let is_adjusted_to_u_t_c = parse_bool(
365                                    self.tokenizer.next(),
366                                    "Invalid boolean found",
367                                    "Failed to parse timezone info for TIME type",
368                                )?;
369                                assert_token(self.tokenizer.next(), ")")?;
370                                logical = Some(LogicalType::time(is_adjusted_to_u_t_c, unit));
371                                converted = ConvertedType::from(logical.clone());
372                            } else {
373                                // Invalid token for unit
374                                self.tokenizer.backtrack();
375                            }
376                        }
377                    }
378                    LogicalType::Timestamp { .. } => {
379                        if self.tokenizer.next() == Some("(") {
380                            let unit = parse_timeunit(
381                                self.tokenizer.next(),
382                                "Invalid timeunit found",
383                                "Failed to parse timeunit for TIMESTAMP type",
384                            )?;
385                            if self.tokenizer.next() == Some(",") {
386                                let is_adjusted_to_u_t_c = parse_bool(
387                                    self.tokenizer.next(),
388                                    "Invalid boolean found",
389                                    "Failed to parse timezone info for TIMESTAMP type",
390                                )?;
391                                assert_token(self.tokenizer.next(), ")")?;
392                                logical = Some(LogicalType::timestamp(is_adjusted_to_u_t_c, unit));
393                                converted = ConvertedType::from(logical.clone());
394                            } else {
395                                // Invalid token for unit
396                                self.tokenizer.backtrack();
397                            }
398                        }
399                    }
400                    LogicalType::Integer { .. } if self.tokenizer.next() == Some("(") => {
401                        let bit_width = parse_i32(
402                            self.tokenizer.next(),
403                            "Invalid bit_width found",
404                            "Failed to parse bit_width for INTEGER type",
405                        )? as i8;
406                        match physical_type {
407                            PhysicalType::INT32 => match bit_width {
408                                8 | 16 | 32 => {}
409                                _ => {
410                                    return Err(general_err!(
411                                        "Incorrect bit width {} for INT32",
412                                        bit_width
413                                    ));
414                                }
415                            },
416                            PhysicalType::INT64 => {
417                                if bit_width != 64 {
418                                    return Err(general_err!(
419                                        "Incorrect bit width {} for INT64",
420                                        bit_width
421                                    ));
422                                }
423                            }
424                            _ => {
425                                return Err(general_err!(
426                                    "Logical type Integer cannot be used with physical type {}",
427                                    physical_type
428                                ));
429                            }
430                        }
431                        if self.tokenizer.next() == Some(",") {
432                            let is_signed = parse_bool(
433                                self.tokenizer.next(),
434                                "Invalid boolean found",
435                                "Failed to parse is_signed for INTEGER type",
436                            )?;
437                            assert_token(self.tokenizer.next(), ")")?;
438                            logical = Some(LogicalType::integer(bit_width, is_signed));
439                            converted = ConvertedType::from(logical.clone());
440                        } else {
441                            // Invalid token for unit
442                            self.tokenizer.backtrack();
443                        }
444                    }
445                    _ => {}
446                }
447            } else if converted == ConvertedType::DECIMAL {
448                if self.tokenizer.next() == Some("(") {
449                    // Parse precision
450                    precision = parse_i32(
451                        self.tokenizer.next(),
452                        "Expected precision, found None",
453                        "Failed to parse precision for DECIMAL type",
454                    )?;
455
456                    // Parse scale
457                    scale = if self.tokenizer.next() == Some(",") {
458                        parse_i32(
459                            self.tokenizer.next(),
460                            "Expected scale, found None",
461                            "Failed to parse scale for DECIMAL type",
462                        )?
463                    } else {
464                        // Scale is not provided, set it to 0.
465                        self.tokenizer.backtrack();
466                        0
467                    };
468
469                    assert_token(self.tokenizer.next(), ")")?;
470                } else {
471                    self.tokenizer.backtrack();
472                }
473            }
474
475            assert_token(self.tokenizer.next(), ")")?;
476            (logical, converted, precision, scale)
477        } else {
478            self.tokenizer.backtrack();
479            (None, ConvertedType::NONE, -1, -1)
480        };
481
482        // Parse optional id
483        let id = if self.tokenizer.next() == Some("=") {
484            self.tokenizer.next().and_then(|v| v.parse::<i32>().ok())
485        } else {
486            self.tokenizer.backtrack();
487            None
488        };
489        assert_token(self.tokenizer.next(), ";")?;
490
491        Type::primitive_type_builder(name, physical_type)
492            .with_repetition(repetition)
493            .with_logical_type(logical_type)
494            .with_converted_type(converted_type)
495            .with_length(length)
496            .with_precision(precision)
497            .with_scale(scale)
498            .with_id(id)
499            .build()
500    }
501}
502
503#[cfg(test)]
504mod tests {
505    use super::*;
506
507    #[test]
508    fn test_tokenize_empty_string() {
509        assert_eq!(Tokenizer::from_str("").next(), None);
510    }
511
512    #[test]
513    fn test_tokenize_delimiters() {
514        let mut iter = Tokenizer::from_str(",;{}()=");
515        assert_eq!(iter.next(), Some(","));
516        assert_eq!(iter.next(), Some(";"));
517        assert_eq!(iter.next(), Some("{"));
518        assert_eq!(iter.next(), Some("}"));
519        assert_eq!(iter.next(), Some("("));
520        assert_eq!(iter.next(), Some(")"));
521        assert_eq!(iter.next(), Some("="));
522        assert_eq!(iter.next(), None);
523    }
524
525    #[test]
526    fn test_tokenize_delimiters_with_whitespaces() {
527        let mut iter = Tokenizer::from_str(" , ; { } ( ) = ");
528        assert_eq!(iter.next(), Some(","));
529        assert_eq!(iter.next(), Some(";"));
530        assert_eq!(iter.next(), Some("{"));
531        assert_eq!(iter.next(), Some("}"));
532        assert_eq!(iter.next(), Some("("));
533        assert_eq!(iter.next(), Some(")"));
534        assert_eq!(iter.next(), Some("="));
535        assert_eq!(iter.next(), None);
536    }
537
538    #[test]
539    fn test_tokenize_words() {
540        let mut iter = Tokenizer::from_str("abc def ghi jkl mno");
541        assert_eq!(iter.next(), Some("abc"));
542        assert_eq!(iter.next(), Some("def"));
543        assert_eq!(iter.next(), Some("ghi"));
544        assert_eq!(iter.next(), Some("jkl"));
545        assert_eq!(iter.next(), Some("mno"));
546        assert_eq!(iter.next(), None);
547    }
548
549    #[test]
550    fn test_tokenize_backtrack() {
551        let mut iter = Tokenizer::from_str("abc;");
552        assert_eq!(iter.next(), Some("abc"));
553        assert_eq!(iter.next(), Some(";"));
554        iter.backtrack();
555        assert_eq!(iter.next(), Some(";"));
556        assert_eq!(iter.next(), None);
557    }
558
559    #[test]
560    fn test_tokenize_message_type() {
561        let schema = "
562    message schema {
563      required int32 a;
564      optional binary c (UTF8);
565      required group d {
566        required int32 a;
567        optional binary c (UTF8);
568      }
569      required group e (LIST) {
570        repeated group list {
571          required int32 element;
572        }
573      }
574    }
575    ";
576        let iter = Tokenizer::from_str(schema);
577        let mut res = Vec::new();
578        for token in iter {
579            res.push(token);
580        }
581        assert_eq!(
582            res,
583            vec![
584                "message", "schema", "{", "required", "int32", "a", ";", "optional", "binary", "c",
585                "(", "UTF8", ")", ";", "required", "group", "d", "{", "required", "int32", "a",
586                ";", "optional", "binary", "c", "(", "UTF8", ")", ";", "}", "required", "group",
587                "e", "(", "LIST", ")", "{", "repeated", "group", "list", "{", "required", "int32",
588                "element", ";", "}", "}", "}"
589            ]
590        );
591    }
592
593    #[test]
594    fn test_assert_token() {
595        assert!(assert_token(Some("a"), "a").is_ok());
596        assert!(assert_token(Some("a"), "b").is_err());
597        assert!(assert_token(None, "b").is_err());
598    }
599
600    fn parse(schema: &str) -> Result<Type, ParquetError> {
601        let mut iter = Tokenizer::from_str(schema);
602        Parser {
603            tokenizer: &mut iter,
604        }
605        .parse_message_type()
606    }
607
608    #[test]
609    fn test_parse_message_type_invalid() {
610        assert_eq!(
611            parse("test").unwrap_err().to_string(),
612            "Parquet error: Message type does not start with 'message'"
613        );
614    }
615
616    #[test]
617    fn test_parse_message_type_no_name() {
618        assert_eq!(
619            parse("message").unwrap_err().to_string(),
620            "Parquet error: Expected name, found None"
621        );
622    }
623
624    #[test]
625    fn test_parse_message_type_fixed_byte_array() {
626        let schema = "
627            message schema {
628              REQUIRED FIXED_LEN_BYTE_ARRAY col;
629            }
630        ";
631        assert_eq!(
632            parse(schema).unwrap_err().to_string(),
633            "Parquet error: Expected '(', found token 'col'"
634        );
635
636        let schema = "
637            message schema {
638              REQUIRED FIXED_LEN_BYTE_ARRAY(16) col;
639            }
640        ";
641        parse(schema).unwrap();
642    }
643
644    #[test]
645    fn test_parse_message_type_integer() {
646        // Invalid integer syntax
647        let schema = "
648            message root {
649              optional int64 f1 (INTEGER());
650            }
651        ";
652        assert_eq!(
653            parse(schema).unwrap_err().to_string(),
654            "Parquet error: Failed to parse bit_width for INTEGER type"
655        );
656
657        // Invalid integer syntax, needs both bit-width and UTC sign
658        let schema = "
659    message root {
660      optional int64 f1 (INTEGER(32,));
661    }
662    ";
663        assert_eq!(
664            parse(schema).unwrap_err().to_string(),
665            "Parquet error: Incorrect bit width 32 for INT64"
666        );
667
668        // Invalid integer because of non-numeric bit width
669        let schema = "
670            message root {
671              optional int32 f1 (INTEGER(eight,true));
672            }
673        ";
674        assert_eq!(
675            parse(schema).unwrap_err().to_string(),
676            "Parquet error: Failed to parse bit_width for INTEGER type"
677        );
678
679        // Valid types
680        let schema = "
681            message root {
682              optional int32 f1 (INTEGER(8,false));
683              optional int32 f2 (INTEGER(8,true));
684              optional int32 f3 (INTEGER(16,false));
685              optional int32 f4 (INTEGER(16,true));
686              optional int32 f5 (INTEGER(32,false));
687              optional int32 f6 (INTEGER(32,true));
688              optional int64 f7 (INTEGER(64,false));
689              optional int64 f7 (INTEGER(64,true));
690            }
691        ";
692        parse(schema).unwrap();
693    }
694
695    #[test]
696    fn test_parse_message_type_temporal() {
697        // Invalid timestamp syntax
698        let schema = "
699            message root {
700              optional int64 f1 (TIMESTAMP();
701            }
702        ";
703        assert_eq!(
704            parse(schema).unwrap_err().to_string(),
705            "Parquet error: Failed to parse timeunit for TIMESTAMP type"
706        );
707
708        // Invalid timestamp syntax, needs both unit and UTC adjustment
709        let schema = "
710            message root {
711              optional int64 f1 (TIMESTAMP(MILLIS,));
712            }
713        ";
714        assert_eq!(
715            parse(schema).unwrap_err().to_string(),
716            "Parquet error: Failed to parse timezone info for TIMESTAMP type"
717        );
718
719        // Invalid timestamp because of unknown unit
720        let schema = "
721            message root {
722              optional int64 f1 (TIMESTAMP(YOCTOS,));
723            }
724        ";
725
726        assert_eq!(
727            parse(schema).unwrap_err().to_string(),
728            "Parquet error: Failed to parse timeunit for TIMESTAMP type"
729        );
730
731        // Valid types
732        let schema = "
733            message root {
734              optional int32 f1 (DATE);
735              optional int32 f2 (TIME(MILLIS,true));
736              optional int64 f3 (TIME(MICROS,false));
737              optional int64 f4 (TIME(NANOS,true));
738              optional int64 f5 (TIMESTAMP(MILLIS,true));
739              optional int64 f6 (TIMESTAMP(MICROS,true));
740              optional int64 f7 (TIMESTAMP(NANOS,false));
741            }
742        ";
743        parse(schema).unwrap();
744    }
745
746    #[test]
747    fn test_parse_message_type_decimal() {
748        // It is okay for decimal to omit precision and scale with right syntax.
749        // Here we test wrong syntax of decimal type
750
751        // Invalid decimal syntax
752        let schema = "
753            message root {
754              optional int32 f1 (DECIMAL();
755            }
756        ";
757        assert_eq!(
758            parse(schema).unwrap_err().to_string(),
759            "Parquet error: Failed to parse precision for DECIMAL type"
760        );
761
762        // Invalid decimal, need precision and scale
763        let schema = "
764            message root {
765              optional int32 f1 (DECIMAL());
766            }
767        ";
768        assert_eq!(
769            parse(schema).unwrap_err().to_string(),
770            "Parquet error: Failed to parse precision for DECIMAL type"
771        );
772
773        // Invalid decimal because of `,` - has precision, needs scale
774        let schema = "
775            message root {
776              optional int32 f1 (DECIMAL(8,));
777            }
778        ";
779        assert_eq!(
780            parse(schema).unwrap_err().to_string(),
781            "Parquet error: Failed to parse scale for DECIMAL type"
782        );
783
784        // Invalid decimal because, we always require either precision or scale to be
785        // specified as part of converted type
786        let schema = "
787            message root {
788              optional int32 f3 (DECIMAL);
789            }
790        ";
791        assert_eq!(
792            parse(schema).unwrap_err().to_string(),
793            "Parquet error: Expected ')', found token ';'"
794        );
795
796        // Valid decimal (precision, scale)
797        let schema = "
798            message root {
799              optional int32 f1 (DECIMAL(8, 3));
800              optional int32 f2 (DECIMAL(8));
801            }
802        ";
803        parse(schema).unwrap();
804    }
805
806    #[test]
807    fn test_parse_message_type_compare_1() {
808        let schema = "
809            message root {
810              optional fixed_len_byte_array(5) f1 (DECIMAL(9, 3));
811              optional fixed_len_byte_array (16) f2 (DECIMAL (38, 18));
812              optional fixed_len_byte_array (2) f3 (FLOAT16);
813            }
814        ";
815        let message = parse(schema).unwrap();
816
817        let expected = Type::group_type_builder("root")
818            .with_fields(vec![
819                Arc::new(
820                    Type::primitive_type_builder("f1", PhysicalType::FIXED_LEN_BYTE_ARRAY)
821                        .with_logical_type(Some(LogicalType::decimal(3, 9)))
822                        .with_converted_type(ConvertedType::DECIMAL)
823                        .with_length(5)
824                        .with_precision(9)
825                        .with_scale(3)
826                        .build()
827                        .unwrap(),
828                ),
829                Arc::new(
830                    Type::primitive_type_builder("f2", PhysicalType::FIXED_LEN_BYTE_ARRAY)
831                        .with_logical_type(Some(LogicalType::decimal(18, 38)))
832                        .with_converted_type(ConvertedType::DECIMAL)
833                        .with_length(16)
834                        .with_precision(38)
835                        .with_scale(18)
836                        .build()
837                        .unwrap(),
838                ),
839                Arc::new(
840                    Type::primitive_type_builder("f3", PhysicalType::FIXED_LEN_BYTE_ARRAY)
841                        .with_logical_type(Some(LogicalType::Float16))
842                        .with_length(2)
843                        .build()
844                        .unwrap(),
845                ),
846            ])
847            .build()
848            .unwrap();
849
850        assert_eq!(message, expected);
851    }
852
853    #[test]
854    fn test_parse_message_type_compare_2() {
855        let schema = "
856            message root {
857              required group a0 {
858                optional group a1 (LIST) {
859                  repeated binary a2 (UTF8);
860                }
861
862                optional group b1 (LIST) {
863                  repeated group b2 {
864                    optional int32 b3;
865                    optional double b4;
866                  }
867                }
868              }
869            }
870        ";
871        let message = parse(schema).unwrap();
872
873        let expected = Type::group_type_builder("root")
874            .with_fields(vec![Arc::new(
875                Type::group_type_builder("a0")
876                    .with_repetition(Repetition::REQUIRED)
877                    .with_fields(vec![
878                        Arc::new(
879                            Type::group_type_builder("a1")
880                                .with_repetition(Repetition::OPTIONAL)
881                                .with_logical_type(Some(LogicalType::List))
882                                .with_converted_type(ConvertedType::LIST)
883                                .with_fields(vec![Arc::new(
884                                    Type::primitive_type_builder("a2", PhysicalType::BYTE_ARRAY)
885                                        .with_repetition(Repetition::REPEATED)
886                                        .with_converted_type(ConvertedType::UTF8)
887                                        .build()
888                                        .unwrap(),
889                                )])
890                                .build()
891                                .unwrap(),
892                        ),
893                        Arc::new(
894                            Type::group_type_builder("b1")
895                                .with_repetition(Repetition::OPTIONAL)
896                                .with_logical_type(Some(LogicalType::List))
897                                .with_converted_type(ConvertedType::LIST)
898                                .with_fields(vec![Arc::new(
899                                    Type::group_type_builder("b2")
900                                        .with_repetition(Repetition::REPEATED)
901                                        .with_fields(vec![
902                                            Arc::new(
903                                                Type::primitive_type_builder(
904                                                    "b3",
905                                                    PhysicalType::INT32,
906                                                )
907                                                .build()
908                                                .unwrap(),
909                                            ),
910                                            Arc::new(
911                                                Type::primitive_type_builder(
912                                                    "b4",
913                                                    PhysicalType::DOUBLE,
914                                                )
915                                                .build()
916                                                .unwrap(),
917                                            ),
918                                        ])
919                                        .build()
920                                        .unwrap(),
921                                )])
922                                .build()
923                                .unwrap(),
924                        ),
925                    ])
926                    .build()
927                    .unwrap(),
928            )])
929            .build()
930            .unwrap();
931
932        assert_eq!(message, expected);
933    }
934
935    #[test]
936    fn test_parse_message_type_compare_3() {
937        let schema = "
938            message root {
939              required int32 _1 (INT_8);
940              required int32 _2 (INT_16);
941              required float _3;
942              required double _4;
943              optional int32 _5 (DATE);
944              optional binary _6 (UTF8);
945            }
946        ";
947        let message = parse(schema).unwrap();
948
949        let fields = vec![
950            Arc::new(
951                Type::primitive_type_builder("_1", PhysicalType::INT32)
952                    .with_repetition(Repetition::REQUIRED)
953                    .with_converted_type(ConvertedType::INT_8)
954                    .build()
955                    .unwrap(),
956            ),
957            Arc::new(
958                Type::primitive_type_builder("_2", PhysicalType::INT32)
959                    .with_repetition(Repetition::REQUIRED)
960                    .with_converted_type(ConvertedType::INT_16)
961                    .build()
962                    .unwrap(),
963            ),
964            Arc::new(
965                Type::primitive_type_builder("_3", PhysicalType::FLOAT)
966                    .with_repetition(Repetition::REQUIRED)
967                    .build()
968                    .unwrap(),
969            ),
970            Arc::new(
971                Type::primitive_type_builder("_4", PhysicalType::DOUBLE)
972                    .with_repetition(Repetition::REQUIRED)
973                    .build()
974                    .unwrap(),
975            ),
976            Arc::new(
977                Type::primitive_type_builder("_5", PhysicalType::INT32)
978                    .with_logical_type(Some(LogicalType::Date))
979                    .with_converted_type(ConvertedType::DATE)
980                    .build()
981                    .unwrap(),
982            ),
983            Arc::new(
984                Type::primitive_type_builder("_6", PhysicalType::BYTE_ARRAY)
985                    .with_converted_type(ConvertedType::UTF8)
986                    .build()
987                    .unwrap(),
988            ),
989        ];
990
991        let expected = Type::group_type_builder("root")
992            .with_fields(fields)
993            .build()
994            .unwrap();
995        assert_eq!(message, expected);
996    }
997
998    #[test]
999    fn test_parse_message_type_compare_4() {
1000        let schema = "
1001            message root {
1002              required int32 _1 (INTEGER(8,true));
1003              required int32 _2 (INTEGER(16,false));
1004              required float _3;
1005              required double _4;
1006              optional int32 _5 (DATE);
1007              optional int32 _6 (TIME(MILLIS,false));
1008              optional int64 _7 (TIME(MICROS,true));
1009              optional int64 _8 (TIMESTAMP(MILLIS,true));
1010              optional int64 _9 (TIMESTAMP(NANOS,false));
1011              optional binary _10 (STRING);
1012            }
1013        ";
1014        let message = parse(schema).unwrap();
1015
1016        let fields = vec![
1017            Arc::new(
1018                Type::primitive_type_builder("_1", PhysicalType::INT32)
1019                    .with_repetition(Repetition::REQUIRED)
1020                    .with_logical_type(Some(LogicalType::integer(8, true)))
1021                    .build()
1022                    .unwrap(),
1023            ),
1024            Arc::new(
1025                Type::primitive_type_builder("_2", PhysicalType::INT32)
1026                    .with_repetition(Repetition::REQUIRED)
1027                    .with_logical_type(Some(LogicalType::integer(16, false)))
1028                    .build()
1029                    .unwrap(),
1030            ),
1031            Arc::new(
1032                Type::primitive_type_builder("_3", PhysicalType::FLOAT)
1033                    .with_repetition(Repetition::REQUIRED)
1034                    .build()
1035                    .unwrap(),
1036            ),
1037            Arc::new(
1038                Type::primitive_type_builder("_4", PhysicalType::DOUBLE)
1039                    .with_repetition(Repetition::REQUIRED)
1040                    .build()
1041                    .unwrap(),
1042            ),
1043            Arc::new(
1044                Type::primitive_type_builder("_5", PhysicalType::INT32)
1045                    .with_logical_type(Some(LogicalType::Date))
1046                    .build()
1047                    .unwrap(),
1048            ),
1049            Arc::new(
1050                Type::primitive_type_builder("_6", PhysicalType::INT32)
1051                    .with_logical_type(Some(LogicalType::time(false, TimeUnit::MILLIS)))
1052                    .build()
1053                    .unwrap(),
1054            ),
1055            Arc::new(
1056                Type::primitive_type_builder("_7", PhysicalType::INT64)
1057                    .with_logical_type(Some(LogicalType::time(true, TimeUnit::MICROS)))
1058                    .build()
1059                    .unwrap(),
1060            ),
1061            Arc::new(
1062                Type::primitive_type_builder("_8", PhysicalType::INT64)
1063                    .with_logical_type(Some(LogicalType::timestamp(true, TimeUnit::MILLIS)))
1064                    .build()
1065                    .unwrap(),
1066            ),
1067            Arc::new(
1068                Type::primitive_type_builder("_9", PhysicalType::INT64)
1069                    .with_logical_type(Some(LogicalType::timestamp(false, TimeUnit::NANOS)))
1070                    .build()
1071                    .unwrap(),
1072            ),
1073            Arc::new(
1074                Type::primitive_type_builder("_10", PhysicalType::BYTE_ARRAY)
1075                    .with_logical_type(Some(LogicalType::String))
1076                    .build()
1077                    .unwrap(),
1078            ),
1079        ];
1080
1081        let expected = Type::group_type_builder("root")
1082            .with_fields(fields)
1083            .build()
1084            .unwrap();
1085        assert_eq!(message, expected);
1086    }
1087}