sqltk_parser/dialect/
postgresql.rs1use log::debug;
30
31use crate::ast::{LockTableType, LockTables, ObjectName, Statement, UserDefinedTypeRepresentation};
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 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 == '_'
75 }
76
77 fn is_identifier_part(&self, ch: char) -> bool {
78 ch.is_alphabetic() || ch.is_ascii_digit() || ch == '$' || ch == '_'
79 }
80
81 fn supports_unicode_string_literal(&self) -> bool {
82 true
83 }
84
85 fn is_custom_operator_part(&self, ch: char) -> bool {
87 matches!(
88 ch,
89 '+' | '-'
90 | '*'
91 | '/'
92 | '<'
93 | '>'
94 | '='
95 | '~'
96 | '!'
97 | '@'
98 | '#'
99 | '%'
100 | '^'
101 | '&'
102 | '|'
103 | '`'
104 | '?'
105 )
106 }
107
108 fn get_next_precedence(&self, parser: &Parser) -> Option<Result<u8, ParserError>> {
109 let token = parser.peek_token();
110 debug!("get_next_precedence() {:?}", token);
111
112 match token.token {
115 Token::Word(w) if w.keyword == Keyword::COLLATE => Some(Ok(COLLATE_PREC)),
116 Token::LBracket => Some(Ok(BRACKET_PREC)),
117 Token::Arrow
118 | Token::LongArrow
119 | Token::HashArrow
120 | Token::HashLongArrow
121 | Token::AtArrow
122 | Token::ArrowAt
123 | Token::HashMinus
124 | Token::AtQuestion
125 | Token::AtAt
126 | Token::Question
127 | Token::QuestionAnd
128 | Token::QuestionPipe
129 | Token::ExclamationMark
130 | Token::Overlap
131 | Token::CaretAt
132 | Token::StringConcat
133 | Token::Sharp
134 | Token::ShiftRight
135 | Token::ShiftLeft
136 | Token::CustomBinaryOperator(_) => Some(Ok(PG_OTHER_PREC)),
137 _ => None,
138 }
139 }
140
141 fn parse_statement(&self, parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
142 if parser.parse_keyword(Keyword::CREATE) {
143 parser.prev_token(); parse_create(parser)
145 } else if parser.parse_keyword(Keyword::LOCK) {
146 parser.prev_token(); Some(parse_lock_table(parser))
148 } else {
149 None
150 }
151 }
152
153 fn supports_filter_during_aggregation(&self) -> bool {
154 true
155 }
156
157 fn supports_group_by_expr(&self) -> bool {
158 true
159 }
160
161 fn prec_value(&self, prec: Precedence) -> u8 {
162 match prec {
163 Precedence::DoubleColon => DOUBLE_COLON_PREC,
164 Precedence::AtTz => AT_TZ_PREC,
165 Precedence::MulDivModOp => MUL_DIV_MOD_OP_PREC,
166 Precedence::PlusMinus => PLUS_MINUS_PREC,
167 Precedence::Xor => XOR_PREC,
168 Precedence::Ampersand => PG_OTHER_PREC,
169 Precedence::Caret => CARET_PREC,
170 Precedence::Pipe => PG_OTHER_PREC,
171 Precedence::Between => BETWEEN_LIKE_PREC,
172 Precedence::Eq => EQ_PREC,
173 Precedence::Like => BETWEEN_LIKE_PREC,
174 Precedence::Is => IS_PREC,
175 Precedence::PgOther => PG_OTHER_PREC,
176 Precedence::UnaryNot => NOT_PREC,
177 Precedence::And => AND_PREC,
178 Precedence::Or => OR_PREC,
179 }
180 }
181
182 fn allow_extract_custom(&self) -> bool {
183 true
184 }
185
186 fn allow_extract_single_quotes(&self) -> bool {
187 true
188 }
189
190 fn supports_create_index_with_clause(&self) -> bool {
191 true
192 }
193
194 fn supports_explain_with_utility_options(&self) -> bool {
196 true
197 }
198
199 fn supports_listen_notify(&self) -> bool {
203 true
204 }
205
206 fn supports_factorial_operator(&self) -> bool {
208 true
209 }
210
211 fn supports_comment_on(&self) -> bool {
213 true
214 }
215
216 fn supports_load_extension(&self) -> bool {
218 true
219 }
220
221 fn supports_named_fn_args_with_colon_operator(&self) -> bool {
228 true
229 }
230
231 fn supports_named_fn_args_with_expr_name(&self) -> bool {
238 true
239 }
240}
241
242pub fn parse_create(parser: &mut Parser) -> Option<Result<Statement, ParserError>> {
243 let name = parser.maybe_parse(|parser| -> Result<ObjectName, ParserError> {
244 parser.expect_keyword(Keyword::CREATE)?;
245 parser.expect_keyword(Keyword::TYPE)?;
246 let name = parser.parse_object_name(false)?;
247 parser.expect_keyword(Keyword::AS)?;
248 parser.expect_keyword(Keyword::ENUM)?;
249 Ok(name)
250 });
251
252 match name {
253 Ok(name) => name.map(|name| parse_create_type_as_enum(parser, name)),
254 Err(e) => Some(Err(e)),
255 }
256}
257
258pub fn parse_create_type_as_enum(
260 parser: &mut Parser,
261 name: ObjectName,
262) -> Result<Statement, ParserError> {
263 if !parser.consume_token(&Token::LParen) {
264 return parser.expected("'(' after CREATE TYPE AS ENUM", parser.peek_token());
265 }
266
267 let labels = parser.parse_comma_separated0(|p| p.parse_identifier(false), Token::RParen)?;
268 parser.expect_token(&Token::RParen)?;
269
270 Ok(Statement::CreateType {
271 name,
272 representation: UserDefinedTypeRepresentation::Enum { labels },
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}