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("row".to_string())))
284 }
285
286 Token::Rows => {
287 trace!("ROWS token treated as identifier in expression context");
288 ExpressionParser::advance(parser);
289 Ok(SqlExpression::Column(ColumnRef::unquoted("rows".to_string())))
290 }
291
292 Token::Range => {
293 trace!("RANGE token treated as identifier in expression context");
294 ExpressionParser::advance(parser);
295 Ok(SqlExpression::Column(ColumnRef::unquoted("range".to_string())))
296 }
297
298 _ => {
299 let err = format!(
300 "Unexpected token in primary expression: {:?}",
301 ExpressionParser::current_token(parser)
302 );
303 debug!(error = %err);
304 Err(err)
305 }
306 };
307
308 trace_parse_exit("parse_primary", &result);
309 result
310}
311
312fn parse_datetime_constructor<P>(parser: &mut P) -> Result<SqlExpression, String>
314where
315 P: ParsePrimary + ExpressionParser + ?Sized,
316{
317 ExpressionParser::advance(parser); ExpressionParser::consume(parser, Token::LeftParen)?;
319
320 if matches!(ExpressionParser::current_token(parser), Token::RightParen) {
322 ExpressionParser::advance(parser); debug!("DateTime() - today's date");
324 return Ok(SqlExpression::DateTimeToday {
325 hour: None,
326 minute: None,
327 second: None,
328 });
329 }
330
331 let year = if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
333 n.parse::<i32>().map_err(|_| "Invalid year")?
334 } else {
335 return Err("Expected year in DateTime constructor".to_string());
336 };
337 ExpressionParser::advance(parser);
338 ExpressionParser::consume(parser, Token::Comma)?;
339
340 let month = if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
342 n.parse::<u32>().map_err(|_| "Invalid month")?
343 } else {
344 return Err("Expected month in DateTime constructor".to_string());
345 };
346 ExpressionParser::advance(parser);
347 ExpressionParser::consume(parser, Token::Comma)?;
348
349 let day = if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
351 n.parse::<u32>().map_err(|_| "Invalid day")?
352 } else {
353 return Err("Expected day in DateTime constructor".to_string());
354 };
355 ExpressionParser::advance(parser);
356
357 let mut hour = None;
359 let mut minute = None;
360 let mut second = None;
361
362 if matches!(ExpressionParser::current_token(parser), Token::Comma) {
363 ExpressionParser::advance(parser); if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
367 hour = Some(n.parse::<u32>().map_err(|_| "Invalid hour")?);
368 ExpressionParser::advance(parser);
369
370 if matches!(ExpressionParser::current_token(parser), Token::Comma) {
372 ExpressionParser::advance(parser); if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
375 minute = Some(n.parse::<u32>().map_err(|_| "Invalid minute")?);
376 ExpressionParser::advance(parser);
377
378 if matches!(ExpressionParser::current_token(parser), Token::Comma) {
380 ExpressionParser::advance(parser); if let Token::NumberLiteral(n) = ExpressionParser::current_token(parser) {
383 second = Some(n.parse::<u32>().map_err(|_| "Invalid second")?);
384 ExpressionParser::advance(parser);
385 }
386 }
387 }
388 }
389 }
390 }
391
392 ExpressionParser::consume(parser, Token::RightParen)?;
393
394 debug!(year = year, month = month, day = day, hour = ?hour, minute = ?minute, second = ?second, "DateTime constructor parsed");
395
396 Ok(SqlExpression::DateTimeConstructor {
397 year,
398 month,
399 day,
400 hour,
401 minute,
402 second,
403 })
404}
405
406fn parse_not_expression<P>(parser: &mut P) -> Result<SqlExpression, String>
408where
409 P: ParsePrimary + ExpressionParser + ?Sized,
410{
411 ExpressionParser::advance(parser); if let Ok(inner_expr) = parser.parse_comparison() {
415 if matches!(ExpressionParser::current_token(parser), Token::In) {
417 debug!("NOT IN expression detected");
418 ExpressionParser::advance(parser); ExpressionParser::consume(parser, Token::LeftParen)?;
420 let values = parser.parse_expression_list()?;
421 ExpressionParser::consume(parser, Token::RightParen)?;
422
423 Ok(SqlExpression::NotInList {
424 expr: Box::new(inner_expr),
425 values,
426 })
427 } else {
428 debug!("Regular NOT expression");
430 Ok(SqlExpression::Not {
431 expr: Box::new(inner_expr),
432 })
433 }
434 } else {
435 Err("Expected expression after NOT".to_string())
436 }
437}
438
439pub trait ParsePrimary {
441 fn current_token(&self) -> &Token;
442 fn advance(&mut self);
443 fn consume(&mut self, expected: Token) -> Result<(), String>;
444
445 fn parse_case_expression(&mut self) -> Result<SqlExpression, String>;
447 fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String>;
448 fn parse_window_spec(&mut self) -> Result<WindowSpec, String>;
449 fn parse_logical_or(&mut self) -> Result<SqlExpression, String>;
450 fn parse_comparison(&mut self) -> Result<SqlExpression, String>;
451 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String>;
452
453 fn parse_subquery(&mut self) -> Result<crate::sql::parser::ast::SelectStatement, String>;
455}