From 15a4e628b8d2e53bdabd55bc88a86d875739858c Mon Sep 17 00:00:00 2001
From: Igor Kuznetsov <kuznetsovin@gmail.com>
Date: Mon, 17 Jan 2022 15:06:50 +0300
Subject: [PATCH] feat: add transformation ast to ir for simple and union query

---
 src/errors.rs                                 |  20 +
 src/frontend/sql.rs                           |   1 +
 src/frontend/sql/ast.rs                       |  33 +-
 src/frontend/sql/ast/tests.rs                 |  19 +-
 src/frontend/sql/grammar.pest                 |  44 +-
 src/frontend/sql/ir.rs                        | 238 +++++++
 src/frontend/sql/ir/tests.rs                  | 203 ++++++
 src/ir/value.rs                               |   1 -
 .../frontend/sql/ir/complex_cond_query.yaml   | 282 ++++++++
 .../sql/ir/complex_union_cond_query.yaml      | 667 ++++++++++++++++++
 .../frontend/sql/ir/simple_query.yaml         | 205 ++++++
 .../frontend/sql/ir/simple_union_query.yaml   | 563 +++++++++++++++
 .../frontend/sql/simple_query.yaml            |  10 +-
 .../frontend/sql/transform_select_2.yaml      |   2 +-
 .../frontend/sql/transform_select_3.yaml      |   4 +-
 .../frontend/sql/transform_select_4.yaml      |   4 +-
 .../frontend/sql/transform_select_5.yaml      |   6 +-
 17 files changed, 2244 insertions(+), 58 deletions(-)
 create mode 100644 src/frontend/sql/ir.rs
 create mode 100644 src/frontend/sql/ir/tests.rs
 create mode 100644 tests/artifactory/frontend/sql/ir/complex_cond_query.yaml
 create mode 100644 tests/artifactory/frontend/sql/ir/complex_union_cond_query.yaml
 create mode 100644 tests/artifactory/frontend/sql/ir/simple_query.yaml
 create mode 100644 tests/artifactory/frontend/sql/ir/simple_union_query.yaml

diff --git a/src/errors.rs b/src/errors.rs
index 1eeeb3ec4d..58259178e8 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -9,6 +9,11 @@ const EMPTY_PLAN_RELATION: &str = "empty plan relations";
 const EMPTY_RESULT: &str = "empty result";
 const INCORRECT_BUCKET_ID_ERROR: &str = "incorrect bucket id";
 const INVALID_AST: &str = "invalid AST";
+const INVALID_AST_CONDITION_NODE: &str = "Invalid selection condition part";
+const INVALID_AST_SCAN_NODE: &str = "Invalid scan node";
+const INVALID_AST_SELECTION_NODE: &str = "Selection node not found";
+const INVALID_AST_SUBQUERY_NODE: &str = "Invalid subquery node";
+const INVALID_AST_TOP_NODE: &str = "Top node not found";
 const INVALID_BOOL_ERROR: &str = "invalid boolean";
 const INVALID_CONSTANT: &str = "invalid constant";
 const INVALID_COLUMN_NAME: &str = "invalid column name";
@@ -34,18 +39,25 @@ const SIMPLE_UNION_QUERY_ERROR: &str = "query doesn't simple union";
 const SPACE_NOT_FOUND: &str = "space not found";
 const SPACE_FORMAT_NOT_FOUND: &str = "space format not found";
 const UNINITIALIZED_DISTRIBUTION: &str = "uninitialized distribution";
+const UNSUPPORTED_TYPE_IR_VALUE: &str = "unsupported type ir value";
 const VALUE_OUT_OF_RANGE_ERROR: &str = "value out of range";
 const TYPE_NOT_IMPLEMENTED: &str = "type is not implemented";
 
 #[derive(Debug, Clone, PartialEq, Serialize)]
 pub enum QueryPlannerError {
     BucketIdError,
+    CustomError(String),
     DoSkip,
     DuplicateColumn,
     EmptyPlanRelations,
     EmptyResult,
     IncorrectBucketIdError,
     InvalidAst,
+    InvalidAstConditionNode,
+    InvalidAstScanNode,
+    InvalidAstSelectionNode,
+    InvalidAstSubQueryNode,
+    InvalidAstTopNode,
     InvalidBool,
     InvalidConstant,
     InvalidColumnName,
@@ -73,11 +85,13 @@ pub enum QueryPlannerError {
     UninitializedDistribution,
     ValueOutOfRange,
     TypeNotImplemented,
+    UnsupportedIrValueType,
 }
 
 impl fmt::Display for QueryPlannerError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let p = match self {
+            QueryPlannerError::CustomError(s) => s.as_str(),
             QueryPlannerError::BucketIdError => BUCKET_ID_ERROR,
             QueryPlannerError::DoSkip => DO_SKIP,
             QueryPlannerError::DuplicateColumn => DUPLICATE_COLUMN_ERROR,
@@ -85,6 +99,11 @@ impl fmt::Display for QueryPlannerError {
             QueryPlannerError::EmptyResult => EMPTY_RESULT,
             QueryPlannerError::IncorrectBucketIdError => INCORRECT_BUCKET_ID_ERROR,
             QueryPlannerError::InvalidAst => INVALID_AST,
+            QueryPlannerError::InvalidAstConditionNode => INVALID_AST_CONDITION_NODE,
+            QueryPlannerError::InvalidAstScanNode => INVALID_AST_SCAN_NODE,
+            QueryPlannerError::InvalidAstSelectionNode => INVALID_AST_SELECTION_NODE,
+            QueryPlannerError::InvalidAstSubQueryNode => INVALID_AST_SUBQUERY_NODE,
+            QueryPlannerError::InvalidAstTopNode => INVALID_AST_TOP_NODE,
             QueryPlannerError::InvalidBool => INVALID_BOOL_ERROR,
             QueryPlannerError::InvalidConstant => INVALID_CONSTANT,
             QueryPlannerError::InvalidColumnName => INVALID_COLUMN_NAME,
@@ -112,6 +131,7 @@ impl fmt::Display for QueryPlannerError {
             QueryPlannerError::UninitializedDistribution => UNINITIALIZED_DISTRIBUTION,
             QueryPlannerError::ValueOutOfRange => VALUE_OUT_OF_RANGE_ERROR,
             QueryPlannerError::TypeNotImplemented => TYPE_NOT_IMPLEMENTED,
+            QueryPlannerError::UnsupportedIrValueType => UNSUPPORTED_TYPE_IR_VALUE,
         };
         write!(f, "{}", p)
     }
diff --git a/src/frontend/sql.rs b/src/frontend/sql.rs
index 851c0bc27f..f4ae8f2b1a 100644
--- a/src/frontend/sql.rs
+++ b/src/frontend/sql.rs
@@ -1 +1,2 @@
 pub mod ast;
+pub mod ir;
diff --git a/src/frontend/sql/ast.rs b/src/frontend/sql/ast.rs
index 071533177b..87b022c9cd 100644
--- a/src/frontend/sql/ast.rs
+++ b/src/frontend/sql/ast.rs
@@ -1,10 +1,12 @@
 extern crate pest;
 
-use crate::errors::QueryPlannerError;
+use std::cell::RefCell;
+
 use pest::iterators::Pair;
 use pest::Parser;
 use serde::{Deserialize, Serialize};
-use std::cell::RefCell;
+
+use crate::errors::QueryPlannerError;
 
 /// Parse tree
 #[derive(Parser)]
@@ -14,7 +16,7 @@ pub struct ParseTree;
 /// A list of current rules from the actual grammar.
 /// When new tokens are added to the grammar they
 /// should be also added in the current list.
-#[derive(Serialize, Deserialize, PartialEq, Debug)]
+#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
 pub enum Type {
     Alias,
     And,
@@ -30,6 +32,7 @@ pub enum Type {
     Insert,
     Lt,
     LtEq,
+    Name,
     NotEq,
     Null,
     Number,
@@ -37,13 +40,14 @@ pub enum Type {
     Parentheses,
     Primary,
     Projection,
-    QuotedName,
+    ProjectedName,
     Row,
     Scan,
     Select,
     Selection,
     String,
     SubQuery,
+    SubQueryName,
     Table,
     UnionAll,
     Value,
@@ -68,6 +72,7 @@ impl Type {
             Rule::Insert => Ok(Type::Insert),
             Rule::Lt => Ok(Type::Lt),
             Rule::LtEq => Ok(Type::LtEq),
+            Rule::Name => Ok(Type::Name),
             Rule::NotEq => Ok(Type::NotEq),
             Rule::Null => Ok(Type::Null),
             Rule::Number => Ok(Type::Number),
@@ -75,13 +80,14 @@ impl Type {
             Rule::Parentheses => Ok(Type::Parentheses),
             Rule::Primary => Ok(Type::Primary),
             Rule::Projection => Ok(Type::Projection),
-            Rule::QuotedName => Ok(Type::QuotedName),
+            Rule::ProjectedName => Ok(Type::ProjectedName),
             Rule::Row => Ok(Type::Row),
             Rule::Scan => Ok(Type::Scan),
             Rule::Select => Ok(Type::Select),
             Rule::Selection => Ok(Type::Selection),
             Rule::String => Ok(Type::String),
             Rule::SubQuery => Ok(Type::SubQuery),
+            Rule::SubQueryName => Ok(Type::SubQueryName),
             Rule::Table => Ok(Type::Table),
             Rule::UnionAll => Ok(Type::UnionAll),
             Rule::Value => Ok(Type::Value),
@@ -91,11 +97,11 @@ impl Type {
     }
 }
 
-#[derive(Serialize, Deserialize, PartialEq, Debug)]
+#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
 pub struct Node {
     children: Vec<usize>,
-    rule: Type,
-    value: Option<String>,
+    pub(in crate::frontend::sql) rule: Type,
+    pub(in crate::frontend::sql) value: Option<String>,
 }
 
 #[allow(dead_code)]
@@ -109,7 +115,7 @@ impl Node {
     }
 }
 
-#[derive(Serialize, Deserialize, PartialEq, Debug)]
+#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
 pub struct Nodes {
     arena: Vec<Node>,
 }
@@ -189,8 +195,8 @@ impl<'n> StackNode<'n> {
 /// Positions in a list act like references.
 #[derive(Serialize, Deserialize, PartialEq, Debug)]
 pub struct AbstractSyntaxTree {
-    nodes: Nodes,
-    top: Option<usize>,
+    pub(in crate::frontend::sql) nodes: Nodes,
+    pub(in crate::frontend::sql) top: Option<usize>,
 }
 
 #[allow(dead_code)]
@@ -255,12 +261,15 @@ impl AbstractSyntaxTree {
         }
 
         ast.set_top(0)?;
+
+        ast.transform_select()?;
+
         Ok(ast)
     }
 
     /// `Select` node is not IR-friendly as it can have up to five children.
     /// Transform this node in IR-way (to a binary sub-tree).
-    pub fn transform_select(&mut self) -> Result<(), QueryPlannerError> {
+    fn transform_select(&mut self) -> Result<(), QueryPlannerError> {
         let mut selects: Vec<usize> = Vec::new();
         for (pos, node) in self.nodes.arena.iter().enumerate() {
             if node.rule == Type::Select {
diff --git a/src/frontend/sql/ast/tests.rs b/src/frontend/sql/ast/tests.rs
index 0f0df3ce63..52dbd126f5 100644
--- a/src/frontend/sql/ast/tests.rs
+++ b/src/frontend/sql/ast/tests.rs
@@ -22,8 +22,7 @@ fn ast() {
 #[test]
 fn transfrom_select_2() {
     let query = r#"select a from t"#;
-    let mut ast = AbstractSyntaxTree::new(query).unwrap();
-    ast.transform_select().unwrap();
+    let ast = AbstractSyntaxTree::new(query).unwrap();
     let path = Path::new("")
         .join("tests")
         .join("artifactory")
@@ -38,8 +37,7 @@ fn transfrom_select_2() {
 #[test]
 fn transfrom_select_3() {
     let query = r#"select a from t where a = 1"#;
-    let mut ast = AbstractSyntaxTree::new(query).unwrap();
-    ast.transform_select().unwrap();
+    let ast = AbstractSyntaxTree::new(query).unwrap();
     let path = Path::new("")
         .join("tests")
         .join("artifactory")
@@ -54,8 +52,7 @@ fn transfrom_select_3() {
 #[test]
 fn transfrom_select_4() {
     let query = r#"select * from t1 inner join t2 on t1.a = t2.a"#;
-    let mut ast = AbstractSyntaxTree::new(query).unwrap();
-    ast.transform_select().unwrap();
+    let ast = AbstractSyntaxTree::new(query).unwrap();
     let path = Path::new("")
         .join("tests")
         .join("artifactory")
@@ -70,8 +67,7 @@ fn transfrom_select_4() {
 #[test]
 fn transfrom_select_5() {
     let query = r#"select * from t1 inner join t2 on t1.a = t2.a where t1.a > 0"#;
-    let mut ast = AbstractSyntaxTree::new(query).unwrap();
-    ast.transform_select().unwrap();
+    let ast = AbstractSyntaxTree::new(query).unwrap();
     let path = Path::new("")
         .join("tests")
         .join("artifactory")
@@ -86,8 +82,7 @@ fn transfrom_select_5() {
 #[test]
 fn traversal() {
     let query = r#"select a from t where a = 1"#;
-    let mut ast = AbstractSyntaxTree::new(query).unwrap();
-    ast.transform_select().unwrap();
+    let ast = AbstractSyntaxTree::new(query).unwrap();
     let top = ast.top.unwrap();
     let mut dft_pre = DftPost::new(&top, |node| ast.nodes.tree_iter(node));
 
@@ -101,7 +96,7 @@ fn traversal() {
 
     let (_, a_id) = dft_pre.next().unwrap();
     let node = ast.nodes.get_node(*a_id).unwrap();
-    assert_eq!(node.rule, Type::String);
+    assert_eq!(node.rule, Type::Name);
 
     let (_, num_id) = dft_pre.next().unwrap();
     let node = ast.nodes.get_node(*num_id).unwrap();
@@ -117,7 +112,7 @@ fn traversal() {
 
     let (_, str_id) = dft_pre.next().unwrap();
     let node = ast.nodes.get_node(*str_id).unwrap();
-    assert_eq!(node.rule, Type::String);
+    assert_eq!(node.rule, Type::ProjectedName);
 
     let (_, col_id) = dft_pre.next().unwrap();
     let node = ast.nodes.get_node(*col_id).unwrap();
diff --git a/src/frontend/sql/grammar.pest b/src/frontend/sql/grammar.pest
index 2a6152fd67..62270d66f0 100644
--- a/src/frontend/sql/grammar.pest
+++ b/src/frontend/sql/grammar.pest
@@ -7,25 +7,28 @@ Query = _{ UnionAll | Select | Values | Insert }
         (^"on" ~ Condition)? ~ (^"where" ~ Selection)?
     }
         Projection = { Column ~ ("," ~ Column)*? }
-            Column = { Row | Asterisk | Alias | Value }
-                Alias = {Value ~ ^"as" ~ (String | QuotedName) }
+            Column = { Row | Asterisk | Alias | Value | ProjectedName }
+                Alias = {Value ~ ^"as" ~ ProjectedName }
+                ProjectedName = @{ Name }
+                Name = @{ String | "\"" ~ String ~ "\"" ~ (".\"" ~ String ~ "\"")?}
                 Asterisk = @{ "*" }
         Selection = { Expr* }
         Scan = { SubQuery | Table }
-            Table = @{ String | QuotedName }
+            Table = @{ Name }
         InnerJoin = { Scan }
         Condition = { Selection }
     UnionAll = { (SubQuery | Select) ~ ^"union" ~ ^"all" ~ (UnionAll | SubQuery | Select) }
-    SubQuery = { "(" ~ (UnionAll | Select) ~ ")" ~ (^"as" ~ (String | QuotedName))? }
+    SubQuery = { "(" ~ (UnionAll | Select) ~ ")" ~ (^"as" ~ SubQueryName)? }
+		SubQueryName = @{ Name }
     Insert = { ^"insert" ~ ^"into" ~ Table ~ Values }
     Values = { ^"values" ~ Row ~ ("," ~ Row)*?}
 
 Expr = _{  Or | And | Cmp | Primary | Parentheses }
     Parentheses = _{ "(" ~ Expr ~ ")" }
-    Primary = _{ SubQuery | Value }
+    Primary = _{ SubQuery | Value | Name }
     Cmp = _{ Eq | In | Gt | GtEq | Lt | LtEq | NotEq }
     Eq = { EqLeft ~ "=" ~ EqRight }
-        EqLeft = _{ Primary | Parentheses }
+        EqLeft = _{ Primary }
         EqRight = _{ Eq | EqLeft }
     In = { InLeft ~ ^"in" ~ InRight }
         InLeft = _{ EqRight }
@@ -44,7 +47,7 @@ Expr = _{  Or | And | Cmp | Primary | Parentheses }
         LtEqRight = _{ LtEq | LtEqLeft }
     NotEq = { NotEqLeft ~ ("<>" | "!=") ~ NotEqRight }
         NotEqLeft = _{ LtEqRight }
-        NotEqRight = _{ NotEq | NotEqLeft }  
+        NotEqRight = _{ NotEq | NotEqLeft }
     And = { AndLeft ~ ^"and" ~ AndRight }
         AndLeft = _{ Cmp | Primary | Parentheses }
         AndRight = _{ And | AndLeft }
@@ -52,22 +55,23 @@ Expr = _{  Or | And | Cmp | Primary | Parentheses }
         OrLeft = _{ AndRight }
         OrRight = _{ Or | OrLeft }
 
-Value = _{ Row | Bool | Null | QuotedName | Number | String }
-    Bool = @{ ^"true" | ^"false" }
-    Null = @{ ^"null" }
+String = @{ !(Keyword) ~ ('a'..'z' | "_" | Number)+ }
+    Keyword = {
+        ^"all" | ^"and" | ^"as" | ^"false" | ^"from"
+        | ^"in" | ^"inner" | ^"insert" | ^"into" | ^"join" | ^"null"
+        | ^"on" | ^"or" | ^"row" | ^"select" | ^"true" | ^"union"
+        | ^"where" | ^"values"
+    }
     Number = @{ Int ~ ("." ~ ASCII_DIGIT*)? ~ (^"e" ~ Int)? }
         Int = @{ ("+" | "-")? ~ ASCII_DIGIT+ }
-    String = @{ !(Keyword) ~ ('a'..'z' | "_" | Number)+ }
-        Keyword = {
-            ^"all" | ^"and" | ^"as" | ^"false" | ^"from"
-            | ^"in" | ^"inner" | ^"insert" | ^"into" | ^"join" | ^"null"
-            | ^"on" | ^"or" | ^"row" | ^"select" | ^"true" | ^"union"
-            | ^"where" | ^"values"
-        }
-    QuotedName = @{ "\"" ~ String ~ "\"" ~ ("." ~ "\"" ~ String ~ "\"")? }
+
+Value = _{ Row | Bool | Null | Number | SingleQuotedString }
+    Bool = @{ ^"true" | ^"false" }
+    Null = @{ ^"null" }
+    SingleQuotedString = _{ "'" ~ String ~ "'" }
     Row = {
-        ("(" ~ Value ~ ("," ~ Value)* ~ ")")
-        | (^"row" ~ "(" ~ Value ~ ("," ~ Value)* ~ ")")
+        ("(" ~ (Value | Name) ~ ("," ~ (Value | Name))* ~ ")")
+        | (^"row" ~ "(" ~ (Value | Name) ~ ("," ~ (Value | Name))* ~ ")")
     }
 
 EOF = { EOI | ";" }
diff --git a/src/frontend/sql/ir.rs b/src/frontend/sql/ir.rs
new file mode 100644
index 0000000000..858df22aee
--- /dev/null
+++ b/src/frontend/sql/ir.rs
@@ -0,0 +1,238 @@
+use traversal::DftPost;
+
+use crate::cache::Metadata;
+use crate::errors::QueryPlannerError;
+use crate::frontend::sql::ast::{AbstractSyntaxTree, Node, Type};
+use crate::ir::operator::Bool;
+use crate::ir::value::Value;
+use crate::ir::Plan;
+
+impl Bool {
+    /// Create `Bool` from ast node type.
+    ///
+    /// # Errors
+    /// Returns `QueryPlannerError` when the operator is invalid.
+    #[allow(dead_code)]
+    fn from_node_type(s: &Type) -> Result<Self, QueryPlannerError> {
+        match s {
+            Type::And => Ok(Bool::And),
+            Type::Or => Ok(Bool::Or),
+            Type::Eq => Ok(Bool::Eq),
+            Type::In => Ok(Bool::In),
+            Type::Gt => Ok(Bool::Gt),
+            Type::GtEq => Ok(Bool::GtEq),
+            Type::Lt => Ok(Bool::Lt),
+            Type::LtEq => Ok(Bool::LtEq),
+            Type::NotEq => Ok(Bool::NotEq),
+            _ => Err(QueryPlannerError::InvalidBool),
+        }
+    }
+}
+
+impl Value {
+    /// Create `Value` from ast node type and text.
+    ///
+    /// # Errors
+    /// Returns `QueryPlannerError` when the operator is invalid.
+    #[allow(dead_code)]
+    fn from_node(s: &Node) -> Result<Self, QueryPlannerError> {
+        let val = match s.clone().value {
+            Some(v) => v,
+            None => "".into(),
+        };
+
+        match s.rule {
+            Type::Number => Ok(Value::number_from_str(val.as_str())?),
+            Type::String => Ok(Value::string_from_str(val.as_str())),
+            Type::Null => Ok(Value::Null),
+            _ => Err(QueryPlannerError::UnsupportedIrValueType),
+        }
+    }
+}
+
+/// Temporary stack for traversing ast
+struct Stack {
+    store: Vec<usize>,
+}
+
+impl Stack {
+    /// Create empty stack instance
+    fn new() -> Self {
+        Stack { store: vec![] }
+    }
+
+    /// Function push element on the top of stack
+    fn push(&mut self, node_id: usize) {
+        self.store.push(node_id);
+    }
+
+    /// Extract a top stack element or return an error from the `err` parameter
+    ///
+    /// # Errors
+    /// - failed to extract an element from the stack.
+    fn pop_or_err(&mut self, err: QueryPlannerError) -> Result<usize, QueryPlannerError> {
+        match self.store.pop() {
+            Some(v) => Ok(v),
+            None => Err(err),
+        }
+    }
+}
+
+impl AbstractSyntaxTree {
+    /// Transform ast to ir plan tree.
+    ///
+    /// Creates a plan from AST (based on AST node type).
+    /// Traverse the tree in Post-Order with [Depth-First Traversal](https://en.wikipedia.org/wiki/Tree_traversal).
+    ///
+    /// # Errors
+    /// - IR plan can't be built.
+    #[allow(dead_code)]
+    #[allow(clippy::too_many_lines)]
+    pub fn to_ir(&self, metadata: &Metadata) -> Result<Plan, QueryPlannerError> {
+        let mut plan = Plan::new();
+
+        let top = match self.top {
+            Some(t) => t,
+            None => return Err(QueryPlannerError::InvalidAst),
+        };
+        let dft_pre = DftPost::new(&top, |node| self.nodes.tree_iter(node));
+
+        let mut current_scan_id = 0;
+        let mut current_logical_id = 0;
+        let mut stack = Stack::new();
+        let mut projection = vec![];
+        let mut subquery_alias = "";
+
+        for (_, node_id) in dft_pre {
+            let node = self.nodes.get_node(*node_id)?;
+
+            match node.clone().rule {
+                Type::Table => {
+                    // add scan node to plan
+
+                    if let Some(node_val) = node.clone().value {
+                        let table = node_val.as_str().trim_matches('\"');
+                        let t = metadata.get_table_segment(table)?;
+                        plan.add_rel(t);
+                        stack.push(plan.add_scan(table)?);
+                    }
+                }
+                Type::Name => {
+                    if let Some(name) = &node.value {
+                        let col = name.trim_matches('\"');
+                        stack.push(plan.add_row_from_child(
+                            current_logical_id,
+                            current_scan_id,
+                            &[col],
+                        )?);
+                    }
+                }
+                Type::Number | Type::String => {
+                    let val = Value::from_node(node)?;
+                    stack.push(plan.add_const(val));
+                }
+                Type::And
+                | Type::Or
+                | Type::Eq
+                | Type::In
+                | Type::Gt
+                | Type::GtEq
+                | Type::Lt
+                | Type::LtEq
+                | Type::NotEq => {
+                    let op = Bool::from_node_type(&node.rule)?;
+
+                    // Extract left and right nodes id from stack for creation condition plan node
+                    let right_id = stack.pop_or_err(QueryPlannerError::CustomError(
+                        "Incorrect right part of condition".to_string(),
+                    ))?;
+
+                    let left_id = stack.pop_or_err(QueryPlannerError::CustomError(
+                        "Incorrect left part of condition".to_string(),
+                    ))?;
+
+                    stack.push(plan.add_cond(left_id, op, right_id)?);
+                }
+                Type::Selection => {
+                    // extract from stack condition node id for creating selection plan node
+                    let selection_id =
+                        stack.pop_or_err(QueryPlannerError::InvalidAstConditionNode)?;
+
+                    stack.push(plan.add_select(
+                        current_scan_id,
+                        selection_id,
+                        current_logical_id,
+                    )?);
+                }
+                Type::ProjectedName => {
+                    // save projection column for append it later
+
+                    if let Some(col) = &node.value {
+                        projection.push(col.as_str().trim_matches('\"'));
+                    }
+                }
+                Type::Projection => {
+                    // extract from stack selection node id for creating projection plan node
+
+                    let selection_id =
+                        stack.pop_or_err(QueryPlannerError::InvalidAstSelectionNode)?;
+
+                    stack.push(plan.add_proj(selection_id, &projection)?);
+
+                    // clear projection columns for next tables
+                    projection.clear();
+                }
+                Type::UnionAll => {
+                    // extract from stack left and right union subtree node for creating union plan node
+
+                    let right_id = stack.pop_or_err(QueryPlannerError::CustomError(
+                        "Invalid right union part".to_string(),
+                    ))?;
+
+                    let left_id = stack.pop_or_err(QueryPlannerError::CustomError(
+                        "Invalid left union part".to_string(),
+                    ))?;
+
+                    stack.push(plan.add_union_all(left_id, right_id)?);
+                }
+                Type::SubQueryName => {
+                    // save alias name for using in the next step
+                    if let Some(v) = &node.value {
+                        subquery_alias = v.as_str().trim_matches('\"');
+                    }
+                }
+                Type::SubQuery => {
+                    // add subquery node for it stack must have scan (or union) node id
+
+                    let sq_id = stack.pop_or_err(QueryPlannerError::InvalidAstSubQueryNode)?;
+
+                    stack.push(plan.add_sub_query(sq_id, subquery_alias)?);
+                }
+                Type::Asterisk => {
+                    projection.clear();
+                }
+                Type::Scan => {
+                    // extract current scan node id from stack and getting logical id for appending other node
+                    current_scan_id = stack.pop_or_err(QueryPlannerError::InvalidAstScanNode)?;
+                    current_logical_id = plan.next_id();
+                }
+                Type::Column | Type::Select => {}
+                rule => {
+                    return Err(QueryPlannerError::CustomError(format!(
+                        "Not implements type: {:?}",
+                        rule
+                    )));
+                }
+            }
+        }
+
+        // get root node id
+        let top_id = stack.pop_or_err(QueryPlannerError::InvalidAstTopNode)?;
+        plan.set_top(top_id)?;
+
+        Ok(plan)
+    }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/src/frontend/sql/ir/tests.rs b/src/frontend/sql/ir/tests.rs
new file mode 100644
index 0000000000..c0b154f169
--- /dev/null
+++ b/src/frontend/sql/ir/tests.rs
@@ -0,0 +1,203 @@
+use std::fs;
+use std::path::Path;
+
+use crate::cache::Metadata;
+use crate::ir::Plan;
+
+use super::*;
+use pretty_assertions::assert_eq;
+
+const CARTRIDGE_SCHEMA: &str = r#"spaces:
+  hash_testing:
+    is_local: false
+    temporary: false
+    engine: "memtx"
+    format:
+      - name: "identification_number"
+        type: "integer"
+        is_nullable: false
+      - name: "product_code"
+        type: "string"
+        is_nullable: false
+      - name: "product_units"
+        type: "boolean"
+        is_nullable: false
+      - name: "sys_op"
+        type: "number"
+        is_nullable: false
+      - name: "bucket_id"
+        type: "unsigned"
+        is_nullable: true
+    indexes:
+      - name: "id"
+        unique: true
+        type: "TREE"
+        parts:
+          - path: "identification_number"
+            is_nullable: false
+            type: "integer"
+      - name: bucket_id
+        unique: false
+        parts:
+          - path: "bucket_id"
+            is_nullable: true
+            type: "unsigned"
+        type: "TREE"
+    sharding_key:
+      - identification_number
+      - product_code
+  hash_testing_hist:
+    is_local: false
+    temporary: false
+    engine: "memtx"
+    format:
+      - name: "identification_number"
+        type: "integer"
+        is_nullable: false
+      - name: "product_code"
+        type: "string"
+        is_nullable: false
+      - name: "product_units"
+        type: "boolean"
+        is_nullable: false
+      - name: "sys_op"
+        type: "number"
+        is_nullable: false
+      - name: "bucket_id"
+        type: "unsigned"
+        is_nullable: true
+    indexes:
+      - name: "id"
+        unique: true
+        type: "TREE"
+        parts:
+          - path: "identification_number"
+            is_nullable: false
+            type: "integer"
+      - name: bucket_id
+        unique: false
+        parts:
+          - path: "bucket_id"
+            is_nullable: true
+            type: "unsigned"
+        type: "TREE"
+    sharding_key:
+      - identification_number
+      - product_code"#;
+
+#[test]
+fn simple_query_to_ir() {
+    let query = r#"SELECT "identification_number", "product_code" FROM "hash_testing" WHERE "identification_number" = 1"#;
+
+    let mut metadata = Metadata::new();
+    metadata.load(CARTRIDGE_SCHEMA).unwrap();
+
+    let path = Path::new("")
+        .join("tests")
+        .join("artifactory")
+        .join("frontend")
+        .join("sql")
+        .join("ir")
+        .join("simple_query.yaml");
+    let yml_str = fs::read_to_string(path).unwrap();
+    let expected = Plan::from_yaml(&yml_str).unwrap();
+
+    let ast = AbstractSyntaxTree::new(query).unwrap();
+    let actual = ast.to_ir(&metadata).unwrap();
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn complex_cond_query_transform() {
+    let query = r#"SELECT "identification_number", "product_code"
+    FROM "hash_testing"
+    WHERE "identification_number" = 1 AND "product_code" = '1'
+    OR "identification_number" = 2 AND "product_code" = '2'"#;
+
+    let mut metadata = Metadata::new();
+    metadata.load(CARTRIDGE_SCHEMA).unwrap();
+
+    let path = Path::new("")
+        .join("tests")
+        .join("artifactory")
+        .join("frontend")
+        .join("sql")
+        .join("ir")
+        .join("complex_cond_query.yaml");
+    let yml_str = fs::read_to_string(path).unwrap();
+    let expected = Plan::from_yaml(&yml_str).unwrap();
+
+    let ast = AbstractSyntaxTree::new(query).unwrap();
+    let actual = ast.to_ir(&metadata).unwrap();
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn simple_union_query_transform() {
+    let query = r#"SELECT *
+FROM
+    (SELECT "identification_number", "product_code"
+    FROM "hash_testing"
+    WHERE "sys_op" = 1
+    UNION ALL
+    SELECT "identification_number", "product_code"
+    FROM "hash_testing_hist"
+    WHERE "sys_op" > 1) AS "t3"
+WHERE "identification_number" = 1"#;
+
+    let mut metadata = Metadata::new();
+    metadata.load(CARTRIDGE_SCHEMA).unwrap();
+
+    let path = Path::new("")
+        .join("tests")
+        .join("artifactory")
+        .join("frontend")
+        .join("sql")
+        .join("ir")
+        .join("simple_union_query.yaml");
+    let yml_str = fs::read_to_string(path).unwrap();
+    let expected = Plan::from_yaml(&yml_str).unwrap();
+
+    let ast = AbstractSyntaxTree::new(query).unwrap();
+    let actual = ast.to_ir(&metadata).unwrap();
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn union_complex_cond_query_transform() {
+    let query = r#"SELECT *
+FROM
+    (SELECT "identification_number", "product_code"
+    FROM "hash_testing"
+    WHERE "sys_op" = 1
+    UNION ALL
+    SELECT "identification_number", "product_code"
+    FROM "hash_testing_hist"
+    WHERE "sys_op" > 1) AS "t3"
+WHERE ("identification_number" = 1
+    OR ("identification_number" = 2
+    OR "identification_number" = 3))
+    AND ("product_code" = '1'
+    OR "product_code" = '2')"#;
+
+    let mut metadata = Metadata::new();
+    metadata.load(CARTRIDGE_SCHEMA).unwrap();
+
+    let path = Path::new("")
+        .join("tests")
+        .join("artifactory")
+        .join("frontend")
+        .join("sql")
+        .join("ir")
+        .join("complex_union_cond_query.yaml");
+    let yml_str = fs::read_to_string(path).unwrap();
+    let expected = Plan::from_yaml(&yml_str).unwrap();
+
+    let ast = AbstractSyntaxTree::new(query).unwrap();
+    let actual = ast.to_ir(&metadata).unwrap();
+
+    assert_eq!(expected, actual);
+}
diff --git a/src/ir/value.rs b/src/ir/value.rs
index 731d494f9b..860de074e4 100644
--- a/src/ir/value.rs
+++ b/src/ir/value.rs
@@ -52,7 +52,6 @@ impl fmt::Display for Value {
     }
 }
 
-#[allow(dead_code)]
 impl Value {
     /// Construct a number from the string.
     ///
diff --git a/tests/artifactory/frontend/sql/ir/complex_cond_query.yaml b/tests/artifactory/frontend/sql/ir/complex_cond_query.yaml
new file mode 100644
index 0000000000..404048b93e
--- /dev/null
+++ b/tests/artifactory/frontend/sql/ir/complex_cond_query.yaml
@@ -0,0 +1,282 @@
+#
+# SELECT "identification_number", "product_code"
+#    FROM "hash_testing"
+#    WHERE "identification_number" = 1 AND "product_code" = '1'
+#    OR "identification_number" = 2 AND "product_code" = '2';
+#
+---
+nodes:
+  arena:
+    - Expression:
+        Reference:
+          targets: ~
+          position: 0
+          parent: 0
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 0
+    - Expression:
+        Reference:
+          targets: ~
+          position: 1
+          parent: 0
+    - Expression:
+        Alias:
+          name: product_code
+          child: 2
+    - Expression:
+        Reference:
+          targets: ~
+          position: 2
+          parent: 0
+    - Expression:
+        Alias:
+          name: product_units
+          child: 4
+    - Expression:
+        Reference:
+          targets: ~
+          position: 3
+          parent: 0
+    - Expression:
+        Alias:
+          name: sys_op
+          child: 6
+    - Expression:
+        Reference:
+          targets: ~
+          position: 4
+          parent: 0
+    - Expression:
+        Alias:
+          name: bucket_id
+          child: 8
+    - Expression:
+        Row:
+          list:
+            - 1
+            - 3
+            - 5
+            - 7
+            - 9
+          distribution: ~
+    - Relational:
+        ScanRelation:
+          output: 10
+          id: 0
+          relation: hash_testing
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 12
+    - Expression:
+        Row:
+          list:
+            - 12
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            Number: 1
+    - Expression:
+        Bool:
+          left: 13
+          op: Eq
+          right: 14
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 12
+    - Expression:
+        Row:
+          list:
+            - 16
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            String: "1"
+    - Expression:
+        Bool:
+          left: 17
+          op: Eq
+          right: 18
+    - Expression:
+        Bool:
+          left: 15
+          op: And
+          right: 19
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 12
+    - Expression:
+        Row:
+          list:
+            - 21
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            Number: 2
+    - Expression:
+        Bool:
+          left: 22
+          op: Eq
+          right: 23
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 12
+    - Expression:
+        Row:
+          list:
+            - 25
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            String: "2"
+    - Expression:
+        Bool:
+          left: 26
+          op: Eq
+          right: 27
+    - Expression:
+        Bool:
+          left: 24
+          op: And
+          right: 28
+    - Expression:
+        Bool:
+          left: 20
+          op: Or
+          right: 29
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 12
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 31
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 12
+    - Expression:
+        Alias:
+          name: product_code
+          child: 33
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 2
+          parent: 12
+    - Expression:
+        Alias:
+          name: product_units
+          child: 35
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 3
+          parent: 12
+    - Expression:
+        Alias:
+          name: sys_op
+          child: 37
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 4
+          parent: 12
+    - Expression:
+        Alias:
+          name: bucket_id
+          child: 39
+    - Expression:
+        Row:
+          list:
+            - 32
+            - 34
+            - 36
+            - 38
+            - 40
+          distribution: ~
+    - Relational:
+        Selection:
+          children:
+            - 11
+          filter: 30
+          id: 12
+          output: 41
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 43
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 43
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 43
+    - Expression:
+        Alias:
+          name: product_code
+          child: 45
+    - Expression:
+        Row:
+          list:
+            - 44
+            - 46
+          distribution: ~
+    - Relational:
+        Projection:
+          children:
+            - 42
+          id: 43
+          output: 47
+relations:
+  hash_testing:
+    Segment:
+      columns:
+        - name: identification_number
+          type: integer
+        - name: product_code
+          type: string
+        - name: product_units
+          type: boolean
+        - name: sys_op
+          type: number
+        - name: bucket_id
+          type: unsigned
+      key:
+        positions:
+          - 0
+          - 1
+      name: hash_testing
+slices: ~
+top: 48
diff --git a/tests/artifactory/frontend/sql/ir/complex_union_cond_query.yaml b/tests/artifactory/frontend/sql/ir/complex_union_cond_query.yaml
new file mode 100644
index 0000000000..44032674dd
--- /dev/null
+++ b/tests/artifactory/frontend/sql/ir/complex_union_cond_query.yaml
@@ -0,0 +1,667 @@
+#
+# SELECT *
+# FROM
+#   (
+#     SELECT "identification_number", "product_code"
+#       FROM "hash_testing"
+#       WHERE "sys_op" = 1
+#     UNION ALL
+#     SELECT "identification_number", "product_code"
+#     FROM "hash_testing_hist"
+#     WHERE "sys_op" > 1
+#    ) AS "t3"
+# WHERE ("identification_number" = 1
+#   OR ("identification_number" = 2
+#     OR "identification_number" = 3))
+#   AND ("product_code" = '1'
+#     OR "product_code" = '2')
+#
+---
+nodes:
+  arena:
+    - Expression:
+        Reference:
+          targets: ~
+          position: 0
+          parent: 0
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 0
+    - Expression:
+        Reference:
+          targets: ~
+          position: 1
+          parent: 0
+    - Expression:
+        Alias:
+          name: product_code
+          child: 2
+    - Expression:
+        Reference:
+          targets: ~
+          position: 2
+          parent: 0
+    - Expression:
+        Alias:
+          name: product_units
+          child: 4
+    - Expression:
+        Reference:
+          targets: ~
+          position: 3
+          parent: 0
+    - Expression:
+        Alias:
+          name: sys_op
+          child: 6
+    - Expression:
+        Reference:
+          targets: ~
+          position: 4
+          parent: 0
+    - Expression:
+        Alias:
+          name: bucket_id
+          child: 8
+    - Expression:
+        Row:
+          list:
+            - 1
+            - 3
+            - 5
+            - 7
+            - 9
+          distribution: ~
+    - Relational:
+        ScanRelation:
+          output: 10
+          id: 0
+          relation: hash_testing
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 3
+          parent: 12
+    - Expression:
+        Row:
+          list:
+            - 12
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            Number: 1
+    - Expression:
+        Bool:
+          left: 13
+          op: Eq
+          right: 14
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 12
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 16
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 12
+    - Expression:
+        Alias:
+          name: product_code
+          child: 18
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 2
+          parent: 12
+    - Expression:
+        Alias:
+          name: product_units
+          child: 20
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 3
+          parent: 12
+    - Expression:
+        Alias:
+          name: sys_op
+          child: 22
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 4
+          parent: 12
+    - Expression:
+        Alias:
+          name: bucket_id
+          child: 24
+    - Expression:
+        Row:
+          list:
+            - 17
+            - 19
+            - 21
+            - 23
+            - 25
+          distribution: ~
+    - Relational:
+        Selection:
+          children:
+            - 11
+          filter: 15
+          id: 12
+          output: 26
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 28
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 28
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 28
+    - Expression:
+        Alias:
+          name: product_code
+          child: 30
+    - Expression:
+        Row:
+          list:
+            - 29
+            - 31
+          distribution: ~
+    - Relational:
+        Projection:
+          children:
+            - 27
+          id: 28
+          output: 32
+    - Expression:
+        Reference:
+          targets: ~
+          position: 0
+          parent: 34
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 34
+    - Expression:
+        Reference:
+          targets: ~
+          position: 1
+          parent: 34
+    - Expression:
+        Alias:
+          name: product_code
+          child: 36
+    - Expression:
+        Reference:
+          targets: ~
+          position: 2
+          parent: 34
+    - Expression:
+        Alias:
+          name: product_units
+          child: 38
+    - Expression:
+        Reference:
+          targets: ~
+          position: 3
+          parent: 34
+    - Expression:
+        Alias:
+          name: sys_op
+          child: 40
+    - Expression:
+        Reference:
+          targets: ~
+          position: 4
+          parent: 34
+    - Expression:
+        Alias:
+          name: bucket_id
+          child: 42
+    - Expression:
+        Row:
+          list:
+            - 35
+            - 37
+            - 39
+            - 41
+            - 43
+          distribution: ~
+    - Relational:
+        ScanRelation:
+          output: 44
+          id: 34
+          relation: hash_testing_hist
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 3
+          parent: 46
+    - Expression:
+        Row:
+          list:
+            - 46
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            Number: 1
+    - Expression:
+        Bool:
+          left: 47
+          op: Gt
+          right: 48
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 46
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 50
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 46
+    - Expression:
+        Alias:
+          name: product_code
+          child: 52
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 2
+          parent: 46
+    - Expression:
+        Alias:
+          name: product_units
+          child: 54
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 3
+          parent: 46
+    - Expression:
+        Alias:
+          name: sys_op
+          child: 56
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 4
+          parent: 46
+    - Expression:
+        Alias:
+          name: bucket_id
+          child: 58
+    - Expression:
+        Row:
+          list:
+            - 51
+            - 53
+            - 55
+            - 57
+            - 59
+          distribution: ~
+    - Relational:
+        Selection:
+          children:
+            - 45
+          filter: 49
+          id: 46
+          output: 60
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 62
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 62
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 62
+    - Expression:
+        Alias:
+          name: product_code
+          child: 64
+    - Expression:
+        Row:
+          list:
+            - 63
+            - 65
+          distribution: ~
+    - Relational:
+        Projection:
+          children:
+            - 61
+          id: 62
+          output: 66
+    - Expression:
+        Reference:
+          targets:
+            - 0
+            - 1
+          position: 0
+          parent: 68
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 68
+    - Expression:
+        Reference:
+          targets:
+            - 0
+            - 1
+          position: 1
+          parent: 68
+    - Expression:
+        Alias:
+          name: product_code
+          child: 70
+    - Expression:
+        Row:
+          list:
+            - 69
+            - 71
+          distribution: ~
+    - Relational:
+        UnionAll:
+          children:
+            - 33
+            - 67
+          id: 68
+          output: 72
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 74
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 74
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 74
+    - Expression:
+        Alias:
+          name: product_code
+          child: 76
+    - Expression:
+        Row:
+          list:
+            - 75
+            - 77
+          distribution: ~
+    - Relational:
+        ScanSubQuery:
+          alias: t3
+          children:
+            - 73
+          id: 74
+          output: 78
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 80
+    - Expression:
+        Row:
+          list:
+            - 80
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            Number: 1
+    - Expression:
+        Bool:
+          left: 81
+          op: Eq
+          right: 82
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 80
+    - Expression:
+        Row:
+          list:
+            - 84
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            Number: 2
+    - Expression:
+        Bool:
+          left: 85
+          op: Eq
+          right: 86
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 80
+    - Expression:
+        Row:
+          list:
+            - 88
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            Number: 3
+    - Expression:
+        Bool:
+          left: 89
+          op: Eq
+          right: 90
+    - Expression:
+        Bool:
+          left: 87
+          op: Or
+          right: 91
+    - Expression:
+        Bool:
+          left: 83
+          op: Or
+          right: 92
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 80
+    - Expression:
+        Row:
+          list:
+            - 94
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            String: "1"
+    - Expression:
+        Bool:
+          left: 95
+          op: Eq
+          right: 96
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 80
+    - Expression:
+        Row:
+          list:
+            - 98
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            String: "2"
+    - Expression:
+        Bool:
+          left: 99
+          op: Eq
+          right: 100
+    - Expression:
+        Bool:
+          left: 97
+          op: Or
+          right: 101
+    - Expression:
+        Bool:
+          left: 93
+          op: And
+          right: 102
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 80
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 104
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 80
+    - Expression:
+        Alias:
+          name: product_code
+          child: 106
+    - Expression:
+        Row:
+          list:
+            - 105
+            - 107
+          distribution: ~
+    - Relational:
+        Selection:
+          children:
+            - 79
+          filter: 103
+          id: 80
+          output: 108
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 110
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 110
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 110
+    - Expression:
+        Alias:
+          name: product_code
+          child: 112
+    - Expression:
+        Row:
+          list:
+            - 111
+            - 113
+          distribution: ~
+    - Relational:
+        Projection:
+          children:
+            - 109
+          id: 110
+          output: 114
+relations:
+  hash_testing:
+    Segment:
+      columns:
+        - name: identification_number
+          type: integer
+        - name: product_code
+          type: string
+        - name: product_units
+          type: boolean
+        - name: sys_op
+          type: number
+        - name: bucket_id
+          type: unsigned
+      key:
+        positions:
+          - 0
+          - 1
+      name: hash_testing
+  hash_testing_hist:
+    Segment:
+      columns:
+        - name: identification_number
+          type: integer
+        - name: product_code
+          type: string
+        - name: product_units
+          type: boolean
+        - name: sys_op
+          type: number
+        - name: bucket_id
+          type: unsigned
+      key:
+        positions:
+          - 0
+          - 1
+      name: hash_testing_hist
+slices: ~
+top: 115
diff --git a/tests/artifactory/frontend/sql/ir/simple_query.yaml b/tests/artifactory/frontend/sql/ir/simple_query.yaml
new file mode 100644
index 0000000000..3ad5d00263
--- /dev/null
+++ b/tests/artifactory/frontend/sql/ir/simple_query.yaml
@@ -0,0 +1,205 @@
+#
+# SELECT "identification_number", "product_code" FROM "test_space" WHERE "identification_number" = 1;
+#
+
+---
+nodes:
+  arena:
+    - Expression:
+        Reference:
+          targets: ~
+          position: 0
+          parent: 0
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 0
+    - Expression:
+        Reference:
+          targets: ~
+          position: 1
+          parent: 0
+    - Expression:
+        Alias:
+          name: product_code
+          child: 2
+    - Expression:
+        Reference:
+          targets: ~
+          position: 2
+          parent: 0
+    - Expression:
+        Alias:
+          name: product_units
+          child: 4
+    - Expression:
+        Reference:
+          targets: ~
+          position: 3
+          parent: 0
+    - Expression:
+        Alias:
+          name: sys_op
+          child: 6
+    - Expression:
+        Reference:
+          targets: ~
+          position: 4
+          parent: 0
+    - Expression:
+        Alias:
+          name: bucket_id
+          child: 8
+    - Expression:
+        Row:
+          list:
+            - 1
+            - 3
+            - 5
+            - 7
+            - 9
+          distribution: ~
+    - Relational:
+        ScanRelation:
+          output: 10
+          id: 0
+          relation: hash_testing
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 12
+    - Expression:
+        Row:
+          list:
+            - 12
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            Number: 1
+    - Expression:
+        Bool:
+          left: 13
+          op: Eq
+          right: 14
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 12
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 16
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 12
+    - Expression:
+        Alias:
+          name: product_code
+          child: 18
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 2
+          parent: 12
+    - Expression:
+        Alias:
+          name: product_units
+          child: 20
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 3
+          parent: 12
+    - Expression:
+        Alias:
+          name: sys_op
+          child: 22
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 4
+          parent: 12
+    - Expression:
+        Alias:
+          name: bucket_id
+          child: 24
+    - Expression:
+        Row:
+          list:
+            - 17
+            - 19
+            - 21
+            - 23
+            - 25
+          distribution: ~
+    - Relational:
+        Selection:
+          children:
+            - 11
+          filter: 15
+          id: 12
+          output: 26
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 28
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 28
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 28
+    - Expression:
+        Alias:
+          name: product_code
+          child: 30
+    - Expression:
+        Row:
+          list:
+            - 29
+            - 31
+          distribution: ~
+    - Relational:
+        Projection:
+          children:
+            - 27
+          id: 28
+          output: 32
+relations:
+  hash_testing:
+    Segment:
+      columns:
+        - name: identification_number
+          type: integer
+        - name: product_code
+          type: string
+        - name: product_units
+          type: boolean
+        - name: sys_op
+          type: number
+        - name: bucket_id
+          type: unsigned
+      key:
+        positions:
+          - 0
+          - 1
+      name: hash_testing
+slices: ~
+top: 33
diff --git a/tests/artifactory/frontend/sql/ir/simple_union_query.yaml b/tests/artifactory/frontend/sql/ir/simple_union_query.yaml
new file mode 100644
index 0000000000..c34f93ff15
--- /dev/null
+++ b/tests/artifactory/frontend/sql/ir/simple_union_query.yaml
@@ -0,0 +1,563 @@
+# 
+# SELECT *
+# FROM
+#   (
+#     SELECT "identification_number", "product_code"
+#     FROM "hash_testing"
+#     WHERE "sys_op" = 1
+#     UNION ALL
+#     SELECT "identification_number", "product_code"
+#     FROM "hash_testing_hist"
+#     WHERE "sys_op" > 1
+#   ) AS "t3"
+# WHERE "identification_number" = 1
+#
+---
+nodes:
+  arena:
+    - Expression:
+        Reference:
+          targets: ~
+          position: 0
+          parent: 0
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 0
+    - Expression:
+        Reference:
+          targets: ~
+          position: 1
+          parent: 0
+    - Expression:
+        Alias:
+          name: product_code
+          child: 2
+    - Expression:
+        Reference:
+          targets: ~
+          position: 2
+          parent: 0
+    - Expression:
+        Alias:
+          name: product_units
+          child: 4
+    - Expression:
+        Reference:
+          targets: ~
+          position: 3
+          parent: 0
+    - Expression:
+        Alias:
+          name: sys_op
+          child: 6
+    - Expression:
+        Reference:
+          targets: ~
+          position: 4
+          parent: 0
+    - Expression:
+        Alias:
+          name: bucket_id
+          child: 8
+    - Expression:
+        Row:
+          list:
+            - 1
+            - 3
+            - 5
+            - 7
+            - 9
+          distribution: ~
+    - Relational:
+        ScanRelation:
+          output: 10
+          id: 0
+          relation: hash_testing
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 3
+          parent: 12
+    - Expression:
+        Row:
+          list:
+            - 12
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            Number: 1
+    - Expression:
+        Bool:
+          left: 13
+          op: Eq
+          right: 14
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 12
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 16
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 12
+    - Expression:
+        Alias:
+          name: product_code
+          child: 18
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 2
+          parent: 12
+    - Expression:
+        Alias:
+          name: product_units
+          child: 20
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 3
+          parent: 12
+    - Expression:
+        Alias:
+          name: sys_op
+          child: 22
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 4
+          parent: 12
+    - Expression:
+        Alias:
+          name: bucket_id
+          child: 24
+    - Expression:
+        Row:
+          list:
+            - 17
+            - 19
+            - 21
+            - 23
+            - 25
+          distribution: ~
+    - Relational:
+        Selection:
+          children:
+            - 11
+          filter: 15
+          id: 12
+          output: 26
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 28
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 28
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 28
+    - Expression:
+        Alias:
+          name: product_code
+          child: 30
+    - Expression:
+        Row:
+          list:
+            - 29
+            - 31
+          distribution: ~
+    - Relational:
+        Projection:
+          children:
+            - 27
+          id: 28
+          output: 32
+    - Expression:
+        Reference:
+          targets: ~
+          position: 0
+          parent: 34
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 34
+    - Expression:
+        Reference:
+          targets: ~
+          position: 1
+          parent: 34
+    - Expression:
+        Alias:
+          name: product_code
+          child: 36
+    - Expression:
+        Reference:
+          targets: ~
+          position: 2
+          parent: 34
+    - Expression:
+        Alias:
+          name: product_units
+          child: 38
+    - Expression:
+        Reference:
+          targets: ~
+          position: 3
+          parent: 34
+    - Expression:
+        Alias:
+          name: sys_op
+          child: 40
+    - Expression:
+        Reference:
+          targets: ~
+          position: 4
+          parent: 34
+    - Expression:
+        Alias:
+          name: bucket_id
+          child: 42
+    - Expression:
+        Row:
+          list:
+            - 35
+            - 37
+            - 39
+            - 41
+            - 43
+          distribution: ~
+    - Relational:
+        ScanRelation:
+          output: 44
+          id: 34
+          relation: hash_testing_hist
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 3
+          parent: 46
+    - Expression:
+        Row:
+          list:
+            - 46
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            Number: 1
+    - Expression:
+        Bool:
+          left: 47
+          op: Gt
+          right: 48
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 46
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 50
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 46
+    - Expression:
+        Alias:
+          name: product_code
+          child: 52
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 2
+          parent: 46
+    - Expression:
+        Alias:
+          name: product_units
+          child: 54
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 3
+          parent: 46
+    - Expression:
+        Alias:
+          name: sys_op
+          child: 56
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 4
+          parent: 46
+    - Expression:
+        Alias:
+          name: bucket_id
+          child: 58
+    - Expression:
+        Row:
+          list:
+            - 51
+            - 53
+            - 55
+            - 57
+            - 59
+          distribution: ~
+    - Relational:
+        Selection:
+          children:
+            - 45
+          filter: 49
+          id: 46
+          output: 60
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 62
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 62
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 62
+    - Expression:
+        Alias:
+          name: product_code
+          child: 64
+    - Expression:
+        Row:
+          list:
+            - 63
+            - 65
+          distribution: ~
+    - Relational:
+        Projection:
+          children:
+            - 61
+          id: 62
+          output: 66
+    - Expression:
+        Reference:
+          targets:
+            - 0
+            - 1
+          position: 0
+          parent: 68
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 68
+    - Expression:
+        Reference:
+          targets:
+            - 0
+            - 1
+          position: 1
+          parent: 68
+    - Expression:
+        Alias:
+          name: product_code
+          child: 70
+    - Expression:
+        Row:
+          list:
+            - 69
+            - 71
+          distribution: ~
+    - Relational:
+        UnionAll:
+          children:
+            - 33
+            - 67
+          id: 68
+          output: 72
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 74
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 74
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 74
+    - Expression:
+        Alias:
+          name: product_code
+          child: 76
+    - Expression:
+        Row:
+          list:
+            - 75
+            - 77
+          distribution: ~
+    - Relational:
+        ScanSubQuery:
+          alias: t3
+          children:
+            - 73
+          id: 74
+          output: 78
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 80
+    - Expression:
+        Row:
+          list:
+            - 80
+          distribution: ~
+    - Expression:
+        Constant:
+          value:
+            Number: 1
+    - Expression:
+        Bool:
+          left: 81
+          op: Eq
+          right: 82
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 80
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 84
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 80
+    - Expression:
+        Alias:
+          name: product_code
+          child: 86
+    - Expression:
+        Row:
+          list:
+            - 85
+            - 87
+          distribution: ~
+    - Relational:
+        Selection:
+          children:
+            - 79
+          filter: 83
+          id: 80
+          output: 88
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 0
+          parent: 90
+    - Expression:
+        Alias:
+          name: identification_number
+          child: 90
+    - Expression:
+        Reference:
+          targets:
+            - 0
+          position: 1
+          parent: 90
+    - Expression:
+        Alias:
+          name: product_code
+          child: 92
+    - Expression:
+        Row:
+          list:
+            - 91
+            - 93
+          distribution: ~
+    - Relational:
+        Projection:
+          children:
+            - 89
+          id: 90
+          output: 94
+relations:
+  hash_testing_hist:
+    Segment:
+      columns:
+        - name: identification_number
+          type: integer
+        - name: product_code
+          type: string
+        - name: product_units
+          type: boolean
+        - name: sys_op
+          type: number
+        - name: bucket_id
+          type: unsigned
+      key:
+        positions:
+          - 0
+          - 1
+      name: hash_testing_hist
+  hash_testing:
+    Segment:
+      columns:
+        - name: identification_number
+          type: integer
+        - name: product_code
+          type: string
+        - name: product_units
+          type: boolean
+        - name: sys_op
+          type: number
+        - name: bucket_id
+          type: unsigned
+      key:
+        positions:
+          - 0
+          - 1
+      name: hash_testing
+slices: ~
+top: 95
diff --git a/tests/artifactory/frontend/sql/simple_query.yaml b/tests/artifactory/frontend/sql/simple_query.yaml
index d1b0524e4e..ac9962ba0b 100644
--- a/tests/artifactory/frontend/sql/simple_query.yaml
+++ b/tests/artifactory/frontend/sql/simple_query.yaml
@@ -3,11 +3,10 @@ nodes:
   arena:
     - children:
         - 7
-        - 5
-        - 1
       rule: Select
       value: ~
     - children:
+        - 5
         - 2
       rule: Selection
       value: ~
@@ -20,7 +19,7 @@ nodes:
       rule: Number
       value: 1
     - children: []
-      rule: QuotedName
+      rule: Name
       value: "\"identification_number\""
     - children:
         - 6
@@ -30,6 +29,7 @@ nodes:
       rule: Table
       value: "\"test_space\""
     - children:
+        - 1
         - 10
         - 8
       rule: Projection
@@ -39,13 +39,13 @@ nodes:
       rule: Column
       value: ~
     - children: []
-      rule: QuotedName
+      rule: ProjectedName
       value: "\"product_code\""
     - children:
         - 11
       rule: Column
       value: ~
     - children: []
-      rule: QuotedName
+      rule: ProjectedName
       value: "\"identification_number\""
 top: 0
\ No newline at end of file
diff --git a/tests/artifactory/frontend/sql/transform_select_2.yaml b/tests/artifactory/frontend/sql/transform_select_2.yaml
index 4d3ef0e21c..b8704ca94e 100644
--- a/tests/artifactory/frontend/sql/transform_select_2.yaml
+++ b/tests/artifactory/frontend/sql/transform_select_2.yaml
@@ -22,6 +22,6 @@ nodes:
       rule: Column
       value: ~
     - children: []
-      rule: String
+      rule: ProjectedName
       value: a
 top: 0
diff --git a/tests/artifactory/frontend/sql/transform_select_3.yaml b/tests/artifactory/frontend/sql/transform_select_3.yaml
index 31fc36183f..1d90650130 100644
--- a/tests/artifactory/frontend/sql/transform_select_3.yaml
+++ b/tests/artifactory/frontend/sql/transform_select_3.yaml
@@ -19,7 +19,7 @@ nodes:
       rule: Number
       value: 1
     - children: []
-      rule: String
+      rule: Name
       value: a
     - children:
         - 6
@@ -38,6 +38,6 @@ nodes:
       rule: Column
       value: ~
     - children: []
-      rule: String
+      rule: ProjectedName
       value: a
 top: 0
diff --git a/tests/artifactory/frontend/sql/transform_select_4.yaml b/tests/artifactory/frontend/sql/transform_select_4.yaml
index 89be662949..13acc82cf9 100644
--- a/tests/artifactory/frontend/sql/transform_select_4.yaml
+++ b/tests/artifactory/frontend/sql/transform_select_4.yaml
@@ -19,10 +19,10 @@ nodes:
       rule: Eq
       value: ~
     - children: []
-      rule: String
+      rule: Name
       value: t2.a
     - children: []
-      rule: String
+      rule: Name
       value: t1.a
     - children:
         - 9
diff --git a/tests/artifactory/frontend/sql/transform_select_5.yaml b/tests/artifactory/frontend/sql/transform_select_5.yaml
index c4eb4f4087..bc3ef7ade6 100644
--- a/tests/artifactory/frontend/sql/transform_select_5.yaml
+++ b/tests/artifactory/frontend/sql/transform_select_5.yaml
@@ -19,7 +19,7 @@ nodes:
       rule: Number
       value: 0
     - children: []
-      rule: String
+      rule: Name
       value: t1.a
     - children:
         - 6
@@ -35,10 +35,10 @@ nodes:
       rule: Eq
       value: ~
     - children: []
-      rule: String
+      rule: Name
       value: t2.a
     - children: []
-      rule: String
+      rule: Name
       value: t1.a
     - children:
         - 13
-- 
GitLab