sqlparser/dialect/
postgresql.rs1use log::debug;
30
31use crate::dialect::{Dialect, Precedence};
32use crate::keywords::Keyword;
33use crate::parser::{Parser, ParserError};
34use crate::tokenizer::Token;
35
36use super::keywords::RESERVED_FOR_IDENTIFIER;
37
38#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
40#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41pub struct PostgreSqlDialect {}
42
43const PERIOD_PREC: u8 = 200;
44const DOUBLE_COLON_PREC: u8 = 140;
45const BRACKET_PREC: u8 = 130;
46const COLLATE_PREC: u8 = 120;
47const AT_TZ_PREC: u8 = 110;
48const CARET_PREC: u8 = 100;
49const MUL_DIV_MOD_OP_PREC: u8 = 90;
50const PLUS_MINUS_PREC: u8 = 80;
51const XOR_PREC: u8 = 75;
53const PG_OTHER_PREC: u8 = 70;
54const BETWEEN_LIKE_PREC: u8 = 60;
55const EQ_PREC: u8 = 50;
56const IS_PREC: u8 = 40;
57const NOT_PREC: u8 = 30;
58const AND_PREC: u8 = 20;
59const OR_PREC: u8 = 10;
60
61impl Dialect for PostgreSqlDialect {
62 fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
63 Some('"')
64 }
65
66 fn is_delimited_identifier_start(&self, ch: char) -> bool {
67 ch == '"' }
69
70 fn is_identifier_start(&self, ch: char) -> bool {
71 ch.is_alphabetic() || ch == '_' ||
72 !ch.is_ascii()
74 }
75
76 fn is_identifier_part(&self, ch: char) -> bool {
77 ch.is_alphabetic() || ch.is_ascii_digit() || ch == '$' || ch == '_' ||
78 !ch.is_ascii()
80 }
81
82 fn supports_unicode_string_literal(&self) -> bool {
83 true
84 }
85
86 fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
87 if matches!(kw, Keyword::INTERVAL) {
88 false
89 } else {
90 RESERVED_FOR_IDENTIFIER.contains(&kw)
91 }
92 }
93
94 fn is_custom_operator_part(&self, ch: char) -> bool {
96 matches!(
97 ch,
98 '+' | '-'
99 | '*'
100 | '/'
101 | '<'
102 | '>'
103 | '='
104 | '~'
105 | '!'
106 | '@'
107 | '#'
108 | '%'
109 | '^'
110 | '&'
111 | '|'
112 | '`'
113 | '?'
114 )
115 }
116
117 fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
118 let token = parser.peek_token_ref();
119 debug!("get_next_precedence() {token:?}");
120
121 match &token.token {
124 Token::Word(w)
125 if w.keyword == Keyword::COLLATE && !parser.in_column_definition_state() =>
126 {
127 Some(Ok(COLLATE_PREC))
128 }
129 Token::LBracket => Some(Ok(BRACKET_PREC)),
130 Token::Arrow
131 | Token::LongArrow
132 | Token::HashArrow
133 | Token::HashLongArrow
134 | Token::AtArrow
135 | Token::ArrowAt
136 | Token::HashMinus
137 | Token::AtQuestion
138 | Token::AtAt
139 | Token::Question
140 | Token::QuestionAnd
141 | Token::QuestionPipe
142 | Token::ExclamationMark
143 | Token::Overlap
144 | Token::CaretAt
145 | Token::StringConcat
146 | Token::Sharp
147 | Token::ShiftRight
148 | Token::ShiftLeft
149 | Token::CustomBinaryOperator(_) => Some(Ok(PG_OTHER_PREC)),
150 Token::Colon => Some(Ok(self.prec_unknown())),
152 _ => None,
153 }
154 }
155
156 fn supports_filter_during_aggregation(&self) -> bool {
157 true
158 }
159
160 fn supports_group_by_expr(&self) -> bool {
161 true
162 }
163
164 fn prec_value(&self, prec: Precedence) -> u8 {
165 match prec {
166 Precedence::Period => PERIOD_PREC,
167 Precedence::DoubleColon => DOUBLE_COLON_PREC,
168 Precedence::AtTz => AT_TZ_PREC,
169 Precedence::MulDivModOp => MUL_DIV_MOD_OP_PREC,
170 Precedence::PlusMinus => PLUS_MINUS_PREC,
171 Precedence::Xor => XOR_PREC,
172 Precedence::Ampersand => PG_OTHER_PREC,
173 Precedence::Caret => CARET_PREC,
174 Precedence::Pipe => PG_OTHER_PREC,
175 Precedence::Colon => PG_OTHER_PREC,
176 Precedence::Between => BETWEEN_LIKE_PREC,
177 Precedence::Eq => EQ_PREC,
178 Precedence::Like => BETWEEN_LIKE_PREC,
179 Precedence::Is => IS_PREC,
180 Precedence::PgOther => PG_OTHER_PREC,
181 Precedence::UnaryNot => NOT_PREC,
182 Precedence::And => AND_PREC,
183 Precedence::Or => OR_PREC,
184 }
185 }
186
187 fn allow_extract_custom(&self) -> bool {
188 true
189 }
190
191 fn allow_extract_single_quotes(&self) -> bool {
192 true
193 }
194
195 fn supports_create_index_with_clause(&self) -> bool {
196 true
197 }
198
199 fn supports_explain_with_utility_options(&self) -> bool {
201 true
202 }
203
204 fn supports_listen_notify(&self) -> bool {
208 true
209 }
210
211 fn supports_factorial_operator(&self) -> bool {
213 true
214 }
215
216 fn supports_bitwise_shift_operators(&self) -> bool {
217 true
218 }
219
220 fn supports_comment_on(&self) -> bool {
222 true
223 }
224
225 fn supports_load_extension(&self) -> bool {
227 true
228 }
229
230 fn supports_named_fn_args_with_colon_operator(&self) -> bool {
237 true
238 }
239
240 fn supports_named_fn_args_with_expr_name(&self) -> bool {
247 true
248 }
249
250 fn supports_empty_projections(&self) -> bool {
257 true
258 }
259
260 fn supports_nested_comments(&self) -> bool {
261 true
262 }
263
264 fn supports_string_escape_constant(&self) -> bool {
265 true
266 }
267
268 fn supports_numeric_literal_underscores(&self) -> bool {
269 true
270 }
271
272 fn supports_array_typedef_with_brackets(&self) -> bool {
274 true
275 }
276
277 fn supports_geometric_types(&self) -> bool {
278 true
279 }
280
281 fn supports_set_names(&self) -> bool {
282 true
283 }
284
285 fn supports_alter_column_type_using(&self) -> bool {
286 true
287 }
288
289 fn supports_notnull_operator(&self) -> bool {
292 true
293 }
294
295 fn supports_interval_options(&self) -> bool {
299 true
300 }
301
302 fn supports_insert_table_alias(&self) -> bool {
303 true
304 }
305
306 fn supports_create_table_like_parenthesized(&self) -> bool {
307 true
308 }
309
310 fn supports_select_wildcard_with_alias(&self) -> bool {
311 true
312 }
313
314 fn supports_comma_separated_trim(&self) -> bool {
315 true
316 }
317
318 fn supports_xml_expressions(&self) -> bool {
319 true
320 }
321}