sqlparser/dialect/
postgresql.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13use crate::ast::{CommentObject, Statement};
14use crate::dialect::Dialect;
15use crate::keywords::Keyword;
16use crate::parser::{Parser, ParserError};
17use crate::tokenizer::Token;
18
19/// A [`Dialect`] for [PostgreSQL](https://www.postgresql.org/)
20#[derive(Debug)]
21pub struct PostgreSqlDialect {}
22
23impl Dialect for PostgreSqlDialect {
24    fn is_identifier_start(&self, ch: char) -> bool {
25        // See https://www.postgresql.org/docs/11/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
26        // We don't yet support identifiers beginning with "letters with
27        // diacritical marks"
28        ch.is_alphabetic() || ch == '_'
29    }
30
31    fn is_identifier_part(&self, ch: char) -> bool {
32        ch.is_alphabetic() || ch.is_ascii_digit() || ch == '$' || ch == '_'
33    }
34
35    fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
36        if parser.parse_keyword(Keyword::COMMENT) {
37            Some(parse_comment(parser))
38        } else {
39            None
40        }
41    }
42
43    fn supports_filter_during_aggregation(&self) -> bool {
44        true
45    }
46
47    fn supports_group_by_expr(&self) -> bool {
48        true
49    }
50}
51
52pub fn parse_comment(parser: &mut Parser) -> Result<Statement, ParserError> {
53    let if_exists = parser.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
54
55    parser.expect_keyword(Keyword::ON)?;
56    let token = parser.next_token();
57
58    let (object_type, object_name) = match token.token {
59        Token::Word(w) if w.keyword == Keyword::COLUMN => {
60            let object_name = parser.parse_object_name(false)?;
61            (CommentObject::Column, object_name)
62        }
63        Token::Word(w) if w.keyword == Keyword::TABLE => {
64            let object_name = parser.parse_object_name(false)?;
65            (CommentObject::Table, object_name)
66        }
67        _ => parser.expected("comment object_type", token)?,
68    };
69
70    parser.expect_keyword(Keyword::IS)?;
71    let comment = if parser.parse_keyword(Keyword::NULL) {
72        None
73    } else {
74        Some(parser.parse_literal_string()?)
75    };
76    Ok(Statement::Comment {
77        object_type,
78        object_name,
79        comment,
80        if_exists,
81    })
82}