sql_cli/sql/parser/expressions/
primary.rs1use crate::sql::parser::ast::{ColumnRef, SqlExpression, WindowSpec};
5use crate::sql::parser::lexer::Token;
6use tracing::{debug, trace};
7
8use super::{log_parse_decision, trace_parse_entry, trace_parse_exit, ExpressionParser};
9
10pub struct PrimaryExpressionContext<'a> {
12 pub columns: &'a [String],
13 pub in_method_args: bool,
14}
15
16impl<'a> Default for PrimaryExpressionContext<'a> {
17 fn default() -> Self {
18 Self {
19 columns: &[],
20 in_method_args: false,
21 }
22 }
23}
24
25pub fn parse_primary<P>(
28 parser: &mut P,
29 ctx: &PrimaryExpressionContext,
30) -> Result<SqlExpression, String>
31where
32 P: ParsePrimary + ExpressionParser + ?Sized,
33{
34 trace_parse_entry("parse_primary", ExpressionParser::current_token(parser));
35
36 if let Token::NumberLiteral(num_str) = ExpressionParser::current_token(parser) {
39 if ctx.columns.iter().any(|col| col == num_str) {
40 log_parse_decision(
41 "parse_primary",
42 ExpressionParser::current_token(parser),
43 "Number literal matches column name, treating as column",
44 );
45 let expr = SqlExpression::Column(ColumnRef::unquoted(num_str.clone()));
46 ExpressionParser::advance(parser);
47 let result = Ok(expr);
48 trace_parse_exit("parse_primary", &result);
49 return result;
50 }
51 }
52
53 let result = match ExpressionParser::current_token(parser) {
54 Token::Case => {
55 debug!("Parsing CASE expression");
56 parser.parse_case_expression()
57 }
58
59 Token::DateTime => {
60 debug!("Parsing DateTime constructor");
61 parse_datetime_constructor(parser)
62 }
63
64 Token::Unnest => {
65 debug!("Parsing UNNEST expression");
66 parse_unnest(parser)
67 }
68
69 Token::Identifier(id) => {
70 let id_upper = id.to_uppercase();
71 let id_clone = id.clone();
72
73 if id_upper == "TRUE" {
75 log_parse_decision(
76 "parse_primary",
77 ExpressionParser::current_token(parser),
78 "Boolean literal TRUE",
79 );
80 ExpressionParser::advance(parser);
81 Ok(SqlExpression::BooleanLiteral(true))
82 } else if id_upper == "FALSE" {
83 log_parse_decision(
84 "parse_primary",
85 ExpressionParser::current_token(parser),
86 "Boolean literal FALSE",
87 );
88 ExpressionParser::advance(parser);
89 Ok(SqlExpression::BooleanLiteral(false))
90 } else {
91 ExpressionParser::advance(parser);
92
93 if matches!(ExpressionParser::current_token(parser), Token::Dot) {
95 ExpressionParser::advance(parser); if let Token::Identifier(next_id) = ExpressionParser::current_token(parser) {
98 let next_id = next_id.clone();
99 ExpressionParser::advance(parser);
100
101 if matches!(ExpressionParser::current_token(parser), Token::LeftParen) {
103 debug!(object = %id_clone, method = %next_id, "Parsing method call");
104 ExpressionParser::advance(parser); let args = if matches!(
108 ExpressionParser::current_token(parser),
109 Token::RightParen
110 ) {
111 Vec::new()
112 } else {
113 parser.parse_expression_list()?
114 };
115 ExpressionParser::consume(parser, Token::RightParen)?;
116
117 log_parse_decision(
118 "parse_primary",
119 &Token::Identifier(next_id.clone()),
120 "Method call",
121 );
122 Ok(SqlExpression::MethodCall {
123 object: id_clone,
124 method: next_id,
125 args,
126 })
127 } else {
128 let col_ref = ColumnRef::qualified(id_clone, next_id.clone());
130 log_parse_decision(
131 "parse_primary",
132 &Token::Identifier(next_id),
133 "Qualified column reference",
134 );
135 Ok(SqlExpression::Column(col_ref))
136 }
137 } else {
138 Err("Expected identifier after '.'".to_string())
139 }
140 } else if matches!(ExpressionParser::current_token(parser), Token::LeftParen) {
142 debug!(function = %id_upper, "Parsing function call");
143 ExpressionParser::advance(parser); let (args, has_distinct) = parser.parse_function_args()?;
145 ExpressionParser::consume(parser, Token::RightParen)?;
146
147 if matches!(ExpressionParser::current_token(parser), Token::Over) {
149 debug!(function = %id_upper, "Window function detected");
150 ExpressionParser::advance(parser); ExpressionParser::consume(parser, Token::LeftParen)?;
152 let window_spec = parser.parse_window_spec()?;
153 ExpressionParser::consume(parser, Token::RightParen)?;
154 Ok(SqlExpression::WindowFunction {
155 name: id_upper,
156 args,
157 window_spec,
158 })
159 } else {
160 Ok(SqlExpression::FunctionCall {
161 name: id_upper,
162 args,
163 distinct: has_distinct,
164 })
165 }
166 } else {
167 log_parse_decision(
169 "parse_primary",
170 &Token::Identifier(id_clone.clone()),
171 "Column reference",
172 );
173 Ok(SqlExpression::Column(ColumnRef::unquoted(id_clone)))
174 }
175 }
176 }
177
178 Token::QuotedIdentifier(id) => {
179 let expr = if ctx.in_method_args {
180 log_parse_decision(
182 "parse_primary",
183 ExpressionParser::current_token(parser),
184 "Quoted identifier in method args - treating as string",
185 );
186 SqlExpression::StringLiteral(id.clone())
187 } else {
188 log_parse_decision(
190 "parse_primary",
191 ExpressionParser::current_token(parser),
192 "Quoted identifier as column name",
193 );
194 SqlExpression::Column(ColumnRef::quoted(id.clone()))
195 };
196 ExpressionParser::advance(parser);
197 Ok(expr)
198 }
199
200 Token::StringLiteral(s) => {
201 trace!("String literal: {}", s);
202 let expr = SqlExpression::StringLiteral(s.clone());
203 ExpressionParser::advance(parser);
204 Ok(expr)
205 }
206
207 Token::NumberLiteral(n) => {
208 trace!("Number literal: {}", n);
209 let expr = SqlExpression::NumberLiteral(n.clone());
210 ExpressionParser::advance(parser);
211 Ok(expr)
212 }
213
214 Token::Null => {
215 trace!("NULL literal");
216 ExpressionParser::advance(parser);
217 Ok(SqlExpression::Null)
218 }
219
220 Token::Left | Token::Right => {
222 let func_name = match ExpressionParser::current_token(parser) {
223 Token::Left => "LEFT".to_string(),
224 Token::Right => "RIGHT".to_string(),
225 _ => unreachable!(),
226 };
227
228 ExpressionParser::advance(parser);
229
230 if matches!(ExpressionParser::current_token(parser), Token::LeftParen) {
232 debug!(function = %func_name, "Parsing LEFT/RIGHT function call");
233 ExpressionParser::advance(parser); let (args, _has_distinct) = parser.parse_function_args()?;
235 ExpressionParser::consume(parser, Token::RightParen)?;
236
237 Ok(SqlExpression::FunctionCall {
238 name: func_name,
239 args,
240 distinct: false,
241 })
242 } else {
243 Err(format!(
245 "{} keyword unexpected in expression context",
246 func_name
247 ))
248 }
249 }
250
251 Token::LeftParen => {
252 debug!("Parsing parenthesized expression or subquery");
253 ExpressionParser::advance(parser); if matches!(ExpressionParser::current_token(parser), Token::Select) {
257 debug!("Detected subquery - parsing SELECT statement");
258 let subquery = parser.parse_subquery()?;
259 ExpressionParser::consume(parser, Token::RightParen)?;
260 Ok(SqlExpression::ScalarSubquery {
261 query: Box::new(subquery),
262 })
263 } else {
264 let first = parser.parse_logical_or()?;
267
268 if matches!(ExpressionParser::current_token(parser), Token::Comma) {
269 let mut exprs = vec![first];
271 while matches!(ExpressionParser::current_token(parser), Token::Comma) {
272 ExpressionParser::advance(parser); exprs.push(parser.parse_logical_or()?);
274 }
275 ExpressionParser::consume(parser, Token::RightParen)?;
276
277 match ExpressionParser::current_token(parser) {
279 Token::In => {
280 ExpressionParser::advance(parser); ExpressionParser::consume(parser, Token::LeftParen)?;
282 if !matches!(ExpressionParser::current_token(parser), Token::Select) {
283 return Err("Tuple IN requires a subquery on the right".to_string());
284 }
285 let subquery = parser.parse_subquery()?;
286 ExpressionParser::consume(parser, Token::RightParen)?;
287 Ok(SqlExpression::InSubqueryTuple {
288 exprs,
289 subquery: Box::new(subquery),
290 })
291 }
292 Token::Not => {
293 ExpressionParser::advance(parser); if !matches!(ExpressionParser::current_token(parser), Token::In) {
295 return Err("Expected IN after NOT for tuple".to_string());
296 }
297 ExpressionParser::advance(parser); ExpressionParser::consume(parser, Token::LeftParen)?;
299 if !matches!(ExpressionParser::current_token(parser), Token::Select) {
300 return Err(
301 "Tuple NOT IN requires a subquery on the right".to_string()
302 );
303 }
304 let subquery = parser.parse_subquery()?;
305 ExpressionParser::consume(parser, Token::RightParen)?;
306 Ok(SqlExpression::NotInSubqueryTuple {
307 exprs,
308 subquery: Box::new(subquery),
309 })
310 }
311 _ => Err(
312 "A tuple (expr, expr, ...) may only appear as the left side of IN / NOT IN"
313 .to_string(),
314 ),
315 }
316 } else {
317 debug!("Regular parenthesized expression");
319 ExpressionParser::consume(parser, Token::RightParen)?;
320 Ok(first)
321 }
322 }
323 }
324
325 Token::Not => {
326 debug!("Parsing NOT expression");
327 parse_not_expression(parser)
328 }
329
330 Token::Star => {
331 trace!("Star token as literal");
333 ExpressionParser::advance(parser);
334 Ok(SqlExpression::StringLiteral("*".to_string()))
335 }
336
337 Token::Row => {
339 trace!("ROW token treated as identifier in expression context");
340 ExpressionParser::advance(parser);
341 Ok(SqlExpression::Column(ColumnRef::unquoted(
342 "row".to_string(),
343 )))
344 }
345
346 Token::Rows => {
347 trace!("ROWS token treated as identifier in expression context");
348 ExpressionParser::advance(parser);
349 Ok(SqlExpression::Column(ColumnRef::unquoted(
350 "rows".to_string(),
351 )))
352 }
353
354 Token::Range => {
355 trace!("RANGE token treated as identifier in expression context");
356 ExpressionParser::advance(parser);
357 Ok(SqlExpression::Column(ColumnRef::unquoted(
358 "range".to_string(),
359 )))
360 }
361
362 Token::Minus => {
363 debug!("Parsing unary minus expression");
365 ExpressionParser::advance(parser);
366 let operand = parse_primary(parser, ctx)?;
367 Ok(SqlExpression::BinaryOp {
368 left: Box::new(SqlExpression::NumberLiteral("0".to_string())),
369 op: "-".to_string(),
370 right: Box::new(operand),
371 })
372 }
373
374 _ => {
375 let err = format!(
376 "Unexpected token in primary expression: {:?}",
377 ExpressionParser::current_token(parser)
378 );
379 debug!(error = %err);
380 Err(err)
381 }
382 };
383
384 trace_parse_exit("parse_primary", &result);
385 result
386}
387
388fn parse_datetime_constructor<P>(parser: &mut P) -> Result<SqlExpression, String>
390where
391 P: ParsePrimary + ExpressionParser + ?Sized,
392{
393 ExpressionParser::advance(parser); ExpressionParser::consume(parser, Token::LeftParen)?;
395
396 if matches!(ExpressionParser::current_token(parser), Token::RightParen) {
398 ExpressionParser::advance(parser); debug!("DateTime() - today's date");
400 return Ok(SqlExpression::DateTimeToday {
401 hour: None,
402 minute: None,
403 second: None,
404 });
405 }
406
407 let year = if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
409 n.parse::<i32>().map_err(|_| "Invalid year")?
410 } else {
411 return Err("Expected year in DateTime constructor".to_string());
412 };
413 ExpressionParser::advance(parser);
414 ExpressionParser::consume(parser, Token::Comma)?;
415
416 let month = if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
418 n.parse::<u32>().map_err(|_| "Invalid month")?
419 } else {
420 return Err("Expected month in DateTime constructor".to_string());
421 };
422 ExpressionParser::advance(parser);
423 ExpressionParser::consume(parser, Token::Comma)?;
424
425 let day = if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
427 n.parse::<u32>().map_err(|_| "Invalid day")?
428 } else {
429 return Err("Expected day in DateTime constructor".to_string());
430 };
431 ExpressionParser::advance(parser);
432
433 let mut hour = None;
435 let mut minute = None;
436 let mut second = None;
437
438 if matches!(ExpressionParser::current_token(parser), Token::Comma) {
439 ExpressionParser::advance(parser); if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
443 hour = Some(n.parse::<u32>().map_err(|_| "Invalid hour")?);
444 ExpressionParser::advance(parser);
445
446 if matches!(ExpressionParser::current_token(parser), Token::Comma) {
448 ExpressionParser::advance(parser); if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
451 minute = Some(n.parse::<u32>().map_err(|_| "Invalid minute")?);
452 ExpressionParser::advance(parser);
453
454 if matches!(ExpressionParser::current_token(parser), Token::Comma) {
456 ExpressionParser::advance(parser); if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
459 second = Some(n.parse::<u32>().map_err(|_| "Invalid second")?);
460 ExpressionParser::advance(parser);
461 }
462 }
463 }
464 }
465 }
466 }
467
468 ExpressionParser::consume(parser, Token::RightParen)?;
469
470 debug!(year = year, month = month, day = day, hour = ?hour, minute = ?minute, second = ?second, "DateTime constructor parsed");
471
472 Ok(SqlExpression::DateTimeConstructor {
473 year,
474 month,
475 day,
476 hour,
477 minute,
478 second,
479 })
480}
481
482fn parse_not_expression<P>(parser: &mut P) -> Result<SqlExpression, String>
484where
485 P: ParsePrimary + ExpressionParser + ?Sized,
486{
487 ExpressionParser::advance(parser); if let Ok(inner_expr) = parser.parse_comparison() {
491 if matches!(ExpressionParser::current_token(parser), Token::In) {
493 debug!("NOT IN expression detected");
494 ExpressionParser::advance(parser); ExpressionParser::consume(parser, Token::LeftParen)?;
496 let values = parser.parse_expression_list()?;
497 ExpressionParser::consume(parser, Token::RightParen)?;
498
499 Ok(SqlExpression::NotInList {
500 expr: Box::new(inner_expr),
501 values,
502 })
503 } else {
504 debug!("Regular NOT expression");
506 Ok(SqlExpression::Not {
507 expr: Box::new(inner_expr),
508 })
509 }
510 } else {
511 Err("Expected expression after NOT".to_string())
512 }
513}
514
515fn parse_unnest<P>(parser: &mut P) -> Result<SqlExpression, String>
518where
519 P: ParsePrimary + ExpressionParser + ?Sized,
520{
521 debug!("parse_unnest: starting");
522 ExpressionParser::advance(parser); ExpressionParser::consume(parser, Token::LeftParen)?;
524
525 let column = parser.parse_logical_or()?;
527 debug!("parse_unnest: parsed column expression");
528
529 ExpressionParser::consume(parser, Token::Comma)?;
531
532 let delimiter = match ExpressionParser::current_token(parser) {
534 Token::StringLiteral(s) => {
535 let delim = s.clone();
536 ExpressionParser::advance(parser);
537 delim
538 }
539 _ => {
540 return Err("UNNEST delimiter must be a string literal".to_string());
541 }
542 };
543
544 debug!(delimiter = %delimiter, "parse_unnest: parsed delimiter");
545
546 ExpressionParser::consume(parser, Token::RightParen)?;
547
548 debug!("parse_unnest: complete");
549 Ok(SqlExpression::Unnest {
550 column: Box::new(column),
551 delimiter,
552 })
553}
554
555pub trait ParsePrimary {
557 fn current_token(&self) -> &Token;
558 fn advance(&mut self);
559 fn consume(&mut self, expected: Token) -> Result<(), String>;
560
561 fn parse_case_expression(&mut self) -> Result<SqlExpression, String>;
563 fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String>;
564 fn parse_window_spec(&mut self) -> Result<WindowSpec, String>;
565 fn parse_logical_or(&mut self) -> Result<SqlExpression, String>;
566 fn parse_comparison(&mut self) -> Result<SqlExpression, String>;
567 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String>;
568
569 fn parse_subquery(&mut self) -> Result<crate::sql::parser::ast::SelectStatement, String>;
571}