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 supports_do_statement(&self) -> bool {
77 true
78 }
79
80 fn is_select_item_alias(&self, explicit: bool, keyword: &Keyword, parser: &mut Parser) -> bool {
81 if !explicit && *keyword == Keyword::ON && parser.peek_keyword(Keyword::CONFLICT) {
82 return false;
83 }
84 explicit || !keywords::RESERVED_FOR_COLUMN_ALIAS.contains(keyword)
85 }
86
87 fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
88 Some('"')
89 }
90
91 fn is_delimited_identifier_start(&self, ch: char) -> bool {
92 ch == '"' }
94
95 fn is_identifier_start(&self, ch: char) -> bool {
96 ch.is_alphabetic() || ch == '_' ||
97 !ch.is_ascii()
99 }
100
101 fn is_identifier_part(&self, ch: char) -> bool {
102 ch.is_alphabetic() || ch.is_ascii_digit() || ch == '$' || ch == '_' ||
103 !ch.is_ascii()
105 }
106
107 fn supports_unicode_string_literal(&self) -> bool {
108 true
109 }
110
111 fn is_reserved_for_identifier(&self, kw: Keyword) -> bool {
112 if matches!(kw, Keyword::INTERVAL) {
113 false
114 } else {
115 RESERVED_FOR_IDENTIFIER.contains(&kw)
116 }
117 }
118
119 fn is_table_alias(&self, kw: &Keyword, _parser: &mut Parser) -> bool {
120 !keywords::RESERVED_FOR_TABLE_ALIAS.contains(kw)
121 || RESERVED_EXCLUSIONS_FOR_TABLE_ALIAS.contains(kw)
122 }
123
124 fn is_custom_operator_part(&self, ch: char) -> bool {
126 matches!(
127 ch,
128 '+' | '-'
129 | '*'
130 | '/'
131 | '<'
132 | '>'
133 | '='
134 | '~'
135 | '!'
136 | '@'
137 | '#'
138 | '%'
139 | '^'
140 | '&'
141 | '|'
142 | '`'
143 | '?'
144 )
145 }
146
147 fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
148 let token = parser.peek_token_ref();
149 debug!("get_next_precedence() {token:?}");
150
151 match &token.token {
154 Token::Word(w)
155 if w.keyword == Keyword::COLLATE && !parser.in_column_definition_state() =>
156 {
157 Some(Ok(COLLATE_PREC))
158 }
159 Token::LBracket => Some(Ok(BRACKET_PREC)),
160 Token::Arrow
161 | Token::LongArrow
162 | Token::HashArrow
163 | Token::HashLongArrow
164 | Token::AtArrow
165 | Token::ArrowAt
166 | Token::HashMinus
167 | Token::AtQuestion
168 | Token::AtAt
169 | Token::Question
170 | Token::QuestionAnd
171 | Token::QuestionPipe
172 | Token::ExclamationMark
173 | Token::Overlap
174 | Token::CaretAt
175 | Token::StringConcat
176 | Token::Sharp
177 | Token::ShiftRight
178 | Token::ShiftLeft
179 | Token::CustomBinaryOperator(_) => Some(Ok(PG_OTHER_PREC)),
180 Token::Colon => Some(Ok(self.prec_unknown())),
182 _ => None,
183 }
184 }
185
186 fn supports_filter_during_aggregation(&self) -> bool {
187 true
188 }
189
190 fn supports_group_by_expr(&self) -> bool {
191 true
192 }
193
194 fn supports_alter_user_as_alter_role(&self) -> bool {
195 true
196 }
197
198 fn prec_value(&self, prec: Precedence) -> u8 {
199 match prec {
200 Precedence::Period => PERIOD_PREC,
201 Precedence::DoubleColon => DOUBLE_COLON_PREC,
202 Precedence::AtTz => AT_TZ_PREC,
203 Precedence::MulDivModOp => MUL_DIV_MOD_OP_PREC,
204 Precedence::PlusMinus => PLUS_MINUS_PREC,
205 Precedence::Xor => XOR_PREC,
206 Precedence::Ampersand => PG_OTHER_PREC,
207 Precedence::Caret => CARET_PREC,
208 Precedence::Pipe => PG_OTHER_PREC,
209 Precedence::Colon => PG_OTHER_PREC,
210 Precedence::Between => BETWEEN_LIKE_PREC,
211 Precedence::Eq => EQ_PREC,
212 Precedence::Like => BETWEEN_LIKE_PREC,
213 Precedence::Is => IS_PREC,
214 Precedence::PgOther => PG_OTHER_PREC,
215 Precedence::UnaryNot => NOT_PREC,
216 Precedence::And => AND_PREC,
217 Precedence::Or => OR_PREC,
218 }
219 }
220
221 fn allow_extract_custom(&self) -> bool {
222 true
223 }
224
225 fn allow_extract_single_quotes(&self) -> bool {
226 true
227 }
228
229 fn supports_create_index_with_clause(&self) -> bool {
230 true
231 }
232
233 fn supports_explain_with_utility_options(&self) -> bool {
235 true
236 }
237
238 fn supports_listen_notify(&self) -> bool {
242 true
243 }
244
245 fn supports_exclude_constraint(&self) -> bool {
247 true
248 }
249
250 fn supports_factorial_operator(&self) -> bool {
252 true
253 }
254
255 fn supports_bitwise_shift_operators(&self) -> bool {
256 true
257 }
258
259 fn supports_comment_on(&self) -> bool {
261 true
262 }
263
264 fn supports_load_extension(&self) -> bool {
266 true
267 }
268
269 fn supports_named_fn_args_with_colon_operator(&self) -> bool {
276 true
277 }
278
279 fn supports_named_fn_args_with_expr_name(&self) -> bool {
286 true
287 }
288
289 fn supports_empty_projections(&self) -> bool {
296 true
297 }
298
299 fn supports_nested_comments(&self) -> bool {
300 true
301 }
302
303 fn supports_string_escape_constant(&self) -> bool {
304 true
305 }
306
307 fn supports_numeric_literal_underscores(&self) -> bool {
308 true
309 }
310
311 fn supports_array_typedef_with_brackets(&self) -> bool {
313 true
314 }
315
316 fn supports_geometric_types(&self) -> bool {
317 true
318 }
319
320 fn supports_order_by_using_operator(&self) -> bool {
321 true
322 }
323
324 fn supports_set_names(&self) -> bool {
325 true
326 }
327
328 fn supports_set_schema(&self) -> bool {
329 true
330 }
331
332 fn supports_reset_time_zone(&self) -> bool {
333 true
334 }
335
336 fn supports_alter_column_type_using(&self) -> bool {
337 true
338 }
339
340 fn supports_left_associative_joins_without_parens(&self) -> bool {
343 false
344 }
345
346 fn supports_notnull_operator(&self) -> bool {
349 true
350 }
351
352 fn supports_interval_options(&self) -> bool {
356 true
357 }
358
359 fn supports_insert_table_alias(&self) -> bool {
360 true
361 }
362
363 fn supports_create_table_like_parenthesized(&self) -> bool {
364 true
365 }
366
367 fn supports_select_wildcard_with_alias(&self) -> bool {
368 true
369 }
370
371 fn supports_comma_separated_trim(&self) -> bool {
372 true
373 }
374
375 fn supports_xml_expressions(&self) -> bool {
376 true
377 }
378
379 fn supports_aliased_function_args(&self) -> bool {
380 true
381 }
382
383 fn supports_comment_optimizer_hint(&self) -> bool {
388 true
389 }
390}