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::{self, RESERVED_FOR_IDENTIFIER};
37
38const RESERVED_EXCLUSIONS_FOR_TABLE_ALIAS: &[Keyword] = &[
41 Keyword::CLUSTER,
42 Keyword::DISTRIBUTE,
43 Keyword::EXPLAIN,
44 Keyword::MINUS,
45 Keyword::SAMPLE,
46 Keyword::SORT,
47 Keyword::START,
48 Keyword::TOP,
49 Keyword::VIEW,
50];
51
52#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
54#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
55pub struct PostgreSqlDialect {}
56
57const PERIOD_PREC: u8 = 200;
58const DOUBLE_COLON_PREC: u8 = 140;
59const BRACKET_PREC: u8 = 130;
60const COLLATE_PREC: u8 = 120;
61const AT_TZ_PREC: u8 = 110;
62const CARET_PREC: u8 = 100;
63const MUL_DIV_MOD_OP_PREC: u8 = 90;
64const PLUS_MINUS_PREC: u8 = 80;
65const XOR_PREC: u8 = 75;
67const PG_OTHER_PREC: u8 = 70;
68const BETWEEN_LIKE_PREC: u8 = 60;
69const EQ_PREC: u8 = 50;
70const IS_PREC: u8 = 40;
71const NOT_PREC: u8 = 30;
72const AND_PREC: u8 = 20;
73const OR_PREC: u8 = 10;
74
75impl Dialect for PostgreSqlDialect {
76 fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
77 Some('"')
78 }
79
80 fn is_delimited_identifier_start(&self, ch: char) -> bool {
81 ch == '"' }
83
84 fn is_identifier_start(&self, ch: char) -> bool {
85 ch.is_alphabetic() || ch == '_' ||
86 !ch.is_ascii()
88 }
89
90 fn is_identifier_part(&self, ch: char) -> bool {
91 ch.is_alphabetic() || ch.is_ascii_digit() || ch == '$' || ch == '_' ||
92 !ch.is_ascii()
94 }
95
96 fn supports_unicode_string_literal(&self) -> bool {
97 true
98 }
99
100 fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
101 if matches!(kw, Keyword::INTERVAL) {
102 false
103 } else {
104 RESERVED_FOR_IDENTIFIER.contains(&kw)
105 }
106 }
107
108 fn is_table_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
109 !keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
110 || RESERVED_EXCLUSIONS_FOR_TABLE_ALIAS.contains(kw)
111 }
112
113 fn is_custom_operator_part(&self, ch: char) -> bool {
115 matches!(
116 ch,
117 '+' | '-'
118 | '*'
119 | '/'
120 | '<'
121 | '>'
122 | '='
123 | '~'
124 | '!'
125 | '@'
126 | '#'
127 | '%'
128 | '^'
129 | '&'
130 | '|'
131 | '`'
132 | '?'
133 )
134 }
135
136 fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
137 let token = parser.peek_token_ref();
138 debug!("get_next_precedence() {token:?}");
139
140 match &token.token {
143 Token::Word(w)
144 if w.keyword == Keyword::COLLATE && !parser.in_column_definition_state() =>
145 {
146 Some(Ok(COLLATE_PREC))
147 }
148 Token::LBracket => Some(Ok(BRACKET_PREC)),
149 Token::Arrow
150 | Token::LongArrow
151 | Token::HashArrow
152 | Token::HashLongArrow
153 | Token::AtArrow
154 | Token::ArrowAt
155 | Token::HashMinus
156 | Token::AtQuestion
157 | Token::AtAt
158 | Token::Question
159 | Token::QuestionAnd
160 | Token::QuestionPipe
161 | Token::ExclamationMark
162 | Token::Overlap
163 | Token::CaretAt
164 | Token::StringConcat
165 | Token::Sharp
166 | Token::ShiftRight
167 | Token::ShiftLeft
168 | Token::CustomBinaryOperator(_) => Some(Ok(PG_OTHER_PREC)),
169 Token::Colon => Some(Ok(self.prec_unknown())),
171 _ => None,
172 }
173 }
174
175 fn supports_filter_during_aggregation(&self) -> bool {
176 true
177 }
178
179 fn supports_group_by_expr(&self) -> bool {
180 true
181 }
182
183 fn supports_alter_user_as_alter_role(&self) -> bool {
184 true
185 }
186
187 fn prec_value(&self, prec: Precedence) -> u8 {
188 match prec {
189 Precedence::Period => PERIOD_PREC,
190 Precedence::DoubleColon => DOUBLE_COLON_PREC,
191 Precedence::AtTz => AT_TZ_PREC,
192 Precedence::MulDivModOp => MUL_DIV_MOD_OP_PREC,
193 Precedence::PlusMinus => PLUS_MINUS_PREC,
194 Precedence::Xor => XOR_PREC,
195 Precedence::Ampersand => PG_OTHER_PREC,
196 Precedence::Caret => CARET_PREC,
197 Precedence::Pipe => PG_OTHER_PREC,
198 Precedence::Colon => PG_OTHER_PREC,
199 Precedence::Between => BETWEEN_LIKE_PREC,
200 Precedence::Eq => EQ_PREC,
201 Precedence::Like => BETWEEN_LIKE_PREC,
202 Precedence::Is => IS_PREC,
203 Precedence::PgOther => PG_OTHER_PREC,
204 Precedence::UnaryNot => NOT_PREC,
205 Precedence::And => AND_PREC,
206 Precedence::Or => OR_PREC,
207 }
208 }
209
210 fn allow_extract_custom(&self) -> bool {
211 true
212 }
213
214 fn allow_extract_single_quotes(&self) -> bool {
215 true
216 }
217
218 fn supports_create_index_with_clause(&self) -> bool {
219 true
220 }
221
222 fn supports_explain_with_utility_options(&self) -> bool {
224 true
225 }
226
227 fn supports_listen_notify(&self) -> bool {
231 true
232 }
233
234 fn supports_exclude_constraint(&self) -> bool {
236 true
237 }
238
239 fn supports_factorial_operator(&self) -> bool {
241 true
242 }
243
244 fn supports_bitwise_shift_operators(&self) -> bool {
245 true
246 }
247
248 fn supports_comment_on(&self) -> bool {
250 true
251 }
252
253 fn supports_load_extension(&self) -> bool {
255 true
256 }
257
258 fn supports_named_fn_args_with_colon_operator(&self) -> bool {
265 true
266 }
267
268 fn supports_named_fn_args_with_expr_name(&self) -> bool {
275 true
276 }
277
278 fn supports_empty_projections(&self) -> bool {
285 true
286 }
287
288 fn supports_nested_comments(&self) -> bool {
289 true
290 }
291
292 fn supports_string_escape_constant(&self) -> bool {
293 true
294 }
295
296 fn supports_numeric_literal_underscores(&self) -> bool {
297 true
298 }
299
300 fn supports_array_typedef_with_brackets(&self) -> bool {
302 true
303 }
304
305 fn supports_geometric_types(&self) -> bool {
306 true
307 }
308
309 fn supports_order_by_using_operator(&self) -> bool {
310 true
311 }
312
313 fn supports_set_names(&self) -> bool {
314 true
315 }
316
317 fn supports_alter_column_type_using(&self) -> bool {
318 true
319 }
320
321 fn supports_left_associative_joins_without_parens(&self) -> bool {
324 false
325 }
326
327 fn supports_notnull_operator(&self) -> bool {
330 true
331 }
332
333 fn supports_interval_options(&self) -> bool {
337 true
338 }
339
340 fn supports_insert_table_alias(&self) -> bool {
341 true
342 }
343
344 fn supports_create_table_like_parenthesized(&self) -> bool {
345 true
346 }
347
348 fn supports_select_wildcard_with_alias(&self) -> bool {
349 true
350 }
351
352 fn supports_comma_separated_trim(&self) -> bool {
353 true
354 }
355
356 fn supports_xml_expressions(&self) -> bool {
357 true
358 }
359
360 fn supports_aliased_function_args(&self) -> bool {
361 true
362 }
363
364 fn supports_comment_optimizer_hint(&self) -> bool {
369 true
370 }
371}