1use super::util::parse_placeholder;
4use crate::expr::{AggregateFunction, BinaryOp, Expr, UnaryOp};
5use crate::planner::Planner;
6use featherdb_core::{Error, Result, Value};
7use sqlparser::ast::{self, DateTimeField, Expr as SqlExpr, SelectItem};
8
9impl<'a> Planner<'a> {
10 pub(super) fn convert_select_item(&self, item: &SelectItem) -> Result<Vec<(Expr, String)>> {
12 match item {
13 SelectItem::UnnamedExpr(e) => {
14 let expr = self.convert_expr(e)?;
15 let name = format!("{}", e);
16 Ok(vec![(expr, name)])
17 }
18 SelectItem::ExprWithAlias { expr, alias } => {
19 let e = self.convert_expr(expr)?;
20 Ok(vec![(e, alias.value.clone())])
21 }
22 SelectItem::QualifiedWildcard(name, _) => {
23 let table = name.0.first().map(|i| i.value.clone()).unwrap_or_default();
24 Ok(vec![(
25 Expr::QualifiedWildcard(table.clone()),
26 format!("{}.*", table),
27 )])
28 }
29 SelectItem::Wildcard(_) => Ok(vec![(Expr::Wildcard, "*".to_string())]),
30 }
31 }
32
33 pub fn convert_expr(&self, expr: &SqlExpr) -> Result<Expr> {
35 match expr {
38 SqlExpr::Identifier(ident) => Ok(Expr::Column {
39 table: None,
40 name: ident.value.clone(),
41 index: None,
42 }),
43
44 SqlExpr::CompoundIdentifier(parts) => {
45 if parts.len() == 2 {
46 Ok(Expr::Column {
47 table: Some(parts[0].value.clone()),
48 name: parts[1].value.clone(),
49 index: None,
50 })
51 } else {
52 Err(Error::InvalidQuery {
53 message: format!("Invalid identifier: {:?}", parts),
54 })
55 }
56 }
57
58 SqlExpr::Value(ast::Value::Placeholder(placeholder)) => {
60 let index = parse_placeholder(placeholder)?;
61 Ok(Expr::Parameter { index })
62 }
63
64 SqlExpr::Value(v) => Ok(Expr::Literal(self.convert_value(v)?)),
65
66 SqlExpr::BinaryOp { left, op, right } => {
67 let l = self.convert_expr(left)?;
68 let r = self.convert_expr(right)?;
69 let op = self.convert_binary_op(op)?;
70 Ok(Expr::BinaryOp {
71 left: Box::new(l),
72 op,
73 right: Box::new(r),
74 })
75 }
76
77 SqlExpr::UnaryOp { op, expr } => {
78 let e = self.convert_expr(expr)?;
79 let op = match op {
80 ast::UnaryOperator::Not => UnaryOp::Not,
81 ast::UnaryOperator::Minus => UnaryOp::Negate,
82 _ => {
83 return Err(Error::Unsupported {
84 feature: format!("Unary operator: {:?}", op),
85 })
86 }
87 };
88 Ok(Expr::UnaryOp {
89 op,
90 expr: Box::new(e),
91 })
92 }
93
94 SqlExpr::IsNull(e) => Ok(Expr::UnaryOp {
95 op: UnaryOp::IsNull,
96 expr: Box::new(self.convert_expr(e)?),
97 }),
98
99 SqlExpr::IsNotNull(e) => Ok(Expr::UnaryOp {
100 op: UnaryOp::IsNotNull,
101 expr: Box::new(self.convert_expr(e)?),
102 }),
103
104 SqlExpr::Between {
105 expr,
106 low,
107 high,
108 negated,
109 } => Ok(Expr::Between {
110 expr: Box::new(self.convert_expr(expr)?),
111 low: Box::new(self.convert_expr(low)?),
112 high: Box::new(self.convert_expr(high)?),
113 negated: *negated,
114 }),
115
116 SqlExpr::InList {
117 expr,
118 list,
119 negated,
120 } => {
121 let e = self.convert_expr(expr)?;
122 let l: Vec<Expr> = list
123 .iter()
124 .map(|i| self.convert_expr(i))
125 .collect::<Result<_>>()?;
126 Ok(Expr::InList {
127 expr: Box::new(e),
128 list: l,
129 negated: *negated,
130 })
131 }
132
133 SqlExpr::Like {
134 expr,
135 pattern,
136 negated,
137 ..
138 } => {
139 let e = self.convert_expr(expr)?;
140 let p = match pattern.as_ref() {
141 SqlExpr::Value(ast::Value::SingleQuotedString(s)) => s.clone(),
142 _ => format!("{}", pattern),
143 };
144 Ok(Expr::Like {
145 expr: Box::new(e),
146 pattern: p,
147 negated: *negated,
148 })
149 }
150
151 SqlExpr::Function(func) => {
152 let name = func
153 .name
154 .0
155 .first()
156 .map(|i| i.value.clone())
157 .unwrap_or_default();
158
159 if func.over.is_some() {
161 return self.convert_window_function(func);
162 }
163
164 let agg_func = match name.to_uppercase().as_str() {
166 "COUNT" => Some(AggregateFunction::Count),
167 "SUM" => Some(AggregateFunction::Sum),
168 "AVG" => Some(AggregateFunction::Avg),
169 "MIN" => Some(AggregateFunction::Min),
170 "MAX" => Some(AggregateFunction::Max),
171 _ => None,
172 };
173
174 if let Some(func_type) = agg_func {
175 let arg = if func.args.is_empty() {
176 None
177 } else {
178 match &func.args[0] {
179 ast::FunctionArg::Unnamed(ast::FunctionArgExpr::Wildcard) => None,
180 ast::FunctionArg::Unnamed(ast::FunctionArgExpr::Expr(e)) => {
181 Some(Box::new(self.convert_expr(e)?))
182 }
183 _ => None,
184 }
185 };
186
187 return Ok(Expr::Aggregate {
188 func: func_type,
189 arg,
190 distinct: func.distinct,
191 });
192 }
193
194 let args: Vec<Expr> = func
196 .args
197 .iter()
198 .filter_map(|arg| match arg {
199 ast::FunctionArg::Unnamed(ast::FunctionArgExpr::Expr(e)) => {
200 self.convert_expr(e).ok()
201 }
202 _ => None,
203 })
204 .collect();
205
206 Ok(Expr::Function { name, args })
207 }
208
209 SqlExpr::Case {
210 operand,
211 conditions,
212 results,
213 else_result,
214 } => {
215 let op = operand
216 .as_ref()
217 .map(|e| self.convert_expr(e))
218 .transpose()?
219 .map(Box::new);
220
221 let when_clauses: Vec<(Expr, Expr)> = conditions
222 .iter()
223 .zip(results.iter())
224 .map(|(c, r)| Ok((self.convert_expr(c)?, self.convert_expr(r)?)))
225 .collect::<Result<_>>()?;
226
227 let else_res = else_result
228 .as_ref()
229 .map(|e| self.convert_expr(e))
230 .transpose()?
231 .map(Box::new);
232
233 Ok(Expr::Case {
234 operand: op,
235 when_clauses,
236 else_result: else_res,
237 })
238 }
239
240 SqlExpr::Cast {
241 expr,
242 data_type,
243 format: _,
244 } => {
245 let e = self.convert_expr(expr)?;
247 let target_type = crate::Parser::convert_data_type(data_type)?;
248 Ok(Expr::Function {
250 name: format!("CAST_TO_{:?}", target_type),
251 args: vec![e],
252 })
253 }
254
255 SqlExpr::Nested(e) => self.convert_expr(e),
256
257 SqlExpr::Subquery(query) => {
258 let id = self.next_subquery_id();
260
261 let subquery_plan = self.plan_query(query)?;
263 self.subquery_plans.borrow_mut().insert(id, subquery_plan);
264
265 let correlated = self.detect_correlation(query).unwrap_or(false);
267
268 Ok(Expr::ScalarSubquery {
269 subquery_id: id,
270 correlated,
271 })
272 }
273
274 SqlExpr::InSubquery {
275 expr,
276 subquery,
277 negated,
278 } => {
279 let e = Box::new(self.convert_expr(expr)?);
280
281 let id = self.next_subquery_id();
283
284 let subquery_plan = self.plan_query(subquery)?;
286 self.subquery_plans.borrow_mut().insert(id, subquery_plan);
287
288 Ok(Expr::InSubquery {
289 expr: e,
290 subquery_id: id,
291 negated: *negated,
292 })
293 }
294
295 SqlExpr::Exists { subquery, negated } => {
296 let id = self.next_subquery_id();
298
299 let subquery_plan = self.plan_query(subquery)?;
301 self.subquery_plans.borrow_mut().insert(id, subquery_plan);
302
303 Ok(Expr::Exists {
304 subquery_id: id,
305 negated: *negated,
306 })
307 }
308
309 SqlExpr::Extract { field, expr } => {
311 let e = self.convert_expr(expr)?;
312 let func_name = match field {
313 DateTimeField::Year => "YEAR",
314 DateTimeField::Month => "MONTH",
315 DateTimeField::Day => "DAY",
316 DateTimeField::Hour => "HOUR",
317 DateTimeField::Minute => "MINUTE",
318 DateTimeField::Second => "SECOND",
319 _ => {
320 return Err(Error::Unsupported {
321 feature: format!("EXTRACT field: {:?}", field),
322 })
323 }
324 };
325 Ok(Expr::Function {
326 name: func_name.to_string(),
327 args: vec![e],
328 })
329 }
330
331 SqlExpr::TypedString {
333 data_type: _,
334 value,
335 } => Ok(Expr::Literal(Value::Text(value.clone()))),
336
337 SqlExpr::Interval(interval) => {
339 let value_str = match interval.value.as_ref() {
340 SqlExpr::Value(ast::Value::SingleQuotedString(s)) => s.clone(),
341 SqlExpr::Value(ast::Value::Number(n, _)) => n.clone(),
342 _ => format!("{}", interval.value),
343 };
344 let unit = interval
345 .leading_field
346 .map(|f| format!("{}", f))
347 .unwrap_or_else(|| "DAY".to_string());
348 Ok(Expr::Literal(Value::Text(format!(
350 "{} {}",
351 value_str, unit
352 ))))
353 }
354
355 SqlExpr::Floor { expr, .. } => {
357 let e = self.convert_expr(expr)?;
358 Ok(Expr::Function {
359 name: "FLOOR".to_string(),
360 args: vec![e],
361 })
362 }
363
364 SqlExpr::Ceil { expr, .. } => {
366 let e = self.convert_expr(expr)?;
367 Ok(Expr::Function {
368 name: "CEIL".to_string(),
369 args: vec![e],
370 })
371 }
372
373 SqlExpr::Substring {
375 expr,
376 substring_from,
377 substring_for,
378 ..
379 } => {
380 let e = self.convert_expr(expr)?;
381 let mut args = vec![e];
382 if let Some(from) = substring_from {
383 args.push(self.convert_expr(from)?);
384 }
385 if let Some(len) = substring_for {
386 args.push(self.convert_expr(len)?);
387 }
388 Ok(Expr::Function {
389 name: "SUBSTR".to_string(),
390 args,
391 })
392 }
393
394 _ => Err(Error::Unsupported {
395 feature: format!("Expression: {:?}", expr),
396 }),
397 }
398 }
399
400 pub(super) fn convert_value(&self, value: &ast::Value) -> Result<Value> {
402 match value {
403 ast::Value::Number(n, _) => {
404 if n.contains('.') {
405 Ok(Value::Real(n.parse().map_err(|_| Error::InvalidQuery {
406 message: format!("Invalid number: {}", n),
407 })?))
408 } else {
409 Ok(Value::Integer(n.parse().map_err(|_| {
410 Error::InvalidQuery {
411 message: format!("Invalid integer: {}", n),
412 }
413 })?))
414 }
415 }
416 ast::Value::SingleQuotedString(s) | ast::Value::DoubleQuotedString(s) => {
417 Ok(Value::Text(s.clone()))
418 }
419 ast::Value::Boolean(b) => Ok(Value::Boolean(*b)),
420 ast::Value::Null => Ok(Value::Null),
421 _ => Err(Error::Unsupported {
422 feature: format!("Value: {:?}", value),
423 }),
424 }
425 }
426
427 pub(super) fn convert_binary_op(&self, op: &ast::BinaryOperator) -> Result<BinaryOp> {
429 match op {
430 ast::BinaryOperator::Plus => Ok(BinaryOp::Add),
431 ast::BinaryOperator::Minus => Ok(BinaryOp::Sub),
432 ast::BinaryOperator::Multiply => Ok(BinaryOp::Mul),
433 ast::BinaryOperator::Divide => Ok(BinaryOp::Div),
434 ast::BinaryOperator::Modulo => Ok(BinaryOp::Mod),
435 ast::BinaryOperator::Eq => Ok(BinaryOp::Eq),
436 ast::BinaryOperator::NotEq => Ok(BinaryOp::Ne),
437 ast::BinaryOperator::Lt => Ok(BinaryOp::Lt),
438 ast::BinaryOperator::LtEq => Ok(BinaryOp::Le),
439 ast::BinaryOperator::Gt => Ok(BinaryOp::Gt),
440 ast::BinaryOperator::GtEq => Ok(BinaryOp::Ge),
441 ast::BinaryOperator::And => Ok(BinaryOp::And),
442 ast::BinaryOperator::Or => Ok(BinaryOp::Or),
443 ast::BinaryOperator::StringConcat => Ok(BinaryOp::Concat),
444 _ => Err(Error::Unsupported {
445 feature: format!("Binary operator: {:?}", op),
446 }),
447 }
448 }
449
450 pub(super) fn expr_has_aggregate(&self, expr: &SqlExpr) -> bool {
452 match expr {
453 SqlExpr::Function(func) => {
454 if func.over.is_some() {
456 return false;
457 }
458 let name = func.name.0.first().map(|i| i.value.as_str()).unwrap_or("");
459 matches!(
460 name.to_uppercase().as_str(),
461 "COUNT" | "SUM" | "AVG" | "MIN" | "MAX"
462 )
463 }
464 SqlExpr::BinaryOp { left, right, .. } => {
465 self.expr_has_aggregate(left) || self.expr_has_aggregate(right)
466 }
467 SqlExpr::UnaryOp { expr, .. } => self.expr_has_aggregate(expr),
468 SqlExpr::Nested(e) => self.expr_has_aggregate(e),
469 _ => false,
470 }
471 }
472}