sql_cli/sql/parser/expressions/
primary.rs1use crate::sql::parser::ast::{SqlExpression, WindowSpec};
5use crate::sql::parser::lexer::Token;
6use tracing::{debug, trace};
7
8use super::{log_parse_decision, trace_parse_entry, trace_parse_exit};
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 + ?Sized,
33{
34 trace_parse_entry("parse_primary", parser.current_token());
35
36 if let Token::NumberLiteral(num_str) = parser.current_token() {
39 if ctx.columns.iter().any(|col| col == num_str) {
40 log_parse_decision(
41 "parse_primary",
42 parser.current_token(),
43 "Number literal matches column name, treating as column",
44 );
45 let expr = SqlExpression::Column(num_str.clone());
46 parser.advance();
47 let result = Ok(expr);
48 trace_parse_exit("parse_primary", &result);
49 return result;
50 }
51 }
52
53 let result = match parser.current_token() {
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 parser.current_token(),
73 "Boolean literal TRUE",
74 );
75 parser.advance();
76 Ok(SqlExpression::BooleanLiteral(true))
77 } else if id_upper == "FALSE" {
78 log_parse_decision(
79 "parse_primary",
80 parser.current_token(),
81 "Boolean literal FALSE",
82 );
83 parser.advance();
84 Ok(SqlExpression::BooleanLiteral(false))
85 } else {
86 parser.advance();
87
88 if matches!(parser.current_token(), Token::LeftParen) {
90 debug!(function = %id_upper, "Parsing function call");
91 parser.advance(); let (args, has_distinct) = parser.parse_function_args()?;
93 parser.consume(Token::RightParen)?;
94
95 if matches!(parser.current_token(), Token::Over) {
97 debug!(function = %id_upper, "Window function detected");
98 parser.advance(); parser.consume(Token::LeftParen)?;
100 let window_spec = parser.parse_window_spec()?;
101 parser.consume(Token::RightParen)?;
102 Ok(SqlExpression::WindowFunction {
103 name: id_upper,
104 args,
105 window_spec,
106 })
107 } else {
108 Ok(SqlExpression::FunctionCall {
109 name: id_upper,
110 args,
111 distinct: has_distinct,
112 })
113 }
114 } else {
115 log_parse_decision(
117 "parse_primary",
118 &Token::Identifier(id_clone.clone()),
119 "Column reference",
120 );
121 Ok(SqlExpression::Column(id_clone))
122 }
123 }
124 }
125
126 Token::QuotedIdentifier(id) => {
127 let expr = if ctx.in_method_args {
128 log_parse_decision(
130 "parse_primary",
131 parser.current_token(),
132 "Quoted identifier in method args - treating as string",
133 );
134 SqlExpression::StringLiteral(id.clone())
135 } else {
136 log_parse_decision(
138 "parse_primary",
139 parser.current_token(),
140 "Quoted identifier as column name",
141 );
142 SqlExpression::Column(id.clone())
143 };
144 parser.advance();
145 Ok(expr)
146 }
147
148 Token::StringLiteral(s) => {
149 trace!("String literal: {}", s);
150 let expr = SqlExpression::StringLiteral(s.clone());
151 parser.advance();
152 Ok(expr)
153 }
154
155 Token::NumberLiteral(n) => {
156 trace!("Number literal: {}", n);
157 let expr = SqlExpression::NumberLiteral(n.clone());
158 parser.advance();
159 Ok(expr)
160 }
161
162 Token::Null => {
163 trace!("NULL literal");
164 parser.advance();
165 Ok(SqlExpression::Null)
166 }
167
168 Token::Left | Token::Right => {
170 let func_name = match parser.current_token() {
171 Token::Left => "LEFT".to_string(),
172 Token::Right => "RIGHT".to_string(),
173 _ => unreachable!(),
174 };
175
176 parser.advance();
177
178 if matches!(parser.current_token(), Token::LeftParen) {
180 debug!(function = %func_name, "Parsing LEFT/RIGHT function call");
181 parser.advance(); let (args, _has_distinct) = parser.parse_function_args()?;
183 parser.consume(Token::RightParen)?;
184
185 Ok(SqlExpression::FunctionCall {
186 name: func_name,
187 args,
188 distinct: false,
189 })
190 } else {
191 Err(format!(
193 "{} keyword unexpected in expression context",
194 func_name
195 ))
196 }
197 }
198
199 Token::LeftParen => {
200 debug!("Parsing parenthesized expression or subquery");
201 parser.advance(); if matches!(parser.current_token(), Token::Select) {
205 debug!("Detected subquery - parsing SELECT statement");
206 let subquery = parser.parse_subquery()?;
207 parser.consume(Token::RightParen)?;
208 Ok(SqlExpression::ScalarSubquery {
209 query: Box::new(subquery),
210 })
211 } else {
212 debug!("Regular parenthesized expression");
214 let expr = parser.parse_logical_or()?;
215 parser.consume(Token::RightParen)?;
216 Ok(expr)
217 }
218 }
219
220 Token::Not => {
221 debug!("Parsing NOT expression");
222 parse_not_expression(parser)
223 }
224
225 Token::Star => {
226 trace!("Star token as literal");
228 parser.advance();
229 Ok(SqlExpression::StringLiteral("*".to_string()))
230 }
231
232 _ => {
233 let err = format!(
234 "Unexpected token in primary expression: {:?}",
235 parser.current_token()
236 );
237 debug!(error = %err);
238 Err(err)
239 }
240 };
241
242 trace_parse_exit("parse_primary", &result);
243 result
244}
245
246fn parse_datetime_constructor<P>(parser: &mut P) -> Result<SqlExpression, String>
248where
249 P: ParsePrimary + ?Sized,
250{
251 parser.advance(); parser.consume(Token::LeftParen)?;
253
254 if matches!(parser.current_token(), Token::RightParen) {
256 parser.advance(); debug!("DateTime() - today's date");
258 return Ok(SqlExpression::DateTimeToday {
259 hour: None,
260 minute: None,
261 second: None,
262 });
263 }
264
265 let year = if let Token::NumberLiteral(n) = parser.current_token() {
267 n.parse::<i32>().map_err(|_| "Invalid year")?
268 } else {
269 return Err("Expected year in DateTime constructor".to_string());
270 };
271 parser.advance();
272 parser.consume(Token::Comma)?;
273
274 let month = if let Token::NumberLiteral(n) = parser.current_token() {
276 n.parse::<u32>().map_err(|_| "Invalid month")?
277 } else {
278 return Err("Expected month in DateTime constructor".to_string());
279 };
280 parser.advance();
281 parser.consume(Token::Comma)?;
282
283 let day = if let Token::NumberLiteral(n) = parser.current_token() {
285 n.parse::<u32>().map_err(|_| "Invalid day")?
286 } else {
287 return Err("Expected day in DateTime constructor".to_string());
288 };
289 parser.advance();
290
291 let mut hour = None;
293 let mut minute = None;
294 let mut second = None;
295
296 if matches!(parser.current_token(), Token::Comma) {
297 parser.advance(); if let Token::NumberLiteral(n) = parser.current_token() {
301 hour = Some(n.parse::<u32>().map_err(|_| "Invalid hour")?);
302 parser.advance();
303
304 if matches!(parser.current_token(), Token::Comma) {
306 parser.advance(); if let Token::NumberLiteral(n) = parser.current_token() {
309 minute = Some(n.parse::<u32>().map_err(|_| "Invalid minute")?);
310 parser.advance();
311
312 if matches!(parser.current_token(), Token::Comma) {
314 parser.advance(); if let Token::NumberLiteral(n) = parser.current_token() {
317 second = Some(n.parse::<u32>().map_err(|_| "Invalid second")?);
318 parser.advance();
319 }
320 }
321 }
322 }
323 }
324 }
325
326 parser.consume(Token::RightParen)?;
327
328 debug!(year = year, month = month, day = day, hour = ?hour, minute = ?minute, second = ?second, "DateTime constructor parsed");
329
330 Ok(SqlExpression::DateTimeConstructor {
331 year,
332 month,
333 day,
334 hour,
335 minute,
336 second,
337 })
338}
339
340fn parse_not_expression<P>(parser: &mut P) -> Result<SqlExpression, String>
342where
343 P: ParsePrimary + ?Sized,
344{
345 parser.advance(); if let Ok(inner_expr) = parser.parse_comparison() {
349 if matches!(parser.current_token(), Token::In) {
351 debug!("NOT IN expression detected");
352 parser.advance(); parser.consume(Token::LeftParen)?;
354 let values = parser.parse_expression_list()?;
355 parser.consume(Token::RightParen)?;
356
357 Ok(SqlExpression::NotInList {
358 expr: Box::new(inner_expr),
359 values,
360 })
361 } else {
362 debug!("Regular NOT expression");
364 Ok(SqlExpression::Not {
365 expr: Box::new(inner_expr),
366 })
367 }
368 } else {
369 Err("Expected expression after NOT".to_string())
370 }
371}
372
373pub trait ParsePrimary {
375 fn current_token(&self) -> &Token;
376 fn advance(&mut self);
377 fn consume(&mut self, expected: Token) -> Result<(), String>;
378
379 fn parse_case_expression(&mut self) -> Result<SqlExpression, String>;
381 fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String>;
382 fn parse_window_spec(&mut self) -> Result<WindowSpec, String>;
383 fn parse_logical_or(&mut self) -> Result<SqlExpression, String>;
384 fn parse_comparison(&mut self) -> Result<SqlExpression, String>;
385 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String>;
386
387 fn parse_subquery(&mut self) -> Result<crate::sql::parser::ast::SelectStatement, String>;
389}