mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-07 17:04:59 +00:00
169 lines
4.8 KiB
Rust
169 lines
4.8 KiB
Rust
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
//! Test the ability for dialects to override parsing
|
|
|
|
use sqlparser::{
|
|
ast::{BinaryOperator, Expr, Statement, Value},
|
|
dialect::Dialect,
|
|
keywords::Keyword,
|
|
parser::{Parser, ParserError},
|
|
tokenizer::Token,
|
|
};
|
|
|
|
#[test]
|
|
fn custom_prefix_parser() -> Result<(), ParserError> {
|
|
#[derive(Debug)]
|
|
struct MyDialect {}
|
|
|
|
impl Dialect for MyDialect {
|
|
fn is_identifier_start(&self, ch: char) -> bool {
|
|
is_identifier_start(ch)
|
|
}
|
|
|
|
fn is_identifier_part(&self, ch: char) -> bool {
|
|
is_identifier_part(ch)
|
|
}
|
|
|
|
fn parse_prefix(&self, parser: &mut Parser) -> Option<Result<Expr, ParserError>> {
|
|
if parser.consume_token(&Token::Number("1".to_string(), false)) {
|
|
Some(Ok(Expr::Value(Value::Null.with_empty_span())))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
let dialect = MyDialect {};
|
|
let sql = "SELECT 1 + 2";
|
|
let ast = Parser::parse_sql(&dialect, sql)?;
|
|
let query = &ast[0];
|
|
assert_eq!("SELECT NULL + 2", &format!("{query}"));
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn custom_infix_parser() -> Result<(), ParserError> {
|
|
#[derive(Debug)]
|
|
struct MyDialect {}
|
|
|
|
impl Dialect for MyDialect {
|
|
fn is_identifier_start(&self, ch: char) -> bool {
|
|
is_identifier_start(ch)
|
|
}
|
|
|
|
fn is_identifier_part(&self, ch: char) -> bool {
|
|
is_identifier_part(ch)
|
|
}
|
|
|
|
fn parse_infix(
|
|
&self,
|
|
parser: &mut Parser,
|
|
expr: &Expr,
|
|
_precedence: u8,
|
|
) -> Option<Result<Expr, ParserError>> {
|
|
if parser.consume_token(&Token::Plus) {
|
|
Some(Ok(Expr::BinaryOp {
|
|
left: Box::new(expr.clone()),
|
|
op: BinaryOperator::Multiply, // translate Plus to Multiply
|
|
right: Box::new(parser.parse_expr().unwrap()),
|
|
}))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
let dialect = MyDialect {};
|
|
let sql = "SELECT 1 + 2";
|
|
let ast = Parser::parse_sql(&dialect, sql)?;
|
|
let query = &ast[0];
|
|
assert_eq!("SELECT 1 * 2", &format!("{query}"));
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn custom_statement_parser() -> Result<(), ParserError> {
|
|
#[derive(Debug)]
|
|
struct MyDialect {}
|
|
|
|
impl Dialect for MyDialect {
|
|
fn is_identifier_start(&self, ch: char) -> bool {
|
|
is_identifier_start(ch)
|
|
}
|
|
|
|
fn is_identifier_part(&self, ch: char) -> bool {
|
|
is_identifier_part(ch)
|
|
}
|
|
|
|
fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
|
|
if parser.parse_keyword(Keyword::SELECT) {
|
|
for _ in 0..3 {
|
|
let _ = parser.next_token();
|
|
}
|
|
Some(Ok(Statement::Commit {
|
|
chain: false,
|
|
end: false,
|
|
modifier: None,
|
|
}))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
let dialect = MyDialect {};
|
|
let sql = "SELECT 1 + 2";
|
|
let ast = Parser::parse_sql(&dialect, sql)?;
|
|
let query = &ast[0];
|
|
assert_eq!("COMMIT", &format!("{query}"));
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn test_map_syntax_not_support_default() -> Result<(), ParserError> {
|
|
#[derive(Debug)]
|
|
struct MyDialect {}
|
|
|
|
impl Dialect for MyDialect {
|
|
fn is_identifier_start(&self, ch: char) -> bool {
|
|
is_identifier_start(ch)
|
|
}
|
|
|
|
fn is_identifier_part(&self, ch: char) -> bool {
|
|
is_identifier_part(ch)
|
|
}
|
|
}
|
|
|
|
let dialect = MyDialect {};
|
|
let sql = "SELECT MAP {1: 2}";
|
|
let ast = Parser::parse_sql(&dialect, sql);
|
|
assert!(ast.is_err());
|
|
Ok(())
|
|
}
|
|
|
|
fn is_identifier_start(ch: char) -> bool {
|
|
ch.is_ascii_lowercase() || ch.is_ascii_uppercase() || ch == '_'
|
|
}
|
|
|
|
fn is_identifier_part(ch: char) -> bool {
|
|
ch.is_ascii_lowercase()
|
|
|| ch.is_ascii_uppercase()
|
|
|| ch.is_ascii_digit()
|
|
|| ch == '$'
|
|
|| ch == '_'
|
|
}
|