From 015556a0dbcd2ac6b1a664a986972638ff646996 Mon Sep 17 00:00:00 2001
From: EmirVildanov <reddog201030@gmail.com>
Date: Tue, 3 Sep 2024 19:05:25 +0300
Subject: [PATCH] feat: add logic of correct local SQL generation for the case
 of asterisk (not in a view of references, but as "*")

---
 sbroad-core/src/backend/sql/ir.rs             |   7 +
 .../src/backend/sql/ir/tests/inner_join.rs    |   4 +-
 .../src/backend/sql/ir/tests/projection.rs    |  12 +-
 sbroad-core/src/backend/sql/tree.rs           | 159 ++++++++++++++++--
 sbroad-core/src/executor/tests.rs             |  41 ++---
 sbroad-core/src/executor/tests/bucket_id.rs   |   4 +-
 .../src/executor/tests/empty_motion.rs        |   2 +-
 sbroad-core/src/executor/tests/exec_plan.rs   |  18 +-
 sbroad-core/src/frontend/sql.rs               |  21 ++-
 sbroad-core/src/frontend/sql/ir.rs            |   1 +
 sbroad-core/src/ir/aggregates.rs              |   1 +
 sbroad-core/src/ir/expression.rs              |  49 +++++-
 sbroad-core/src/ir/helpers.rs                 |   3 +-
 sbroad-core/src/ir/helpers/tests.rs           |  96 +++++------
 sbroad-core/src/ir/operator.rs                |  28 +--
 .../ir/transformation/equality_propagation.rs |   6 +-
 .../equality_propagation/tests.rs             |   4 +-
 .../ir/transformation/not_push_down/tests.rs  |  10 +-
 .../transformation/redistribution/eq_cols.rs  |   5 +-
 .../transformation/redistribution/groupby.rs  |   8 +-
 20 files changed, 337 insertions(+), 142 deletions(-)

diff --git a/sbroad-core/src/backend/sql/ir.rs b/sbroad-core/src/backend/sql/ir.rs
index 51bd0da8e..ce28164de 100644
--- a/sbroad-core/src/backend/sql/ir.rs
+++ b/sbroad-core/src/backend/sql/ir.rs
@@ -308,6 +308,13 @@ impl ExecutionPlan {
                 match data {
                     // TODO: should we care about plans without projections?
                     // Or they should be treated as invalid?
+                    SyntaxData::Asterisk(relation_name) => {
+                        if let Some(relation_name) = relation_name {
+                            push_identifier(&mut sql, relation_name.as_str());
+                            sql.push('.')
+                        }
+                        sql.push('*')
+                    }
                     SyntaxData::Alias(s) => {
                         sql.push_str("as ");
                         push_identifier(&mut sql, s);
diff --git a/sbroad-core/src/backend/sql/ir/tests/inner_join.rs b/sbroad-core/src/backend/sql/ir/tests/inner_join.rs
index 2780d7986..43558fd3e 100644
--- a/sbroad-core/src/backend/sql/ir/tests/inner_join.rs
+++ b/sbroad-core/src/backend/sql/ir/tests/inner_join.rs
@@ -64,7 +64,7 @@ fn inner_join2_latest() {
             r#""hash_testing"."product_units","#,
             r#""hash_testing"."sys_op" FROM "hash_testing") as "hash_testing""#,
             r#"INNER JOIN"#,
-            r#"(SELECT "history"."id" FROM "history" WHERE ("history"."id") = (?)) as "t""#,
+            r#"(SELECT * FROM "history" WHERE ("history"."id") = (?)) as "t""#,
             r#"ON ("hash_testing"."identification_number") = ("t"."id")"#,
             r#"WHERE ("hash_testing"."product_code") = (?)"#,
         ),
@@ -89,7 +89,7 @@ fn inner_join2_oldest() {
             r#""hash_testing"."product_units","#,
             r#""hash_testing"."sys_op" FROM "hash_testing") as "hash_testing""#,
             r#"INNER JOIN"#,
-            r#"(SELECT "history"."id" FROM "history" WHERE ("history"."id") = (?)) as "t""#,
+            r#"(SELECT * FROM "history" WHERE ("history"."id") = (?)) as "t""#,
             r#"ON ("hash_testing"."identification_number") = ("t"."id")"#,
             r#"WHERE ("hash_testing"."product_code") = (?)"#,
         ),
diff --git a/sbroad-core/src/backend/sql/ir/tests/projection.rs b/sbroad-core/src/backend/sql/ir/tests/projection.rs
index ff49a8403..aa56503d5 100644
--- a/sbroad-core/src/backend/sql/ir/tests/projection.rs
+++ b/sbroad-core/src/backend/sql/ir/tests/projection.rs
@@ -47,10 +47,8 @@ fn projection2_latest() {
         WHERE "identification_number" = 1"#;
     let expected = PatternWithParams::new(
         format!(
-            "{} {} {} {} {}",
-            r#"SELECT "hash_testing"."identification_number","#,
-            r#""hash_testing"."product_code","#,
-            r#""hash_testing"."product_units", "hash_testing"."sys_op""#,
+            "{} {} {}",
+            r#"SELECT *"#,
             r#"FROM "hash_testing""#,
             r#"WHERE ("hash_testing"."identification_number") = (?)"#
         ),
@@ -66,10 +64,8 @@ fn projection2_oldest() {
         WHERE "identification_number" = 1"#;
     let expected = PatternWithParams::new(
         format!(
-            "{} {} {} {} {}",
-            r#"SELECT "hash_testing"."identification_number","#,
-            r#""hash_testing"."product_code","#,
-            r#""hash_testing"."product_units", "hash_testing"."sys_op""#,
+            "{} {} {}",
+            r#"SELECT *"#,
             r#"FROM "hash_testing""#,
             r#"WHERE ("hash_testing"."identification_number") = (?)"#
         ),
diff --git a/sbroad-core/src/backend/sql/tree.rs b/sbroad-core/src/backend/sql/tree.rs
index 9ec30bd10..2cd8d34c3 100644
--- a/sbroad-core/src/backend/sql/tree.rs
+++ b/sbroad-core/src/backend/sql/tree.rs
@@ -1,5 +1,6 @@
 use serde::{Deserialize, Serialize};
 use smol_str::{format_smolstr, SmolStr};
+use std::collections::HashSet;
 use std::mem::take;
 
 use crate::errors::{Entity, SbroadError};
@@ -26,6 +27,8 @@ use sbroad_proc::otm_child_span;
 pub enum SyntaxData {
     /// "as \"alias_name\""
     Alias(SmolStr),
+    /// "*"
+    Asterisk(Option<SmolStr>),
     /// "as alias_name"
     UnquotedAlias(SmolStr),
     /// "cast"
@@ -116,6 +119,14 @@ pub struct SyntaxNode {
 }
 
 impl SyntaxNode {
+    fn new_asterisk(relation_name: Option<SmolStr>) -> Self {
+        SyntaxNode {
+            data: SyntaxData::Asterisk(relation_name),
+            left: None,
+            right: Vec::new(),
+        }
+    }
+
     fn new_alias(name: SmolStr) -> Self {
         SyntaxNode {
             data: SyntaxData::Alias(name),
@@ -1456,19 +1467,145 @@ impl<'p> SyntaxPlan<'p> {
             }
         }
 
-        let mut children = Vec::with_capacity(list.len() * 2 + 3);
-        // The nodes on the stack are in the reverse order.
-        children.push(self.nodes.push_sn_non_plan(SyntaxNode::new_close()));
-        if let Some((first, others)) = list.split_first() {
-            for child_id in others.iter().rev() {
-                children.push(self.pop_from_stack(*child_id, id));
-                children.push(self.nodes.push_sn_non_plan(SyntaxNode::new_comma()));
-            }
-            children.push(self.pop_from_stack(*first, id));
+        // Vec of row's sn children nodes.
+        let mut list_sn_ids = Vec::with_capacity(list.len());
+        for list_id in list.iter().rev() {
+            list_sn_ids.push(self.pop_from_stack(*list_id, id));
         }
-        children.push(self.nodes.push_sn_non_plan(SyntaxNode::new_open()));
         // Need to reverse the order of the children back.
-        children.reverse();
+        list_sn_ids.reverse();
+
+        // Set of relation names for which we've already generated asterisk (*).
+        // In case we see in output several references that we initially generated from
+        // an asterisk we want to generate that asterisk only once.
+        let mut already_handled_asterisk_sources = HashSet::new();
+        let mut last_handled_asterisk_id: Option<usize> = None;
+
+        // Children number + the same number of commas + parentheses.
+        let mut children = Vec::with_capacity(list.len() * 2 + 2);
+        children.push(self.nodes.push_sn_non_plan(SyntaxNode::new_open()));
+
+        enum NodeToAdd {
+            SnId(usize),
+            Asterisk(SyntaxNode),
+            Comma,
+        }
+
+        let mut handle_reference =
+            |sn_id: usize, need_comma: bool, expr_node: &Expression| -> Vec<NodeToAdd> {
+                let mut non_reference_nodes = || -> Vec<NodeToAdd> {
+                    let mut nodes_to_add = Vec::new();
+                    if last_handled_asterisk_id.is_some() {
+                        nodes_to_add.push(NodeToAdd::Comma);
+                    }
+                    nodes_to_add.push(NodeToAdd::SnId(sn_id));
+                    if need_comma {
+                        nodes_to_add.push(NodeToAdd::Comma);
+                    }
+                    last_handled_asterisk_id = None;
+                    nodes_to_add
+                };
+
+                let mut nodes_to_add = Vec::new();
+                if let Expression::Reference {
+                    asterisk_source:
+                        Some(ReferenceAsteriskSource {
+                            relation_name,
+                            asterisk_id,
+                        }),
+                    ..
+                } = expr_node
+                {
+                    let mut need_comma = false;
+                    let asterisk_id = *asterisk_id;
+                    if let Some(last_handled_asterisk_id) = last_handled_asterisk_id {
+                        if asterisk_id != last_handled_asterisk_id {
+                            need_comma = true;
+                            already_handled_asterisk_sources.clear();
+                        }
+                    }
+
+                    let pair_to_check = if let Some(relation_name) = relation_name {
+                        (Some(relation_name.clone()), asterisk_id)
+                    } else {
+                        (None, asterisk_id)
+                    };
+
+                    let asterisk_node_to_add =
+                        if !already_handled_asterisk_sources.contains(&pair_to_check) {
+                            already_handled_asterisk_sources.insert(pair_to_check);
+                            let res = if relation_name.is_some() {
+                                SyntaxNode::new_asterisk(relation_name.clone())
+                            } else {
+                                SyntaxNode::new_asterisk(None)
+                            };
+                            Some(res)
+                        } else {
+                            None
+                        };
+
+                    last_handled_asterisk_id = Some(asterisk_id);
+                    if need_comma {
+                        nodes_to_add.push(NodeToAdd::Comma);
+                    }
+                    if let Some(asterisk_node_to_add) = asterisk_node_to_add {
+                        nodes_to_add.push(NodeToAdd::Asterisk(asterisk_node_to_add));
+                    }
+                } else {
+                    return non_reference_nodes();
+                }
+                nodes_to_add
+            };
+
+        let mut handle_single_list_sn_id = |sn_id: usize,
+                                            need_comma: bool|
+         -> Result<(), SbroadError> {
+            let sn_node = self.nodes.get_sn(sn_id);
+            let sn_plan_node = self.get_plan_node(&sn_node.data)?;
+
+            let nodes_to_add = if let Some(Node::Expression(node_expr)) = sn_plan_node {
+                match node_expr {
+                    Expression::Alias { child, .. } => {
+                        let alias_child = self.plan.get_ir_plan().get_expression_node(*child)?;
+                        handle_reference(sn_id, need_comma, alias_child)
+                    }
+                    _ => handle_reference(sn_id, need_comma, node_expr),
+                }
+            } else {
+                // As it's not ad Alias under Projection output, we don't have to
+                // dead with its machinery flags.
+                let mut nodes_to_add = Vec::new();
+                nodes_to_add.push(NodeToAdd::SnId(sn_id));
+                if need_comma {
+                    nodes_to_add.push(NodeToAdd::Comma)
+                }
+                nodes_to_add
+            };
+
+            for node in nodes_to_add {
+                match node {
+                    NodeToAdd::SnId(sn_id) => {
+                        children.push(sn_id);
+                    }
+                    NodeToAdd::Asterisk(asterisk) => {
+                        children.push(self.nodes.push_sn_non_plan(asterisk))
+                    }
+                    NodeToAdd::Comma => {
+                        children.push(self.nodes.push_sn_non_plan(SyntaxNode::new_comma()))
+                    }
+                }
+            }
+
+            Ok(())
+        };
+
+        if let Some((list_sn_id_last, list_sn_ids_other)) = list_sn_ids.split_last() {
+            for list_sn_id in list_sn_ids_other {
+                handle_single_list_sn_id(*list_sn_id, true).expect("Row child should be valid.")
+            }
+            handle_single_list_sn_id(*list_sn_id_last, false).expect("Row child should be valid.")
+        }
+        children.push(self.nodes.push_sn_non_plan(SyntaxNode::new_close()));
         let sn = SyntaxNode::new_pointer(id, None, children);
         self.nodes.push_sn_plan(sn);
     }
diff --git a/sbroad-core/src/executor/tests.rs b/sbroad-core/src/executor/tests.rs
index afe2234e8..9b407d9aa 100644
--- a/sbroad-core/src/executor/tests.rs
+++ b/sbroad-core/src/executor/tests.rs
@@ -74,7 +74,7 @@ fn shard_union_query() {
         LuaValue::String(String::from(PatternWithParams::new(
             format!(
                 "{} {}{} {} {}{} {}",
-                r#"SELECT "t3"."id""#,
+                r#"SELECT *"#,
                 r#"FROM ("#,
                 r#"SELECT "test_space"."id" FROM "test_space" WHERE ("test_space"."sys_op") = (?)"#,
                 r#"UNION ALL"#,
@@ -252,7 +252,7 @@ fn union_linker_test() {
             LuaValue::String(String::from(PatternWithParams::new(
                 format!(
                     "{} {}{} {} {} {} {} {} {}{} {}",
-                    r#"SELECT "t1"."id", "t1"."FIRST_NAME""#,
+                    r#"SELECT *"#,
                     r#"FROM ("#,
                     r#"SELECT "test_space"."id", "test_space"."FIRST_NAME""#,
                     r#"FROM "test_space""#,
@@ -272,7 +272,7 @@ fn union_linker_test() {
             LuaValue::String(String::from(PatternWithParams::new(
                 format!(
                     "{} {}{} {} {} {} {} {} {}{} {}",
-                    r#"SELECT "t1"."id", "t1"."FIRST_NAME""#,
+                    r#"SELECT *"#,
                     r#"FROM ("#,
                     r#"SELECT "test_space"."id", "test_space"."FIRST_NAME""#,
                     r#"FROM "test_space""#,
@@ -350,10 +350,8 @@ WHERE "t3"."id" = 2 AND "t8"."identification_number" = 2"#;
         LuaValue::String(format!("Execute query on a bucket [{bucket2}]")),
         LuaValue::String(String::from(PatternWithParams::new(
             format!(
-                "{}, {}, {} {}{} {} {} {} {} {} {}{} {} {}{} {} {}",
-                r#"SELECT "t3"."id""#,
-                r#""t3"."FIRST_NAME""#,
-                r#""t8"."identification_number""#,
+                "{} {}{} {} {} {} {} {} {}{} {} {}{} {} {}",
+                r#"SELECT *"#,
                 r#"FROM ("#,
                 r#"SELECT "test_space"."id", "test_space"."FIRST_NAME""#,
                 r#"FROM "test_space""#,
@@ -678,7 +676,7 @@ on q."f" = "t1"."a""#;
         LuaValue::String(String::from(PatternWithParams::new(
             format!(
                 "{} {} {} {}",
-                r#"SELECT "t1"."a", "t1"."b", "q"."f", "q"."b" FROM"#,
+                r#"SELECT * FROM"#,
                 r#"(SELECT "t1"."a", "t1"."b" FROM "t1") as "t1""#,
                 r#"INNER JOIN (SELECT "COL_1","COL_2" FROM "TMP_test_1136")"#,
                 r#"as "q" ON ("q"."f") = ("t1"."a")"#,
@@ -788,12 +786,8 @@ fn anonymous_col_index_test() {
             LuaValue::String(format!("Execute query on a bucket [{bucket3}]")),
             LuaValue::String(String::from(PatternWithParams::new(
                 format!(
-                    "{} {} {} {} {} {} {} {} {} {}",
-                    "SELECT",
-                    r#""test_space"."id","#,
-                    r#""test_space"."sysFrom","#,
-                    r#""test_space"."FIRST_NAME","#,
-                    r#""test_space"."sys_op""#,
+                    "{} {} {} {} {} {}",
+                    "SELECT *",
                     r#"FROM "test_space""#,
                     r#"WHERE ("test_space"."id") in"#,
                     r#"(SELECT "COL_1" FROM "TMP_test_1136")"#,
@@ -807,13 +801,9 @@ fn anonymous_col_index_test() {
             LuaValue::String(format!("Execute query on a bucket [{bucket2}]")),
             LuaValue::String(String::from(PatternWithParams::new(
                 format!(
-                    "{} {} {} {} {} {} {} {} {} {}",
+                    "{} {} {} {} {} {}",
                     "SELECT",
-                    r#""test_space"."id","#,
-                    r#""test_space"."sysFrom","#,
-                    r#""test_space"."FIRST_NAME","#,
-                    r#""test_space"."sys_op""#,
-                    r#"FROM "test_space""#,
+                    r#"* FROM "test_space""#,
                     r#"WHERE ("test_space"."id") in"#,
                     r#"(SELECT "COL_1" FROM "TMP_test_1136")"#,
                     r#"or ("test_space"."id") in"#,
@@ -846,10 +836,8 @@ fn sharding_column1_test() {
         LuaValue::String(format!("Execute query on a bucket [{bucket}]")),
         LuaValue::String(String::from(PatternWithParams::new(
             format!(
-                "{} {} {}",
-                r#"SELECT "test_space"."id", "test_space"."sysFrom","#,
-                r#""test_space"."FIRST_NAME", "test_space"."sys_op""#,
-                r#"FROM "test_space" WHERE ("test_space"."id") = (?)"#,
+                "{} {}",
+                r#"SELECT *"#, r#"FROM "test_space" WHERE ("test_space"."id") = (?)"#,
             ),
             vec![Value::from(1_u64)],
         ))),
@@ -877,9 +865,8 @@ fn sharding_column2_test() {
         LuaValue::String(format!("Execute query on a bucket [{bucket}]")),
         LuaValue::String(String::from(PatternWithParams::new(
             format!(
-                "{} {} {}",
-                r#"SELECT "test_space"."id", "test_space"."sysFrom","#,
-                r#""test_space"."FIRST_NAME", "test_space"."sys_op","#,
+                "{} {}",
+                r#"SELECT *,"#,
                 r#""test_space"."bucket_id" FROM "test_space" WHERE ("test_space"."id") = (?)"#,
             ),
             vec![Value::from(1_u64)],
diff --git a/sbroad-core/src/executor/tests/bucket_id.rs b/sbroad-core/src/executor/tests/bucket_id.rs
index f494efe31..64f003f6d 100644
--- a/sbroad-core/src/executor/tests/bucket_id.rs
+++ b/sbroad-core/src/executor/tests/bucket_id.rs
@@ -24,7 +24,7 @@ fn bucket1_test() {
     expected.rows.push(vec![
         LuaValue::String("Execute query on all buckets".to_string()),
         LuaValue::String(String::from(PatternWithParams::new(
-            r#"SELECT "t1"."a", "t1"."b", "t1"."bucket_id" FROM "t1""#.to_string(),
+            r#"SELECT *, "t1"."bucket_id" FROM "t1""#.to_string(),
             vec![],
         ))),
     ]);
@@ -83,7 +83,7 @@ fn bucket3_test() {
     expected.rows.push(vec![
         LuaValue::String("Execute query on all buckets".to_string()),
         LuaValue::String(String::from(PatternWithParams::new(
-            r#"SELECT "t1"."a", "t1"."b", "func" (?) as "col_1" FROM "t1""#.to_string(),
+            r#"SELECT *, "func" (?) as "col_1" FROM "t1""#.to_string(),
             vec![Value::from("111".to_string())],
         ))),
     ]);
diff --git a/sbroad-core/src/executor/tests/empty_motion.rs b/sbroad-core/src/executor/tests/empty_motion.rs
index 913412f9b..bbb95c6c7 100644
--- a/sbroad-core/src/executor/tests/empty_motion.rs
+++ b/sbroad-core/src/executor/tests/empty_motion.rs
@@ -64,7 +64,7 @@ fn empty_motion1_test() {
         LuaValue::String(String::from(PatternWithParams::new(
             format!(
                 "{} {} {} {} {} {} {} {} {} {} {} {} {} {}",
-                r#"SELECT "Q"."a", "Q"."b" FROM"#,
+                r#"SELECT * FROM"#,
                 r#"(SELECT "t"."a", "t"."b" FROM"#,
                 r#"(SELECT "t"."a", "t"."b", "t"."c", "t"."d" FROM "t") as "t""#,
                 r#"INNER JOIN"#,
diff --git a/sbroad-core/src/executor/tests/exec_plan.rs b/sbroad-core/src/executor/tests/exec_plan.rs
index a13c00713..b299551cf 100644
--- a/sbroad-core/src/executor/tests/exec_plan.rs
+++ b/sbroad-core/src/executor/tests/exec_plan.rs
@@ -387,7 +387,7 @@ fn exec_plan_subquery_under_motion_without_alias() {
     assert_eq!(
         sql,
         PatternWithParams::new(
-            r#"SELECT "tid", "COL_1" as "sid" FROM (SELECT "test_space"."id" as "tid" FROM "test_space") INNER JOIN (SELECT "COL_1" FROM "TMP_test_0136") ON ?"#.to_string(),
+            r#"SELECT * FROM (SELECT "test_space"."id" as "tid" FROM "test_space") INNER JOIN (SELECT "COL_1" FROM "TMP_test_0136") ON ?"#.to_string(),
             vec![Value::Boolean(true)]
         ));
 }
@@ -428,7 +428,7 @@ fn exec_plan_subquery_under_motion_with_alias() {
     assert_eq!(
         sql,
         PatternWithParams::new(
-            r#"SELECT "tid", "hti"."COL_1" as "sid" FROM (SELECT "test_space"."id" as "tid" FROM "test_space") INNER JOIN (SELECT "COL_1" FROM "TMP_test_0136") as "hti" ON ?"#.to_string(),
+            r#"SELECT * FROM (SELECT "test_space"."id" as "tid" FROM "test_space") INNER JOIN (SELECT "COL_1" FROM "TMP_test_0136") as "hti" ON ?"#.to_string(),
             vec![Value::Boolean(true)]
         ));
 }
@@ -749,13 +749,7 @@ fn global_table_scan() {
 
     assert_eq!(
         sql,
-        PatternWithParams::new(
-            format!(
-                "{}",
-                r#"SELECT "global_t"."a", "global_t"."b" FROM "global_t""#,
-            ),
-            vec![]
-        )
+        PatternWithParams::new(format!("{}", r#"SELECT * FROM "global_t""#,), vec![])
     );
 }
 
@@ -1035,13 +1029,13 @@ fn global_union_all4() {
     let expected = vec![
         ReplicasetDispatchInfo {
             rs_id: 0,
-            pattern: r#" select cast(null as integer) where false UNION ALL SELECT "a" FROM (select cast(null as integer) where false UNION ALL SELECT "t2"."f" FROM "t2")"#.to_string(),
+            pattern: r#" select cast(null as integer) where false UNION ALL SELECT * FROM (select cast(null as integer) where false UNION ALL SELECT "t2"."f" FROM "t2")"#.to_string(),
             params: vec![],
             vtables_map: HashMap::new(),
         },
         ReplicasetDispatchInfo {
             rs_id: 1,
-            pattern: r#"SELECT "global_t"."b" FROM "global_t" UNION ALL SELECT "a" FROM (SELECT "global_t"."a" FROM "global_t" UNION ALL SELECT "t2"."f" FROM "t2")"#.to_string(),
+            pattern: r#"SELECT "global_t"."b" FROM "global_t" UNION ALL SELECT * FROM (SELECT "global_t"."a" FROM "global_t" UNION ALL SELECT "t2"."f" FROM "t2")"#.to_string(),
             params: vec![],
             vtables_map: HashMap::new(),
         },
@@ -1290,7 +1284,7 @@ fn exec_plan_order_by_with_join() {
     assert_eq!(
         sql,
         PatternWithParams::new(
-            r#"SELECT "f"."a", "s"."COL_1" as "a" FROM (SELECT "t"."a" FROM "t") as "f" INNER JOIN (SELECT "COL_1" FROM "TMP_test_28") as "s" ON ?"#.to_string(),
+            r#"SELECT * FROM (SELECT "t"."a" FROM "t") as "f" INNER JOIN (SELECT "COL_1" FROM "TMP_test_28") as "s" ON ?"#.to_string(),
             vec![Value::Boolean(true)]
         )
     );
diff --git a/sbroad-core/src/frontend/sql.rs b/sbroad-core/src/frontend/sql.rs
index 5782229fd..7a552669b 100644
--- a/sbroad-core/src/frontend/sql.rs
+++ b/sbroad-core/src/frontend/sql.rs
@@ -33,7 +33,7 @@ use crate::ir::expression::{
     ColumnPositionMap, ColumnWithScan, ColumnsRetrievalSpec, ExpressionId, FunctionFeature,
     Position, TrimKind,
 };
-use crate::ir::node::expression::{Expression, MutExpression};
+use crate::ir::node::expression::{Expression, MutExpression, ReferenceAsteriskSource};
 use crate::ir::node::relational::Relational;
 use crate::ir::node::{
     AlterSystem, AlterUser, BoolExpr, Constant, CountAsterisk, CreateIndex, CreateProc, CreateRole,
@@ -2268,7 +2268,7 @@ where
                         let col_type = plan
                             .get_expression_node(*child_alias_id)?
                             .calculate_type(plan)?;
-                        let ref_id = plan.nodes.add_ref(None, Some(vec![0]), col_position, col_type);
+                        let ref_id = plan.nodes.add_ref(None, Some(vec![0]), col_position, col_type, None);
                         (ref_id, false)
                     };
                     worker.reference_to_name_map.insert(ref_id, (col_name, is_row));
@@ -3099,6 +3099,10 @@ impl AbstractSyntaxTree {
                     let mut proj_columns: Vec<NodeId> = Vec::with_capacity(ast_columns_ids.len());
 
                     let mut unnamed_col_pos = 0;
+                    // Unique identifier for each "*" met under projection. Uniqueness is local
+                    // for each projection. Used to distinguish the source of asterisk projections
+                    // like `select *, * from t`, where there are several of them.
+                    let mut asterisk_id = 0;
                     for ast_column_id in ast_columns_ids {
                         let ast_column = self.nodes.get_node(*ast_column_id)?;
                         match ast_column.rule {
@@ -3152,15 +3156,25 @@ impl AbstractSyntaxTree {
                                         plan_rel_child_id,
                                         filtered_col_ids,
                                         false,
+                                        Some(ReferenceAsteriskSource::new(
+                                            Some(table_name),
+                                            asterisk_id,
+                                        )),
                                     )?
                                 } else {
-                                    plan.add_row_for_output(plan_rel_child_id, &[], false)?
+                                    plan.add_row_for_output(
+                                        plan_rel_child_id,
+                                        &[],
+                                        false,
+                                        Some(ReferenceAsteriskSource::new(None, asterisk_id)),
+                                    )?
                                 };
 
                                 let row_list = plan.get_row_list(plan_asterisk_id)?;
                                 for row_id in row_list {
                                     proj_columns.push(*row_id);
                                 }
+                                asterisk_id += 1;
                             }
                             _ => {
                                 return Err(SbroadError::Invalid(
@@ -3404,6 +3418,7 @@ impl AbstractSyntaxTree {
                         &NewColumnsSource::Other {
                             child: proj_child_id,
                             columns_spec: Some(ColumnsRetrievalSpec::Names(pk_columns)),
+                            asterisk_source: None,
                         },
                         false,
                         false,
diff --git a/sbroad-core/src/frontend/sql/ir.rs b/sbroad-core/src/frontend/sql/ir.rs
index feb53e417..6b8a5bfeb 100644
--- a/sbroad-core/src/frontend/sql/ir.rs
+++ b/sbroad-core/src/frontend/sql/ir.rs
@@ -467,6 +467,7 @@ impl SubtreeCloner {
                 targets: _,
                 position: _,
                 col_type: _,
+                asterisk_source: _,
             })
             | ExprOwned::CountAsterisk { .. } => {}
             ExprOwned::Alias(Alias {
diff --git a/sbroad-core/src/ir/aggregates.rs b/sbroad-core/src/ir/aggregates.rs
index d06ba2240..8b447a6b9 100644
--- a/sbroad-core/src/ir/aggregates.rs
+++ b/sbroad-core/src/ir/aggregates.rs
@@ -316,6 +316,7 @@ impl SimpleAggregate {
                 targets: Some(vec![0]),
                 position,
                 col_type: fun_type.clone(),
+                asterisk_source: None,
             };
             let ref_id = plan.nodes.push(ref_node.into());
             let children = match self.kind {
diff --git a/sbroad-core/src/ir/expression.rs b/sbroad-core/src/ir/expression.rs
index 9c3eb7579..5700fcdba 100644
--- a/sbroad-core/src/ir/expression.rs
+++ b/sbroad-core/src/ir/expression.rs
@@ -32,6 +32,25 @@ pub mod types;
 
 pub(crate) type ExpressionId = NodeId;
 
+/// Helper structure for cases of references generated from asterisk.
+#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, Hash)]
+pub struct ReferenceAsteriskSource {
+    /// None                -> generated from simple asterisk: `select * from t`
+    /// Some(relation_name) -> generated from table asterisk: `select t.* from t`
+    pub relation_name: Option<SmolStr>,
+    /// Unique asterisk id local for single Projection
+    pub asterisk_id: usize,
+}
+
+impl ReferenceAsteriskSource {
+    pub fn new(relation_name: Option<SmolStr>, asterisk_id: usize) -> Self {
+        Self {
+            relation_name,
+            asterisk_id,
+        }
+    }
+}
+
 #[derive(Clone, Debug, Hash, Deserialize, PartialEq, Eq, Serialize)]
 pub enum FunctionFeature {
     /// Current function is an aggregate function and is marked as DISTINCT.
@@ -139,12 +158,14 @@ impl Nodes {
         targets: Option<Vec<usize>>,
         position: usize,
         col_type: Type,
+        asterisk_source: Option<ReferenceAsteriskSource>,
     ) -> NodeId {
         let r = Reference {
             parent,
             targets,
             position,
             col_type,
+            asterisk_source,
         };
         self.push(r.into())
     }
@@ -549,6 +570,7 @@ impl<'plan> Comparator<'plan> {
                 position,
                 targets,
                 col_type,
+                asterisk_source: is_asterisk,
             }) => match self.policy {
                 ReferencePolicy::ByAliases => {
                     self.plan
@@ -561,6 +583,7 @@ impl<'plan> Comparator<'plan> {
                     position.hash(state);
                     targets.hash(state);
                     col_type.hash(state);
+                    is_asterisk.hash(state);
                 }
             },
             Expression::Row(Row { list, .. }) => {
@@ -574,7 +597,7 @@ impl<'plan> Comparator<'plan> {
                 func_type,
                 feature,
                 is_system: is_aggr,
-            }) => {
+            } => {
                 feature.hash(state);
                 func_type.hash(state);
                 name.hash(state);
@@ -815,6 +838,8 @@ pub enum NewColumnsSource<'targets> {
     Other {
         child: NodeId,
         columns_spec: Option<ColumnsRetrievalSpec<'targets>>,
+        /// Indicates whether requested output is coming from asterisk.
+        asterisk_source: Option<ReferenceAsteriskSource>,
     },
 }
 
@@ -899,6 +924,15 @@ impl<'source> NewColumnsSource<'source> {
         }
     }
 
+    fn get_asterisk_source(&self) -> Option<ReferenceAsteriskSource> {
+        match self {
+            NewColumnsSource::Other {
+                asterisk_source, ..
+            } => asterisk_source.clone(),
+            _ => None,
+        }
+    }
+
     fn targets(&self) -> Vec<usize> {
         match self {
             NewColumnsSource::Join { targets, .. } => match targets {
@@ -1027,9 +1061,13 @@ impl Plan {
         let mut result_row_list: Vec<NodeId> = Vec::with_capacity(filtered_children_row_list.len());
         for (pos, alias_node_id, new_targets) in filtered_children_row_list {
             let alias_expr = self.get_expression_node(alias_node_id)?;
+            let asterisk_source = source.get_asterisk_source();
             let alias_name = SmolStr::from(alias_expr.get_alias_name()?);
             let col_type = alias_expr.calculate_type(self)?;
-            let r_id = self.nodes.add_ref(None, Some(new_targets), pos, col_type);
+
+            let r_id = self
+                .nodes
+                .add_ref(None, Some(new_targets), pos, col_type, asterisk_source);
             if need_aliases {
                 let a_id = self.nodes.add_alias(&alias_name, r_id)?;
                 result_row_list.push(a_id);
@@ -1052,11 +1090,13 @@ impl Plan {
         rel_node: NodeId,
         indices: Vec<usize>,
         need_sharding_column: bool,
+        asterisk_source: Option<ReferenceAsteriskSource>,
     ) -> Result<NodeId, SbroadError> {
         let list = self.new_columns(
             &NewColumnsSource::Other {
                 child: rel_node,
                 columns_spec: Some(ColumnsRetrievalSpec::Indices(indices)),
+                asterisk_source,
             },
             true,
             need_sharding_column,
@@ -1076,6 +1116,7 @@ impl Plan {
         rel_node: NodeId,
         col_names: &[&str],
         need_sharding_column: bool,
+        asterisk_source: Option<ReferenceAsteriskSource>,
     ) -> Result<NodeId, SbroadError> {
         let specific_columns = if col_names.is_empty() {
             None
@@ -1091,6 +1132,7 @@ impl Plan {
             &NewColumnsSource::Other {
                 child: rel_node,
                 columns_spec: specific_columns,
+                asterisk_source,
             },
             true,
             need_sharding_column,
@@ -1166,6 +1208,7 @@ impl Plan {
             &NewColumnsSource::Other {
                 child,
                 columns_spec: specific_columns,
+                asterisk_source: None,
             },
             false,
             true,
@@ -1202,7 +1245,7 @@ impl Plan {
             let alias_type = self.get_expression_node(alias_id)?.calculate_type(self)?;
             let ref_id = self
                 .nodes
-                .add_ref(parent, Some(vec![target]), pos, alias_type);
+                .add_ref(parent, Some(vec![target]), pos, alias_type, None);
             new_refs.push(ref_id);
         }
         let row_id = self.nodes.add_row(new_refs, None);
diff --git a/sbroad-core/src/ir/helpers.rs b/sbroad-core/src/ir/helpers.rs
index 91a263992..33557db97 100644
--- a/sbroad-core/src/ir/helpers.rs
+++ b/sbroad-core/src/ir/helpers.rs
@@ -142,8 +142,9 @@ impl Plan {
                     position,
                     parent,
                     col_type,
+                    ..
                 }) => {
-                    let alias_name = self.get_alias_from_reference_node(&expr).unwrap();
+                    let alias_name = self.get_alias_from_reference_node(expr).unwrap();
 
                     writeln!(buf, "Reference")?;
                     writeln_with_tabulation(
diff --git a/sbroad-core/src/ir/helpers/tests.rs b/sbroad-core/src/ir/helpers/tests.rs
index b02b703a8..cbb7b7291 100644
--- a/sbroad-core/src/ir/helpers/tests.rs
+++ b/sbroad-core/src/ir/helpers/tests.rs
@@ -20,11 +20,11 @@ fn simple_select() {
 	Output_id: 564
 		[id: 564] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })]
 			List:
-				[id: 032] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 0, col_type: Integer })]
-				[id: 132] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 1, col_type: String })]
-				[id: 232] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 2, col_type: Boolean })]
-				[id: 332] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned })]
-				[id: 432] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned })]
+				[id: 032] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 0, col_type: Integer, asterisk_source: None })]
+				[id: 132] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 1, col_type: String, asterisk_source: None })]
+				[id: 232] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 2, col_type: Boolean, asterisk_source: None })]
+				[id: 332] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned, asterisk_source: None })]
+				[id: 432] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 964] relation: Projection
@@ -33,7 +33,7 @@ fn simple_select() {
 	Output_id: 864
 		[id: 864] expression: Row [distribution = Some(Any)]
 			List:
-				[id: 532] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 9, arena_type: Arena64 }), targets: Some([0]), position: 1, col_type: String })]
+				[id: 532] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 9, arena_type: Arena64 }), targets: Some([0]), position: 1, col_type: String, asterisk_source: None })]
 ---------------------------------------------
 "#);
 
@@ -59,11 +59,11 @@ fn simple_join() {
 	Output_id: 564
 		[id: 564] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })]
 			List:
-				[id: 032] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 0, col_type: Unsigned })]
-				[id: 132] expression: Alias [name = sysFrom, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 1, col_type: Unsigned })]
-				[id: 232] expression: Alias [name = FIRST_NAME, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 2, col_type: String })]
-				[id: 332] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned })]
-				[id: 432] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned })]
+				[id: 032] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 0, col_type: Unsigned, asterisk_source: None })]
+				[id: 132] expression: Alias [name = sysFrom, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 1, col_type: Unsigned, asterisk_source: None })]
+				[id: 232] expression: Alias [name = FIRST_NAME, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 2, col_type: String, asterisk_source: None })]
+				[id: 332] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned, asterisk_source: None })]
+				[id: 432] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 964] relation: Projection
@@ -72,7 +72,7 @@ fn simple_join() {
 	Output_id: 864
 		[id: 864] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })]
 			List:
-				[id: 532] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 9, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Unsigned })]
+				[id: 532] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 9, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Unsigned, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 1264] relation: ScanSubQuery
@@ -82,7 +82,7 @@ fn simple_join() {
 	Output_id: 1164
 		[id: 1164] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })]
 			List:
-				[id: 632] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 12, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Unsigned })]
+				[id: 632] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 12, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Unsigned, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 1964] relation: ScanRelation
@@ -91,11 +91,11 @@ fn simple_join() {
 	Output_id: 1864
 		[id: 1864] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })]
 			List:
-				[id: 732] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 0, col_type: Integer })]
-				[id: 832] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 1, col_type: String })]
-				[id: 932] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 2, col_type: Boolean })]
-				[id: 1032] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned })]
-				[id: 1132] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned })]
+				[id: 732] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 0, col_type: Integer, asterisk_source: None })]
+				[id: 832] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 1, col_type: String, asterisk_source: None })]
+				[id: 932] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 2, col_type: Boolean, asterisk_source: None })]
+				[id: 1032] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned, asterisk_source: None })]
+				[id: 1132] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 2264] relation: Projection
@@ -104,7 +104,7 @@ fn simple_join() {
 	Output_id: 2164
 		[id: 2164] expression: Row [distribution = Some(Any)]
 			List:
-				[id: 1232] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 22, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer })]
+				[id: 1232] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 22, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 2564] relation: ScanSubQuery
@@ -114,7 +114,7 @@ fn simple_join() {
 	Output_id: 2464
 		[id: 2464] expression: Row [distribution = Some(Any)]
 			List:
-				[id: 1332] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 25, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer })]
+				[id: 1332] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 25, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 0136] relation: Motion [policy = Segment(MotionKey { targets: [Reference(0)] }), alias = t2]
@@ -123,7 +123,7 @@ fn simple_join() {
 	Output_id: 4064
 		[id: 4064] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })]
 			List:
-				[id: 1932] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 0, arena_type: Arena136 }), targets: Some([0]), position: 0, col_type: Integer })]
+				[id: 1932] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 0, arena_type: Arena136 }), targets: Some([0]), position: 0, col_type: Integer, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 3364] relation: InnerJoin
@@ -153,8 +153,8 @@ fn simple_join() {
 	Output_id: 3264
 		[id: 3264] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [1] }, Key { positions: [0] }}) })]
 			List:
-				[id: 1532] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 33, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Unsigned })]
-				[id: 1632] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 33, arena_type: Arena64 }), targets: Some([1]), position: 0, col_type: Integer })]
+				[id: 1532] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 33, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Unsigned, asterisk_source: None })]
+				[id: 1632] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 33, arena_type: Arena64 }), targets: Some([1]), position: 0, col_type: Integer, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 3664] relation: Projection
@@ -163,7 +163,7 @@ fn simple_join() {
 	Output_id: 3564
 		[id: 3564] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })]
 			List:
-				[id: 1732] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 36, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Unsigned })]
+				[id: 1732] expression: Alias [name = id, child = Reference(Reference { parent: Some(NodeId { offset: 36, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Unsigned, asterisk_source: None })]
 ---------------------------------------------
 "#);
 
@@ -197,11 +197,11 @@ fn simple_join_subtree() {
 	Output_id: 1864
 		[id: 1864] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })]
 			List:
-				[id: 732] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 0, col_type: Integer })]
-				[id: 832] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 1, col_type: String })]
-				[id: 932] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 2, col_type: Boolean })]
-				[id: 1032] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned })]
-				[id: 1132] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned })]
+				[id: 732] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 0, col_type: Integer, asterisk_source: None })]
+				[id: 832] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 1, col_type: String, asterisk_source: None })]
+				[id: 932] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 2, col_type: Boolean, asterisk_source: None })]
+				[id: 1032] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned, asterisk_source: None })]
+				[id: 1132] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 19, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 2264] relation: Projection
@@ -210,7 +210,7 @@ fn simple_join_subtree() {
 	Output_id: 2164
 		[id: 2164] expression: Row [distribution = Some(Any)]
 			List:
-				[id: 1232] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 22, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer })]
+				[id: 1232] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 22, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 2564] relation: ScanSubQuery
@@ -220,7 +220,7 @@ fn simple_join_subtree() {
 	Output_id: 2464
 		[id: 2464] expression: Row [distribution = Some(Any)]
 			List:
-				[id: 1332] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 25, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer })]
+				[id: 1332] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 25, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 0136] relation: Motion [policy = Segment(MotionKey { targets: [Reference(0)] }), alias = t2]
@@ -229,7 +229,7 @@ fn simple_join_subtree() {
 	Output_id: 4064
 		[id: 4064] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })]
 			List:
-				[id: 1932] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 0, arena_type: Arena136 }), targets: Some([0]), position: 0, col_type: Integer })]
+				[id: 1932] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 0, arena_type: Arena136 }), targets: Some([0]), position: 0, col_type: Integer, asterisk_source: None })]
 ---------------------------------------------
 "#
     );
@@ -252,26 +252,26 @@ fn simple_aggregation_with_group_by() {
 	Output_id: 564
 		[id: 564] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })]
 			List:
-				[id: 032] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 0, col_type: Integer })]
-				[id: 132] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 1, col_type: String })]
-				[id: 232] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 2, col_type: Boolean })]
-				[id: 332] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned })]
-				[id: 432] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned })]
+				[id: 032] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 0, col_type: Integer, asterisk_source: None })]
+				[id: 132] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 1, col_type: String, asterisk_source: None })]
+				[id: 232] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 2, col_type: Boolean, asterisk_source: None })]
+				[id: 332] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 3, col_type: Unsigned, asterisk_source: None })]
+				[id: 432] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 6, arena_type: Arena64 }), targets: None, position: 4, col_type: Unsigned, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 1464] relation: GroupBy [is_final = false]
 	Gr_cols:
-		Gr_col: Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 1, col_type: String })
+		Gr_col: Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 1, col_type: String, asterisk_source: None })
 	Children:
 		Child_id = 664
 	Output_id: 1364
 		[id: 1364] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0, 1] }}) })]
 			List:
-				[id: 532] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer })]
-				[id: 632] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 1, col_type: String })]
-				[id: 732] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 2, col_type: Boolean })]
-				[id: 832] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 3, col_type: Unsigned })]
-				[id: 932] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 4, col_type: Unsigned })]
+				[id: 532] expression: Alias [name = identification_number, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: Integer, asterisk_source: None })]
+				[id: 632] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 1, col_type: String, asterisk_source: None })]
+				[id: 732] expression: Alias [name = product_units, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 2, col_type: Boolean, asterisk_source: None })]
+				[id: 832] expression: Alias [name = sys_op, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 3, col_type: Unsigned, asterisk_source: None })]
+				[id: 932] expression: Alias [name = bucket_id, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 4, col_type: Unsigned, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 1964] relation: Projection
@@ -280,7 +280,7 @@ fn simple_aggregation_with_group_by() {
 	Output_id: 1864
 		[id: 1864] expression: Row [distribution = Some(Any)]
 			List:
-				[id: 1132] expression: Alias [name = column_764, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 1, col_type: String })]
+				[id: 1132] expression: Alias [name = column_764, child = Reference(Reference { parent: Some(NodeId { offset: 14, arena_type: Arena64 }), targets: Some([0]), position: 1, col_type: String, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 41] relation: Motion [policy = Segment(MotionKey { targets: [Reference(0)] }), alias = None]
@@ -289,18 +289,18 @@ fn simple_aggregation_with_group_by() {
 	Output_id: 40
 		[id: 40] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })]
 			List:
-				[id: 39] expression: Alias [name = column_12, child = Reference { parent: Some(41), targets: Some([0]), position: 0, col_type: String }]
+				[id: 39] expression: Alias [name = column_12, child = Reference { parent: Some(41), targets: Some([0]), position: 0, col_type: String, asterisk_source: None }]
 ---------------------------------------------
 ---------------------------------------------
 [id: 2664] relation: GroupBy [is_final = true]
 	Gr_cols:
-		Gr_col: Reference(Reference { parent: Some(NodeId { offset: 26, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: String })
+		Gr_col: Reference(Reference { parent: Some(NodeId { offset: 26, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: String, asterisk_source: None })
 	Children:
 		Child_id = 0136
 	Output_id: 2564
 		[id: 2564] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })]
 			List:
-				[id: 1332] expression: Alias [name = column_764, child = Reference(Reference { parent: Some(NodeId { offset: 26, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: String })]
+				[id: 1332] expression: Alias [name = column_764, child = Reference(Reference { parent: Some(NodeId { offset: 26, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: String, asterisk_source: None })]
 ---------------------------------------------
 ---------------------------------------------
 [id: 1764] relation: Projection
@@ -309,7 +309,7 @@ fn simple_aggregation_with_group_by() {
 	Output_id: 1664
 		[id: 1664] expression: Row [distribution = Some(Segment { keys: KeySet({Key { positions: [0] }}) })]
 			List:
-				[id: 1032] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 17, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: String })]
+				[id: 1032] expression: Alias [name = product_code, child = Reference(Reference { parent: Some(NodeId { offset: 17, arena_type: Arena64 }), targets: Some([0]), position: 0, col_type: String, asterisk_source: None })]
 ---------------------------------------------
 "#);
 
diff --git a/sbroad-core/src/ir/operator.rs b/sbroad-core/src/ir/operator.rs
index 6afb09444..3e7e23d4f 100644
--- a/sbroad-core/src/ir/operator.rs
+++ b/sbroad-core/src/ir/operator.rs
@@ -337,7 +337,7 @@ impl Plan {
     /// # Errors
     /// - child id pointes to non-existing or non-relational node.
     pub fn add_delete(&mut self, table: SmolStr, child_id: NodeId) -> Result<NodeId, SbroadError> {
-        let output = self.add_row_for_output(child_id, &[], true)?;
+        let output = self.add_row_for_output(child_id, &[], true, None)?;
         let delete = Delete {
             relation: table,
             children: vec![child_id],
@@ -479,6 +479,7 @@ impl Plan {
                 targets: Some(vec![0]),
                 position: output_pos,
                 col_type,
+                asterisk_source: None,
             };
             let id = plan.nodes.push(node.into());
             Ok(id)
@@ -634,7 +635,7 @@ impl Plan {
         };
         let proj_id = self.add_relational(proj_node.into())?;
         self.replace_parent_in_subtree(proj_output, None, Some(proj_id))?;
-        let upd_output = self.add_row_for_output(proj_id, &[], false)?;
+        let upd_output = self.add_row_for_output(proj_id, &[], false, None)?;
         let update_node = Update {
             relation: relation.to_smolstr(),
             pk_positions: primary_key_positions,
@@ -718,7 +719,9 @@ impl Plan {
 
         let mut refs: Vec<NodeId> = Vec::with_capacity(rel.columns.len());
         for (pos, col) in rel.columns.iter().enumerate() {
-            let r_id = self.nodes.add_ref(None, None, pos, col.r#type.clone());
+            let r_id = self
+                .nodes
+                .add_ref(None, None, pos, col.r#type.clone(), None);
             let col_alias_id = self.nodes.add_alias(&col.name, r_id)?;
             refs.push(col_alias_id);
         }
@@ -754,7 +757,7 @@ impl Plan {
         if let Some(rel) = self.relations.get(table) {
             let mut refs: Vec<NodeId> = Vec::with_capacity(rel.columns.len());
             for (pos, col) in rel.columns.iter().enumerate() {
-                let r_id = nodes.add_ref(None, None, pos, col.r#type.clone());
+                let r_id = nodes.add_ref(None, None, pos, col.r#type.clone(), None);
                 let col_alias_id = nodes.add_alias(&col.name, r_id)?;
                 refs.push(col_alias_id);
             }
@@ -920,7 +923,7 @@ impl Plan {
             _ => None,
         };
 
-        let output = self.add_row_for_output(child_id, &[], true)?;
+        let output = self.add_row_for_output(child_id, &[], true, None)?;
         match policy {
             MotionPolicy::None => {
                 return Err(SbroadError::Invalid(
@@ -977,7 +980,7 @@ impl Plan {
         is_distinct: bool,
         needs_shard_col: bool,
     ) -> Result<NodeId, SbroadError> {
-        let output = self.add_row_for_output(child, col_names, needs_shard_col)?;
+        let output = self.add_row_for_output(child, col_names, needs_shard_col, None)?;
         let proj = Projection {
             children: vec![child],
             output,
@@ -1039,7 +1042,7 @@ impl Plan {
             ));
         }
 
-        let output = self.add_row_for_output(first_child, &[], true)?;
+        let output = self.add_row_for_output(first_child, &[], true, None)?;
         let select = Selection {
             children: children.into(),
             filter,
@@ -1087,7 +1090,7 @@ impl Plan {
             }
         }
 
-        let output = self.add_row_for_output(first_child, &[], true)?;
+        let output = self.add_row_for_output(first_child, &[], true, None)?;
         let having = Having {
             children: children.into(),
             filter,
@@ -1113,7 +1116,7 @@ impl Plan {
         child: NodeId,
         order_by_elements: Vec<OrderByElement>,
     ) -> Result<NodeId, SbroadError> {
-        let output = self.add_row_for_output(child, &[], true)?;
+        let output = self.add_row_for_output(child, &[], true, None)?;
         let order_by = OrderBy {
             child,
             output,
@@ -1147,7 +1150,7 @@ impl Plan {
     ) -> Result<NodeId, SbroadError> {
         let name: Option<SmolStr> = alias.map(SmolStr::from);
 
-        let output = self.add_row_for_output(child, &[], true)?;
+        let output = self.add_row_for_output(child, &[], true, None)?;
         let sq = ScanSubQuery {
             alias: name,
             children: vec![child],
@@ -1219,7 +1222,7 @@ impl Plan {
         }
 
         let output = self
-            .add_row_for_output(child_id, &[], true)
+            .add_row_for_output(child_id, &[], true, None)
             .expect("output row for CTE");
         let cte = ScanCte {
             alias,
@@ -1285,7 +1288,7 @@ impl Plan {
     /// # Errors
     /// - Row node is not of a row type
     pub fn add_limit(&mut self, select: NodeId, limit: u64) -> Result<NodeId, SbroadError> {
-        let output = self.add_row_for_output(select, &[], true)?;
+        let output = self.add_row_for_output(select, &[], true, None)?;
         let limit = Limit {
             output,
             limit,
@@ -1395,6 +1398,7 @@ impl Plan {
                 Some((0..value_rows.len()).collect::<Vec<usize>>()),
                 pos,
                 col_type,
+                None,
             );
             let alias_id = self.nodes.add_alias(name, ref_id)?;
             aliases.push(alias_id);
diff --git a/sbroad-core/src/ir/transformation/equality_propagation.rs b/sbroad-core/src/ir/transformation/equality_propagation.rs
index b4917ad65..ea6aa2bba 100644
--- a/sbroad-core/src/ir/transformation/equality_propagation.rs
+++ b/sbroad-core/src/ir/transformation/equality_propagation.rs
@@ -91,7 +91,7 @@
 
 use crate::errors::{Entity, SbroadError};
 use crate::ir::helpers::RepeatableState;
-use crate::ir::node::expression::Expression;
+use crate::ir::node::expression::{Expression, ReferenceAsteriskSource};
 use crate::ir::node::{Constant, NodeId, Reference, Row};
 use crate::ir::operator::Bool;
 use crate::ir::relation::Type;
@@ -112,6 +112,7 @@ struct EqClassRef {
     position: usize,
     parent: Option<NodeId>,
     col_type: Type,
+    asterisk_source: Option<ReferenceAsteriskSource>,
 }
 
 impl EqClassRef {
@@ -121,6 +122,7 @@ impl EqClassRef {
             position: expr_pos,
             parent: expr_prt,
             col_type: expr_type,
+            asterisk_source: expr_asterisk_source,
         }) = expr
         {
             return Ok(EqClassRef {
@@ -128,6 +130,7 @@ impl EqClassRef {
                 position: *expr_pos,
                 parent: *expr_prt,
                 col_type: expr_type.clone(),
+                asterisk_source: expr_asterisk_source.clone(),
             });
         }
         Err(SbroadError::Invalid(Entity::Expression, None))
@@ -139,6 +142,7 @@ impl EqClassRef {
             self.targets.clone(),
             self.position,
             self.col_type.clone(),
+            self.asterisk_source.clone(),
         );
         plan.nodes.add_row(vec![id], None)
     }
diff --git a/sbroad-core/src/ir/transformation/equality_propagation/tests.rs b/sbroad-core/src/ir/transformation/equality_propagation/tests.rs
index 696ce4b30..f8c6cf6f5 100644
--- a/sbroad-core/src/ir/transformation/equality_propagation/tests.rs
+++ b/sbroad-core/src/ir/transformation/equality_propagation/tests.rs
@@ -107,8 +107,8 @@ fn equality_propagation5() {
             r#"SELECT "t"."a" FROM "t""#,
             r#"WHERE ("t"."d") = (?) and ("t"."c") = (?)"#,
             r#"and ("t"."a") = (?) and ("t"."b") = (?)"#,
-            r#"and ("t"."b") = ("t"."c") and ("t"."c") = ("t"."d")"#,
-            r#"and ("t"."d") = ("t"."a")"#,
+            r#"and ("t"."b") = ("t"."c") and ("t"."c") = ("t"."a")"#,
+            r#"and ("t"."a") = ("t"."d")"#,
         ),
         vec![
             Value::from(1_u64),
diff --git a/sbroad-core/src/ir/transformation/not_push_down/tests.rs b/sbroad-core/src/ir/transformation/not_push_down/tests.rs
index 43db64cd2..a892ce5d9 100644
--- a/sbroad-core/src/ir/transformation/not_push_down/tests.rs
+++ b/sbroad-core/src/ir/transformation/not_push_down/tests.rs
@@ -12,7 +12,7 @@ fn push_down_not(plan: &mut Plan) {
 fn not_true() {
     let input = r#"SELECT * FROM (values (1)) where not true"#;
     let expected = PatternWithParams::new(
-        r#"SELECT "COLUMN_1" FROM (VALUES (?)) WHERE (?)"#.to_string(),
+        r#"SELECT * FROM (VALUES (?)) WHERE (?)"#.to_string(),
         vec![Value::Unsigned(1), Value::from(false)],
     );
     let actual = check_transformation(input, vec![], &push_down_not);
@@ -24,7 +24,7 @@ fn not_true() {
 fn not_double() {
     let input = r#"SELECT * FROM (values (1)) where not not true"#;
     let expected = PatternWithParams::new(
-        r#"SELECT "COLUMN_1" FROM (VALUES (?)) WHERE (?)"#.to_string(),
+        r#"SELECT * FROM (VALUES (?)) WHERE (?)"#.to_string(),
         vec![Value::Unsigned(1), Value::from(true)],
     );
     let actual = check_transformation(input, vec![], &push_down_not);
@@ -36,7 +36,7 @@ fn not_double() {
 fn not_null() {
     let input = r#"SELECT * FROM (values (1)) where not null"#;
     let expected = PatternWithParams::new(
-        r#"SELECT "COLUMN_1" FROM (VALUES (?)) WHERE (?)"#.to_string(),
+        r#"SELECT * FROM (VALUES (?)) WHERE (?)"#.to_string(),
         vec![Value::Unsigned(1), Value::Null],
     );
     let actual = check_transformation(input, vec![], &push_down_not);
@@ -48,7 +48,7 @@ fn not_null() {
 fn not_and() {
     let input = r#"SELECT * FROM (values (1)) where not (true and false)"#;
     let expected = PatternWithParams::new(
-        r#"SELECT "COLUMN_1" FROM (VALUES (?)) WHERE ((?) or (?))"#.to_string(),
+        r#"SELECT * FROM (VALUES (?)) WHERE ((?) or (?))"#.to_string(),
         vec![Value::Unsigned(1), Value::from(false), Value::from(true)],
     );
     let actual = check_transformation(input, vec![], &push_down_not);
@@ -60,7 +60,7 @@ fn not_and() {
 fn not_or() {
     let input = r#"SELECT * FROM (values (1)) where not (false or true)"#;
     let expected = PatternWithParams::new(
-        r#"SELECT "COLUMN_1" FROM (VALUES (?)) WHERE ((?) and (?))"#.to_string(),
+        r#"SELECT * FROM (VALUES (?)) WHERE ((?) and (?))"#.to_string(),
         vec![Value::Unsigned(1), Value::from(true), Value::from(false)],
     );
     let actual = check_transformation(input, vec![], &push_down_not);
diff --git a/sbroad-core/src/ir/transformation/redistribution/eq_cols.rs b/sbroad-core/src/ir/transformation/redistribution/eq_cols.rs
index 82541cf4f..bc532cfe0 100644
--- a/sbroad-core/src/ir/transformation/redistribution/eq_cols.rs
+++ b/sbroad-core/src/ir/transformation/redistribution/eq_cols.rs
@@ -300,12 +300,14 @@ impl EqualityCols {
                         position: pos_left,
                         parent: parent_left,
                         col_type: col_type_left,
+                        asterisk_source: asterisk_source_left,
                     }),
-                    Expression::Reference(Reference {
+                    Expression::Reference {
                         targets: targets_right,
                         position: pos_right,
                         parent: parent_right,
                         col_type: col_type_right,
+                        asterisk_source: asterisk_source_right,
                     }),
                 ) => {
                     // TODO: compare types only if the runtime requires it.
@@ -315,6 +317,7 @@ impl EqualityCols {
                     if targets_left != targets_right
                         && parent_left == parent_right
                         && col_type_left == col_type_right
+                        && asterisk_source_left == asterisk_source_right
                     {
                         let left_referred_child_id =
                             *plan.get_relational_from_reference_node(*left_id)?;
diff --git a/sbroad-core/src/ir/transformation/redistribution/groupby.rs b/sbroad-core/src/ir/transformation/redistribution/groupby.rs
index 941c691fb..1d7a5ec60 100644
--- a/sbroad-core/src/ir/transformation/redistribution/groupby.rs
+++ b/sbroad-core/src/ir/transformation/redistribution/groupby.rs
@@ -696,7 +696,7 @@ impl Plan {
         is_final: bool,
         expr_parent: Option<NodeId>,
     ) -> Result<NodeId, SbroadError> {
-        let final_output = self.add_row_for_output(child_id, &[], true)?;
+        let final_output = self.add_row_for_output(child_id, &[], true, None)?;
         let groupby = GroupBy {
             children: [child_id].to_vec(),
             gr_cols: grouping_exprs.to_vec(),
@@ -1410,6 +1410,7 @@ impl Plan {
                 parent: None,
                 targets: Some(vec![0]),
                 col_type,
+                asterisk_source: None,
             };
             nodes.push(new_col);
         }
@@ -1417,7 +1418,7 @@ impl Plan {
             let new_col_id = self.nodes.push(node.into());
             gr_cols.push(new_col_id);
         }
-        let output = self.add_row_for_output(child_id, &[], true)?;
+        let output = self.add_row_for_output(child_id, &[], true, None)?;
         let final_id = self.nodes.next_id(ArenaType::Arena64);
         for col in &gr_cols {
             self.replace_parent_in_subtree(*col, None, Some(final_id))?;
@@ -1503,6 +1504,7 @@ impl Plan {
                     targets: Some(vec![0]),
                     position,
                     col_type,
+                    asterisk_source: None,
                 };
                 nodes.push((parent, expr_id, gr_expr_id, new_ref));
             }
@@ -1593,7 +1595,7 @@ impl Plan {
                             Some(format_smolstr!("Having ({node_id:?}) has no children!")),
                         )
                     })?;
-                    let output = self.add_row_for_output(child_id, &[], true)?;
+                    let output = self.add_row_for_output(child_id, &[], true, None)?;
                     *self.get_mut_relation_node(*node_id)?.mut_output() = output;
                     self.replace_parent_in_subtree(output, None, Some(*node_id))?;
                 }
-- 
GitLab