sqltk_parser/dialect/
postgresql.rs1use log::debug;
30
31use crate::ast::{LockTableType, LockTables, ObjectName, Statement};
32use crate::dialect::{Dialect, Precedence};
33use crate::keywords::Keyword;
34use crate::parser::{Parser, ParserError};
35use crate::tokenizer::Token;
36
37#[cfg(not(feature = "std"))]
38use alloc::vec::Vec;
39
40#[derive(Debug)]
42pub struct PostgreSqlDialect {}
43
44const PERIOD_PREC: u8 = 200;
45const DOUBLE_COLON_PREC: u8 = 140;
46const BRACKET_PREC: u8 = 130;
47const COLLATE_PREC: u8 = 120;
48const AT_TZ_PREC: u8 = 110;
49const CARET_PREC: u8 = 100;
50const MUL_DIV_MOD_OP_PREC: u8 = 90;
51const PLUS_MINUS_PREC: u8 = 80;
52const XOR_PREC: u8 = 75;
54const PG_OTHER_PREC: u8 = 70;
55const BETWEEN_LIKE_PREC: u8 = 60;
56const EQ_PREC: u8 = 50;
57const IS_PREC: u8 = 40;
58const NOT_PREC: u8 = 30;
59const AND_PREC: u8 = 20;
60const OR_PREC: u8 = 10;
61
62impl Dialect for PostgreSqlDialect {
63 fn identifier_quote_style(&self, _identifier: &str) -> Option<char> {
64 Some('"')
65 }
66
67 fn is_delimited_identifier_start(&self, ch: char) -> bool {
68 ch == '"' }
70
71 fn is_identifier_start(&self, ch: char) -> bool {
72 ch.is_alphabetic() || ch == '_'
76 }
77
78 fn is_identifier_part(&self, ch: char) -> bool {
79 ch.is_alphabetic() || ch.is_ascii_digit() || ch == '$' || ch == '_'
80 }
81
82 fn supports_unicode_string_literal(&self) -> bool {
83 true
84 }
85
86 fn is_custom_operator_part(&self, ch: char) -> bool {
88 matches!(
89 ch,
90 '+' | '-'
91 | '*'
92 | '/'
93 | '<'
94 | '>'
95 | '='
96 | '~'
97 | '!'
98 | '@'
99 | '#'
100 | '%'
101 | '^'
102 | '&'
103 | '|'
104 | '`'
105 | '?'
106 )
107 }
108
109 fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
110 let token = parser.peek_token();
111 debug!("get_next_precedence() {:?}", token);
112
113 match token.token {
116 Token::Word(w) if w.keyword == Keyword::COLLATE => Some(Ok(COLLATE_PREC)),
117 Token::LBracket => Some(Ok(BRACKET_PREC)),
118 Token::Arrow
119 | Token::LongArrow
120 | Token::HashArrow
121 | Token::HashLongArrow
122 | Token::AtArrow
123 | Token::ArrowAt
124 | Token::HashMinus
125 | Token::AtQuestion
126 | Token::AtAt
127 | Token::Question
128 | Token::QuestionAnd
129 | Token::QuestionPipe
130 | Token::ExclamationMark
131 | Token::Overlap
132 | Token::CaretAt
133 | Token::StringConcat
134 | Token::Sharp
135 | Token::ShiftRight
136 | Token::ShiftLeft
137 | Token::CustomBinaryOperator(_) => Some(Ok(PG_OTHER_PREC)),
138 _ => None,
139 }
140 }
141
142 fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
143 if parser.parse_keyword(Keyword::LOCK) {
144 parser.prev_token(); Some(parse_lock_table(parser))
146 } else {
147 None
148 }
149 }
150
151 fn supports_filter_during_aggregation(&self) -> bool {
152 true
153 }
154
155 fn supports_group_by_expr(&self) -> bool {
156 true
157 }
158
159 fn prec_value(&self, prec: Precedence) -> u8 {
160 match prec {
161 Precedence::Period => PERIOD_PREC,
162 Precedence::DoubleColon => DOUBLE_COLON_PREC,
163 Precedence::AtTz => AT_TZ_PREC,
164 Precedence::MulDivModOp => MUL_DIV_MOD_OP_PREC,
165 Precedence::PlusMinus => PLUS_MINUS_PREC,
166 Precedence::Xor => XOR_PREC,
167 Precedence::Ampersand => PG_OTHER_PREC,
168 Precedence::Caret => CARET_PREC,
169 Precedence::Pipe => PG_OTHER_PREC,
170 Precedence::Between => BETWEEN_LIKE_PREC,
171 Precedence::Eq => EQ_PREC,
172 Precedence::Like => BETWEEN_LIKE_PREC,
173 Precedence::Is => IS_PREC,
174 Precedence::PgOther => PG_OTHER_PREC,
175 Precedence::UnaryNot => NOT_PREC,
176 Precedence::And => AND_PREC,
177 Precedence::Or => OR_PREC,
178 }
179 }
180
181 fn allow_extract_custom(&self) -> bool {
182 true
183 }
184
185 fn allow_extract_single_quotes(&self) -> bool {
186 true
187 }
188
189 fn supports_create_index_with_clause(&self) -> bool {
190 true
191 }
192
193 fn supports_explain_with_utility_options(&self) -> bool {
195 true
196 }
197
198 fn supports_listen_notify(&self) -> bool {
202 true
203 }
204
205 fn supports_factorial_operator(&self) -> bool {
207 true
208 }
209
210 fn supports_comment_on(&self) -> bool {
212 true
213 }
214
215 fn supports_load_extension(&self) -> bool {
217 true
218 }
219
220 fn supports_named_fn_args_with_colon_operator(&self) -> bool {
227 true
228 }
229
230 fn supports_named_fn_args_with_expr_name(&self) -> bool {
237 true
238 }
239
240 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 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
276pub fn parse_lock_table(parser: &mut Parser) -> Result<Statement, ParserError> {
277 parser.expect_keyword(Keyword::LOCK)?;
278 let has_table_keyword = parser.parse_keyword(Keyword::TABLE);
279 let only = parser.parse_keyword(Keyword::ONLY);
280 let tables: Vec<ObjectName> =
281 parser.parse_comma_separated(|parser| parser.parse_object_name(false))?;
282 let lock_mode = parse_lock_mode(parser)?;
283 let no_wait = parser.parse_keyword(Keyword::NOWAIT);
284
285 Ok(Statement::LockTables(LockTables::Postgres {
286 tables,
287 lock_mode,
288 has_table_keyword,
289 only,
290 no_wait,
291 }))
292}
293
294pub fn parse_lock_mode(parser: &mut Parser) -> Result<Option<LockTableType>, ParserError> {
295 if !parser.parse_keyword(Keyword::IN) {
296 return Ok(None);
297 }
298
299 let lock_mode = if parser.parse_keywords(&[Keyword::ACCESS, Keyword::SHARE]) {
300 LockTableType::AccessShare
301 } else if parser.parse_keywords(&[Keyword::ACCESS, Keyword::EXCLUSIVE]) {
302 LockTableType::AccessExclusive
303 } else if parser.parse_keywords(&[Keyword::EXCLUSIVE]) {
304 LockTableType::Exclusive
305 } else if parser.parse_keywords(&[Keyword::ROW, Keyword::EXCLUSIVE]) {
306 LockTableType::RowExclusive
307 } else if parser.parse_keywords(&[Keyword::ROW, Keyword::SHARE]) {
308 LockTableType::RowShare
309 } else if parser.parse_keywords(&[Keyword::SHARE, Keyword::ROW, Keyword::EXCLUSIVE]) {
310 LockTableType::ShareRowExclusive
311 } else if parser.parse_keywords(&[Keyword::SHARE, Keyword::UPDATE, Keyword::EXCLUSIVE]) {
312 LockTableType::ShareUpdateExclusive
313 } else if parser.parse_keywords(&[Keyword::SHARE]) {
314 LockTableType::Share
315 } else {
316 return Err(ParserError::ParserError("Expected: ACCESS EXCLUSIVE | ACCESS SHARE | EXCLUSIVE | ROW EXCLUSIVE | ROW SHARE | SHARE | SHARE ROW EXCLUSIVE | SHARE ROW EXCLUSIVE".into()));
317 };
318
319 parser.expect_keyword(Keyword::MODE)?;
320
321 Ok(Some(lock_mode))
322}