diff --git a/lykiadb-lang/src/ast/sql.rs b/lykiadb-lang/src/ast/sql.rs index 1ba425a8..329d7877 100644 --- a/lykiadb-lang/src/ast/sql.rs +++ b/lykiadb-lang/src/ast/sql.rs @@ -21,12 +21,12 @@ pub enum SqlDistinct { pub enum SqlJoinType { #[serde(rename = "SqlJoinType::Left")] Left, - #[serde(rename = "SqlJoinType::LeftOuter")] - LeftOuter, #[serde(rename = "SqlJoinType::Right")] Right, #[serde(rename = "SqlJoinType::Inner")] Inner, + #[serde(rename = "SqlJoinType::Cross")] + Cross, } #[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone)] @@ -151,7 +151,7 @@ pub enum SqlFrom { Collection(SqlCollectionIdentifier), #[serde(rename = "SqlFrom::Select")] Select { - expr: Box, + subquery: Box, alias: Option, }, #[serde(rename = "SqlFrom::Join")] diff --git a/lykiadb-lang/src/ast/visitor.rs b/lykiadb-lang/src/ast/visitor.rs index 9621e912..d661e4f8 100644 --- a/lykiadb-lang/src/ast/visitor.rs +++ b/lykiadb-lang/src/ast/visitor.rs @@ -1,8 +1,5 @@ use super::{ expr::Expr, - sql::{ - SqlFrom, SqlDelete, SqlExpr, SqlInsert, SqlSelect, SqlSelectCore, SqlUpdate, - }, stmt::Stmt, }; diff --git a/lykiadb-lang/src/parser/mod.rs b/lykiadb-lang/src/parser/mod.rs index 93d4fa7a..c346c600 100644 --- a/lykiadb-lang/src/parser/mod.rs +++ b/lykiadb-lang/src/parser/mod.rs @@ -1200,18 +1200,18 @@ impl<'a> Parser<'a> { fn sql_select_from_collection(&mut self) -> ParseResult { if self.match_next(sym!(LeftParen)) { if self.cmp_tok(&skw!(Select)) { - let expr = self.sql_select()?; - self.expected(sym!(RightParen))?; // closing paren + let subquery = Box::new(self.sql_select_inner()?); + self.expected(sym!(RightParen))?; let alias: Option = optional_with_expected!(self, skw!(As), Identifier { dollar: false }); return Ok(SqlFrom::Select { - expr, + subquery, alias: alias.map(|t| t.extract_identifier().unwrap()), }); } - // If the next token is a left paren, then it must be either a select statement or a recursive from - let parsed = self.sql_select_from_join()?; // TODO(vck): Check if using _collection variant makes sense. - self.expected(sym!(RightParen))?; // closing paren + // If the next token is a left paren, then it must be either a select statement or a recursive "from" clause + let parsed = self.sql_select_from_join()?; + self.expected(sym!(RightParen))?; Ok(parsed) } else if let Some(collection) = self.sql_collection_identifier()? { return Ok(SqlFrom::Collection(collection)); diff --git a/lykiadb-lang/tests/lang/sql/select_from.rs b/lykiadb-lang/tests/lang/sql/select_from.rs index df67e5ab..32420c02 100644 --- a/lykiadb-lang/tests/lang/sql/select_from.rs +++ b/lykiadb-lang/tests/lang/sql/select_from.rs @@ -204,9 +204,7 @@ assert_parsing! { "dollar": false, "name": "u" }, - "expr": { - "@type": "Expr::Select", - "query": { + "subquery": { "@type": "SqlSelect", "core": { "@type": "SqlSelectCore", @@ -242,7 +240,6 @@ assert_parsing! { "limit": null, "order_by": null } - } } ] }, diff --git a/lykiadb-lang/tests/lang/sql/select_join.rs b/lykiadb-lang/tests/lang/sql/select_join.rs index 295e3757..bc2405c6 100644 --- a/lykiadb-lang/tests/lang/sql/select_join.rs +++ b/lykiadb-lang/tests/lang/sql/select_join.rs @@ -533,9 +533,7 @@ assert_parsing! { "dollar": false, "name": "c" }, - "expr": { - "@type": "Expr::Select", - "query": { + "subquery": { "@type": "SqlSelect", "core": { "@type": "SqlSelectCore", @@ -632,7 +630,6 @@ assert_parsing! { }, "limit": null, "order_by": null - } } }, "right": { diff --git a/lykiadb-server/src/plan/mod.rs b/lykiadb-server/src/plan/mod.rs index 5219674f..be79cdc7 100644 --- a/lykiadb-server/src/plan/mod.rs +++ b/lykiadb-server/src/plan/mod.rs @@ -1,5 +1,6 @@ -use lykiadb_lang::ast::sql::SqlExpr; +use lykiadb_lang::{ast::sql::{SqlCollectionIdentifier, SqlExpr, SqlJoinType, SqlOrdering}, Identifier}; use serde::{Deserialize, Serialize}; + pub mod planner; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -11,11 +12,6 @@ pub enum Aggregate { Sum(SqlExpr), } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub enum Direction { - Ascending, - Descending, -} #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Plan { @@ -41,12 +37,6 @@ pub enum Node { aliases: Vec, }, - Scan { - collection: String, - filter: Option, - alias: Option, - }, - Limit { source: Box, limit: usize, @@ -59,10 +49,33 @@ pub enum Node { Order { source: Box, - key: Vec<(SqlExpr, Direction)>, + key: Vec<(SqlExpr, SqlOrdering)>, }, Values { rows: Vec>, }, + + ValuesHandle { + identifier: Identifier + }, + + Scan { + source: SqlCollectionIdentifier, + filter: Option, + }, + + Join { + left: Box, + join_type: SqlJoinType, + right: Box, + constraint: Option, + }, + + Subquery { + source: Box, + alias: Identifier, + }, + + Nothing } diff --git a/lykiadb-server/src/plan/planner.rs b/lykiadb-server/src/plan/planner.rs index f943c321..95eb5cca 100644 --- a/lykiadb-server/src/plan/planner.rs +++ b/lykiadb-server/src/plan/planner.rs @@ -1,6 +1,6 @@ -use lykiadb_lang::ast::{expr::Expr, sql::{SqlFrom, SqlSelect}}; +use lykiadb_lang::{ast::{expr::Expr, sql::{SqlFrom, SqlJoinType, SqlSelect}}, Identifier}; -use crate::{engine::interpreter::HaltReason, value::types::RV}; +use crate::engine::interpreter::HaltReason; use super::{Node, Plan}; pub struct Planner; @@ -22,20 +22,51 @@ impl Planner { query, span: _, id: _, - } => self.build_select(query), + } => Ok(Plan::Select(self.build_select(query)?)), _ => panic!("Not implemented yet."), } } - fn build_select(&mut self, query: &SqlSelect) -> Result { - let mut node: Option = None; + fn build_select(&mut self, query: &SqlSelect) -> Result { + let mut node: Node = Node::Nothing; if let Some(from) = &query.core.from { - node = Some(self.build_from(from)?); + node = self.build_from(from)?; } - Ok(Plan::Select(Node::Values { rows: vec![vec![]] })) + Ok(node) } fn build_from(&mut self, from: &SqlFrom) -> Result { - Err(HaltReason::Return(RV::Undefined)) + match &from { + SqlFrom::Select { subquery, alias } => { + let node = Node::Subquery { + source: Box::new(self.build_select(subquery)?), + alias: alias.clone().unwrap() + }; + Ok(node) + } + SqlFrom::Collection(ident) => Ok(Node::Scan { + source: ident.clone(), + filter: None, + }), + SqlFrom::Group { values } => { + let mut froms = values.into_iter(); + let mut node = self.build_from(froms.next().unwrap())?; + for right in froms { + node = Node::Join { + left: Box::new(node), + join_type: SqlJoinType::Cross, + right: Box::new(self.build_from(right)?), + constraint: None, + } + } + Ok(node) + }, + SqlFrom::Join { left , join_type, right, constraint } => Ok(Node::Join { + left: Box::new(self.build_from(left)?), + join_type: join_type.clone(), + right: Box::new(self.build_from(right)?), + constraint: constraint.clone().map(|x| *x.clone()) + }) + } } }