postgresql.rs - source

sqlparser/dialect/

postgresql.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// Licensed under the Apache License, Version 2.0 (the "License");
19// you may not use this file except in compliance with the License.
20// You may obtain a copy of the License at
21//
22// http://www.apache.org/licenses/LICENSE-2.0
23//
24// Unless required by applicable law or agreed to in writing, software
25// distributed under the License is distributed on an "AS IS" BASIS,
26// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27// See the License for the specific language governing permissions and
28// limitations under the License.
29use log::debug;
30
31use crate::dialect::{Dialect, Precedence};
32use crate::keywords::Keyword;
33use crate::parser::{Parser, ParserError};
34use crate::tokenizer::Token;
35
36/// A [`Dialect`] for [PostgreSQL](https://www.postgresql.org/)
37#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
39pub struct PostgreSqlDialect {}
40
41const PERIOD_PREC: u8 = 200;
42const DOUBLE_COLON_PREC: u8 = 140;
43const BRACKET_PREC: u8 = 130;
44const COLLATE_PREC: u8 = 120;
45const AT_TZ_PREC: u8 = 110;
46const CARET_PREC: u8 = 100;
47const MUL_DIV_MOD_OP_PREC: u8 = 90;
48const PLUS_MINUS_PREC: u8 = 80;
49// there's no XOR operator in PostgreSQL, but support it here to avoid breaking tests
50const XOR_PREC: u8 = 75;
51const PG_OTHER_PREC: u8 = 70;
52const BETWEEN_LIKE_PREC: u8 = 60;
53const EQ_PREC: u8 = 50;
54const IS_PREC: u8 = 40;
55const NOT_PREC: u8 = 30;
56const AND_PREC: u8 = 20;
57const OR_PREC: u8 = 10;
58
59impl Dialect for PostgreSqlDialect {
60    fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
61        Some('"')
62    }
63
64    fn is_delimited_identifier_start(&self, ch: char) -> bool {
65        ch == '"' // Postgres does not support backticks to quote identifiers
66    }
67
68    fn is_identifier_start(&self, ch: char) -> bool {
69        ch.is_alphabetic() || ch == '_' ||
70        // PostgreSQL implements Unicode characters in identifiers.
71        !ch.is_ascii()
72    }
73
74    fn is_identifier_part(&self, ch: char) -> bool {
75        ch.is_alphabetic() || ch.is_ascii_digit() || ch == '$' || ch == '_'  ||
76        // PostgreSQL implements Unicode characters in identifiers.
77        !ch.is_ascii()
78    }
79
80    fn supports_unicode_string_literal(&self) -> bool {
81        true
82    }
83
84    /// See <https://www.postgresql.org/docs/current/sql-createoperator.html>
85    fn is_custom_operator_part(&self, ch: char) -> bool {
86        matches!(
87            ch,
88            '+' | '-'
89                | '*'
90                | '/'
91                | '<'
92                | '>'
93                | '='
94                | '~'
95                | '!'
96                | '@'
97                | '#'
98                | '%'
99                | '^'
100                | '&'
101                | '|'
102                | '`'
103                | '?'
104        )
105    }
106
107    fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
108        let token = parser.peek_token();
109        debug!("get_next_precedence() {token:?}");
110
111        // we only return some custom value here when the behaviour (not merely the numeric value) differs
112        // from the default implementation
113        match token.token {
114            Token::Word(w)
115                if w.keyword == Keyword::COLLATE && !parser.in_column_definition_state() =>
116            {
117                Some(Ok(COLLATE_PREC))
118            }
119            Token::LBracket => Some(Ok(BRACKET_PREC)),
120            Token::Arrow
121            | Token::LongArrow
122            | Token::HashArrow
123            | Token::HashLongArrow
124            | Token::AtArrow
125            | Token::ArrowAt
126            | Token::HashMinus
127            | Token::AtQuestion
128            | Token::AtAt
129            | Token::Question
130            | Token::QuestionAnd
131            | Token::QuestionPipe
132            | Token::ExclamationMark
133            | Token::Overlap
134            | Token::CaretAt
135            | Token::StringConcat
136            | Token::Sharp
137            | Token::ShiftRight
138            | Token::ShiftLeft
139            | Token::CustomBinaryOperator(_) => Some(Ok(PG_OTHER_PREC)),
140            // lowest prec to prevent it from turning into a binary op
141            Token::Colon => Some(Ok(self.prec_unknown())),
142            _ => None,
143        }
144    }
145
146    fn supports_filter_during_aggregation(&self) -> bool {
147        true
148    }
149
150    fn supports_group_by_expr(&self) -> bool {
151        true
152    }
153
154    fn prec_value(&self, prec: Precedence) -> u8 {
155        match prec {
156            Precedence::Period => PERIOD_PREC,
157            Precedence::DoubleColon => DOUBLE_COLON_PREC,
158            Precedence::AtTz => AT_TZ_PREC,
159            Precedence::MulDivModOp => MUL_DIV_MOD_OP_PREC,
160            Precedence::PlusMinus => PLUS_MINUS_PREC,
161            Precedence::Xor => XOR_PREC,
162            Precedence::Ampersand => PG_OTHER_PREC,
163            Precedence::Caret => CARET_PREC,
164            Precedence::Pipe => PG_OTHER_PREC,
165            Precedence::Colon => PG_OTHER_PREC,
166            Precedence::Between => BETWEEN_LIKE_PREC,
167            Precedence::Eq => EQ_PREC,
168            Precedence::Like => BETWEEN_LIKE_PREC,
169            Precedence::Is => IS_PREC,
170            Precedence::PgOther => PG_OTHER_PREC,
171            Precedence::UnaryNot => NOT_PREC,
172            Precedence::And => AND_PREC,
173            Precedence::Or => OR_PREC,
174        }
175    }
176
177    fn allow_extract_custom(&self) -> bool {
178        true
179    }
180
181    fn allow_extract_single_quotes(&self) -> bool {
182        true
183    }
184
185    fn supports_create_index_with_clause(&self) -> bool {
186        true
187    }
188
189    /// see <https://www.postgresql.org/docs/current/sql-explain.html>
190    fn supports_explain_with_utility_options(&self) -> bool {
191        true
192    }
193
194    /// see <https://www.postgresql.org/docs/current/sql-listen.html>
195    /// see <https://www.postgresql.org/docs/current/sql-unlisten.html>
196    /// see <https://www.postgresql.org/docs/current/sql-notify.html>
197    fn supports_listen_notify(&self) -> bool {
198        true
199    }
200
201    /// see <https://www.postgresql.org/docs/13/functions-math.html>
202    fn supports_factorial_operator(&self) -> bool {
203        true
204    }
205
206    fn supports_bitwise_shift_operators(&self) -> bool {
207        true
208    }
209
210    /// see <https://www.postgresql.org/docs/current/sql-comment.html>
211    fn supports_comment_on(&self) -> bool {
212        true
213    }
214
215    /// See <https://www.postgresql.org/docs/current/sql-load.html>
216    fn supports_load_extension(&self) -> bool {
217        true
218    }
219
220    /// See <https://www.postgresql.org/docs/current/functions-json.html>
221    ///
222    /// Required to support the colon in:
223    /// ```sql
224    /// SELECT json_object('a': 'b')
225    /// ```
226    fn supports_named_fn_args_with_colon_operator(&self) -> bool {
227        true
228    }
229
230    /// See <https://www.postgresql.org/docs/current/functions-json.html>
231    ///
232    /// Required to support the label in:
233    /// ```sql
234    /// SELECT json_object('label': 'value')
235    /// ```
236    fn supports_named_fn_args_with_expr_name(&self) -> bool {
237        true
238    }
239
240    /// Return true if the dialect supports empty projections in SELECT statements
241    ///
242    /// Example
243    /// ```sql
244    /// SELECT from table_name
245    /// ```
246    fn supports_empty_projections(&self) -> bool {
247        true
248    }
249
250    fn supports_nested_comments(&self) -> bool {
251        true
252    }
253
254    fn supports_string_escape_constant(&self) -> bool {
255        true
256    }
257
258    fn supports_numeric_literal_underscores(&self) -> bool {
259        true
260    }
261
262    /// See: <https://www.postgresql.org/docs/current/arrays.html#ARRAYS-DECLARATION>
263    fn supports_array_typedef_with_brackets(&self) -> bool {
264        true
265    }
266
267    fn supports_geometric_types(&self) -> bool {
268        true
269    }
270
271    fn supports_set_names(&self) -> bool {
272        true
273    }
274
275    fn supports_alter_column_type_using(&self) -> bool {
276        true
277    }
278
279    /// Postgres supports `NOTNULL` as an alias for `IS NOT NULL`
280    /// See: <https://www.postgresql.org/docs/17/functions-comparison.html>
281    fn supports_notnull_operator(&self) -> bool {
282        true
283    }
284
285    /// [Postgres] supports optional field and precision options for `INTERVAL` data type.
286    ///
287    /// [Postgres]: https://www.postgresql.org/docs/17/datatype-datetime.html
288    fn supports_interval_options(&self) -> bool {
289        true
290    }
291}