From ac4a691e44c0a50b069a40f8fec3f61bfa4b8da7 Mon Sep 17 00:00:00 2001
From: Denis Smirnov <sd@picodata.io>
Date: Mon, 31 Oct 2022 18:36:25 +0700
Subject: [PATCH] feat: plan snapshots and flashback traversal

Now we support a flashback traversal for the subtree iterator. As
a result we can traverse the original selections in a way they looked
before any transformations were applied. This solves the problem
of too verbose DNFs that can easily reach tarantool's parser stack
limit.
---
 sbroad-benches/benches/parse.rs               |   3 +-
 sbroad-benches/src/engine.rs                  |   3 +-
 sbroad-cartridge/src/cartridge/router.rs      |   3 +-
 .../test_app/test/data/test_data.lua          |  12 +-
 .../test/integration/large_query_test.lua     |   8 +-
 sbroad-core/src/backend/sql/ir/tests.rs       | 334 +---------
 .../src/backend/sql/ir/tests/except.rs        |  51 ++
 .../src/backend/sql/ir/tests/inner_join.rs    |  99 +++
 .../src/backend/sql/ir/tests/projection.rs    |  79 +++
 .../src/backend/sql/ir/tests/selection.rs     | 600 ++++++++++++++++++
 .../src/backend/sql/ir/tests/sub_query.rs     | 101 +++
 .../src/backend/sql/ir/tests/union_all.rs     |  51 ++
 sbroad-core/src/backend/sql/tree.rs           |  50 +-
 sbroad-core/src/backend/sql/tree/tests.rs     |   5 +-
 sbroad-core/src/executor/engine/mock.rs       |   3 +-
 sbroad-core/src/executor/tests.rs             |  74 +--
 sbroad-core/src/executor/tests/between.rs     |  14 +-
 sbroad-core/src/executor/tests/bucket_id.rs   |   2 +-
 sbroad-core/src/executor/tests/not_eq.rs      |   4 +-
 sbroad-core/src/ir.rs                         |  35 +-
 sbroad-core/src/ir/transformation.rs          |   2 +-
 .../src/ir/transformation/bool_in/tests.rs    |  17 +-
 .../src/ir/transformation/dnf/tests.rs        |  14 +-
 .../equality_propagation/tests.rs             |  27 +-
 sbroad-core/src/ir/transformation/helpers.rs  |   5 +-
 .../ir/transformation/merge_tuples/tests.rs   |  14 +-
 .../ir/transformation/split_columns/tests.rs  |  22 +-
 sbroad-core/src/ir/tree.rs                    |   8 +
 sbroad-core/src/ir/tree/and.rs                |   1 +
 sbroad-core/src/ir/tree/eq_class.rs           |   1 +
 sbroad-core/src/ir/tree/expression.rs         |   1 +
 sbroad-core/src/ir/tree/subtree.rs            |  79 ++-
 .../backend/sql/tree/sql_order_selection.yaml |   1 +
 .../ir/distribution/join_unite_keys.yaml      |   1 +
 .../ir/distribution/shrink_dist_key_1.yaml    |   1 +
 .../ir/distribution/shrink_dist_key_2.yaml    |   1 +
 .../ir/distribution/shuffle_dist_key.yaml     |   1 +
 .../union_fallback_to_random.yaml             |   1 +
 .../ir/distribution/union_preserve_dist.yaml  |   1 +
 .../tests/artifactory/ir/operator/join.yaml   |   1 +
 .../ir/operator/output_aliases.yaml           |   1 +
 .../operator/output_aliases_duplicates.yaml   |   1 +
 .../ir/operator/output_aliases_oor.yaml       |   1 +
 .../output_aliases_unsupported_type.yaml      |   1 +
 .../artifactory/ir/operator/projection.yaml   |   1 +
 .../artifactory/ir/operator/scan_rel.yaml     |   1 +
 .../artifactory/ir/operator/selection.yaml    |   1 +
 .../ir/operator/selection_with_sub_query.yaml |   1 +
 .../artifactory/ir/operator/sub_query.yaml    |   1 +
 .../tests/artifactory/ir/plan_no_top.yaml     |   1 +
 .../tests/artifactory/ir/plan_oor_top.yaml    |   1 +
 .../full_motion_less_for_sub_query.yaml       |   1 +
 ...otion_non_segment_outer_for_sub_query.yaml |   1 +
 .../redistribution/local_sub_query.yaml       |   1 +
 .../redistribution/multiple_sub_queries.yaml  |   1 +
 .../segment_motion_for_sub_query.yaml         |   1 +
 56 files changed, 1316 insertions(+), 430 deletions(-)
 create mode 100644 sbroad-core/src/backend/sql/ir/tests/except.rs
 create mode 100644 sbroad-core/src/backend/sql/ir/tests/inner_join.rs
 create mode 100644 sbroad-core/src/backend/sql/ir/tests/projection.rs
 create mode 100644 sbroad-core/src/backend/sql/ir/tests/selection.rs
 create mode 100644 sbroad-core/src/backend/sql/ir/tests/sub_query.rs
 create mode 100644 sbroad-core/src/backend/sql/ir/tests/union_all.rs

diff --git a/sbroad-benches/benches/parse.rs b/sbroad-benches/benches/parse.rs
index 7bc8e5f9b5..4552218082 100644
--- a/sbroad-benches/benches/parse.rs
+++ b/sbroad-benches/benches/parse.rs
@@ -1,6 +1,7 @@
 use criterion::{criterion_group, criterion_main, Criterion};
 use sbroad::backend::sql::tree::{OrderedSyntaxNodes, SyntaxPlan};
 use sbroad::executor::Query;
+use sbroad::ir::tree::Snapshot;
 use sbroad::ir::value::Value;
 use sbroad_benches::engine::RouterRuntimeMock;
 
@@ -237,7 +238,7 @@ fn query1(pattern: &str, params: Vec<Value>, engine: &mut RouterRuntimeMock) {
     let top_id = query.get_exec_plan().get_ir_plan().get_top().unwrap();
     let buckets = query.bucket_discovery(top_id).unwrap();
     let plan = query.get_exec_plan();
-    let sp = SyntaxPlan::new(plan, top_id).unwrap();
+    let sp = SyntaxPlan::new(plan, top_id, Snapshot::Oldest).unwrap();
     let ordered = OrderedSyntaxNodes::try_from(sp).unwrap();
     let nodes = ordered.to_syntax_data().unwrap();
     plan.to_sql(&nodes, &buckets).unwrap();
diff --git a/sbroad-benches/src/engine.rs b/sbroad-benches/src/engine.rs
index 47e5ff30a8..e87a52b35e 100644
--- a/sbroad-benches/src/engine.rs
+++ b/sbroad-benches/src/engine.rs
@@ -17,6 +17,7 @@ use sbroad::executor::vtable::VirtualTable;
 use sbroad::frontend::sql::ast::AbstractSyntaxTree;
 use sbroad::ir::function::Function;
 use sbroad::ir::relation::{Column, ColumnRole, Table, Type};
+use sbroad::ir::tree::Snapshot;
 use sbroad::ir::value::Value;
 use sbroad::ir::Plan;
 
@@ -431,7 +432,7 @@ impl Coordinator for RouterRuntimeMock {
         buckets: &Buckets,
     ) -> Result<Box<dyn Any>, QueryPlannerError> {
         let result = ProducerResult::new();
-        let sp = SyntaxPlan::new(plan, top_id)?;
+        let sp = SyntaxPlan::new(plan, top_id, Snapshot::Oldest)?;
         let ordered = OrderedSyntaxNodes::try_from(sp)?;
         let nodes = ordered.to_syntax_data()?;
         plan.to_sql(&nodes, buckets)?;
diff --git a/sbroad-cartridge/src/cartridge/router.rs b/sbroad-cartridge/src/cartridge/router.rs
index fd7ed9a2c0..cdad68b649 100644
--- a/sbroad-cartridge/src/cartridge/router.rs
+++ b/sbroad-cartridge/src/cartridge/router.rs
@@ -30,6 +30,7 @@ use sbroad::executor::result::ProducerResult;
 use sbroad::executor::vtable::VirtualTable;
 use sbroad::frontend::sql::ast::AbstractSyntaxTree;
 use sbroad::ir::helpers::RepeatableState;
+use sbroad::ir::tree::Snapshot;
 use sbroad::ir::value::Value;
 use sbroad::ir::Plan;
 use sbroad::otm::child_span;
@@ -185,7 +186,7 @@ impl Coordinator for RouterRuntime {
         top_id: usize,
         buckets: &Buckets,
     ) -> Result<Box<dyn Any>, QueryPlannerError> {
-        let sp = SyntaxPlan::new(plan, top_id)?;
+        let sp = SyntaxPlan::new(plan, top_id, Snapshot::Oldest)?;
         let ordered = OrderedSyntaxNodes::try_from(sp)?;
         let nodes = ordered.to_syntax_data()?;
         let is_data_modifier = plan.subtree_modifies_data(top_id)?;
diff --git a/sbroad-cartridge/test_app/test/data/test_data.lua b/sbroad-cartridge/test_app/test/data/test_data.lua
index 4770dfa22c..f36b66d55c 100644
--- a/sbroad-cartridge/test_app/test/data/test_data.lua
+++ b/sbroad-cartridge/test_app/test/data/test_data.lua
@@ -1,5 +1,15 @@
 local vsa_proxy_records = {
-    { 6659253, -20191, 0, "111", box.NULL, "{\"inn\":1234567890\"\",\"name\":\"КАПИБАРА ТЮЛЕНЬ ВОМБАТОВИЧ\"}", "", box.NULL, box.NULL },
+    {
+        6659253,
+        -20191,
+        0,
+        "111",
+        box.NULL,
+        "{\"inn\":1234567890\"\",\"name\":\"КАПИБАРА ТЮЛЕНЬ ВОМБАТОВИЧ\"}",
+        "",
+        box.NULL,
+        box.NULL
+    },
 }
 
 return {
diff --git a/sbroad-cartridge/test_app/test/integration/large_query_test.lua b/sbroad-cartridge/test_app/test/integration/large_query_test.lua
index 3dfaa87674..bbf9e530a8 100644
--- a/sbroad-cartridge/test_app/test/integration/large_query_test.lua
+++ b/sbroad-cartridge/test_app/test/integration/large_query_test.lua
@@ -116,8 +116,12 @@ g.before_all(
         local _, err = api:call(
           "sbroad.execute",
           {
-            [[INSERT INTO "VSA_PROXY"
-               ("fid","date_start","date_end","common_id","exclude_id", "common_text", "common_detail", "typology_type", "typology_id")
+            [[INSERT INTO "VSA_PROXY" (
+              "fid", "date_start", "date_end",
+              "common_id", "exclude_id",
+              "common_text", "common_detail",
+              "typology_type", "typology_id"
+             )
              VALUES (?,?,?,?,?,?,?,?,?)]],
             rec
           }
diff --git a/sbroad-core/src/backend/sql/ir/tests.rs b/sbroad-core/src/backend/sql/ir/tests.rs
index 1c34f1f83e..27146258d4 100644
--- a/sbroad-core/src/backend/sql/ir/tests.rs
+++ b/sbroad-core/src/backend/sql/ir/tests.rs
@@ -6,337 +6,45 @@ use crate::executor::engine::mock::RouterConfigurationMock;
 use crate::executor::ir::ExecutionPlan;
 use crate::frontend::sql::ast::AbstractSyntaxTree;
 use crate::frontend::Ast;
-use crate::ir::value::Value;
+use crate::ir::tree::Snapshot;
 
 use super::*;
 
-#[test]
-fn one_table_projection() {
-    let query = r#"SELECT "identification_number", "product_code"
-    FROM "hash_testing"
-    WHERE "identification_number" = 1"#;
-
-    let metadata = &RouterConfigurationMock::new();
-    let ast = AbstractSyntaxTree::new(query).unwrap();
-    let mut plan = ast.resolve_metadata(metadata).unwrap();
-    plan.bind_params(vec![]).unwrap();
-    let ex_plan = ExecutionPlan::from(plan);
-
-    let top_id = ex_plan.get_ir_plan().get_top().unwrap();
-    let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap();
-    let ordered = OrderedSyntaxNodes::try_from(sp).unwrap();
-    let nodes = ordered.to_syntax_data().unwrap();
-    let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap();
-
-    assert_eq!(
-        PatternWithParams::new(
-            format!(
-                "{} {} {} {}",
-                r#"SELECT "hash_testing"."identification_number","#,
-                r#""hash_testing"."product_code""#,
-                r#"FROM "hash_testing""#,
-                r#"WHERE ("hash_testing"."identification_number") = (?)"#,
-            ),
-            vec![Value::from(1_u64)]
-        ),
-        sql
-    );
-}
-
-#[test]
-fn one_table_with_asterisk() {
-    let query = r#"SELECT *
-    FROM "hash_testing"
-    WHERE "identification_number" = 1"#;
-
-    let metadata = &RouterConfigurationMock::new();
-    let ast = AbstractSyntaxTree::new(query).unwrap();
-    let mut plan = ast.resolve_metadata(metadata).unwrap();
-    plan.bind_params(vec![]).unwrap();
-    let ex_plan = ExecutionPlan::from(plan);
-
-    let top_id = ex_plan.get_ir_plan().get_top().unwrap();
-    let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap();
-    let ordered = OrderedSyntaxNodes::try_from(sp).unwrap();
-    let nodes = ordered.to_syntax_data().unwrap();
-    let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap();
-
-    assert_eq!(
-        PatternWithParams::new(
-            format!(
-                "{} {} {} {} {}",
-                r#"SELECT "hash_testing"."identification_number","#,
-                r#""hash_testing"."product_code","#,
-                r#""hash_testing"."product_units", "hash_testing"."sys_op""#,
-                r#"FROM "hash_testing""#,
-                r#"WHERE ("hash_testing"."identification_number") = (?)"#
-            ),
-            vec![Value::from(1_u64)]
-        ),
-        sql
-    );
-}
-
-#[test]
-fn union_all() {
-    let query = r#"SELECT "product_code"
-    FROM "hash_testing"
-    WHERE "identification_number" = 1
-    UNION ALL
-    SELECT "product_code"
-    FROM "hash_testing_hist"
-    WHERE "product_code" = 'a' 
-    "#;
-
-    let metadata = &RouterConfigurationMock::new();
-    let ast = AbstractSyntaxTree::new(query).unwrap();
-    let mut plan = ast.resolve_metadata(metadata).unwrap();
-    plan.bind_params(vec![]).unwrap();
-    let ex_plan = ExecutionPlan::from(plan);
-
-    let top_id = ex_plan.get_ir_plan().get_top().unwrap();
-    let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap();
-    let ordered = OrderedSyntaxNodes::try_from(sp).unwrap();
-    let nodes = ordered.to_syntax_data().unwrap();
-    let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap();
-
-    assert_eq!(
-        PatternWithParams::new(
-            format!(
-                "{} {} {} {} {}",
-                r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#,
-                r#"WHERE ("hash_testing"."identification_number") = (?)"#,
-                r#"UNION ALL"#,
-                r#"SELECT "hash_testing_hist"."product_code" FROM "hash_testing_hist""#,
-                r#"WHERE ("hash_testing_hist"."product_code") = (?)"#
-            ),
-            vec![Value::from(1_u64), Value::from("a")],
-        ),
-        sql
-    );
-}
-
-#[test]
-fn from_sub_query() {
-    let query = r#"SELECT "product_code"
-    FROM (SELECT "product_code"
-    FROM "hash_testing"
-    WHERE "identification_number" = 1) as t1
-    WHERE "product_code" = 'a'"#;
-
-    let metadata = &RouterConfigurationMock::new();
-    let ast = AbstractSyntaxTree::new(query).unwrap();
-    let mut plan = ast.resolve_metadata(metadata).unwrap();
-    plan.bind_params(vec![]).unwrap();
-    let ex_plan = ExecutionPlan::from(plan);
-
-    let top_id = ex_plan.get_ir_plan().get_top().unwrap();
-    let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap();
-    let ordered = OrderedSyntaxNodes::try_from(sp).unwrap();
-    let nodes = ordered.to_syntax_data().unwrap();
-    let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap();
-
-    assert_eq!(
-        PatternWithParams::new(
-            format!(
-                "{} {} {} {}",
-                r#"SELECT "T1"."product_code" FROM"#,
-                r#"(SELECT "hash_testing"."product_code" FROM "hash_testing""#,
-                r#"WHERE ("hash_testing"."identification_number") = (?)) as "T1""#,
-                r#"WHERE ("T1"."product_code") = (?)"#
-            ),
-            vec![Value::from(1_u64), Value::from("a")],
-        ),
-        sql
-    );
-}
-
-#[test]
-fn from_sub_query_with_union() {
-    let query = r#"SELECT "product_code"
-  FROM (SELECT "product_code"
-    FROM "hash_testing"
-    WHERE "identification_number" = 1
-    UNION ALL
-    SELECT "product_code"
-    FROM "hash_testing_hist"
-    WHERE "product_code" = 'a') as "t1"
-  WHERE "product_code" = 'a'"#;
-
+fn check_sql_with_snapshot(query: &str, expected: PatternWithParams, snapshot: Snapshot) {
     let metadata = &RouterConfigurationMock::new();
     let ast = AbstractSyntaxTree::new(query).unwrap();
     let mut plan = ast.resolve_metadata(metadata).unwrap();
     plan.bind_params(vec![]).unwrap();
+    plan.replace_in_operator().unwrap();
+    plan.split_columns().unwrap();
+    plan.set_dnf().unwrap();
+    plan.derive_equalities().unwrap();
+    plan.merge_tuples().unwrap();
     let ex_plan = ExecutionPlan::from(plan);
 
     let top_id = ex_plan.get_ir_plan().get_top().unwrap();
-    let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap();
+    let sp = SyntaxPlan::new(&ex_plan, top_id, snapshot).unwrap();
     let ordered = OrderedSyntaxNodes::try_from(sp).unwrap();
     let nodes = ordered.to_syntax_data().unwrap();
     let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap();
 
-    assert_eq!(
-        PatternWithParams::new(
-            format!(
-                "{} {} {} {} {} {} {}",
-                r#"SELECT "t1"."product_code" FROM"#,
-                r#"(SELECT "hash_testing"."product_code" FROM "hash_testing""#,
-                r#"WHERE ("hash_testing"."identification_number") = (?)"#,
-                r#"UNION ALL"#,
-                r#"SELECT "hash_testing_hist"."product_code" FROM "hash_testing_hist""#,
-                r#"WHERE ("hash_testing_hist"."product_code") = (?)) as "t1""#,
-                r#"WHERE ("t1"."product_code") = (?)"#,
-            ),
-            vec![Value::from(1_u64), Value::from("a"), Value::from("a")],
-        ),
-        sql
-    );
+    assert_eq!(expected, sql,);
 }
 
-#[test]
-fn inner_join() {
-    let query = r#"SELECT "product_code" FROM "hash_testing" join "history"
-    on "hash_testing"."identification_number" = "history"."id"
-    WHERE "product_code" = 'a'"#;
+#[cfg(test)]
+mod except;
 
-    let metadata = &RouterConfigurationMock::new();
-    let ast = AbstractSyntaxTree::new(query).unwrap();
-    let mut plan = ast.resolve_metadata(metadata).unwrap();
-    plan.bind_params(vec![]).unwrap();
-    let ex_plan = ExecutionPlan::from(plan);
+#[cfg(test)]
+mod projection;
 
-    let top_id = ex_plan.get_ir_plan().get_top().unwrap();
-    let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap();
-    let ordered = OrderedSyntaxNodes::try_from(sp).unwrap();
-    let nodes = ordered.to_syntax_data().unwrap();
-    let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap();
+#[cfg(test)]
+mod inner_join;
 
-    assert_eq!(
-        PatternWithParams::new(
-            format!(
-                "{} {} {} {} {} {} {} {}",
-                r#"SELECT "hash_testing"."product_code""#,
-                r#"FROM (SELECT "hash_testing"."identification_number","#,
-                r#""hash_testing"."product_code","#,
-                r#""hash_testing"."product_units","#,
-                r#""hash_testing"."sys_op" FROM "hash_testing") as "hash_testing""#,
-                r#"INNER JOIN (SELECT "history"."id" FROM "history") as "history""#,
-                r#"ON ("hash_testing"."identification_number") = ("history"."id")"#,
-                r#"WHERE ("hash_testing"."product_code") = (?)"#,
-            ),
-            vec![Value::from("a")],
-        ),
-        sql
-    );
-}
+#[cfg(test)]
+mod selection;
 
-#[test]
-fn inner_join_with_sq() {
-    let query = r#"SELECT "product_code" FROM "hash_testing" join
-    (SELECT * FROM "history" WHERE "id" = 1) as "t"
-    on "hash_testing"."identification_number" = "t"."id"
-    WHERE "product_code" = 'a'"#;
-
-    let metadata = &RouterConfigurationMock::new();
-    let ast = AbstractSyntaxTree::new(query).unwrap();
-    let mut plan = ast.resolve_metadata(metadata).unwrap();
-    plan.bind_params(vec![]).unwrap();
-    let ex_plan = ExecutionPlan::from(plan);
-
-    let top_id = ex_plan.get_ir_plan().get_top().unwrap();
-    let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap();
-    let ordered = OrderedSyntaxNodes::try_from(sp).unwrap();
-    let nodes = ordered.to_syntax_data().unwrap();
-    let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap();
-
-    assert_eq!(
-        PatternWithParams::new(
-            format!(
-                "{} {} {} {} {} {} {} {} {}",
-                r#"SELECT "hash_testing"."product_code" FROM (SELECT"#,
-                r#""hash_testing"."identification_number","#,
-                r#""hash_testing"."product_code","#,
-                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#"ON ("hash_testing"."identification_number") = ("t"."id")"#,
-                r#"WHERE ("hash_testing"."product_code") = (?)"#,
-            ),
-            vec![Value::from(1_u64), Value::from("a")],
-        ),
-        sql
-    );
-}
+#[cfg(test)]
+mod sub_query;
 
-#[test]
-fn selection_with_sq() {
-    let query = r#"SELECT "product_code" FROM "hash_testing"
-    WHERE "identification_number" in
-    (SELECT "identification_number" FROM "hash_testing_hist" WHERE "product_code" = 'b') and "product_code" < 'a'"#;
-
-    let metadata = &RouterConfigurationMock::new();
-    let ast = AbstractSyntaxTree::new(query).unwrap();
-    let mut plan = ast.resolve_metadata(metadata).unwrap();
-    plan.bind_params(vec![]).unwrap();
-    let ex_plan = ExecutionPlan::from(plan);
-    let top_id = ex_plan.get_ir_plan().get_top().unwrap();
-    let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap();
-    let ordered = OrderedSyntaxNodes::try_from(sp).unwrap();
-    let nodes = ordered.to_syntax_data().unwrap();
-    let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap();
-
-    assert_eq!(
-        PatternWithParams::new(
-            format!(
-                "{} {} {} {} {}",
-                r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#,
-                r#"WHERE ("hash_testing"."identification_number") in"#,
-                r#"(SELECT "hash_testing_hist"."identification_number" FROM "hash_testing_hist""#,
-                r#"WHERE ("hash_testing_hist"."product_code") = (?))"#,
-                r#"and ("hash_testing"."product_code") < (?)"#,
-            ),
-            vec![Value::from("b"), Value::from("a")],
-        ),
-        sql
-    );
-}
-
-#[test]
-fn except() {
-    let query = r#"SELECT "id"
-    FROM "test_space"
-    WHERE "sysFrom" = 1
-    EXCEPT DISTINCT
-    SELECT "id"
-    FROM "test_space"
-    WHERE "FIRST_NAME" = 'a' 
-    "#;
-
-    let metadata = &RouterConfigurationMock::new();
-    let ast = AbstractSyntaxTree::new(query).unwrap();
-    let mut plan = ast.resolve_metadata(metadata).unwrap();
-    plan.bind_params(vec![]).unwrap();
-    let ex_plan = ExecutionPlan::from(plan);
-
-    let top_id = ex_plan.get_ir_plan().get_top().unwrap();
-    let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap();
-    let ordered = OrderedSyntaxNodes::try_from(sp).unwrap();
-    let nodes = ordered.to_syntax_data().unwrap();
-    let sql = ex_plan.to_sql(&nodes, &Buckets::All).unwrap();
-
-    assert_eq!(
-        PatternWithParams::new(
-            format!(
-                "{} {} {} {} {}",
-                r#"SELECT "test_space"."id" FROM "test_space""#,
-                r#"WHERE ("test_space"."sysFrom") = (?)"#,
-                r#"EXCEPT"#,
-                r#"SELECT "test_space"."id" FROM "test_space""#,
-                r#"WHERE ("test_space"."FIRST_NAME") = (?)"#
-            ),
-            vec![Value::from(1_u64), Value::from("a")],
-        ),
-        sql
-    );
-}
+#[cfg(test)]
+mod union_all;
diff --git a/sbroad-core/src/backend/sql/ir/tests/except.rs b/sbroad-core/src/backend/sql/ir/tests/except.rs
new file mode 100644
index 0000000000..b12eb30696
--- /dev/null
+++ b/sbroad-core/src/backend/sql/ir/tests/except.rs
@@ -0,0 +1,51 @@
+use super::*;
+use crate::ir::tree::Snapshot;
+use crate::ir::value::Value;
+
+#[test]
+fn except1_latest() {
+    let query = r#"SELECT "id"
+        FROM "test_space"
+        WHERE "sysFrom" = 1
+        EXCEPT DISTINCT
+        SELECT "id"
+        FROM "test_space"
+        WHERE "FIRST_NAME" = 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {}",
+            r#"SELECT "test_space"."id" FROM "test_space""#,
+            r#"WHERE ("test_space"."sysFrom") = (?)"#,
+            r#"EXCEPT"#,
+            r#"SELECT "test_space"."id" FROM "test_space""#,
+            r#"WHERE ("test_space"."FIRST_NAME") = (?)"#
+        ),
+        vec![Value::from(1_u64), Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Latest);
+}
+
+#[test]
+fn except1_oldest() {
+    let query = r#"SELECT "id"
+        FROM "test_space"
+        WHERE "sysFrom" = 1
+        EXCEPT DISTINCT
+        SELECT "id"
+        FROM "test_space"
+        WHERE "FIRST_NAME" = 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {}",
+            r#"SELECT "test_space"."id" FROM "test_space""#,
+            r#"WHERE ("test_space"."sysFrom") = (?)"#,
+            r#"EXCEPT"#,
+            r#"SELECT "test_space"."id" FROM "test_space""#,
+            r#"WHERE ("test_space"."FIRST_NAME") = (?)"#
+        ),
+        vec![Value::from(1_u64), Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Oldest);
+}
diff --git a/sbroad-core/src/backend/sql/ir/tests/inner_join.rs b/sbroad-core/src/backend/sql/ir/tests/inner_join.rs
new file mode 100644
index 0000000000..2c714a7e85
--- /dev/null
+++ b/sbroad-core/src/backend/sql/ir/tests/inner_join.rs
@@ -0,0 +1,99 @@
+use super::*;
+use crate::ir::tree::Snapshot;
+use crate::ir::value::Value;
+
+#[test]
+fn inner_join1_latest() {
+    let query = r#"SELECT "product_code" FROM "hash_testing" join "history"
+        on "hash_testing"."identification_number" = "history"."id"
+        WHERE "product_code" = 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {} {} {} {}",
+            r#"SELECT "hash_testing"."product_code""#,
+            r#"FROM (SELECT "hash_testing"."identification_number","#,
+            r#""hash_testing"."product_code","#,
+            r#""hash_testing"."product_units","#,
+            r#""hash_testing"."sys_op" FROM "hash_testing") as "hash_testing""#,
+            r#"INNER JOIN (SELECT "history"."id" FROM "history") as "history""#,
+            r#"ON ("hash_testing"."identification_number") = ("history"."id")"#,
+            r#"WHERE ("hash_testing"."product_code") = (?)"#,
+        ),
+        vec![Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Latest);
+}
+
+#[test]
+fn inner_join1_oldest() {
+    let query = r#"SELECT "product_code" FROM "hash_testing" join "history"
+        on "hash_testing"."identification_number" = "history"."id"
+        WHERE "product_code" = 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {} {} {} {}",
+            r#"SELECT "hash_testing"."product_code""#,
+            r#"FROM (SELECT "hash_testing"."identification_number","#,
+            r#""hash_testing"."product_code","#,
+            r#""hash_testing"."product_units","#,
+            r#""hash_testing"."sys_op" FROM "hash_testing") as "hash_testing""#,
+            r#"INNER JOIN (SELECT "history"."id" FROM "history") as "history""#,
+            r#"ON ("hash_testing"."identification_number") = ("history"."id")"#,
+            r#"WHERE ("hash_testing"."product_code") = (?)"#,
+        ),
+        vec![Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Oldest);
+}
+
+#[test]
+fn inner_join2_latest() {
+    let query = r#"SELECT "product_code" FROM "hash_testing" join
+        (SELECT * FROM "history" WHERE "id" = 1) as "t"
+        on "hash_testing"."identification_number" = "t"."id"
+        WHERE "product_code" = 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {} {} {} {} {}",
+            r#"SELECT "hash_testing"."product_code" FROM (SELECT"#,
+            r#""hash_testing"."identification_number","#,
+            r#""hash_testing"."product_code","#,
+            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#"ON ("hash_testing"."identification_number") = ("t"."id")"#,
+            r#"WHERE ("hash_testing"."product_code") = (?)"#,
+        ),
+        vec![Value::from(1_u64), Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Latest);
+}
+
+#[test]
+fn inner_join2_oldest() {
+    let query = r#"SELECT "product_code" FROM "hash_testing" join
+        (SELECT * FROM "history" WHERE "id" = 1) as "t"
+        on "hash_testing"."identification_number" = "t"."id"
+        WHERE "product_code" = 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {} {} {} {} {}",
+            r#"SELECT "hash_testing"."product_code" FROM (SELECT"#,
+            r#""hash_testing"."identification_number","#,
+            r#""hash_testing"."product_code","#,
+            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#"ON ("hash_testing"."identification_number") = ("t"."id")"#,
+            r#"WHERE ("hash_testing"."product_code") = (?)"#,
+        ),
+        vec![Value::from(1_u64), Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Oldest);
+}
diff --git a/sbroad-core/src/backend/sql/ir/tests/projection.rs b/sbroad-core/src/backend/sql/ir/tests/projection.rs
new file mode 100644
index 0000000000..57c1b248b2
--- /dev/null
+++ b/sbroad-core/src/backend/sql/ir/tests/projection.rs
@@ -0,0 +1,79 @@
+use super::*;
+use crate::ir::tree::Snapshot;
+use crate::ir::value::Value;
+
+#[test]
+fn projection1_latest() {
+    let query = r#"SELECT "identification_number", "product_code"
+        FROM "hash_testing"
+        WHERE "identification_number" = 1"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {}",
+            r#"SELECT "hash_testing"."identification_number","#,
+            r#""hash_testing"."product_code""#,
+            r#"FROM "hash_testing""#,
+            r#"WHERE ("hash_testing"."identification_number") = (?)"#,
+        ),
+        vec![Value::from(1_u64)],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Latest);
+}
+
+#[test]
+fn projection1_oldest() {
+    let query = r#"SELECT "identification_number", "product_code"
+        FROM "hash_testing"
+        WHERE "identification_number" = 1"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {}",
+            r#"SELECT "hash_testing"."identification_number","#,
+            r#""hash_testing"."product_code""#,
+            r#"FROM "hash_testing""#,
+            r#"WHERE ("hash_testing"."identification_number") = (?)"#,
+        ),
+        vec![Value::from(1_u64)],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Oldest);
+}
+
+#[test]
+fn projection2_latest() {
+    let query = r#"SELECT *
+        FROM "hash_testing"
+        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#"FROM "hash_testing""#,
+            r#"WHERE ("hash_testing"."identification_number") = (?)"#
+        ),
+        vec![Value::from(1_u64)],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Latest);
+}
+
+#[test]
+fn projection2_oldest() {
+    let query = r#"SELECT *
+        FROM "hash_testing"
+        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#"FROM "hash_testing""#,
+            r#"WHERE ("hash_testing"."identification_number") = (?)"#
+        ),
+        vec![Value::from(1_u64)],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Oldest);
+}
diff --git a/sbroad-core/src/backend/sql/ir/tests/selection.rs b/sbroad-core/src/backend/sql/ir/tests/selection.rs
new file mode 100644
index 0000000000..0759275fee
--- /dev/null
+++ b/sbroad-core/src/backend/sql/ir/tests/selection.rs
@@ -0,0 +1,600 @@
+use super::*;
+use crate::ir::tree::Snapshot;
+use crate::ir::value::Value;
+
+#[test]
+fn selection1_latest() {
+    let query = r#"SELECT "product_code" FROM "hash_testing"
+        WHERE "identification_number" in
+        (SELECT "identification_number" FROM "hash_testing_hist" WHERE "product_code" = 'b') and "product_code" < 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {}",
+            r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#,
+            r#"WHERE ("hash_testing"."product_code") < (?)"#,
+            r#"and ("hash_testing"."identification_number") in"#,
+            r#"(SELECT "hash_testing_hist"."identification_number" FROM "hash_testing_hist""#,
+            r#"WHERE ("hash_testing_hist"."product_code") = (?))"#,
+        ),
+        vec![Value::from("a"), Value::from("b")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Latest);
+}
+
+#[test]
+fn selection1_oldest() {
+    let query = r#"SELECT "product_code" FROM "hash_testing"
+        WHERE "identification_number" in
+        (SELECT "identification_number" FROM "hash_testing_hist" WHERE "product_code" = 'b') and "product_code" < 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {}",
+            r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#,
+            r#"WHERE ("hash_testing"."identification_number") in"#,
+            r#"(SELECT "hash_testing_hist"."identification_number" FROM "hash_testing_hist""#,
+            r#"WHERE ("hash_testing_hist"."product_code") = (?))"#,
+            r#"and ("hash_testing"."product_code") < (?)"#,
+        ),
+        vec![Value::from("b"), Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Oldest);
+}
+
+#[test]
+fn selection2_latest() {
+    let query = r#"SELECT "product_code" FROM "hash_testing"
+        WHERE "identification_number" IN (6659253, -21, 5933116, 8257405, 3676468, 6580234, 9557717)
+        AND "product_code" IN (6659253, -21, 5933116, 8257405, 3676468, 6580234, 9557717)
+        AND "identification_number" < "product_code"
+        AND ("product_units" <> "sys_op" OR "product_units" IS NULL)"#;
+
+    let expected = PatternWithParams::new(
+            [
+                r#"SELECT "hash_testing"."product_code" FROM "hash_testing" WHERE (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op")"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") <> ("hash_testing"."sys_op"))"#,
+                r#"or ("hash_testing"."identification_number", "hash_testing"."identification_number", "hash_testing"."product_code") = ("hash_testing"."product_code", ?, ?)"#,
+                r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+                r#"and ("hash_testing"."product_units") is null)"#,
+            ].join(" "),
+        vec![
+            Value::from(6659253_u64),
+            Value::from(6659253_u64),
+            Value::from(6659253_u64),
+            Value::from(6659253_u64),
+            Value::from(6659253_u64),
+            Value::from(-21_i64),
+            Value::from(6659253_u64),
+            Value::from(-21_i64),
+            Value::from(6659253_u64),
+            Value::from(5933116_u64),
+            Value::from(6659253_u64),
+            Value::from(5933116_u64),
+            Value::from(6659253_u64),
+            Value::from(8257405_u64),
+            Value::from(6659253_u64),
+            Value::from(8257405_u64),
+            Value::from(6659253_u64),
+            Value::from(3676468_u64),
+            Value::from(6659253_u64),
+            Value::from(3676468_u64),
+            Value::from(6659253_u64),
+            Value::from(6580234_u64),
+            Value::from(6659253_u64),
+            Value::from(6580234_u64),
+            Value::from(6659253_u64),
+            Value::from(9557717_u64),
+            Value::from(6659253_u64),
+            Value::from(9557717_u64),
+            Value::from(-21_i64),
+            Value::from(6659253_u64),
+            Value::from(-21_i64),
+            Value::from(6659253_u64),
+            Value::from(-21_i64),
+            Value::from(-21_i64),
+            Value::from(-21_i64),
+            Value::from(-21_i64),
+            Value::from(-21_i64),
+            Value::from(5933116_u64),
+            Value::from(-21_i64),
+            Value::from(5933116_u64),
+            Value::from(-21_i64),
+            Value::from(8257405_u64),
+            Value::from(-21_i64),
+            Value::from(8257405_u64),
+            Value::from(-21_i64),
+            Value::from(3676468_u64),
+            Value::from(-21_i64),
+            Value::from(3676468_u64),
+            Value::from(-21_i64),
+            Value::from(6580234_u64),
+            Value::from(-21_i64),
+            Value::from(6580234_u64),
+            Value::from(-21_i64),
+            Value::from(9557717_u64),
+            Value::from(-21_i64),
+            Value::from(9557717_u64),
+            Value::from(5933116_u64),
+            Value::from(6659253_u64),
+            Value::from(5933116_u64),
+            Value::from(6659253_u64),
+            Value::from(5933116_u64),
+            Value::from(-21_i64),
+            Value::from(5933116_u64),
+            Value::from(-21_i64),
+            Value::from(5933116_u64),
+            Value::from(5933116_u64),
+            Value::from(5933116_u64),
+            Value::from(5933116_u64),
+            Value::from(5933116_u64),
+            Value::from(8257405_u64),
+            Value::from(5933116_u64),
+            Value::from(8257405_u64),
+            Value::from(5933116_u64),
+            Value::from(3676468_u64),
+            Value::from(5933116_u64),
+            Value::from(3676468_u64),
+            Value::from(5933116_u64),
+            Value::from(6580234_u64),
+            Value::from(5933116_u64),
+            Value::from(6580234_u64),
+            Value::from(5933116_u64),
+            Value::from(9557717_u64),
+            Value::from(5933116_u64),
+            Value::from(9557717_u64),
+            Value::from(8257405_u64),
+            Value::from(6659253_u64),
+            Value::from(8257405_u64),
+            Value::from(6659253_u64),
+            Value::from(8257405_u64),
+            Value::from(-21_i64),
+            Value::from(8257405_u64),
+            Value::from(-21_i64),
+            Value::from(8257405_u64),
+            Value::from(5933116_u64),
+            Value::from(8257405_u64),
+            Value::from(5933116_u64),
+            Value::from(8257405_u64),
+            Value::from(8257405_u64),
+            Value::from(8257405_u64),
+            Value::from(8257405_u64),
+            Value::from(8257405_u64),
+            Value::from(3676468_u64),
+            Value::from(8257405_u64),
+            Value::from(3676468_u64),
+            Value::from(8257405_u64),
+            Value::from(6580234_u64),
+            Value::from(8257405_u64),
+            Value::from(6580234_u64),
+            Value::from(8257405_u64),
+            Value::from(9557717_u64),
+            Value::from(8257405_u64),
+            Value::from(9557717_u64),
+            Value::from(3676468_u64),
+            Value::from(6659253_u64),
+            Value::from(3676468_u64),
+            Value::from(6659253_u64),
+            Value::from(3676468_u64),
+            Value::from(-21_i64),
+            Value::from(3676468_u64),
+            Value::from(-21_i64),
+            Value::from(3676468_u64),
+            Value::from(5933116_u64),
+            Value::from(3676468_u64),
+            Value::from(5933116_u64),
+            Value::from(3676468_u64),
+            Value::from(8257405_u64),
+            Value::from(3676468_u64),
+            Value::from(8257405_u64),
+            Value::from(3676468_u64),
+            Value::from(3676468_u64),
+            Value::from(3676468_u64),
+            Value::from(3676468_u64),
+            Value::from(3676468_u64),
+            Value::from(6580234_u64),
+            Value::from(3676468_u64),
+            Value::from(6580234_u64),
+            Value::from(3676468_u64),
+            Value::from(9557717_u64),
+            Value::from(3676468_u64),
+            Value::from(9557717_u64),
+            Value::from(6580234_u64),
+            Value::from(6659253_u64),
+            Value::from(6580234_u64),
+            Value::from(6659253_u64),
+            Value::from(6580234_u64),
+            Value::from(-21_i64),
+            Value::from(6580234_u64),
+            Value::from(-21_i64),
+            Value::from(6580234_u64),
+            Value::from(5933116_u64),
+            Value::from(6580234_u64),
+            Value::from(5933116_u64),
+            Value::from(6580234_u64),
+            Value::from(8257405_u64),
+            Value::from(6580234_u64),
+            Value::from(8257405_u64),
+            Value::from(6580234_u64),
+            Value::from(3676468_u64),
+            Value::from(6580234_u64),
+            Value::from(3676468_u64),
+            Value::from(6580234_u64),
+            Value::from(6580234_u64),
+            Value::from(6580234_u64),
+            Value::from(6580234_u64),
+            Value::from(6580234_u64),
+            Value::from(9557717_u64),
+            Value::from(6580234_u64),
+            Value::from(9557717_u64),
+            Value::from(9557717_u64),
+            Value::from(6659253_u64),
+            Value::from(9557717_u64),
+            Value::from(6659253_u64),
+            Value::from(9557717_u64),
+            Value::from(-21_i64),
+            Value::from(9557717_u64),
+            Value::from(-21_i64),
+            Value::from(9557717_u64),
+            Value::from(5933116_u64),
+            Value::from(9557717_u64),
+            Value::from(5933116_u64),
+            Value::from(9557717_u64),
+            Value::from(8257405_u64),
+            Value::from(9557717_u64),
+            Value::from(8257405_u64),
+            Value::from(9557717_u64),
+            Value::from(3676468_u64),
+            Value::from(9557717_u64),
+            Value::from(3676468_u64),
+            Value::from(9557717_u64),
+            Value::from(6580234_u64),
+            Value::from(9557717_u64),
+            Value::from(6580234_u64),
+            Value::from(9557717_u64),
+            Value::from(9557717_u64),
+            Value::from(9557717_u64),
+            Value::from(9557717_u64),
+        ],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Latest);
+}
+
+#[test]
+fn selection2_oldest() {
+    let query = r#"SELECT "product_code" FROM "hash_testing"
+        WHERE "identification_number" IN (6659253, -21, 5933116, 8257405, 3676468, 6580234, 9557717)
+        AND "product_code" IN (6659253, -21, 5933116, 8257405, 3676468, 6580234, 9557717)
+        AND "identification_number" < "product_code"
+        AND ("product_units" <> "sys_op" OR "product_units" IS NULL)"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}",
+            r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#,
+            r#"WHERE ((((((("hash_testing"."identification_number") = (?)"#,
+            r#"or ("hash_testing"."identification_number") = (?))"#,
+            r#"or ("hash_testing"."identification_number") = (?))"#,
+            r#"or ("hash_testing"."identification_number") = (?))"#,
+            r#"or ("hash_testing"."identification_number") = (?))"#,
+            r#"or ("hash_testing"."identification_number") = (?))"#,
+            r#"or ("hash_testing"."identification_number") = (?))"#,
+            r#"and ((((((("hash_testing"."product_code") = (?)"#,
+            r#"or ("hash_testing"."product_code") = (?))"#,
+            r#"or ("hash_testing"."product_code") = (?))"#,
+            r#"or ("hash_testing"."product_code") = (?))"#,
+            r#"or ("hash_testing"."product_code") = (?))"#,
+            r#"or ("hash_testing"."product_code") = (?))"#,
+            r#"or ("hash_testing"."product_code") = (?))"#,
+            r#"and ("hash_testing"."identification_number") < ("hash_testing"."product_code")"#,
+            r#"and (("hash_testing"."product_units") <> ("hash_testing"."sys_op")"#,
+            r#"or ("hash_testing"."product_units") is null)"#,
+        ),
+        vec![
+            Value::from(6659253_u64),
+            Value::from(-21_i64),
+            Value::from(5933116_u64),
+            Value::from(8257405_u64),
+            Value::from(3676468_u64),
+            Value::from(6580234_u64),
+            Value::from(9557717_u64),
+            Value::from(6659253_u64),
+            Value::from(-21_i64),
+            Value::from(5933116_u64),
+            Value::from(8257405_u64),
+            Value::from(3676468_u64),
+            Value::from(6580234_u64),
+            Value::from(9557717_u64),
+        ],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Oldest);
+}
diff --git a/sbroad-core/src/backend/sql/ir/tests/sub_query.rs b/sbroad-core/src/backend/sql/ir/tests/sub_query.rs
new file mode 100644
index 0000000000..3b35a158fb
--- /dev/null
+++ b/sbroad-core/src/backend/sql/ir/tests/sub_query.rs
@@ -0,0 +1,101 @@
+use super::*;
+use crate::ir::tree::Snapshot;
+use crate::ir::value::Value;
+
+#[test]
+fn sub_query1_latest() {
+    let query = r#"SELECT "product_code"
+        FROM (SELECT "product_code"
+        FROM "hash_testing"
+        WHERE "identification_number" = 1) as t1
+        WHERE "product_code" = 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {}",
+            r#"SELECT "T1"."product_code" FROM"#,
+            r#"(SELECT "hash_testing"."product_code" FROM "hash_testing""#,
+            r#"WHERE ("hash_testing"."identification_number") = (?)) as "T1""#,
+            r#"WHERE ("T1"."product_code") = (?)"#
+        ),
+        vec![Value::from(1_u64), Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Latest);
+}
+
+#[test]
+fn sub_query1_oldest() {
+    let query = r#"SELECT "product_code"
+        FROM (SELECT "product_code"
+        FROM "hash_testing"
+        WHERE "identification_number" = 1) as t1
+        WHERE "product_code" = 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {}",
+            r#"SELECT "T1"."product_code" FROM"#,
+            r#"(SELECT "hash_testing"."product_code" FROM "hash_testing""#,
+            r#"WHERE ("hash_testing"."identification_number") = (?)) as "T1""#,
+            r#"WHERE ("T1"."product_code") = (?)"#
+        ),
+        vec![Value::from(1_u64), Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Oldest);
+}
+
+#[test]
+fn sub_query2_latest() {
+    let query = r#"SELECT "product_code"
+        FROM (SELECT "product_code"
+            FROM "hash_testing"
+            WHERE "identification_number" = 1
+            UNION ALL
+            SELECT "product_code"
+            FROM "hash_testing_hist"
+            WHERE "product_code" = 'a') as "t1"
+        WHERE "product_code" = 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {} {} {}",
+            r#"SELECT "t1"."product_code" FROM"#,
+            r#"(SELECT "hash_testing"."product_code" FROM "hash_testing""#,
+            r#"WHERE ("hash_testing"."identification_number") = (?)"#,
+            r#"UNION ALL"#,
+            r#"SELECT "hash_testing_hist"."product_code" FROM "hash_testing_hist""#,
+            r#"WHERE ("hash_testing_hist"."product_code") = (?)) as "t1""#,
+            r#"WHERE ("t1"."product_code") = (?)"#,
+        ),
+        vec![Value::from(1_u64), Value::from("a"), Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Latest);
+}
+
+#[test]
+fn sub_query2_oldest() {
+    let query = r#"SELECT "product_code"
+        FROM (SELECT "product_code"
+            FROM "hash_testing"
+            WHERE "identification_number" = 1
+            UNION ALL
+            SELECT "product_code"
+            FROM "hash_testing_hist"
+            WHERE "product_code" = 'a') as "t1"
+        WHERE "product_code" = 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {} {} {}",
+            r#"SELECT "t1"."product_code" FROM"#,
+            r#"(SELECT "hash_testing"."product_code" FROM "hash_testing""#,
+            r#"WHERE ("hash_testing"."identification_number") = (?)"#,
+            r#"UNION ALL"#,
+            r#"SELECT "hash_testing_hist"."product_code" FROM "hash_testing_hist""#,
+            r#"WHERE ("hash_testing_hist"."product_code") = (?)) as "t1""#,
+            r#"WHERE ("t1"."product_code") = (?)"#,
+        ),
+        vec![Value::from(1_u64), Value::from("a"), Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Oldest);
+}
diff --git a/sbroad-core/src/backend/sql/ir/tests/union_all.rs b/sbroad-core/src/backend/sql/ir/tests/union_all.rs
new file mode 100644
index 0000000000..008c27e876
--- /dev/null
+++ b/sbroad-core/src/backend/sql/ir/tests/union_all.rs
@@ -0,0 +1,51 @@
+use super::*;
+use crate::ir::tree::Snapshot;
+use crate::ir::value::Value;
+
+#[test]
+fn union_all1_latest() {
+    let query = r#"SELECT "product_code"
+        FROM "hash_testing"
+        WHERE "identification_number" = 1
+        UNION ALL
+        SELECT "product_code"
+        FROM "hash_testing_hist"
+        WHERE "product_code" = 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {}",
+            r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#,
+            r#"WHERE ("hash_testing"."identification_number") = (?)"#,
+            r#"UNION ALL"#,
+            r#"SELECT "hash_testing_hist"."product_code" FROM "hash_testing_hist""#,
+            r#"WHERE ("hash_testing_hist"."product_code") = (?)"#
+        ),
+        vec![Value::from(1_u64), Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Latest);
+}
+
+#[test]
+fn union_all1_oldest() {
+    let query = r#"SELECT "product_code"
+        FROM "hash_testing"
+        WHERE "identification_number" = 1
+        UNION ALL
+        SELECT "product_code"
+        FROM "hash_testing_hist"
+        WHERE "product_code" = 'a'"#;
+
+    let expected = PatternWithParams::new(
+        format!(
+            "{} {} {} {} {}",
+            r#"SELECT "hash_testing"."product_code" FROM "hash_testing""#,
+            r#"WHERE ("hash_testing"."identification_number") = (?)"#,
+            r#"UNION ALL"#,
+            r#"SELECT "hash_testing_hist"."product_code" FROM "hash_testing_hist""#,
+            r#"WHERE ("hash_testing_hist"."product_code") = (?)"#
+        ),
+        vec![Value::from(1_u64), Value::from("a")],
+    );
+    check_sql_with_snapshot(query, expected, Snapshot::Oldest);
+}
diff --git a/sbroad-core/src/backend/sql/tree.rs b/sbroad-core/src/backend/sql/tree.rs
index a5b20f9aa6..8c1649d23d 100644
--- a/sbroad-core/src/backend/sql/tree.rs
+++ b/sbroad-core/src/backend/sql/tree.rs
@@ -11,6 +11,7 @@ use crate::executor::ir::ExecutionPlan;
 use crate::executor::vtable::VirtualTable;
 use crate::ir::expression::Expression;
 use crate::ir::operator::{Bool, Relational};
+use crate::ir::tree::Snapshot;
 use crate::ir::Node;
 use crate::otm::child_span;
 use sbroad_proc::otm_child_span;
@@ -238,7 +239,10 @@ impl SyntaxNodes {
     /// - nothing was found
     fn get_syntax_node_id(&self, plan_id: usize) -> Result<usize, QueryPlannerError> {
         self.map.get(&plan_id).copied().ok_or_else(|| {
-            QueryPlannerError::CustomError("Current plan node is absent in the map".into())
+            QueryPlannerError::CustomError(format!(
+                "Current plan node ({}) is absent in the map",
+                plan_id
+            ))
         })
     }
 
@@ -424,6 +428,7 @@ pub struct SyntaxPlan<'p> {
     pub(crate) nodes: SyntaxNodes,
     top: Option<usize>,
     plan: &'p ExecutionPlan,
+    snapshot: Snapshot,
 }
 
 #[allow(dead_code)]
@@ -560,10 +565,17 @@ impl<'p> SyntaxPlan<'p> {
                     let left_id = *children.first().ok_or_else(|| {
                         QueryPlannerError::CustomError("Selection has no children.".into())
                     })?;
+                    let filter_id = match self.snapshot {
+                        Snapshot::Latest => *filter,
+                        Snapshot::Oldest => *ir_plan
+                            .undo
+                            .get_oldest(filter)
+                            .map_or_else(|| filter, |id| id),
+                    };
                     let sn = SyntaxNode::new_pointer(
                         id,
                         Some(self.nodes.get_syntax_node_id(left_id)?),
-                        vec![self.nodes.get_syntax_node_id(*filter)?],
+                        vec![self.nodes.get_syntax_node_id(filter_id)?],
                     );
                     Ok(self.nodes.push_syntax_node(sn))
                 }
@@ -906,6 +918,7 @@ impl<'p> SyntaxPlan<'p> {
             nodes: SyntaxNodes::with_capacity(plan.get_ir_plan().next_id()),
             top: None,
             plan,
+            snapshot: Snapshot::Latest,
         }
     }
 
@@ -916,17 +929,36 @@ impl<'p> SyntaxPlan<'p> {
     /// - Failed to get to the top of the syntax tree
     /// - Failed to move projection nodes under their scans
     #[otm_child_span("syntax.new")]
-    pub fn new(plan: &'p ExecutionPlan, top: usize) -> Result<Self, QueryPlannerError> {
+    pub fn new(
+        plan: &'p ExecutionPlan,
+        top: usize,
+        snapshot: Snapshot,
+    ) -> Result<Self, QueryPlannerError> {
         let mut sp = SyntaxPlan::empty(plan);
+        sp.snapshot = snapshot.clone();
         let ir_plan = plan.get_ir_plan();
 
         // Wrap plan's nodes and preserve their ids.
-        let dft_post = DftPost::new(&top, |node| ir_plan.subtree_iter(node));
-        for (_, id) in dft_post {
-            // it works only for post-order traversal
-            let sn_id = sp.add_plan_node(*id)?;
-            if *id == top {
-                sp.set_top(sn_id)?;
+        match snapshot {
+            Snapshot::Latest => {
+                let dft_post = DftPost::new(&top, |node| ir_plan.subtree_iter(node));
+                for (_, id) in dft_post {
+                    // it works only for post-order traversal
+                    let sn_id = sp.add_plan_node(*id)?;
+                    if *id == top {
+                        sp.set_top(sn_id)?;
+                    }
+                }
+            }
+            Snapshot::Oldest => {
+                let dft_post = DftPost::new(&top, |node| ir_plan.flashback_subtree_iter(node));
+                for (_, id) in dft_post {
+                    // it works only for post-order traversal
+                    let sn_id = sp.add_plan_node(*id)?;
+                    if *id == top {
+                        sp.set_top(sn_id)?;
+                    }
+                }
             }
         }
         sp.move_proj_under_scan()?;
diff --git a/sbroad-core/src/backend/sql/tree/tests.rs b/sbroad-core/src/backend/sql/tree/tests.rs
index 14f59c512d..efae9280b1 100644
--- a/sbroad-core/src/backend/sql/tree/tests.rs
+++ b/sbroad-core/src/backend/sql/tree/tests.rs
@@ -6,6 +6,7 @@ use pretty_assertions::assert_eq;
 use crate::backend::sql::tree::{OrderedSyntaxNodes, SyntaxPlan};
 use crate::ir::operator::Bool;
 use crate::ir::relation::{Column, ColumnRole, Table, Type};
+use crate::ir::tree::Snapshot;
 use crate::ir::value::Value;
 use crate::ir::Plan;
 
@@ -49,7 +50,7 @@ fn sql_order_selection() {
     let top_id = exec_plan.get_ir_plan().get_top().unwrap();
 
     // test the syntax plan
-    let sp = SyntaxPlan::new(&exec_plan, top_id).unwrap();
+    let sp = SyntaxPlan::new(&exec_plan, top_id, Snapshot::Latest).unwrap();
     let path = Path::new("")
         .join("tests")
         .join("artifactory")
@@ -65,7 +66,7 @@ fn sql_order_selection() {
     let top_id = exec_plan.get_ir_plan().get_top().unwrap();
 
     // get nodes in the sql-convenient order
-    let sp = SyntaxPlan::new(&exec_plan, top_id).unwrap();
+    let sp = SyntaxPlan::new(&exec_plan, top_id, Snapshot::Latest).unwrap();
     let ordered = OrderedSyntaxNodes::try_from(sp).unwrap();
     let nodes = ordered.to_syntax_data().unwrap();
     let mut nodes_iter = nodes.into_iter();
diff --git a/sbroad-core/src/executor/engine/mock.rs b/sbroad-core/src/executor/engine/mock.rs
index b49c677b77..ed14cc3c04 100644
--- a/sbroad-core/src/executor/engine/mock.rs
+++ b/sbroad-core/src/executor/engine/mock.rs
@@ -20,6 +20,7 @@ use crate::frontend::sql::ast::AbstractSyntaxTree;
 use crate::ir::function::Function;
 use crate::ir::helpers::RepeatableState;
 use crate::ir::relation::{Column, ColumnRole, Table, Type};
+use crate::ir::tree::Snapshot;
 use crate::ir::value::Value;
 use crate::ir::Plan;
 
@@ -318,7 +319,7 @@ impl Coordinator for RouterRuntimeMock {
         buckets: &Buckets,
     ) -> Result<Box<dyn Any>, QueryPlannerError> {
         let mut result = ProducerResult::new();
-        let sp = SyntaxPlan::new(plan, top_id)?;
+        let sp = SyntaxPlan::new(plan, top_id, Snapshot::Oldest)?;
         let ordered = OrderedSyntaxNodes::try_from(sp)?;
         let nodes = ordered.to_syntax_data()?;
 
diff --git a/sbroad-core/src/executor/tests.rs b/sbroad-core/src/executor/tests.rs
index 98f7167f86..7554144cf4 100644
--- a/sbroad-core/src/executor/tests.rs
+++ b/sbroad-core/src/executor/tests.rs
@@ -114,7 +114,7 @@ fn map_reduce_query() {
                         "{} {} {}",
                         r#"SELECT "hash_testing"."product_code""#,
                         r#"FROM "hash_testing""#,
-                        r#"WHERE ("hash_testing"."identification_number", "hash_testing"."product_code") = (?, ?)"#,
+                        r#"WHERE ("hash_testing"."identification_number") = (?) and ("hash_testing"."product_code") = (?)"#,
                     ), vec![param1, param457],
                 )
             )
@@ -332,45 +332,39 @@ WHERE "t3"."id" = 2 AND "t8"."identification_number" = 2"#;
     let param2 = Value::from(2_u64);
     let bucket2 = query.coordinator.determine_bucket_id(&[&param2]);
 
-    expected.rows.extend(vec![
-        vec![
-            Value::String(format!("Execute query on a bucket [{}]", bucket2)),
-            Value::String(
-                String::from(
-                    PatternWithParams::new(
-                        format!(
-                            "{}, {}, {} {}{} {} {} {} {} {} {}{} {} {}{} {} {}",
-                            r#"SELECT "t3"."id""#,
-                            r#""t3"."FIRST_NAME""#,
-                            r#""t8"."identification_number""#,
-                            r#"FROM ("#,
-                            r#"SELECT "test_space"."id", "test_space"."FIRST_NAME""#,
-                            r#"FROM "test_space""#,
-                            r#"WHERE ("test_space"."sysFrom") >= (?) and ("test_space"."sys_op") < (?)"#,
-                            r#"UNION ALL"#,
-                            r#"SELECT "test_space_hist"."id", "test_space_hist"."FIRST_NAME""#,
-                            r#"FROM "test_space_hist""#,
-                            r#"WHERE ("test_space_hist"."sysFrom") <= (?)"#,
-                            r#") as "t3""#,
-                            r#"INNER JOIN"#,
-                            r#"(SELECT COLUMN_1 as "identification_number" FROM (VALUES (?))"#,
-                            r#") as "t8""#,
-                            r#"ON ("t3"."id") = ("t8"."identification_number")"#,
-                            r#"WHERE ("t3"."id", "t3"."id", "t8"."identification_number") = ("t8"."identification_number", ?, ?)"#
-                        ),
-                        vec![
-                            Value::from(0_u64),
-                            Value::from(0_u64),
-                            Value::from(0_u64),
-                            Value::from(2_u64),
-                            Value::from(2_u64),
-                            Value::from(2_u64)
-                        ]
-                    )
-                )
-            )
-        ],
-    ]);
+    expected.rows.extend(vec![vec![
+        Value::String(format!("Execute query on a bucket [{}]", bucket2)),
+        Value::String(String::from(PatternWithParams::new(
+            format!(
+                "{}, {}, {} {}{} {} {} {} {} {} {}{} {} {}{} {} {}",
+                r#"SELECT "t3"."id""#,
+                r#""t3"."FIRST_NAME""#,
+                r#""t8"."identification_number""#,
+                r#"FROM ("#,
+                r#"SELECT "test_space"."id", "test_space"."FIRST_NAME""#,
+                r#"FROM "test_space""#,
+                r#"WHERE ("test_space"."sys_op") < (?) and ("test_space"."sysFrom") >= (?)"#,
+                r#"UNION ALL"#,
+                r#"SELECT "test_space_hist"."id", "test_space_hist"."FIRST_NAME""#,
+                r#"FROM "test_space_hist""#,
+                r#"WHERE ("test_space_hist"."sysFrom") <= (?)"#,
+                r#") as "t3""#,
+                r#"INNER JOIN"#,
+                r#"(SELECT COLUMN_1 as "identification_number" FROM (VALUES (?))"#,
+                r#") as "t8""#,
+                r#"ON ("t3"."id") = ("t8"."identification_number")"#,
+                r#"WHERE ("t3"."id") = (?) and ("t8"."identification_number") = (?)"#
+            ),
+            vec![
+                Value::from(0_u64),
+                Value::from(0_u64),
+                Value::from(0_u64),
+                Value::from(2_u64),
+                Value::from(2_u64),
+                Value::from(2_u64),
+            ],
+        ))),
+    ]]);
     assert_eq!(expected, result);
 }
 
diff --git a/sbroad-core/src/executor/tests/between.rs b/sbroad-core/src/executor/tests/between.rs
index 6514471781..5be94415fe 100644
--- a/sbroad-core/src/executor/tests/between.rs
+++ b/sbroad-core/src/executor/tests/between.rs
@@ -57,12 +57,12 @@ fn between1_test() {
             format!(
                 "{} {} {}",
                 r#"SELECT "t"."identification_number" FROM "hash_testing" as "t""#,
-                r#"WHERE ("t"."identification_number") <= (SELECT COLUMN_1 as "id" FROM (VALUES (?)))"#,
-                r#"and ("t"."identification_number") >= (?)"#,
+                r#"WHERE ("t"."identification_number") >= (?)"#,
+                r#"and ("t"."identification_number") <= (SELECT COLUMN_1 as "id" FROM (VALUES (?)))"#,
             ),
             vec![
-                Value::from(2_u64),
                 Value::from(1_u64),
+                Value::from(2_u64),
             ],
         ))),
     ]]);
@@ -123,14 +123,14 @@ fn between2_test() {
             format!(
                 "{} {} {}",
                 r#"SELECT "t"."identification_number" FROM "hash_testing" as "t""#,
-                r#"WHERE (SELECT COLUMN_1 as "id" FROM (VALUES (?))) <= (?)"#,
-                r#"and (SELECT COLUMN_2 as "id" FROM (VALUES (?))) >= (?)"#,
+                r#"WHERE (SELECT COLUMN_1 as "id" FROM (VALUES (?))) >= (?)"#,
+                r#"and (SELECT COLUMN_2 as "id" FROM (VALUES (?))) <= (?)"#,
             ),
             vec![
-                Value::from(2_u64),
-                Value::from(3_u64),
                 Value::from(2_u64),
                 Value::from(1_u64),
+                Value::from(2_u64),
+                Value::from(3_u64),
             ],
         ))),
     ]]);
diff --git a/sbroad-core/src/executor/tests/bucket_id.rs b/sbroad-core/src/executor/tests/bucket_id.rs
index 17abd75618..6ea2280ddb 100644
--- a/sbroad-core/src/executor/tests/bucket_id.rs
+++ b/sbroad-core/src/executor/tests/bucket_id.rs
@@ -55,7 +55,7 @@ fn bucket2_test() {
             format!(
                 "{} {}",
                 r#"SELECT "t1"."a", "t1"."bucket_id", "t1"."b" FROM "t1""#,
-                r#"WHERE ("t1"."a", "t1"."b") = (?, ?)"#,
+                r#"WHERE ("t1"."a") = (?) and ("t1"."b") = (?)"#,
             ),
             vec![param1, param2],
         ))),
diff --git a/sbroad-core/src/executor/tests/not_eq.rs b/sbroad-core/src/executor/tests/not_eq.rs
index f9d134de7c..a2f7ab4565 100644
--- a/sbroad-core/src/executor/tests/not_eq.rs
+++ b/sbroad-core/src/executor/tests/not_eq.rs
@@ -41,9 +41,9 @@ fn not_eq1_test() {
             format!(
                 "{} {}",
                 r#"SELECT "t"."identification_number" FROM "hash_testing" as "t""#,
-                r#"WHERE ("t"."product_code") <> (?) and ("t"."identification_number") <> (?)"#,
+                r#"WHERE ("t"."identification_number") <> (?) and ("t"."product_code") <> (?)"#,
             ),
-            vec![Value::from(2_u64), Value::from(1_u64)],
+            vec![Value::from(1_u64), Value::from(2_u64)],
         ))),
     ]]);
     assert_eq!(expected, result);
diff --git a/sbroad-core/src/ir.rs b/sbroad-core/src/ir.rs
index abdab500c9..bb6a3f89c6 100644
--- a/sbroad-core/src/ir.rs
+++ b/sbroad-core/src/ir.rs
@@ -28,7 +28,14 @@ pub mod value;
 #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
 pub struct TreeMap(HashMap<usize, usize, RepeatableState>);
 
+impl Default for TreeMap {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
 impl TreeMap {
+    #[must_use]
     pub fn new() -> Self {
         Self(HashMap::with_hasher(RepeatableState))
     }
@@ -37,16 +44,23 @@ impl TreeMap {
         self.0.insert(new_id, old_id);
     }
 
-    pub fn get(&self, new_id: usize) -> Option<usize> {
-        self.0.get(&new_id).copied()
+    #[must_use]
+    pub fn get(&self, new_id: &usize) -> Option<&usize> {
+        self.0.get(new_id)
     }
 
-    pub fn get_oldest(&self, new_id: usize) -> usize {
-        let mut id = new_id;
-        while let Some(old_id) = self.get(id) {
-            id = old_id;
+    #[must_use]
+    pub fn get_oldest(&self, new_id: &usize) -> Option<&usize> {
+        match self.0.get_key_value(new_id) {
+            None => None,
+            Some((id, _)) => {
+                let mut current = id;
+                while let Some(parent) = self.get(current) {
+                    current = parent;
+                }
+                Some(current)
+            }
         }
-        id
     }
 }
 
@@ -138,10 +152,9 @@ pub struct Plan {
     /// The flag is enabled if user wants to get a query plan only.
     /// In this case we don't need to execute query.
     is_explain: bool,
-    /// The undo log is used to track the changes in the plan tree
-    /// during the optimization process. It is used to restore the
-    /// original subtree after the optimization (if it is needed).
-    undo: TreeMap,
+    /// The undo log keeps the history of the plan transformations. It can
+    /// be used to revert the plan subtree to some previous snapshot if needed.
+    pub(crate) undo: TreeMap,
 }
 
 impl Default for Plan {
diff --git a/sbroad-core/src/ir/transformation.rs b/sbroad-core/src/ir/transformation.rs
index c5ffa20462..28cb3401a3 100644
--- a/sbroad-core/src/ir/transformation.rs
+++ b/sbroad-core/src/ir/transformation.rs
@@ -95,7 +95,7 @@ impl Plan {
                 _ => continue,
             };
             if old_tree_id != new_tree_id {
-                self.undo.add(new_tree_id, old_tree_id);
+                self.undo.add(old_tree_id, new_tree_id);
             }
             let rel = self.get_mut_relation_node(*id)?;
             match rel {
diff --git a/sbroad-core/src/ir/transformation/bool_in/tests.rs b/sbroad-core/src/ir/transformation/bool_in/tests.rs
index feccf6b742..6de0158fa3 100644
--- a/sbroad-core/src/ir/transformation/bool_in/tests.rs
+++ b/sbroad-core/src/ir/transformation/bool_in/tests.rs
@@ -1,5 +1,5 @@
 use crate::backend::sql::ir::PatternWithParams;
-use crate::ir::transformation::helpers::sql_to_sql;
+use crate::ir::transformation::helpers::check_transformation;
 use crate::ir::value::Value;
 use crate::ir::Plan;
 use pretty_assertions::assert_eq;
@@ -20,7 +20,10 @@ fn bool_in1() {
         vec![Value::from(1_u64), Value::from(2_u64), Value::from(3_u64)],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &replace_in_operator), expected);
+    assert_eq!(
+        check_transformation(input, vec![], &replace_in_operator),
+        expected
+    );
 }
 
 #[test]
@@ -43,7 +46,10 @@ fn bool_in2() {
         ],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &replace_in_operator), expected);
+    assert_eq!(
+        check_transformation(input, vec![], &replace_in_operator),
+        expected
+    );
 }
 
 #[test]
@@ -58,5 +64,8 @@ fn bool_in3() {
         vec![Value::from(1_u64), Value::from(2_u64), Value::from(3_u64)],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &replace_in_operator), expected);
+    assert_eq!(
+        check_transformation(input, vec![], &replace_in_operator),
+        expected
+    );
 }
diff --git a/sbroad-core/src/ir/transformation/dnf/tests.rs b/sbroad-core/src/ir/transformation/dnf/tests.rs
index 37b671f120..9943e95318 100644
--- a/sbroad-core/src/ir/transformation/dnf/tests.rs
+++ b/sbroad-core/src/ir/transformation/dnf/tests.rs
@@ -1,5 +1,5 @@
 use crate::backend::sql::ir::PatternWithParams;
-use crate::ir::transformation::helpers::sql_to_sql;
+use crate::ir::transformation::helpers::check_transformation;
 use crate::ir::value::Value;
 use crate::ir::Plan;
 use pretty_assertions::assert_eq;
@@ -28,7 +28,7 @@ fn dnf1() {
         ],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &set_dnf), expected);
+    assert_eq!(check_transformation(input, vec![], &set_dnf), expected);
 }
 
 #[test]
@@ -54,7 +54,7 @@ fn dnf2() {
         ],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &set_dnf), expected);
+    assert_eq!(check_transformation(input, vec![], &set_dnf), expected);
 }
 
 #[test]
@@ -75,7 +75,7 @@ fn dnf3() {
         ],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &set_dnf), expected);
+    assert_eq!(check_transformation(input, vec![], &set_dnf), expected);
 }
 
 #[test]
@@ -96,7 +96,7 @@ fn dnf4() {
         ],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &set_dnf), expected);
+    assert_eq!(check_transformation(input, vec![], &set_dnf), expected);
 }
 
 #[test]
@@ -117,7 +117,7 @@ fn dnf5() {
         ],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &set_dnf), expected);
+    assert_eq!(check_transformation(input, vec![], &set_dnf), expected);
 }
 
 #[test]
@@ -133,5 +133,5 @@ fn dnf6() {
         vec![Value::from(1_u64), Value::from(1_u64), Value::from(2_u64)],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &set_dnf), expected);
+    assert_eq!(check_transformation(input, vec![], &set_dnf), expected);
 }
diff --git a/sbroad-core/src/ir/transformation/equality_propagation/tests.rs b/sbroad-core/src/ir/transformation/equality_propagation/tests.rs
index 7f1b0fdb5f..4a7f7ddcf8 100644
--- a/sbroad-core/src/ir/transformation/equality_propagation/tests.rs
+++ b/sbroad-core/src/ir/transformation/equality_propagation/tests.rs
@@ -1,5 +1,5 @@
 use crate::backend::sql::ir::PatternWithParams;
-use crate::ir::transformation::helpers::sql_to_sql;
+use crate::ir::transformation::helpers::check_transformation;
 use crate::ir::value::Value;
 use crate::ir::Plan;
 use pretty_assertions::assert_eq;
@@ -28,7 +28,10 @@ fn equality_propagation1() {
         ],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &derive_equalities), expected);
+    assert_eq!(
+        check_transformation(input, vec![], &derive_equalities),
+        expected
+    );
 }
 
 #[test]
@@ -41,7 +44,10 @@ fn equality_propagation2() {
         vec![Value::Null, Value::Null],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &derive_equalities), expected);
+    assert_eq!(
+        check_transformation(input, vec![], &derive_equalities),
+        expected
+    );
 }
 
 #[test]
@@ -58,7 +64,10 @@ fn equality_propagation3() {
         vec![Value::from(1_u64), Value::Null, Value::Null],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &derive_equalities), expected);
+    assert_eq!(
+        check_transformation(input, vec![], &derive_equalities),
+        expected
+    );
 }
 
 #[test]
@@ -81,7 +90,10 @@ fn equality_propagation4() {
         ],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &derive_equalities), expected);
+    assert_eq!(
+        check_transformation(input, vec![], &derive_equalities),
+        expected
+    );
 }
 
 #[test]
@@ -106,5 +118,8 @@ fn equality_propagation5() {
         ],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &derive_equalities), expected);
+    assert_eq!(
+        check_transformation(input, vec![], &derive_equalities),
+        expected
+    );
 }
diff --git a/sbroad-core/src/ir/transformation/helpers.rs b/sbroad-core/src/ir/transformation/helpers.rs
index 424d23287c..41d921892f 100644
--- a/sbroad-core/src/ir/transformation/helpers.rs
+++ b/sbroad-core/src/ir/transformation/helpers.rs
@@ -7,6 +7,7 @@ use crate::executor::engine::mock::RouterConfigurationMock;
 use crate::executor::ir::ExecutionPlan;
 use crate::frontend::sql::ast::AbstractSyntaxTree;
 use crate::frontend::Ast;
+use crate::ir::tree::Snapshot;
 use crate::ir::value::Value;
 use crate::ir::Plan;
 
@@ -40,7 +41,7 @@ pub fn sql_to_ir(query: &str, params: Vec<Value>) -> Plan {
 /// # Panics
 ///   if query is not correct
 #[allow(dead_code)]
-pub fn sql_to_sql(
+pub fn check_transformation(
     query: &str,
     params: Vec<Value>,
     f_transform: &dyn Fn(&mut Plan),
@@ -49,7 +50,7 @@ pub fn sql_to_sql(
     f_transform(&mut plan);
     let ex_plan = ExecutionPlan::from(plan);
     let top_id = ex_plan.get_ir_plan().get_top().unwrap();
-    let sp = SyntaxPlan::new(&ex_plan, top_id).unwrap();
+    let sp = SyntaxPlan::new(&ex_plan, top_id, Snapshot::Latest).unwrap();
     let ordered = OrderedSyntaxNodes::try_from(sp).unwrap();
     let nodes = ordered.to_syntax_data().unwrap();
     ex_plan.to_sql(&nodes, &Buckets::All).unwrap()
diff --git a/sbroad-core/src/ir/transformation/merge_tuples/tests.rs b/sbroad-core/src/ir/transformation/merge_tuples/tests.rs
index 22c8361e50..11e9c8ffdd 100644
--- a/sbroad-core/src/ir/transformation/merge_tuples/tests.rs
+++ b/sbroad-core/src/ir/transformation/merge_tuples/tests.rs
@@ -1,5 +1,5 @@
 use crate::backend::sql::ir::PatternWithParams;
-use crate::ir::transformation::helpers::sql_to_sql;
+use crate::ir::transformation::helpers::check_transformation;
 use crate::ir::value::Value;
 use crate::ir::Plan;
 use pretty_assertions::assert_eq;
@@ -25,7 +25,7 @@ fn merge_tuples1() {
         ],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &merge_tuples), expected);
+    assert_eq!(check_transformation(input, vec![], &merge_tuples), expected);
 }
 
 #[test]
@@ -50,7 +50,7 @@ fn merge_tuples2() {
         ],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &merge_tuples), expected);
+    assert_eq!(check_transformation(input, vec![], &merge_tuples), expected);
 }
 
 #[test]
@@ -61,7 +61,7 @@ fn merge_tuples3() {
         vec![Value::Boolean(true)],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &merge_tuples), expected);
+    assert_eq!(check_transformation(input, vec![], &merge_tuples), expected);
 }
 
 #[test]
@@ -75,7 +75,7 @@ fn merge_tuples4() {
         vec![Value::from(1_u64), Value::from(2_u64), Value::from(3_u64)],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &merge_tuples), expected);
+    assert_eq!(check_transformation(input, vec![], &merge_tuples), expected);
 }
 
 #[test]
@@ -90,7 +90,7 @@ fn merge_tuples5() {
         vec![Value::from(1_u64), Value::from(2_u64), Value::from(3_u64)],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &merge_tuples), expected);
+    assert_eq!(check_transformation(input, vec![], &merge_tuples), expected);
 }
 
 #[test]
@@ -104,5 +104,5 @@ fn merge_tuples6() {
         vec![Value::from(2_u64), Value::from(1_u64)],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &merge_tuples), expected);
+    assert_eq!(check_transformation(input, vec![], &merge_tuples), expected);
 }
diff --git a/sbroad-core/src/ir/transformation/split_columns/tests.rs b/sbroad-core/src/ir/transformation/split_columns/tests.rs
index 7eaaf0a762..02ad99fe98 100644
--- a/sbroad-core/src/ir/transformation/split_columns/tests.rs
+++ b/sbroad-core/src/ir/transformation/split_columns/tests.rs
@@ -2,7 +2,7 @@ use crate::backend::sql::ir::PatternWithParams;
 use crate::executor::engine::mock::RouterConfigurationMock;
 use crate::frontend::sql::ast::AbstractSyntaxTree;
 use crate::frontend::Ast;
-use crate::ir::transformation::helpers::sql_to_sql;
+use crate::ir::transformation::helpers::check_transformation;
 use crate::ir::value::Value;
 use crate::ir::Plan;
 use pretty_assertions::assert_eq;
@@ -19,7 +19,10 @@ fn split_columns1() {
         vec![Value::from(1_u64), Value::from(2_u64)],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &split_columns), expected);
+    assert_eq!(
+        check_transformation(input, vec![], &split_columns),
+        expected
+    );
 }
 
 #[test]
@@ -30,7 +33,10 @@ fn split_columns2() {
         vec![Value::from(1_u64)],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &split_columns), expected);
+    assert_eq!(
+        check_transformation(input, vec![], &split_columns),
+        expected
+    );
 }
 
 #[test]
@@ -61,7 +67,10 @@ fn split_columns4() {
         vec![Value::from(1_u64), Value::from(2_u64)],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &split_columns), expected);
+    assert_eq!(
+        check_transformation(input, vec![], &split_columns),
+        expected
+    );
 }
 
 #[test]
@@ -76,5 +85,8 @@ fn split_columns5() {
         vec![Value::from(1_u64), Value::from(2_u64), Value::from(2_u64)],
     );
 
-    assert_eq!(sql_to_sql(input, vec![], &split_columns), expected);
+    assert_eq!(
+        check_transformation(input, vec![], &split_columns),
+        expected
+    );
 }
diff --git a/sbroad-core/src/ir/tree.rs b/sbroad-core/src/ir/tree.rs
index ea174a34ae..d0df786dc3 100644
--- a/sbroad-core/src/ir/tree.rs
+++ b/sbroad-core/src/ir/tree.rs
@@ -13,6 +13,14 @@ trait PlanTreeIterator<'plan>: TreeIterator<'plan> {
     fn get_plan(&self) -> &'plan Plan;
 }
 
+/// A snapshot describes the version of the plan
+/// subtree to iterate over.
+#[derive(Debug, Clone)]
+pub enum Snapshot {
+    Latest,
+    Oldest,
+}
+
 pub mod and;
 pub mod eq_class;
 pub mod expression;
diff --git a/sbroad-core/src/ir/tree/and.rs b/sbroad-core/src/ir/tree/and.rs
index f38259e079..1c6c8377f9 100644
--- a/sbroad-core/src/ir/tree/and.rs
+++ b/sbroad-core/src/ir/tree/and.rs
@@ -10,6 +10,7 @@ trait AndTreeIterator<'nodes>: TreeIterator<'nodes> {}
 /// Children iterator for "and"-ed expression chains.
 ///
 /// The iterator returns the next child for the chained `Bool::And` nodes.
+#[allow(clippy::module_name_repetitions)]
 #[derive(Debug)]
 pub struct AndIterator<'n> {
     current: &'n usize,
diff --git a/sbroad-core/src/ir/tree/eq_class.rs b/sbroad-core/src/ir/tree/eq_class.rs
index a96ad63b8c..c8febae73d 100644
--- a/sbroad-core/src/ir/tree/eq_class.rs
+++ b/sbroad-core/src/ir/tree/eq_class.rs
@@ -11,6 +11,7 @@ trait EqClassTreeIterator<'nodes>: TreeIterator<'nodes> {}
 ///
 /// The iterator returns the next child for the chained `Bool::And`
 /// and `Bool::Eq` nodes.
+#[allow(clippy::module_name_repetitions)]
 #[derive(Debug)]
 pub struct EqClassIterator<'n> {
     current: &'n usize,
diff --git a/sbroad-core/src/ir/tree/expression.rs b/sbroad-core/src/ir/tree/expression.rs
index aeafaebc88..f46e4ebb69 100644
--- a/sbroad-core/src/ir/tree/expression.rs
+++ b/sbroad-core/src/ir/tree/expression.rs
@@ -12,6 +12,7 @@ trait ExpressionTreeIterator<'nodes>: TreeIterator<'nodes> {
 ///
 /// The iterator returns the next child for expression
 /// nodes. It is required to use `traversal` crate.
+#[allow(clippy::module_name_repetitions)]
 #[derive(Debug)]
 pub struct ExpressionIterator<'n> {
     current: &'n usize,
diff --git a/sbroad-core/src/ir/tree/subtree.rs b/sbroad-core/src/ir/tree/subtree.rs
index 0868168be5..17845d0335 100644
--- a/sbroad-core/src/ir/tree/subtree.rs
+++ b/sbroad-core/src/ir/tree/subtree.rs
@@ -1,7 +1,7 @@
 use std::cell::RefCell;
 use std::cmp::Ordering;
 
-use super::{PlanTreeIterator, TreeIterator};
+use super::{PlanTreeIterator, Snapshot, TreeIterator};
 use crate::ir::expression::Expression;
 use crate::ir::operator::Relational;
 use crate::ir::{Node, Nodes, Plan};
@@ -9,6 +9,7 @@ use crate::ir::{Node, Nodes, Plan};
 trait SubtreePlanIterator<'plan>: PlanTreeIterator<'plan> {}
 
 /// Expression and relational nodes iterator.
+#[allow(clippy::module_name_repetitions)]
 #[derive(Debug)]
 pub struct SubtreeIterator<'plan> {
     current: &'plan usize,
@@ -42,7 +43,7 @@ impl<'plan> Iterator for SubtreeIterator<'plan> {
     type Item = &'plan usize;
 
     fn next(&mut self) -> Option<Self::Item> {
-        subtree_next(self)
+        subtree_next(self, &Snapshot::Latest)
     }
 }
 
@@ -57,8 +58,66 @@ impl<'plan> Plan {
     }
 }
 
+/// Expression and relational nodes flashback iterator.
+/// It uses the UNDO transformation log to go back to the
+/// original state of some subtrees in the plan (selections
+/// at the moment).
+#[derive(Debug)]
+pub struct FlashbackSubtreeIterator<'plan> {
+    current: &'plan usize,
+    child: RefCell<usize>,
+    plan: &'plan Plan,
+}
+
+impl<'nodes> TreeIterator<'nodes> for FlashbackSubtreeIterator<'nodes> {
+    fn get_current(&self) -> &'nodes usize {
+        self.current
+    }
+
+    fn get_child(&self) -> &RefCell<usize> {
+        &self.child
+    }
+
+    fn get_nodes(&self) -> &'nodes Nodes {
+        &self.plan.nodes
+    }
+}
+
+impl<'plan> PlanTreeIterator<'plan> for FlashbackSubtreeIterator<'plan> {
+    fn get_plan(&self) -> &'plan Plan {
+        self.plan
+    }
+}
+
+impl<'plan> SubtreePlanIterator<'plan> for FlashbackSubtreeIterator<'plan> {}
+
+impl<'plan> Iterator for FlashbackSubtreeIterator<'plan> {
+    type Item = &'plan usize;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        subtree_next(self, &Snapshot::Oldest)
+    }
+}
+
+impl<'plan> Plan {
+    #[must_use]
+    pub fn flashback_subtree_iter(
+        &'plan self,
+        current: &'plan usize,
+    ) -> FlashbackSubtreeIterator<'plan> {
+        FlashbackSubtreeIterator {
+            current,
+            child: RefCell::new(0),
+            plan: self,
+        }
+    }
+}
+
 #[allow(clippy::too_many_lines)]
-fn subtree_next<'plan>(iter: &mut impl SubtreePlanIterator<'plan>) -> Option<&'plan usize> {
+fn subtree_next<'plan>(
+    iter: &mut impl SubtreePlanIterator<'plan>,
+    snapshot: &Snapshot,
+) -> Option<&'plan usize> {
     if let Some(child) = iter.get_nodes().arena.get(*iter.get_current()) {
         return match child {
             Node::Parameter => None,
@@ -198,9 +257,17 @@ fn subtree_next<'plan>(iter: &mut impl SubtreePlanIterator<'plan>) -> Option<&'p
                         Ordering::Less => {
                             return children.get(step);
                         }
-                        Ordering::Equal => {
-                            return Some(filter);
-                        }
+                        Ordering::Equal => match snapshot {
+                            Snapshot::Latest => Some(filter),
+                            Snapshot::Oldest => {
+                                return Some(
+                                    iter.get_plan()
+                                        .undo
+                                        .get_oldest(filter)
+                                        .map_or_else(|| filter, |id| id),
+                                );
+                            }
+                        },
                         Ordering::Greater => None,
                     }
                 }
diff --git a/sbroad-core/tests/artifactory/backend/sql/tree/sql_order_selection.yaml b/sbroad-core/tests/artifactory/backend/sql/tree/sql_order_selection.yaml
index 19a2aa7dae..a1125e3312 100644
--- a/sbroad-core/tests/artifactory/backend/sql/tree/sql_order_selection.yaml
+++ b/sbroad-core/tests/artifactory/backend/sql/tree/sql_order_selection.yaml
@@ -113,3 +113,4 @@ relations:
 slices: ~
 top: 16
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/distribution/join_unite_keys.yaml b/sbroad-core/tests/artifactory/ir/distribution/join_unite_keys.yaml
index b1ac3d0077..a5eec7cf42 100644
--- a/sbroad-core/tests/artifactory/ir/distribution/join_unite_keys.yaml
+++ b/sbroad-core/tests/artifactory/ir/distribution/join_unite_keys.yaml
@@ -171,3 +171,4 @@ relations:
 slices: ~
 top: 28
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_1.yaml b/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_1.yaml
index 0646bb3bf3..2ff4e07729 100644
--- a/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_1.yaml
+++ b/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_1.yaml
@@ -99,3 +99,4 @@ relations:
 slices: ~
 top: 15
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_2.yaml b/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_2.yaml
index 8249414613..8e1c4a050b 100644
--- a/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_2.yaml
+++ b/sbroad-core/tests/artifactory/ir/distribution/shrink_dist_key_2.yaml
@@ -88,3 +88,4 @@ relations:
 slices: ~
 top: 13
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/distribution/shuffle_dist_key.yaml b/sbroad-core/tests/artifactory/ir/distribution/shuffle_dist_key.yaml
index d2f81b5ca9..2c3200dc93 100644
--- a/sbroad-core/tests/artifactory/ir/distribution/shuffle_dist_key.yaml
+++ b/sbroad-core/tests/artifactory/ir/distribution/shuffle_dist_key.yaml
@@ -99,3 +99,4 @@ relations:
 slices: ~
 top: 15
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/distribution/union_fallback_to_random.yaml b/sbroad-core/tests/artifactory/ir/distribution/union_fallback_to_random.yaml
index e10eccccdd..0365fd8300 100644
--- a/sbroad-core/tests/artifactory/ir/distribution/union_fallback_to_random.yaml
+++ b/sbroad-core/tests/artifactory/ir/distribution/union_fallback_to_random.yaml
@@ -115,3 +115,4 @@ relations:
 slices: ~
 top: 17
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/distribution/union_preserve_dist.yaml b/sbroad-core/tests/artifactory/ir/distribution/union_preserve_dist.yaml
index 60ae5e3b6a..d5e530d7c0 100644
--- a/sbroad-core/tests/artifactory/ir/distribution/union_preserve_dist.yaml
+++ b/sbroad-core/tests/artifactory/ir/distribution/union_preserve_dist.yaml
@@ -115,3 +115,4 @@ relations:
 slices: ~
 top: 17
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/operator/join.yaml b/sbroad-core/tests/artifactory/ir/operator/join.yaml
index b1ac3d0077..a5eec7cf42 100644
--- a/sbroad-core/tests/artifactory/ir/operator/join.yaml
+++ b/sbroad-core/tests/artifactory/ir/operator/join.yaml
@@ -171,3 +171,4 @@ relations:
 slices: ~
 top: 28
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/operator/output_aliases.yaml b/sbroad-core/tests/artifactory/ir/operator/output_aliases.yaml
index 0e2235de84..fd3fa6fe03 100644
--- a/sbroad-core/tests/artifactory/ir/operator/output_aliases.yaml
+++ b/sbroad-core/tests/artifactory/ir/operator/output_aliases.yaml
@@ -44,3 +44,4 @@ relations:
     name: t
 slices: ~
 top: 5
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/operator/output_aliases_duplicates.yaml b/sbroad-core/tests/artifactory/ir/operator/output_aliases_duplicates.yaml
index febed528f0..1bbafd3ef9 100644
--- a/sbroad-core/tests/artifactory/ir/operator/output_aliases_duplicates.yaml
+++ b/sbroad-core/tests/artifactory/ir/operator/output_aliases_duplicates.yaml
@@ -44,3 +44,4 @@ relations:
     name: t
 slices: ~
 top: 5
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/operator/output_aliases_oor.yaml b/sbroad-core/tests/artifactory/ir/operator/output_aliases_oor.yaml
index 33d04e1e73..159ff0c773 100644
--- a/sbroad-core/tests/artifactory/ir/operator/output_aliases_oor.yaml
+++ b/sbroad-core/tests/artifactory/ir/operator/output_aliases_oor.yaml
@@ -35,3 +35,4 @@ relations:
     name: t
 slices: ~
 top: 3
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/operator/output_aliases_unsupported_type.yaml b/sbroad-core/tests/artifactory/ir/operator/output_aliases_unsupported_type.yaml
index a39463aae4..30cc8279ce 100644
--- a/sbroad-core/tests/artifactory/ir/operator/output_aliases_unsupported_type.yaml
+++ b/sbroad-core/tests/artifactory/ir/operator/output_aliases_unsupported_type.yaml
@@ -40,3 +40,4 @@ relations:
     name: t
 slices: ~
 top: 4
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/operator/projection.yaml b/sbroad-core/tests/artifactory/ir/operator/projection.yaml
index 965a3d0c2a..49e42253cf 100644
--- a/sbroad-core/tests/artifactory/ir/operator/projection.yaml
+++ b/sbroad-core/tests/artifactory/ir/operator/projection.yaml
@@ -74,3 +74,4 @@ relations:
 slices: ~
 top: 9
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/operator/scan_rel.yaml b/sbroad-core/tests/artifactory/ir/operator/scan_rel.yaml
index 314dc8b09f..a46ea0c1f9 100644
--- a/sbroad-core/tests/artifactory/ir/operator/scan_rel.yaml
+++ b/sbroad-core/tests/artifactory/ir/operator/scan_rel.yaml
@@ -73,3 +73,4 @@ relations:
 slices: ~
 top: 9
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/operator/selection.yaml b/sbroad-core/tests/artifactory/ir/operator/selection.yaml
index dafbec9d8d..7509099734 100644
--- a/sbroad-core/tests/artifactory/ir/operator/selection.yaml
+++ b/sbroad-core/tests/artifactory/ir/operator/selection.yaml
@@ -149,3 +149,4 @@ relations:
 slices: ~
 top: 23
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/operator/selection_with_sub_query.yaml b/sbroad-core/tests/artifactory/ir/operator/selection_with_sub_query.yaml
index 323c7fce30..5705e4195f 100644
--- a/sbroad-core/tests/artifactory/ir/operator/selection_with_sub_query.yaml
+++ b/sbroad-core/tests/artifactory/ir/operator/selection_with_sub_query.yaml
@@ -150,3 +150,4 @@ relations:
 slices: ~
 top: 24
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/operator/sub_query.yaml b/sbroad-core/tests/artifactory/ir/operator/sub_query.yaml
index 60b9c05883..a01aaf0566 100644
--- a/sbroad-core/tests/artifactory/ir/operator/sub_query.yaml
+++ b/sbroad-core/tests/artifactory/ir/operator/sub_query.yaml
@@ -82,3 +82,4 @@ relations:
 slices: ~
 top: 11
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/plan_no_top.yaml b/sbroad-core/tests/artifactory/ir/plan_no_top.yaml
index bb091a3b4f..d35a5a3d54 100644
--- a/sbroad-core/tests/artifactory/ir/plan_no_top.yaml
+++ b/sbroad-core/tests/artifactory/ir/plan_no_top.yaml
@@ -35,3 +35,4 @@ relations:
 slices: ~
 top: ~
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/plan_oor_top.yaml b/sbroad-core/tests/artifactory/ir/plan_oor_top.yaml
index 652b2be063..c4bb1f225c 100644
--- a/sbroad-core/tests/artifactory/ir/plan_oor_top.yaml
+++ b/sbroad-core/tests/artifactory/ir/plan_oor_top.yaml
@@ -35,3 +35,4 @@ relations:
 slices: ~
 top: 42
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_less_for_sub_query.yaml b/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_less_for_sub_query.yaml
index 7e7ab85177..a24ad86786 100644
--- a/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_less_for_sub_query.yaml
+++ b/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_less_for_sub_query.yaml
@@ -199,3 +199,4 @@ slices:
      - 30
 top: 26
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_non_segment_outer_for_sub_query.yaml b/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_non_segment_outer_for_sub_query.yaml
index ddac69bf95..a0b1102c93 100644
--- a/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_non_segment_outer_for_sub_query.yaml
+++ b/sbroad-core/tests/artifactory/ir/transformation/redistribution/full_motion_non_segment_outer_for_sub_query.yaml
@@ -218,3 +218,4 @@ slices:
     - 32
 top: 28
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/transformation/redistribution/local_sub_query.yaml b/sbroad-core/tests/artifactory/ir/transformation/redistribution/local_sub_query.yaml
index c7fda607c3..19c59a6245 100644
--- a/sbroad-core/tests/artifactory/ir/transformation/redistribution/local_sub_query.yaml
+++ b/sbroad-core/tests/artifactory/ir/transformation/redistribution/local_sub_query.yaml
@@ -175,3 +175,4 @@ relations:
 slices: ~
 top: 24
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/transformation/redistribution/multiple_sub_queries.yaml b/sbroad-core/tests/artifactory/ir/transformation/redistribution/multiple_sub_queries.yaml
index 138593e3ab..6f2aa7c28e 100644
--- a/sbroad-core/tests/artifactory/ir/transformation/redistribution/multiple_sub_queries.yaml
+++ b/sbroad-core/tests/artifactory/ir/transformation/redistribution/multiple_sub_queries.yaml
@@ -347,3 +347,4 @@ slices:
     - 54
 top: 46
 is_explain: false
+undo: {}
diff --git a/sbroad-core/tests/artifactory/ir/transformation/redistribution/segment_motion_for_sub_query.yaml b/sbroad-core/tests/artifactory/ir/transformation/redistribution/segment_motion_for_sub_query.yaml
index bd84709310..52c411d236 100644
--- a/sbroad-core/tests/artifactory/ir/transformation/redistribution/segment_motion_for_sub_query.yaml
+++ b/sbroad-core/tests/artifactory/ir/transformation/redistribution/segment_motion_for_sub_query.yaml
@@ -206,3 +206,4 @@ slices:
     - 30
 top: 26
 is_explain: false
+undo: {}
-- 
GitLab