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::LeftParen => {
169 debug!("Parsing parenthesized expression or subquery");
170 parser.advance(); if matches!(parser.current_token(), Token::Select) {
174 debug!("Detected subquery - parsing SELECT statement");
175 let subquery = parser.parse_subquery()?;
176 parser.consume(Token::RightParen)?;
177 Ok(SqlExpression::ScalarSubquery {
178 query: Box::new(subquery),
179 })
180 } else {
181 debug!("Regular parenthesized expression");
183 let expr = parser.parse_logical_or()?;
184 parser.consume(Token::RightParen)?;
185 Ok(expr)
186 }
187 }
188
189 Token::Not => {
190 debug!("Parsing NOT expression");
191 parse_not_expression(parser)
192 }
193
194 Token::Star => {
195 trace!("Star token as literal");
197 parser.advance();
198 Ok(SqlExpression::StringLiteral("*".to_string()))
199 }
200
201 _ => {
202 let err = format!(
203 "Unexpected token in primary expression: {:?}",
204 parser.current_token()
205 );
206 debug!(error = %err);
207 Err(err)
208 }
209 };
210
211 trace_parse_exit("parse_primary", &result);
212 result
213}
214
215fn parse_datetime_constructor<P>(parser: &mut P) -> Result<SqlExpression, String>
217where
218 P: ParsePrimary + ?Sized,
219{
220 parser.advance(); parser.consume(Token::LeftParen)?;
222
223 if matches!(parser.current_token(), Token::RightParen) {
225 parser.advance(); debug!("DateTime() - today's date");
227 return Ok(SqlExpression::DateTimeToday {
228 hour: None,
229 minute: None,
230 second: None,
231 });
232 }
233
234 let year = if let Token::NumberLiteral(n) = parser.current_token() {
236 n.parse::<i32>().map_err(|_| "Invalid year")?
237 } else {
238 return Err("Expected year in DateTime constructor".to_string());
239 };
240 parser.advance();
241 parser.consume(Token::Comma)?;
242
243 let month = if let Token::NumberLiteral(n) = parser.current_token() {
245 n.parse::<u32>().map_err(|_| "Invalid month")?
246 } else {
247 return Err("Expected month in DateTime constructor".to_string());
248 };
249 parser.advance();
250 parser.consume(Token::Comma)?;
251
252 let day = if let Token::NumberLiteral(n) = parser.current_token() {
254 n.parse::<u32>().map_err(|_| "Invalid day")?
255 } else {
256 return Err("Expected day in DateTime constructor".to_string());
257 };
258 parser.advance();
259
260 let mut hour = None;
262 let mut minute = None;
263 let mut second = None;
264
265 if matches!(parser.current_token(), Token::Comma) {
266 parser.advance(); if let Token::NumberLiteral(n) = parser.current_token() {
270 hour = Some(n.parse::<u32>().map_err(|_| "Invalid hour")?);
271 parser.advance();
272
273 if matches!(parser.current_token(), Token::Comma) {
275 parser.advance(); if let Token::NumberLiteral(n) = parser.current_token() {
278 minute = Some(n.parse::<u32>().map_err(|_| "Invalid minute")?);
279 parser.advance();
280
281 if matches!(parser.current_token(), Token::Comma) {
283 parser.advance(); if let Token::NumberLiteral(n) = parser.current_token() {
286 second = Some(n.parse::<u32>().map_err(|_| "Invalid second")?);
287 parser.advance();
288 }
289 }
290 }
291 }
292 }
293 }
294
295 parser.consume(Token::RightParen)?;
296
297 debug!(year = year, month = month, day = day, hour = ?hour, minute = ?minute, second = ?second, "DateTime constructor parsed");
298
299 Ok(SqlExpression::DateTimeConstructor {
300 year,
301 month,
302 day,
303 hour,
304 minute,
305 second,
306 })
307}
308
309fn parse_not_expression<P>(parser: &mut P) -> Result<SqlExpression, String>
311where
312 P: ParsePrimary + ?Sized,
313{
314 parser.advance(); if let Ok(inner_expr) = parser.parse_comparison() {
318 if matches!(parser.current_token(), Token::In) {
320 debug!("NOT IN expression detected");
321 parser.advance(); parser.consume(Token::LeftParen)?;
323 let values = parser.parse_expression_list()?;
324 parser.consume(Token::RightParen)?;
325
326 Ok(SqlExpression::NotInList {
327 expr: Box::new(inner_expr),
328 values,
329 })
330 } else {
331 debug!("Regular NOT expression");
333 Ok(SqlExpression::Not {
334 expr: Box::new(inner_expr),
335 })
336 }
337 } else {
338 Err("Expected expression after NOT".to_string())
339 }
340}
341
342pub trait ParsePrimary {
344 fn current_token(&self) -> &Token;
345 fn advance(&mut self);
346 fn consume(&mut self, expected: Token) -> Result<(), String>;
347
348 fn parse_case_expression(&mut self) -> Result<SqlExpression, String>;
350 fn parse_function_args(&mut self) -> Result<(Vec<SqlExpression>, bool), String>;
351 fn parse_window_spec(&mut self) -> Result<WindowSpec, String>;
352 fn parse_logical_or(&mut self) -> Result<SqlExpression, String>;
353 fn parse_comparison(&mut self) -> Result<SqlExpression, String>;
354 fn parse_expression_list(&mut self) -> Result<Vec<SqlExpression>, String>;
355
356 fn parse_subquery(&mut self) -> Result<crate::sql::parser::ast::SelectStatement, String>;
358}