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::Identifier(id) => {
65 let id_upper = id.to_uppercase();
66 let id_clone = id.clone();
67
68 if id_upper == "TRUE" {
70 log_parse_decision(
71 "parse_primary",
72 ExpressionParser::current_token(parser),
73 "Boolean literal TRUE",
74 );
75 ExpressionParser::advance(parser);
76 Ok(SqlExpression::BooleanLiteral(true))
77 } else if id_upper == "FALSE" {
78 log_parse_decision(
79 "parse_primary",
80 ExpressionParser::current_token(parser),
81 "Boolean literal FALSE",
82 );
83 ExpressionParser::advance(parser);
84 Ok(SqlExpression::BooleanLiteral(false))
85 } else {
86 ExpressionParser::advance(parser);
87
88 if matches!(ExpressionParser::current_token(parser), Token::Dot) {
90 ExpressionParser::advance(parser); if let Token::Identifier(next_id) = ExpressionParser::current_token(parser) {
93 let next_id = next_id.clone();
94 ExpressionParser::advance(parser);
95
96 if matches!(ExpressionParser::current_token(parser), Token::LeftParen) {
98 debug!(object = %id_clone, method = %next_id, "Parsing method call");
99 ExpressionParser::advance(parser); let args = if matches!(
103 ExpressionParser::current_token(parser),
104 Token::RightParen
105 ) {
106 Vec::new()
107 } else {
108 parser.parse_expression_list()?
109 };
110 ExpressionParser::consume(parser, Token::RightParen)?;
111
112 log_parse_decision(
113 "parse_primary",
114 &Token::Identifier(next_id.clone()),
115 "Method call",
116 );
117 Ok(SqlExpression::MethodCall {
118 object: id_clone,
119 method: next_id,
120 args,
121 })
122 } else {
123 let col_ref = ColumnRef::qualified(id_clone, next_id.clone());
125 log_parse_decision(
126 "parse_primary",
127 &Token::Identifier(next_id),
128 "Qualified column reference",
129 );
130 Ok(SqlExpression::Column(col_ref))
131 }
132 } else {
133 Err("Expected identifier after '.'".to_string())
134 }
135 } else if matches!(ExpressionParser::current_token(parser), Token::LeftParen) {
137 debug!(function = %id_upper, "Parsing function call");
138 ExpressionParser::advance(parser); let (args, has_distinct) = parser.parse_function_args()?;
140 ExpressionParser::consume(parser, Token::RightParen)?;
141
142 if matches!(ExpressionParser::current_token(parser), Token::Over) {
144 debug!(function = %id_upper, "Window function detected");
145 ExpressionParser::advance(parser); ExpressionParser::consume(parser, Token::LeftParen)?;
147 let window_spec = parser.parse_window_spec()?;
148 ExpressionParser::consume(parser, Token::RightParen)?;
149 Ok(SqlExpression::WindowFunction {
150 name: id_upper,
151 args,
152 window_spec,
153 })
154 } else {
155 Ok(SqlExpression::FunctionCall {
156 name: id_upper,
157 args,
158 distinct: has_distinct,
159 })
160 }
161 } else {
162 log_parse_decision(
164 "parse_primary",
165 &Token::Identifier(id_clone.clone()),
166 "Column reference",
167 );
168 Ok(SqlExpression::Column(ColumnRef::unquoted(id_clone)))
169 }
170 }
171 }
172
173 Token::QuotedIdentifier(id) => {
174 let expr = if ctx.in_method_args {
175 log_parse_decision(
177 "parse_primary",
178 ExpressionParser::current_token(parser),
179 "Quoted identifier in method args - treating as string",
180 );
181 SqlExpression::StringLiteral(id.clone())
182 } else {
183 log_parse_decision(
185 "parse_primary",
186 ExpressionParser::current_token(parser),
187 "Quoted identifier as column name",
188 );
189 SqlExpression::Column(ColumnRef::quoted(id.clone()))
190 };
191 ExpressionParser::advance(parser);
192 Ok(expr)
193 }
194
195 Token::StringLiteral(s) => {
196 trace!("String literal: {}", s);
197 let expr = SqlExpression::StringLiteral(s.clone());
198 ExpressionParser::advance(parser);
199 Ok(expr)
200 }
201
202 Token::NumberLiteral(n) => {
203 trace!("Number literal: {}", n);
204 let expr = SqlExpression::NumberLiteral(n.clone());
205 ExpressionParser::advance(parser);
206 Ok(expr)
207 }
208
209 Token::Null => {
210 trace!("NULL literal");
211 ExpressionParser::advance(parser);
212 Ok(SqlExpression::Null)
213 }
214
215 Token::Left | Token::Right => {
217 let func_name = match ExpressionParser::current_token(parser) {
218 Token::Left => "LEFT".to_string(),
219 Token::Right => "RIGHT".to_string(),
220 _ => unreachable!(),
221 };
222
223 ExpressionParser::advance(parser);
224
225 if matches!(ExpressionParser::current_token(parser), Token::LeftParen) {
227 debug!(function = %func_name, "Parsing LEFT/RIGHT function call");
228 ExpressionParser::advance(parser); let (args, _has_distinct) = parser.parse_function_args()?;
230 ExpressionParser::consume(parser, Token::RightParen)?;
231
232 Ok(SqlExpression::FunctionCall {
233 name: func_name,
234 args,
235 distinct: false,
236 })
237 } else {
238 Err(format!(
240 "{} keyword unexpected in expression context",
241 func_name
242 ))
243 }
244 }
245
246 Token::LeftParen => {
247 debug!("Parsing parenthesized expression or subquery");
248 ExpressionParser::advance(parser); if matches!(ExpressionParser::current_token(parser), Token::Select) {
252 debug!("Detected subquery - parsing SELECT statement");
253 let subquery = parser.parse_subquery()?;
254 ExpressionParser::consume(parser, Token::RightParen)?;
255 Ok(SqlExpression::ScalarSubquery {
256 query: Box::new(subquery),
257 })
258 } else {
259 debug!("Regular parenthesized expression");
261 let expr = parser.parse_logical_or()?;
262 ExpressionParser::consume(parser, Token::RightParen)?;
263 Ok(expr)
264 }
265 }
266
267 Token::Not => {
268 debug!("Parsing NOT expression");
269 parse_not_expression(parser)
270 }
271
272 Token::Star => {
273 trace!("Star token as literal");
275 ExpressionParser::advance(parser);
276 Ok(SqlExpression::StringLiteral("*".to_string()))
277 }
278
279 Token::Row => {
281 trace!("ROW token treated as identifier in expression context");
282 ExpressionParser::advance(parser);
283 Ok(SqlExpression::Column(ColumnRef::unquoted(
284 "row".to_string(),
285 )))
286 }
287
288 Token::Rows => {
289 trace!("ROWS token treated as identifier in expression context");
290 ExpressionParser::advance(parser);
291 Ok(SqlExpression::Column(ColumnRef::unquoted(
292 "rows".to_string(),
293 )))
294 }
295
296 Token::Range => {
297 trace!("RANGE token treated as identifier in expression context");
298 ExpressionParser::advance(parser);
299 Ok(SqlExpression::Column(ColumnRef::unquoted(
300 "range".to_string(),
301 )))
302 }
303
304 _ => {
305 let err = format!(
306 "Unexpected token in primary expression: {:?}",
307 ExpressionParser::current_token(parser)
308 );
309 debug!(error = %err);
310 Err(err)
311 }
312 };
313
314 trace_parse_exit("parse_primary", &result);
315 result
316}
317
318fn parse_datetime_constructor<P>(parser: &mut P) -> Result<SqlExpression, String>
320where
321 P: ParsePrimary + ExpressionParser + ?Sized,
322{
323 ExpressionParser::advance(parser); ExpressionParser::consume(parser, Token::LeftParen)?;
325
326 if matches!(ExpressionParser::current_token(parser), Token::RightParen) {
328 ExpressionParser::advance(parser); debug!("DateTime() - today's date");
330 return Ok(SqlExpression::DateTimeToday {
331 hour: None,
332 minute: None,
333 second: None,
334 });
335 }
336
337 let year = if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
339 n.parse::<i32>().map_err(|_| "Invalid year")?
340 } else {
341 return Err("Expected year in DateTime constructor".to_string());
342 };
343 ExpressionParser::advance(parser);
344 ExpressionParser::consume(parser, Token::Comma)?;
345
346 let month = if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
348 n.parse::<u32>().map_err(|_| "Invalid month")?
349 } else {
350 return Err("Expected month in DateTime constructor".to_string());
351 };
352 ExpressionParser::advance(parser);
353 ExpressionParser::consume(parser, Token::Comma)?;
354
355 let day = if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
357 n.parse::<u32>().map_err(|_| "Invalid day")?
358 } else {
359 return Err("Expected day in DateTime constructor".to_string());
360 };
361 ExpressionParser::advance(parser);
362
363 let mut hour = None;
365 let mut minute = None;
366 let mut second = None;
367
368 if matches!(ExpressionParser::current_token(parser), Token::Comma) {
369 ExpressionParser::advance(parser); if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
373 hour = Some(n.parse::<u32>().map_err(|_| "Invalid hour")?);
374 ExpressionParser::advance(parser);
375
376 if matches!(ExpressionParser::current_token(parser), Token::Comma) {
378 ExpressionParser::advance(parser); if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
381 minute = Some(n.parse::<u32>().map_err(|_| "Invalid minute")?);
382 ExpressionParser::advance(parser);
383
384 if matches!(ExpressionParser::current_token(parser), Token::Comma) {
386 ExpressionParser::advance(parser); if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
389 second = Some(n.parse::<u32>().map_err(|_| "Invalid second")?);
390 ExpressionParser::advance(parser);
391 }
392 }
393 }
394 }
395 }
396 }
397
398 ExpressionParser::consume(parser, Token::RightParen)?;
399
400 debug!(year = year, month = month, day = day, hour = ?hour, minute = ?minute, second = ?second, "DateTime constructor parsed");
401
402 Ok(SqlExpression::DateTimeConstructor {
403 year,
404 month,
405 day,
406 hour,
407 minute,
408 second,
409 })
410}
411
412fn parse_not_expression<P>(parser: &mut P) -> Result<SqlExpression, String>
414where
415 P: ParsePrimary + ExpressionParser + ?Sized,
416{
417 ExpressionParser::advance(parser); if let Ok(inner_expr) = parser.parse_comparison() {
421 if matches!(ExpressionParser::current_token(parser), Token::In) {
423 debug!("NOT IN expression detected");
424 ExpressionParser::advance(parser); ExpressionParser::consume(parser, Token::LeftParen)?;
426 let values = parser.parse_expression_list()?;
427 ExpressionParser::consume(parser, Token::RightParen)?;
428
429 Ok(SqlExpression::NotInList {
430 expr: Box::new(inner_expr),
431 values,
432 })
433 } else {
434 debug!("Regular NOT expression");
436 Ok(SqlExpression::Not {
437 expr: Box::new(inner_expr),
438 })
439 }
440 } else {
441 Err("Expected expression after NOT".to_string())
442 }
443}
444
445pub trait ParsePrimary {
447 fn current_token(&self) -> &Token;
448 fn advance(&mut self);
449 fn consume(&mut self, expected: Token) -> Result<(), String>;
450
451 fn parse_case_expression(&mut self) -> Result<SqlExpression, String>;
453 fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String>;
454 fn parse_window_spec(&mut self) -> Result<WindowSpec, String>;
455 fn parse_logical_or(&mut self) -> Result<SqlExpression, String>;
456 fn parse_comparison(&mut self) -> Result<SqlExpression, String>;
457 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String>;
458
459 fn parse_subquery(&mut self) -> Result<crate::sql::parser::ast::SelectStatement, String>;
461}