From ceb73b0839bbbdb0ea36b3c2cc0b857abcbddf14 Mon Sep 17 00:00:00 2001
From: Emir Vildanov <e.vildanov@picodata.io>
Date: Fri, 13 Oct 2023 09:53:11 +0000
Subject: [PATCH] feat: add checks on table columns creation and insertion, add
 check on parameters number, add support of is_nullable metadata

---
 sbroad-cartridge/src/cartridge/config.rs      |  13 +-
 .../src/cartridge/config/tests.rs             |  19 +-
 .../test_app/test/integration/ddl_test.lua    |   4 +-
 sbroad-core/src/backend/sql/tree/tests.rs     |  44 +-
 sbroad-core/src/core-router.lua               |  12 +-
 sbroad-core/src/executor/engine/helpers.rs    |  53 +-
 sbroad-core/src/executor/engine/mock.rs       | 496 ++++++++++++++----
 sbroad-core/src/executor/result.rs            |  60 ++-
 sbroad-core/src/executor/result/tests.rs      |   6 +-
 sbroad-core/src/executor/tests.rs             |  70 +--
 sbroad-core/src/executor/tests/between.rs     |  14 +-
 .../src/executor/tests/empty_motion.rs        |  14 +-
 sbroad-core/src/executor/tests/exec_plan.rs   | 155 ++----
 sbroad-core/src/executor/tests/frontend.rs    |   4 +-
 sbroad-core/src/executor/tests/not_eq.rs      |   8 +-
 sbroad-core/src/executor/tests/not_in.rs      |   8 +-
 sbroad-core/src/executor/vtable/tests.rs      |  86 +--
 sbroad-core/src/frontend/sql.rs               |  62 ++-
 sbroad-core/src/frontend/sql/ir/tests.rs      |  33 +-
 sbroad-core/src/ir.rs                         |   2 +-
 sbroad-core/src/ir/api/parameter.rs           |  23 +-
 sbroad-core/src/ir/ddl.rs                     |  12 +-
 sbroad-core/src/ir/distribution/tests.rs      |  11 +-
 sbroad-core/src/ir/expression/tests.rs        |   7 +-
 sbroad-core/src/ir/operator/tests.rs          |  92 ++--
 sbroad-core/src/ir/relation.rs                |  43 +-
 sbroad-core/src/ir/relation/tests.rs          | 115 ++--
 sbroad-core/src/ir/tests.rs                   |  50 +-
 .../ir/transformation/redistribution/tests.rs |  25 +-
 .../redistribution/tests/segment.rs           |  20 +-
 sbroad-core/src/ir/tree/tests.rs              |  17 +-
 .../sql/tree/arbitrary_projection_plan.yaml   |   5 +
 .../sql/tree/arithmetic_projection_plan.yaml  |   7 +
 .../sql/tree/arithmetic_selection_plan.yaml   |   7 +
 34 files changed, 971 insertions(+), 626 deletions(-)

diff --git a/sbroad-cartridge/src/cartridge/config.rs b/sbroad-cartridge/src/cartridge/config.rs
index 843f941f8a..dacc434e04 100644
--- a/sbroad-cartridge/src/cartridge/config.rs
+++ b/sbroad-cartridge/src/cartridge/config.rs
@@ -121,6 +121,17 @@ impl RouterConfiguration {
                                 ))
                             }
                         };
+                        let is_nullable: bool = match val["is_nullable"].as_bool() {
+                            Some(b) => b,
+                            None => {
+                                return Err(SbroadError::Invalid(
+                                    Entity::ClusterSchema,
+                                    Some(format!(
+                                    "column is_nullable of table {current_space_name} is invalid"
+                                )),
+                                ))
+                            }
+                        };
                         let qualified_name = normalize_name_from_schema(name);
                         debug!(
                             Option::from("configuration parsing"),
@@ -133,7 +144,7 @@ impl RouterConfiguration {
                         } else {
                             ColumnRole::User
                         };
-                        let col = Column::new(&qualified_name, t, role);
+                        let col = Column::new(&qualified_name, t, role, is_nullable);
                         result.push(col);
                     }
                     result
diff --git a/sbroad-cartridge/src/cartridge/config/tests.rs b/sbroad-cartridge/src/cartridge/config/tests.rs
index ee32ffced4..2bd4134ed9 100644
--- a/sbroad-cartridge/src/cartridge/config/tests.rs
+++ b/sbroad-cartridge/src/cartridge/config/tests.rs
@@ -143,12 +143,17 @@ fn test_getting_table_segment() {
     let expected = Table::new_seg(
         "\"hash_testing\"",
         vec![
-            Column::new("\"identification_number\"", Type::Integer, ColumnRole::User),
-            Column::new("\"product_code\"", Type::String, ColumnRole::User),
-            Column::new("\"product_units\"", Type::Boolean, ColumnRole::User),
-            Column::new("\"sys_op\"", Type::Number, ColumnRole::User),
-            Column::new("\"detail\"", Type::Array, ColumnRole::User),
-            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding),
+            Column::new(
+                "\"identification_number\"",
+                Type::Integer,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new("\"product_code\"", Type::String, ColumnRole::User, false),
+            Column::new("\"product_units\"", Type::Boolean, ColumnRole::User, false),
+            Column::new("\"sys_op\"", Type::Number, ColumnRole::User, false),
+            Column::new("\"detail\"", Type::Array, ColumnRole::User, false),
+            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding, true),
         ],
         &["\"identification_number\"", "\"product_code\""],
         &["\"identification_number\""],
@@ -231,7 +236,7 @@ fn test_invalid_schema() {
             parts:
               - path: bucket_id
                 type: unsigned
-                is_nullable: false
+                is_nullable: true
         sharding_key:
           - FID
           - COMMON_ID
diff --git a/sbroad-cartridge/test_app/test/integration/ddl_test.lua b/sbroad-cartridge/test_app/test/integration/ddl_test.lua
index d7033291c7..85d04ab4d1 100644
--- a/sbroad-cartridge/test_app/test/integration/ddl_test.lua
+++ b/sbroad-cartridge/test_app/test/integration/ddl_test.lua
@@ -219,8 +219,8 @@ g.test_create_table = function()
         "sbroad.execute",
         { [[
             CREATE TABLE t (
-                a INT,
-                b TEXT,
+                a INT NOT NULL,
+                b TEXT NOT NULL,
                 PRIMARY KEY (a, b)
             )
             USING memtx
diff --git a/sbroad-core/src/backend/sql/tree/tests.rs b/sbroad-core/src/backend/sql/tree/tests.rs
index 1fb8d336b8..09b1574f66 100644
--- a/sbroad-core/src/backend/sql/tree/tests.rs
+++ b/sbroad-core/src/backend/sql/tree/tests.rs
@@ -5,12 +5,14 @@ use pretty_assertions::assert_eq;
 
 use crate::backend::sql::tree::{OrderedSyntaxNodes, SyntaxPlan};
 use crate::ir::operator::{Arithmetic, Bool, Unary};
-use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type};
+use crate::ir::relation::{SpaceEngine, Table, Type};
+use crate::ir::tests::sharding_column;
 use crate::ir::tree::Snapshot;
 use crate::ir::value::Value;
 use crate::ir::Plan;
 
 use super::*;
+use crate::ir::tests::{column_integer_user_non_null, column_user_non_null};
 
 #[test]
 fn sql_order_selection() {
@@ -19,7 +21,7 @@ fn sql_order_selection() {
     let mut plan = Plan::default();
     let t = Table::new_seg(
         "t",
-        vec![Column::new("a", Type::Boolean, ColumnRole::User)],
+        vec![column_user_non_null(String::from("a"), Type::Boolean)],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -99,13 +101,13 @@ fn sql_arithmetic_selection_plan() {
     let t = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Integer, ColumnRole::User),
-            Column::new("b", Type::Integer, ColumnRole::User),
-            Column::new("c", Type::Integer, ColumnRole::User),
-            Column::new("d", Type::Integer, ColumnRole::User),
-            Column::new("e", Type::Integer, ColumnRole::User),
-            Column::new("f", Type::Integer, ColumnRole::User),
-            Column::new("bucket_id", Type::Unsigned, ColumnRole::Sharding),
+            column_integer_user_non_null(String::from("a")),
+            column_integer_user_non_null(String::from("b")),
+            column_integer_user_non_null(String::from("c")),
+            column_integer_user_non_null(String::from("d")),
+            column_integer_user_non_null(String::from("e")),
+            column_integer_user_non_null(String::from("f")),
+            sharding_column(),
         ],
         &["a"],
         &["a"],
@@ -296,13 +298,13 @@ fn sql_arithmetic_projection_plan() {
     let t = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Integer, ColumnRole::User),
-            Column::new("b", Type::Integer, ColumnRole::User),
-            Column::new("c", Type::Integer, ColumnRole::User),
-            Column::new("d", Type::Integer, ColumnRole::User),
-            Column::new("e", Type::Integer, ColumnRole::User),
-            Column::new("f", Type::Integer, ColumnRole::User),
-            Column::new("bucket_id", Type::Unsigned, ColumnRole::Sharding),
+            column_integer_user_non_null(String::from("a")),
+            column_integer_user_non_null(String::from("b")),
+            column_integer_user_non_null(String::from("c")),
+            column_integer_user_non_null(String::from("d")),
+            column_integer_user_non_null(String::from("e")),
+            column_integer_user_non_null(String::from("f")),
+            sharding_column(),
         ],
         &["a"],
         &["a"],
@@ -470,11 +472,11 @@ fn sql_arbitrary_projection_plan() {
     let t = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Integer, ColumnRole::User),
-            Column::new("b", Type::Integer, ColumnRole::User),
-            Column::new("c", Type::Integer, ColumnRole::User),
-            Column::new("d", Type::Integer, ColumnRole::User),
-            Column::new("bucket_id", Type::Unsigned, ColumnRole::Sharding),
+            column_integer_user_non_null(String::from("a")),
+            column_integer_user_non_null(String::from("b")),
+            column_integer_user_non_null(String::from("c")),
+            column_integer_user_non_null(String::from("d")),
+            sharding_column(),
         ],
         &["a"],
         &["a"],
diff --git a/sbroad-core/src/core-router.lua b/sbroad-core/src/core-router.lua
index 4af155919d..ad9aea936f 100644
--- a/sbroad-core/src/core-router.lua
+++ b/sbroad-core/src/core-router.lua
@@ -197,11 +197,15 @@ end
 _G.group_buckets_by_replicasets = function(buckets)
     local map = {}
     for _, bucket_id in pairs(buckets) do
-        local rs = vshard.router.route(bucket_id).uuid
-        if map[rs] then
-            table.insert(map[rs], bucket_id)
+        local rs, err = vshard.router.route(bucket_id)
+        if err ~= nil then
+            return nil, err
+        end
+        local uuid = rs.uuid
+        if map[uuid] then
+            table.insert(map[uuid], bucket_id)
         else
-            map[rs] = {bucket_id}
+            map[uuid] = {bucket_id}
         end
     end
 
diff --git a/sbroad-core/src/executor/engine/helpers.rs b/sbroad-core/src/executor/engine/helpers.rs
index d1056c3bff..70e4862bdc 100644
--- a/sbroad-core/src/executor/engine/helpers.rs
+++ b/sbroad-core/src/executor/engine/helpers.rs
@@ -1,5 +1,6 @@
 use ahash::AHashMap;
 
+use itertools::enumerate;
 use std::{
     any::Any,
     cmp::Ordering,
@@ -628,9 +629,9 @@ pub fn dispatch(
                 for (motion_id, vtable) in vtables.map() {
                     if !vtable.get_bucket_index().is_empty() {
                         return Err(SbroadError::Invalid(
-                                Entity::Motion,
-                                Some(format!("motion ({motion_id}) in subtree with distribution Single, but policy is not Full!"))
-                            ));
+                            Entity::Motion,
+                            Some(format!("motion ({motion_id}) in subtree with distribution Single, but policy is not Full!")),
+                        ));
                     }
                 }
             }
@@ -650,6 +651,7 @@ pub fn dispatch(
     }
 }
 
+#[allow(clippy::too_many_lines)]
 pub(crate) fn materialize_values(
     plan: &mut ExecutionPlan,
     motion_node_id: usize,
@@ -678,14 +680,36 @@ pub(crate) fn materialize_values(
     let child_node_ref = plan.get_mut_ir_plan().get_mut_node(child_id)?;
     let child_node = std::mem::replace(child_node_ref, Node::Parameter);
     if let Node::Relational(Relational::Values {
-        children, output, ..
+        ref children,
+        output,
+        ..
     }) = child_node
     {
         // Build a new virtual table (check that all the rows are made of constants only).
         let mut vtable = VirtualTable::new();
         vtable.get_mut_tuples().reserve(children.len());
+
+        let columns_len = if let Some(first_row_id) = children.first() {
+            let row_node = plan.get_ir_plan().get_relation_node(*first_row_id)?;
+            let Relational::ValuesRow { data, .. } = row_node else {
+                return Err(SbroadError::Invalid(
+                    Entity::Node,
+                    Some(format!("Expected ValuesRow, got {row_node:?}")),
+                ));
+            };
+            plan.get_ir_plan()
+                .get_expression_node(*data)?
+                .get_row_list()?
+                .len()
+        } else {
+            return Err(SbroadError::Invalid(
+                Entity::Node,
+                Some(format!("Values node {child_node:?} must contain children")),
+            ));
+        };
+        let mut nullable_column_indices = HashSet::with_capacity(columns_len);
         for row_id in children {
-            let row_node = plan.get_ir_plan().get_relation_node(row_id)?;
+            let row_node = plan.get_ir_plan().get_relation_node(*row_id)?;
             if let Relational::ValuesRow { data, children, .. } = row_node {
                 // Check that there are no subqueries in the values node.
                 // (If any we'll need to materialize them first with dispatch
@@ -719,6 +743,9 @@ pub(crate) fn materialize_values(
                     let column_node_ref = plan.get_mut_ir_plan().get_mut_node(column_id)?;
                     let column_node = std::mem::replace(column_node_ref, Node::Parameter);
                     if let Node::Expression(Expression::Constant { value, .. }) = column_node {
+                        if let Value::Null = value {
+                            nullable_column_indices.insert(idx);
+                        }
                         row.push(value);
                     } else {
                         return Err(SbroadError::Invalid(
@@ -746,13 +773,15 @@ pub(crate) fn materialize_values(
             .get_row_list()?;
         let columns = vtable.get_mut_columns();
         columns.reserve(output_cols.len());
-        for column_id in output_cols {
+        for (idx, column_id) in enumerate(output_cols) {
+            let is_nullable = nullable_column_indices.contains(&idx);
             let alias = plan.get_ir_plan().get_expression_node(*column_id)?;
             if let Expression::Alias { name, .. } = alias {
                 let column = Column {
                     name: name.clone(),
                     r#type: Type::Scalar,
                     role: ColumnRole::User,
+                    is_nullable,
                 };
                 columns.push(column);
             } else {
@@ -879,7 +908,7 @@ pub fn sharding_key_from_tuple<'tuple>(
                         Some(format!(
                             r#"the tuple {tuple:?} contains a "bucket_id" position {position} in a sharding key {sharding_positions:?}"#
                         )),
-                    ))
+                    ));
                 }
                 Ordering::Greater => *position - 1,
             };
@@ -1291,7 +1320,7 @@ fn execute_sharded_update(
                             return Err(SbroadError::Invalid(
                                 Entity::TupleBuilderCommand,
                                 Some(format!("got command {command:?} for update insert")),
-                            ))
+                            ));
                         }
                     }
                 }
@@ -1384,7 +1413,7 @@ fn execute_local_update(
                     return Err(SbroadError::Invalid(
                         Entity::TupleBuilderCommand,
                         Some(format!("got command {command:?} for update")),
-                    ))
+                    ));
                 }
             }
         }
@@ -1601,7 +1630,7 @@ where
                                     Action::Insert,
                                     Some(Entity::Space),
                                     format!("{tnt_err}"),
-                                ))
+                                ));
                             }
                         }
                         // if either DoReplace or DoNothing was done,
@@ -1758,8 +1787,8 @@ pub fn sharding_key_from_map<'rec, S: ::std::hash::BuildHasher>(
             return Err(SbroadError::NotFound(
                 Entity::ShardingKey,
                 format!(
-                "(quoted) column {quoted_column:?} in the quoted map {quoted_map:?} (original map: {map:?})"
-            )));
+                    "(quoted) column {quoted_column:?} in the quoted map {quoted_map:?} (original map: {map:?})"
+                )));
         }
     }
     Ok(tuple)
diff --git a/sbroad-core/src/executor/engine/mock.rs b/sbroad-core/src/executor/engine/mock.rs
index d130744624..9c7ad9958a 100644
--- a/sbroad-core/src/executor/engine/mock.rs
+++ b/sbroad-core/src/executor/engine/mock.rs
@@ -103,11 +103,16 @@ impl RouterConfigurationMock {
         let mut tables = HashMap::new();
 
         let columns = vec![
-            Column::new("\"identification_number\"", Type::Integer, ColumnRole::User),
-            Column::new("\"product_code\"", Type::String, ColumnRole::User),
-            Column::new("\"product_units\"", Type::Boolean, ColumnRole::User),
-            Column::new("\"sys_op\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding),
+            Column::new(
+                "\"identification_number\"",
+                Type::Integer,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new("\"product_code\"", Type::String, ColumnRole::User, false),
+            Column::new("\"product_units\"", Type::Boolean, ColumnRole::User, true),
+            Column::new("\"sys_op\"", Type::Unsigned, ColumnRole::User, true),
+            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding, true),
         ];
         let sharding_key = &["\"identification_number\"", "\"product_code\""];
         let primary_key = &["\"product_code\"", "\"identification_number\""];
@@ -161,11 +166,11 @@ impl RouterConfigurationMock {
         );
 
         let columns = vec![
-            Column::new("\"id\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"sysFrom\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"FIRST_NAME\"", Type::String, ColumnRole::User),
-            Column::new("\"sys_op\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding),
+            Column::new("\"id\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"sysFrom\"", Type::Unsigned, ColumnRole::User, true),
+            Column::new("\"FIRST_NAME\"", Type::String, ColumnRole::User, true),
+            Column::new("\"sys_op\"", Type::Unsigned, ColumnRole::User, true),
+            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding, true),
         ];
         let sharding_key = &["\"id\""];
         let primary_key = &["\"id\""];
@@ -195,8 +200,8 @@ impl RouterConfigurationMock {
         );
 
         let columns = vec![
-            Column::new("\"id\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding),
+            Column::new("\"id\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding, true),
         ];
         let sharding_key: &[&str] = &["\"id\""];
         let primary_key: &[&str] = &["\"id\""];
@@ -213,11 +218,11 @@ impl RouterConfigurationMock {
         );
 
         let columns = vec![
-            Column::new("\"a\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"b\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"c\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"d\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding),
+            Column::new("\"a\"", Type::Unsigned, ColumnRole::User, true),
+            Column::new("\"b\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"c\"", Type::Unsigned, ColumnRole::User, true),
+            Column::new("\"d\"", Type::Unsigned, ColumnRole::User, true),
+            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding, true),
         ];
         let sharding_key: &[&str] = &["\"a\"", "\"b\""];
         let primary_key: &[&str] = &["\"b\""];
@@ -234,9 +239,9 @@ impl RouterConfigurationMock {
         );
 
         let columns = vec![
-            Column::new("\"a\"", Type::String, ColumnRole::User),
-            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding),
-            Column::new("\"b\"", Type::Integer, ColumnRole::User),
+            Column::new("\"a\"", Type::String, ColumnRole::User, false),
+            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding, true),
+            Column::new("\"b\"", Type::Integer, ColumnRole::User, false),
         ];
         let sharding_key: &[&str] = &["\"a\"", "\"b\""];
         let primary_key: &[&str] = &["\"a\"", "\"b\""];
@@ -253,11 +258,11 @@ impl RouterConfigurationMock {
         );
 
         let columns = vec![
-            Column::new("\"e\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"f\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"g\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"h\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding),
+            Column::new("\"e\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"f\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"g\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"h\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding, true),
         ];
         let sharding_key: &[&str] = &["\"e\"", "\"f\""];
         let primary_key: &[&str] = &["\"g\"", "\"h\""];
@@ -274,9 +279,9 @@ impl RouterConfigurationMock {
         );
 
         let columns = vec![
-            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding),
-            Column::new("\"a\"", Type::String, ColumnRole::User),
-            Column::new("\"b\"", Type::Integer, ColumnRole::User),
+            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding, true),
+            Column::new("\"a\"", Type::String, ColumnRole::User, false),
+            Column::new("\"b\"", Type::Integer, ColumnRole::User, false),
         ];
         let sharding_key: &[&str] = &["\"a\""];
         let primary_key: &[&str] = &["\"a\""];
@@ -294,222 +299,505 @@ impl RouterConfigurationMock {
 
         // Table for sbroad-benches
         let columns = vec![
-            Column::new("\"vehicleguid\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"reestrid\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"reestrstatus\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehicleregno\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclevin\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclevin2\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclechassisnum\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclereleaseyear\"", Type::Unsigned, ColumnRole::User),
+            Column::new("\"vehicleguid\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"reestrid\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"reestrstatus\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"vehicleregno\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"vehiclevin\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"vehiclevin2\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new(
+                "\"vehiclechassisnum\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehiclereleaseyear\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
             Column::new(
                 "\"operationregdoctypename\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"operationregdoc\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"operationregdoc\"", Type::Unsigned, ColumnRole::User),
             Column::new(
                 "\"operationregdocissuedate\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"operationregdoccomments\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehicleptstypename\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new("\"vehicleptsnum\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new(
+                "\"vehicleptsissuedate\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehicleptsissuer\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehicleptscomments\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehiclebodycolor\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new("\"vehiclebrand\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"vehiclemodel\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new(
+                "\"vehiclebrandmodel\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehiclebodynum\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new("\"vehiclecost\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new(
+                "\"vehiclegasequip\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehicleproducername\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehiclegrossmass\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"vehicleptstypename\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehicleptsnum\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehicleptsissuedate\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehicleptsissuer\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehicleptscomments\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclebodycolor\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclebrand\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclemodel\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclebrandmodel\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclebodynum\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclecost\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclegasequip\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehicleproducername\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclegrossmass\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclemass\"", Type::Unsigned, ColumnRole::User),
+            Column::new("\"vehiclemass\"", Type::Unsigned, ColumnRole::User, false),
             Column::new(
                 "\"vehiclesteeringwheeltypeid\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehiclekpptype\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"vehiclekpptype\"", Type::Unsigned, ColumnRole::User),
             Column::new(
                 "\"vehicletransmissiontype\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehicletypename\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehiclecategory\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehicletypeunit\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehicleecoclass\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehiclespecfuncname\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"vehicletypename\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclecategory\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehicletypeunit\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehicleecoclass\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehiclespecfuncname\"", Type::Unsigned, ColumnRole::User),
             Column::new(
                 "\"vehicleenclosedvolume\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehicleenginemodel\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehicleenginenum\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehicleenginepower\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehicleenginepowerkw\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"vehicleenginetype\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"holdrestrictiondate\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new("\"approvalnum\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"approvaldate\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"approvaltype\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new(
+                "\"utilizationfeename\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new("\"customsdoc\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new(
+                "\"customsdocdate\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"customsdocissue\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"vehicleenginemodel\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehicleenginenum\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehicleenginepower\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehicleenginepowerkw\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"vehicleenginetype\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"holdrestrictiondate\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"approvalnum\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"approvaldate\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"approvaltype\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"utilizationfeename\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"customsdoc\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"customsdocdate\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"customsdocissue\"", Type::Unsigned, ColumnRole::User),
             Column::new(
                 "\"customsdocrestriction\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"customscountryremovalid\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"customscountryremovalname\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new("\"ownerorgname\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"ownerinn\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"ownerogrn\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"ownerkpp\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new(
+                "\"ownerpersonlastname\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"ownerpersonfirstname\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"ownerorgname\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"ownerinn\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"ownerogrn\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"ownerkpp\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"ownerpersonlastname\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"ownerpersonfirstname\"", Type::Unsigned, ColumnRole::User),
             Column::new(
                 "\"ownerpersonmiddlename\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"ownerpersonbirthdate\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"ownerbirthplace\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"ownerpersonogrnip\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"owneraddressindex\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"ownerpersonbirthdate\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"ownerbirthplace\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"ownerpersonogrnip\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"owneraddressindex\"", Type::Unsigned, ColumnRole::User),
             Column::new(
                 "\"owneraddressmundistrict\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"owneraddresssettlement\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"owneraddressstreet\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"owneraddressstreet\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"ownerpersoninn\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"ownerpersondoccode\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"ownerpersondocnum\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"ownerpersondocdate\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"operationname\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"operationdate\"", Type::Unsigned, ColumnRole::User),
+            Column::new(
+                "\"ownerpersoninn\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"ownerpersondoccode\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"ownerpersondocnum\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"ownerpersondocdate\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new("\"operationname\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"operationdate\"", Type::Unsigned, ColumnRole::User, false),
             Column::new(
                 "\"operationdepartmentname\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"operationattorney\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"operationlising\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new("\"holdertypeid\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new(
+                "\"holderpersondoccode\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"holderpersondocnum\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"holderpersondocdate\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"operationattorney\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"operationlising\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"holdertypeid\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"holderpersondoccode\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"holderpersondocnum\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"holderpersondocdate\"", Type::Unsigned, ColumnRole::User),
             Column::new(
                 "\"holderpersondocissuer\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"holderpersonlastname\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"holderpersonlastname\"", Type::Unsigned, ColumnRole::User),
             Column::new(
                 "\"holderpersonfirstname\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"holderpersonmiddlename\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"holderpersonbirthdate\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"holderpersonbirthregionid\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"holderpersonsex\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"holderpersonsex\"", Type::Unsigned, ColumnRole::User),
             Column::new(
                 "\"holderpersonbirthplace\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"holderpersoninn\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"holderpersonsnils\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"holderpersonogrnip\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"holderaddressguid\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"holderpersoninn\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"holderpersonsnils\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"holderpersonogrnip\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"holderaddressguid\"", Type::Unsigned, ColumnRole::User),
             Column::new(
                 "\"holderaddressregionid\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"holderaddressregionname\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"holderaddressdistrict\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"holderaddressmundistrict\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"holderaddresssettlement\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
+            ),
+            Column::new(
+                "\"holderaddressstreet\"",
+                Type::Unsigned,
+                ColumnRole::User,
+                false,
             ),
-            Column::new("\"holderaddressstreet\"", Type::Unsigned, ColumnRole::User),
             Column::new(
                 "\"holderaddressbuilding\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"holderaddressstructureid\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"holderaddressstructurename\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
             Column::new(
                 "\"holderaddressstructure\"",
                 Type::Unsigned,
                 ColumnRole::User,
+                false,
             ),
-            Column::new("\"sys_from\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"sys_to\"", Type::Unsigned, ColumnRole::User),
-            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding),
+            Column::new("\"sys_from\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"sys_to\"", Type::Unsigned, ColumnRole::User, false),
+            Column::new("\"bucket_id\"", Type::Unsigned, ColumnRole::Sharding, true),
         ];
         let sharding_key: &[&str] = &["\"reestrid\""];
         let primary_key: &[&str] = &["\"reestrid\""];
diff --git a/sbroad-core/src/executor/result.rs b/sbroad-core/src/executor/result.rs
index bd306eec05..b78a2d7870 100644
--- a/sbroad-core/src/executor/result.rs
+++ b/sbroad-core/src/executor/result.rs
@@ -56,16 +56,54 @@ impl TryInto<Column> for &MetadataColumn {
 
     fn try_into(self) -> Result<Column, Self::Error> {
         match self.r#type.as_str() {
-            "boolean" => Ok(Column::new(&self.name, Type::Boolean, ColumnRole::User)),
-            "decimal" => Ok(Column::new(&self.name, Type::Decimal, ColumnRole::User)),
-            "double" => Ok(Column::new(&self.name, Type::Double, ColumnRole::User)),
-            "integer" => Ok(Column::new(&self.name, Type::Integer, ColumnRole::User)),
-            "number" | "numeric" => Ok(Column::new(&self.name, Type::Number, ColumnRole::User)),
-            "scalar" => Ok(Column::new(&self.name, Type::Scalar, ColumnRole::User)),
-            "string" | "text" | "varchar" => {
-                Ok(Column::new(&self.name, Type::String, ColumnRole::User))
-            }
-            "unsigned" => Ok(Column::new(&self.name, Type::Unsigned, ColumnRole::User)),
+            "boolean" => Ok(Column::new(
+                &self.name,
+                Type::Boolean,
+                ColumnRole::User,
+                true,
+            )),
+            "decimal" => Ok(Column::new(
+                &self.name,
+                Type::Decimal,
+                ColumnRole::User,
+                true,
+            )),
+            "double" => Ok(Column::new(
+                &self.name,
+                Type::Double,
+                ColumnRole::User,
+                true,
+            )),
+            "integer" => Ok(Column::new(
+                &self.name,
+                Type::Integer,
+                ColumnRole::User,
+                true,
+            )),
+            "number" | "numeric" => Ok(Column::new(
+                &self.name,
+                Type::Number,
+                ColumnRole::User,
+                true,
+            )),
+            "scalar" => Ok(Column::new(
+                &self.name,
+                Type::Scalar,
+                ColumnRole::User,
+                true,
+            )),
+            "string" | "text" | "varchar" => Ok(Column::new(
+                &self.name,
+                Type::String,
+                ColumnRole::User,
+                true,
+            )),
+            "unsigned" => Ok(Column::new(
+                &self.name,
+                Type::Unsigned,
+                ColumnRole::User,
+                true,
+            )),
             _ => Err(SbroadError::Unsupported(
                 Entity::Type,
                 Some(format!("column type {}", self.r#type)),
@@ -118,7 +156,7 @@ impl ProducerResult {
         for col in &self.metadata {
             let column: Column = if possibly_incorrect_types {
                 let column_type = Type::new_from_possibly_incorrect(&col.r#type)?;
-                Column::new(&col.name, column_type, ColumnRole::User)
+                Column::new(&col.name, column_type, ColumnRole::User, true)
             } else {
                 col.try_into()?
             };
diff --git a/sbroad-core/src/executor/result/tests.rs b/sbroad-core/src/executor/result/tests.rs
index 326aaa6a84..aa45cbe24d 100644
--- a/sbroad-core/src/executor/result/tests.rs
+++ b/sbroad-core/src/executor/result/tests.rs
@@ -2,7 +2,7 @@ use pretty_assertions::{assert_eq, assert_ne};
 use tarantool::decimal;
 
 use super::*;
-use crate::ir::relation::{ColumnRole, Type};
+use crate::ir::relation::Type;
 
 #[test]
 fn box_execute_result_serialize() {
@@ -78,22 +78,26 @@ fn convert_to_vtable() {
         name: col_names[0].into(),
         r#type: Type::Integer,
         role: ColumnRole::User,
+        is_nullable: true,
     });
     excepted.add_column(Column {
         name: col_names[1].into(),
         r#type: Type::String,
         role: ColumnRole::User,
+        is_nullable: true,
     });
     excepted.add_column(Column {
         name: col_names[2].into(),
         r#type: Type::Unsigned,
         role: ColumnRole::User,
+        is_nullable: true,
     });
 
     excepted.add_column(Column {
         name: col_names[3].into(),
         r#type: Type::Decimal,
         role: ColumnRole::User,
+        is_nullable: true,
     });
 
     excepted.add_tuple(vec![
diff --git a/sbroad-core/src/executor/tests.rs b/sbroad-core/src/executor/tests.rs
index a563d3153c..43c351453c 100644
--- a/sbroad-core/src/executor/tests.rs
+++ b/sbroad-core/src/executor/tests.rs
@@ -6,7 +6,7 @@ use crate::executor::engine::mock::RouterRuntimeMock;
 use crate::executor::result::ProducerResult;
 use crate::executor::vtable::VirtualTable;
 use crate::ir::operator::Relational;
-use crate::ir::relation::{Column, ColumnRole, Type};
+use crate::ir::tests::column_integer_user_non_null;
 use crate::ir::transformation::redistribution::MotionPolicy;
 
 use crate::ir::value::{LuaValue, Value};
@@ -406,16 +406,8 @@ fn join_linker2_test() {
         .unwrap();
 
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "id1".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "id2".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("id1")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("id2")));
     virtual_table.add_tuple(vec![Value::from(1_u64), Value::from(1_u64)]);
     virtual_table.add_tuple(vec![Value::from(2_u64), Value::from(2_u64)]);
     virtual_table.set_alias("\"t2\"").unwrap();
@@ -478,16 +470,8 @@ fn join_linker3_test() {
         .unwrap();
 
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "id1".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "FIRST_NAME".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("id1")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("FIRST_NAME")));
     virtual_table.add_tuple(vec![Value::from(1_u64), Value::from(1_u64)]);
     virtual_table.add_tuple(vec![Value::from(2_u64), Value::from(2_u64)]);
     virtual_table.set_alias("\"t2\"").unwrap();
@@ -549,11 +533,7 @@ fn join_linker4_test() {
         .position(0)
         .unwrap();
     let mut virtual_t2 = VirtualTable::new();
-    virtual_t2.add_column(Column {
-        name: "r_id".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_t2.add_column(column_integer_user_non_null(String::from("r_id")));
     virtual_t2.add_tuple(vec![Value::from(1_u64)]);
     virtual_t2.add_tuple(vec![Value::from(2_u64)]);
     virtual_t2.set_alias("\"T2\"").unwrap();
@@ -575,11 +555,7 @@ fn join_linker4_test() {
         .position(1)
         .unwrap();
     let mut virtual_sq = VirtualTable::new();
-    virtual_sq.add_column(Column {
-        name: "fn".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_sq.add_column(column_integer_user_non_null(String::from("fn")));
     virtual_sq.add_tuple(vec![Value::from(2_u64)]);
     virtual_sq.add_tuple(vec![Value::from(3_u64)]);
     if let MotionPolicy::Segment(key) =
@@ -662,11 +638,7 @@ on q."f" = "t1"."a""#;
         .position(0)
         .unwrap();
     let mut virtual_t2 = VirtualTable::new();
-    virtual_t2.add_column(Column {
-        name: "b".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_t2.add_column(column_integer_user_non_null(String::from("b")));
     virtual_t2.set_alias("\"t3\"").unwrap();
     if let MotionPolicy::Segment(key) =
         get_motion_policy(query.exec_plan.get_ir_plan(), motion_t2_id)
@@ -686,16 +658,8 @@ on q."f" = "t1"."a""#;
         .position(0)
         .unwrap();
     let mut virtual_sq = VirtualTable::new();
-    virtual_sq.add_column(Column {
-        name: "f".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_sq.add_column(Column {
-        name: "B".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_sq.add_column(column_integer_user_non_null(String::from("f")));
+    virtual_sq.add_column(column_integer_user_non_null(String::from("B")));
     virtual_sq.set_alias("Q").unwrap();
     if let MotionPolicy::Segment(key) =
         get_motion_policy(query.exec_plan.get_ir_plan(), motion_sq_id)
@@ -895,11 +859,9 @@ fn sharding_column2_test() {
 fn virtual_table_23(alias: Option<&str>) -> VirtualTable {
     let mut virtual_table = VirtualTable::new();
 
-    virtual_table.add_column(Column {
-        name: "identification_number".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from(
+        "identification_number",
+    )));
 
     virtual_table.add_tuple(vec![Value::from(2_u64)]);
     virtual_table.add_tuple(vec![Value::from(3_u64)]);
@@ -964,11 +926,7 @@ fn groupby_linker_test() {
         "Expected Buckets::All for local groupby"
     );
     let mut virtual_t1 = VirtualTable::new();
-    virtual_t1.add_column(Column {
-        name: "id".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_t1.add_column(column_integer_user_non_null(String::from("id")));
 
     let mut buckets: Vec<u64> = vec![];
     let tuples: Vec<Vec<Value>> = vec![vec![Value::from(1_u64)], vec![Value::from(2_u64)]];
diff --git a/sbroad-core/src/executor/tests/between.rs b/sbroad-core/src/executor/tests/between.rs
index 13d2540487..d8e60a81c6 100644
--- a/sbroad-core/src/executor/tests/between.rs
+++ b/sbroad-core/src/executor/tests/between.rs
@@ -4,7 +4,7 @@ use crate::backend::sql::ir::PatternWithParams;
 use crate::executor::engine::mock::RouterRuntimeMock;
 use crate::executor::result::ProducerResult;
 use crate::executor::vtable::VirtualTable;
-use crate::ir::relation::{Column, ColumnRole, Type};
+use crate::ir::tests::column_integer_user_non_null;
 use crate::ir::transformation::redistribution::tests::get_motion_id;
 use crate::ir::transformation::redistribution::MotionPolicy;
 use crate::ir::value::{LuaValue, Value};
@@ -32,11 +32,7 @@ fn between1_test() {
 
     // Mock a virtual table.
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "id".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("id")));
     virtual_table.add_tuple(vec![Value::from(2_u64)]);
     query
         .coordinator
@@ -88,11 +84,7 @@ fn between2_test() {
 
     // Mock a virtual table.
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "id".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("id")));
     virtual_table.add_tuple(vec![Value::from(2_u64)]);
 
     // Bind the virtual table to both motions.
diff --git a/sbroad-core/src/executor/tests/empty_motion.rs b/sbroad-core/src/executor/tests/empty_motion.rs
index bb34976beb..ca323f4264 100644
--- a/sbroad-core/src/executor/tests/empty_motion.rs
+++ b/sbroad-core/src/executor/tests/empty_motion.rs
@@ -4,7 +4,7 @@ use crate::backend::sql::ir::PatternWithParams;
 use crate::executor::engine::mock::RouterRuntimeMock;
 use crate::executor::result::ProducerResult;
 use crate::executor::vtable::VirtualTable;
-use crate::ir::relation::{Column, ColumnRole, Type};
+use crate::ir::tests::column_integer_user_non_null;
 use crate::ir::transformation::redistribution::MotionPolicy;
 use crate::ir::value::{LuaValue, Value};
 
@@ -89,17 +89,9 @@ fn empty_motion1_test() {
 fn t2_empty() -> VirtualTable {
     let mut virtual_table = VirtualTable::new();
 
-    virtual_table.add_column(Column {
-        name: "g".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("g")));
 
-    virtual_table.add_column(Column {
-        name: "h".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("h")));
 
     virtual_table.set_alias("\"t2\"").unwrap();
 
diff --git a/sbroad-core/src/executor/tests/exec_plan.rs b/sbroad-core/src/executor/tests/exec_plan.rs
index 905b3297c3..c55371e287 100644
--- a/sbroad-core/src/executor/tests/exec_plan.rs
+++ b/sbroad-core/src/executor/tests/exec_plan.rs
@@ -2,6 +2,8 @@ use pretty_assertions::assert_eq;
 
 use crate::backend::sql::tree::{OrderedSyntaxNodes, SyntaxPlan};
 use crate::executor::engine::mock::RouterRuntimeMock;
+use crate::ir::relation::Type;
+use crate::ir::tests::{column_integer_user_non_null, column_user_non_null};
 use crate::ir::transformation::redistribution::MotionPolicy;
 use crate::ir::tree::Snapshot;
 
@@ -95,11 +97,10 @@ fn exec_plan_subtree_two_stage_groupby_test() {
         .unwrap();
 
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "FIRST_NAME".into(),
-        r#type: Type::String,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_user_non_null(
+        String::from("FIRST_NAME"),
+        Type::String,
+    ));
 
     if let MotionPolicy::Segment(key) = get_motion_policy(query.exec_plan.get_ir_plan(), motion_id)
     {
@@ -161,21 +162,18 @@ fn exec_plan_subtree_two_stage_groupby_test_2() {
         .position(0)
         .unwrap();
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "column_12".into(),
-        r#type: Type::String,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "column_13".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "column_14".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_user_non_null(
+        String::from("column_12"),
+        Type::String,
+    ));
+    virtual_table.add_column(column_user_non_null(
+        String::from("column_13"),
+        Type::Integer,
+    ));
+    virtual_table.add_column(column_user_non_null(
+        String::from("column_14"),
+        Type::Integer,
+    ));
     if let MotionPolicy::Segment(key) = get_motion_policy(query.exec_plan.get_ir_plan(), motion_id)
     {
         virtual_table.reshard(key, &query.coordinator).unwrap();
@@ -253,56 +251,19 @@ fn exec_plan_subtree_aggregates() {
         .position(0)
         .unwrap();
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "sys_op".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "sum_42".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "count_37".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "sum_49".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "count_51".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "group_concat_58".into(),
-        r#type: Type::String,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "count_61".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "total_64".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "min_67".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "max_70".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("sys_op")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("sum_42")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("count_37")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("sum_49")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("count_51")));
+    virtual_table.add_column(column_user_non_null(
+        String::from("group_concat_58"),
+        Type::String,
+    ));
+    virtual_table.add_column(column_integer_user_non_null(String::from("count_61")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("total_64")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("min_67")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("max_70")));
     if let MotionPolicy::Segment(key) = get_motion_policy(query.exec_plan.get_ir_plan(), motion_id)
     {
         virtual_table.reshard(key, &query.coordinator).unwrap();
@@ -381,16 +342,8 @@ fn exec_plan_subtree_aggregates_no_groupby() {
         .position(0)
         .unwrap();
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "column_19".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "count_13".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("column_19")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("count_13")));
     if let MotionPolicy::Segment(key) = get_motion_policy(query.exec_plan.get_ir_plan(), motion_id)
     {
         virtual_table.reshard(key, &query.coordinator).unwrap();
@@ -609,11 +562,7 @@ fn exec_plan_subtree_count_asterisk() {
         .position(0)
         .unwrap();
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "count_13".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("count_13")));
     if let MotionPolicy::Segment(key) = get_motion_policy(query.exec_plan.get_ir_plan(), motion_id)
     {
         virtual_table.reshard(key, &query.coordinator).unwrap();
@@ -681,21 +630,9 @@ fn exec_plan_subtree_having() {
         .position(0)
         .unwrap();
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "column_63".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "column_12".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "count_58".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("column_63")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("column_12")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("count_58")));
     if let MotionPolicy::Segment(key) = get_motion_policy(query.exec_plan.get_ir_plan(), motion_id)
     {
         virtual_table.reshard(key, &query.coordinator).unwrap();
@@ -775,21 +712,9 @@ fn exec_plan_subtree_having_without_groupby() {
         .position(0)
         .unwrap();
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "column_63".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "column_12".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    virtual_table.add_column(Column {
-        name: "count_58".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("column_63")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("column_12")));
+    virtual_table.add_column(column_integer_user_non_null(String::from("count_58")));
     if let MotionPolicy::Segment(key) = get_motion_policy(query.exec_plan.get_ir_plan(), motion_id)
     {
         virtual_table.reshard(key, &query.coordinator).unwrap();
diff --git a/sbroad-core/src/executor/tests/frontend.rs b/sbroad-core/src/executor/tests/frontend.rs
index 8670b1179e..0d1de81035 100644
--- a/sbroad-core/src/executor/tests/frontend.rs
+++ b/sbroad-core/src/executor/tests/frontend.rs
@@ -28,14 +28,14 @@ fn front_ivalid_sql1() {
 
 #[test]
 fn front_invalid_sql2() {
-    let query = r#"INSERT INTO "t" ("a") VALUES(1, 2)"#;
+    let query = r#"INSERT INTO "t" ("a", "b", "c") VALUES(1, 2, 3, 4)"#;
 
     let metadata = &RouterRuntimeMock::new();
     let plan_err = Query::new(metadata, query, vec![]).unwrap_err();
 
     assert_eq!(
         SbroadError::UnexpectedNumberOfValues(
-            r#"invalid number of values: 2. Table "t" expects 1 column(s)."#.into()
+            r#"invalid number of values: 4. Table "t" expects 3 column(s)."#.into()
         ),
         plan_err
     );
diff --git a/sbroad-core/src/executor/tests/not_eq.rs b/sbroad-core/src/executor/tests/not_eq.rs
index ca1ed7ea58..17512e55c7 100644
--- a/sbroad-core/src/executor/tests/not_eq.rs
+++ b/sbroad-core/src/executor/tests/not_eq.rs
@@ -4,7 +4,7 @@ use crate::backend::sql::ir::PatternWithParams;
 use crate::executor::engine::mock::RouterRuntimeMock;
 use crate::executor::result::ProducerResult;
 use crate::executor::vtable::VirtualTable;
-use crate::ir::relation::{Column, ColumnRole, Type};
+use crate::ir::tests::column_integer_user_non_null;
 use crate::ir::transformation::redistribution::tests::get_motion_id;
 use crate::ir::transformation::redistribution::MotionPolicy;
 use crate::ir::value::{LuaValue, Value};
@@ -71,11 +71,7 @@ fn not_eq2_test() {
 
     // Mock a virtual table.
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "id".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("id")));
     virtual_table.add_tuple(vec![Value::from(3_u64)]);
     query
         .coordinator
diff --git a/sbroad-core/src/executor/tests/not_in.rs b/sbroad-core/src/executor/tests/not_in.rs
index e0bdf05321..eaee7cd6a4 100644
--- a/sbroad-core/src/executor/tests/not_in.rs
+++ b/sbroad-core/src/executor/tests/not_in.rs
@@ -4,7 +4,7 @@ use crate::backend::sql::ir::PatternWithParams;
 use crate::executor::engine::mock::RouterRuntimeMock;
 use crate::executor::result::ProducerResult;
 use crate::executor::vtable::VirtualTable;
-use crate::ir::relation::{Column, ColumnRole, Type};
+use crate::ir::tests::column_integer_user_non_null;
 use crate::ir::transformation::redistribution::tests::get_motion_id;
 use crate::ir::transformation::redistribution::MotionPolicy;
 use crate::ir::value::{LuaValue, Value};
@@ -33,11 +33,7 @@ fn not_in1_test() {
 
     // Mock a virtual table.
     let mut virtual_table = VirtualTable::new();
-    virtual_table.add_column(Column {
-        name: "id".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    virtual_table.add_column(column_integer_user_non_null(String::from("id")));
     virtual_table.add_tuple(vec![Value::from(3_u64)]);
     query
         .coordinator
diff --git a/sbroad-core/src/executor/vtable/tests.rs b/sbroad-core/src/executor/vtable/tests.rs
index e63dd2848d..2371f3e400 100644
--- a/sbroad-core/src/executor/vtable/tests.rs
+++ b/sbroad-core/src/executor/vtable/tests.rs
@@ -1,6 +1,6 @@
 use super::*;
 use crate::executor::engine::mock::RouterRuntimeMock;
-use crate::ir::relation::{ColumnRole, Type};
+use crate::ir::tests::column_integer_user_non_null;
 use crate::ir::transformation::redistribution::{MotionKey, Target};
 use pretty_assertions::assert_eq;
 use std::collections::HashMap;
@@ -10,22 +10,14 @@ use std::collections::HashMap;
 fn virtual_table_1() {
     let mut vtable = VirtualTable::new();
 
-    vtable.add_column(Column {
-        name: "name".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    vtable.add_column(column_integer_user_non_null(String::from("name")));
 
     vtable.add_tuple(vec![Value::from(1_u64)]);
 
     vtable.set_alias("test").unwrap();
 
     let expected = VirtualTable {
-        columns: vec![Column {
-            name: "name".into(),
-            r#type: Type::Integer,
-            role: ColumnRole::User,
-        }],
+        columns: vec![column_integer_user_non_null(String::from("name"))],
         tuples: vec![vec![Value::from(1_u64)]],
         name: Some(String::from("test")),
         primary_key: None,
@@ -39,16 +31,8 @@ fn virtual_table_1() {
 #[test]
 fn virtual_table_2() {
     let mut vtable = VirtualTable::new();
-    vtable.add_column(Column {
-        name: "a".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    vtable.add_column(Column {
-        name: "b".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    vtable.add_column(column_integer_user_non_null(String::from("a")));
+    vtable.add_column(column_integer_user_non_null(String::from("b")));
     let tuple1 = vec![Value::from(1_u64), Value::from(2_u64)];
     let tuple2 = vec![Value::from(3_u64), Value::from(4_u64)];
     vtable.add_tuple(tuple1.clone());
@@ -63,16 +47,8 @@ fn virtual_table_2() {
 
     let expected = VirtualTable {
         columns: vec![
-            Column {
-                name: "a".into(),
-                r#type: Type::Integer,
-                role: ColumnRole::User,
-            },
-            Column {
-                name: "b".into(),
-                r#type: Type::Integer,
-                role: ColumnRole::User,
-            },
+            column_integer_user_non_null(String::from("a")),
+            column_integer_user_non_null(String::from("b")),
         ],
         tuples: vec![tuple1, tuple2],
         name: Some(String::from("t")),
@@ -89,16 +65,8 @@ fn virtual_table_2() {
 #[test]
 fn virtual_table_3() {
     let mut vtable = VirtualTable::new();
-    vtable.add_column(Column {
-        name: "a".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    vtable.add_column(Column {
-        name: "b".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    vtable.add_column(column_integer_user_non_null(String::from("a")));
+    vtable.add_column(column_integer_user_non_null(String::from("b")));
     let tuple1 = vec![Value::from(1_u64), Value::from(2_u64)];
     let tuple2 = vec![Value::from(3_u64), Value::from(4_u64)];
     vtable.add_tuple(tuple1.clone());
@@ -114,16 +82,8 @@ fn virtual_table_3() {
 
     let expected = VirtualTable {
         columns: vec![
-            Column {
-                name: "a".into(),
-                r#type: Type::Integer,
-                role: ColumnRole::User,
-            },
-            Column {
-                name: "b".into(),
-                r#type: Type::Integer,
-                role: ColumnRole::User,
-            },
+            column_integer_user_non_null(String::from("a")),
+            column_integer_user_non_null(String::from("b")),
         ],
         tuples: vec![tuple1, tuple2],
         name: Some(String::from("t")),
@@ -149,16 +109,8 @@ fn vtable_rearrange_for_update() {
         new_sh_key_value.clone(),
         old_sh_key_value.clone(),
     ];
-    vtable.add_column(Column {
-        name: "a".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
-    vtable.add_column(Column {
-        name: "b".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    });
+    vtable.add_column(column_integer_user_non_null(String::from("a")));
+    vtable.add_column(column_integer_user_non_null(String::from("b")));
     vtable.set_alias("t").unwrap();
     vtable.add_tuple(tuple);
 
@@ -180,16 +132,8 @@ fn vtable_rearrange_for_update() {
 
     let expected = VirtualTable {
         columns: vec![
-            Column {
-                name: "a".into(),
-                r#type: Type::Integer,
-                role: ColumnRole::User,
-            },
-            Column {
-                name: "b".into(),
-                r#type: Type::Integer,
-                role: ColumnRole::User,
-            },
+            column_integer_user_non_null(String::from("a")),
+            column_integer_user_non_null(String::from("b")),
         ],
         tuples: vec![vec![pk_value.clone(), new_sh_key_value], vec![pk_value]],
         name: Some(String::from("t")),
diff --git a/sbroad-core/src/frontend/sql.rs b/sbroad-core/src/frontend/sql.rs
index 0fc3f4c97a..9ae2f5238a 100644
--- a/sbroad-core/src/frontend/sql.rs
+++ b/sbroad-core/src/frontend/sql.rs
@@ -264,6 +264,26 @@ fn parse_create_table(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl,
                             )
                         })?,
                     );
+                    let mut column_found = false;
+                    for column in &columns {
+                        if column.name == pk_col_name {
+                            column_found = true;
+                            if column.is_nullable {
+                                return Err(SbroadError::Invalid(
+                                    Entity::Column,
+                                    Some(String::from(
+                                        "Primary key mustn't contain nullable columns",
+                                    )),
+                                ));
+                            }
+                        }
+                    }
+                    if !column_found {
+                        return Err(SbroadError::Invalid(
+                            Entity::Column,
+                            Some(format!("Primary key column {pk_col_name} not found.")),
+                        ));
+                    }
                     pk_keys.push(pk_col_name);
                 }
             }
@@ -331,6 +351,17 @@ fn parse_create_table(ast: &AbstractSyntaxTree, node: &ParseNode) -> Result<Ddl,
                                         )
                                     })?,
                                 );
+
+                                let column_found = columns.iter().any(|c| c.name == shard_col_name);
+                                if !column_found {
+                                    return Err(SbroadError::Invalid(
+                                        Entity::Column,
+                                        Some(format!(
+                                            "Sharding key column {shard_col_name} not found."
+                                        )),
+                                    ));
+                                }
+
                                 shard_key.push(shard_col_name);
                             }
                         }
@@ -1814,11 +1845,12 @@ impl Ast for AbstractSyntaxTree {
                     let ast_child = self.nodes.get_node(*ast_child_id)?;
                     let plan_insert_id = if let Type::TargetColumns = ast_child.rule {
                         // insert into t (a, b, c) ...
-                        let mut col_names: Vec<&str> = Vec::with_capacity(ast_child.children.len());
+                        let mut selected_col_names: Vec<&str> =
+                            Vec::with_capacity(ast_child.children.len());
                         for col_id in &ast_child.children {
                             let col = self.nodes.get_node(*col_id)?;
                             if let Type::ColumnName = col.rule {
-                                col_names.push(col.value.as_ref().ok_or_else(|| {
+                                selected_col_names.push(col.value.as_ref().ok_or_else(|| {
                                     SbroadError::NotFound(
                                         Entity::Name,
                                         "of Column among the AST target columns (insert)".into(),
@@ -1831,6 +1863,30 @@ impl Ast for AbstractSyntaxTree {
                                 ));
                             }
                         }
+
+                        let rel = plan.relations.get(&relation).ok_or_else(|| {
+                            SbroadError::NotFound(
+                                Entity::Table,
+                                format!("{relation} among plan relations"),
+                            )
+                        })?;
+                        for column in &rel.columns {
+                            if let ColumnRole::Sharding = column.get_role() {
+                                continue;
+                            }
+                            if !column.is_nullable
+                                && !selected_col_names.contains(&column.name.as_str())
+                            {
+                                return Err(SbroadError::Invalid(
+                                    Entity::Column,
+                                    Some(format!(
+                                        "NonNull column {} must be specified",
+                                        column.name
+                                    )),
+                                ));
+                            }
+                        }
+
                         let ast_rel_child_id = node.children.get(2).ok_or_else(|| {
                             SbroadError::NotFound(
                                 Entity::Node,
@@ -1842,7 +1898,7 @@ impl Ast for AbstractSyntaxTree {
                         plan.add_insert(
                             &relation,
                             plan_rel_child_id,
-                            &col_names,
+                            &selected_col_names,
                             conflict_strategy,
                         )?
                     } else {
diff --git a/sbroad-core/src/frontend/sql/ir/tests.rs b/sbroad-core/src/frontend/sql/ir/tests.rs
index f664395c17..e343cdd3cd 100644
--- a/sbroad-core/src/frontend/sql/ir/tests.rs
+++ b/sbroad-core/src/frontend/sql/ir/tests.rs
@@ -285,13 +285,13 @@ vtable_max_rows = 5000
 
 #[test]
 fn front_sql11() {
-    let input = r#"INSERT INTO "t" ("a", "c") VALUES(1, 2)"#;
+    let input = r#"INSERT INTO "t" ("b", "d") VALUES(1, 2)"#;
 
     let plan = sql_to_optimized_ir(input, vec![]);
 
     let expected_explain = String::from(
         r#"insert "t" on conflict: fail
-    motion [policy: local segment([ref("COLUMN_1"), value(NULL)])]
+    motion [policy: local segment([value(NULL), ref("COLUMN_1")])]
         values
             value row (data=ROW(1::unsigned, 2::unsigned))
 execution options:
@@ -305,13 +305,13 @@ vtable_max_rows = 5000
 
 #[test]
 fn front_sql14() {
-    let input = r#"INSERT INTO "t" ("a", "c") SELECT "b", "d" FROM "t""#;
+    let input = r#"INSERT INTO "t" ("b", "c") SELECT "b", "d" FROM "t""#;
 
     let plan = sql_to_optimized_ir(input, vec![]);
 
     let expected_explain = String::from(
         r#"insert "t" on conflict: fail
-    motion [policy: segment([ref("b"), value(NULL)])]
+    motion [policy: segment([value(NULL), ref("b")])]
         projection ("t"."b"::unsigned -> "b", "t"."d"::unsigned -> "d")
             scan "t"
 execution options:
@@ -727,13 +727,13 @@ vtable_max_rows = 5000
 
 #[test]
 fn front_sql_groupby_insert() {
-    let input = r#"INSERT INTO "t" ("a", "c") 
+    let input = r#"INSERT INTO "t" ("c", "b")
     SELECT "b", "d" FROM "t" group by "b", "d" ON CONFLICT DO FAIL"#;
 
     let plan = sql_to_optimized_ir(input, vec![]);
     let expected_explain = String::from(
         r#"insert "t" on conflict: fail
-    motion [policy: segment([ref("b"), value(NULL)])]
+    motion [policy: segment([value(NULL), ref("d")])]
         projection ("column_24"::unsigned -> "b", "column_25"::unsigned -> "d")
             group by ("column_24"::unsigned, "column_25"::unsigned) output: ("column_25"::unsigned -> "column_25", "column_24"::unsigned -> "column_24")
                 motion [policy: segment([ref("column_24"), ref("column_25")])]
@@ -1327,13 +1327,13 @@ vtable_max_rows = 5000
 
 #[test]
 fn front_sql_insert_single() {
-    let input = r#"INSERT INTO "t" ("a", "c") SELECT sum("b"), count("d") FROM "t""#;
+    let input = r#"INSERT INTO "t" ("c", "b") SELECT sum("b"), count("d") FROM "t""#;
 
     let plan = sql_to_optimized_ir(input, vec![]);
 
     let expected_explain = String::from(
         r#"insert "t" on conflict: fail
-    motion [policy: segment([ref("COL_1"), value(NULL)])]
+    motion [policy: segment([value(NULL), ref("COL_2")])]
         projection (sum(("sum_25"::decimal))::decimal -> "COL_1", sum(("count_28"::integer))::decimal -> "COL_2")
             motion [policy: full]
                 scan
@@ -2347,7 +2347,7 @@ vtable_max_rows = 5000
 #[test]
 fn front_sql_insert_7() {
     // Check system column can't be inserted
-    let input = r#"insert into "hash_testing" ("sys_op", "bucket_id" ) values (1, 2)"#;
+    let input = r#"insert into "hash_testing" ("identification_number", "product_code", "bucket_id") values (1, 2, 3)"#;
 
     let metadata = &RouterConfigurationMock::new();
     let ast = AbstractSyntaxTree::new(input).unwrap();
@@ -2785,6 +2785,21 @@ vtable_max_rows = 5000
     )
 }
 
+#[test]
+fn front_sql_check_non_null_columns_specified() {
+    let input = r#"insert into "test_space" ("sys_op") values (1)"#;
+
+    let metadata = &RouterConfigurationMock::new();
+    let ast = AbstractSyntaxTree::new(input).unwrap();
+    let plan = ast.resolve_metadata(metadata);
+    let err = plan.unwrap_err();
+    assert_eq!(
+        true,
+        err.to_string()
+            .contains("NonNull column \"id\" must be specified")
+    );
+}
+
 fn assert_explain_eq(query: &str, params: Vec<Value>, expected: &str) {
     let plan = sql_to_optimized_ir(query, params);
     let actual = plan.as_explain().unwrap();
diff --git a/sbroad-core/src/ir.rs b/sbroad-core/src/ir.rs
index 45e0f8e6c5..f8ce70bbbe 100644
--- a/sbroad-core/src/ir.rs
+++ b/sbroad-core/src/ir.rs
@@ -1148,4 +1148,4 @@ impl Plan {
 pub mod api;
 mod explain;
 #[cfg(test)]
-mod tests;
+pub mod tests;
diff --git a/sbroad-core/src/ir/api/parameter.rs b/sbroad-core/src/ir/api/parameter.rs
index 9180092d77..b3eabab9d8 100644
--- a/sbroad-core/src/ir/api/parameter.rs
+++ b/sbroad-core/src/ir/api/parameter.rs
@@ -55,8 +55,9 @@ impl Plan {
         tree.populate_nodes(top_id);
         let nodes = tree.take_nodes();
 
+        let mut binded_params_counter = 0;
         if !self.raw_options.is_empty() {
-            self.bind_option_params(&mut params)?;
+            binded_params_counter = self.bind_option_params(&mut params)?;
         }
 
         // Transform parameters to values (plan constants). The result values are stored in the
@@ -78,6 +79,17 @@ impl Plan {
         let mut param_node_ids = self.get_param_set();
         let mut param_node_ids_cloned = param_node_ids.clone();
 
+        if param_node_ids.len() - binded_params_counter > value_ids.len() {
+            return Err(SbroadError::Invalid(
+                Entity::Value,
+                Some(format!(
+                    "Expected at least {} values for parameters. Got {}.",
+                    param_node_ids.len() - binded_params_counter,
+                    value_ids.len()
+                )),
+            ));
+        }
+
         // Closure to retrieve a corresponding value for a parameter node.
         let get_value = |pos: usize| -> Result<usize, SbroadError> {
             let val_id = value_ids.get(pos).ok_or_else(|| {
@@ -295,17 +307,20 @@ impl Plan {
         Ok(())
     }
 
-    /// Bind params related to `Option` clause
+    /// Bind params related to `Option` clause.
+    /// Returns the number of params binded to options.
     ///
     /// # Errors
     /// - User didn't provide parameter value for corresponding option parameter
-    pub fn bind_option_params(&mut self, params: &mut Vec<Value>) -> Result<(), SbroadError> {
+    pub fn bind_option_params(&mut self, params: &mut Vec<Value>) -> Result<usize, SbroadError> {
         // Bind parameters in options to values.
         // Because the Option clause is the last clause in the
         // query the parameters are located in the end of params list.
+        let mut binded_params_counter = 0usize;
         for opt in self.raw_options.iter_mut().rev() {
             if opt.val.is_none() {
                 if let Some(v) = params.pop() {
+                    binded_params_counter += 1;
                     opt.val = Some(v);
                 } else {
                     return Err(SbroadError::Invalid(
@@ -318,6 +333,6 @@ impl Plan {
                 }
             }
         }
-        Ok(())
+        Ok(binded_params_counter)
     }
 }
diff --git a/sbroad-core/src/ir/ddl.rs b/sbroad-core/src/ir/ddl.rs
index 1e4b6a7dca..6004061066 100644
--- a/sbroad-core/src/ir/ddl.rs
+++ b/sbroad-core/src/ir/ddl.rs
@@ -6,13 +6,23 @@ use serde::{Deserialize, Serialize};
 use tarantool::decimal::Decimal;
 use tarantool::space::SpaceEngineType;
 
-#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
+#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
 pub struct ColumnDef {
     pub name: String,
     pub data_type: Type,
     pub is_nullable: bool,
 }
 
+impl Default for ColumnDef {
+    fn default() -> Self {
+        Self {
+            name: String::default(),
+            data_type: Type::default(),
+            is_nullable: true,
+        }
+    }
+}
+
 #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
 pub enum Ddl {
     CreateTable {
diff --git a/sbroad-core/src/ir/distribution/tests.rs b/sbroad-core/src/ir/distribution/tests.rs
index d67faff613..e3d6241350 100644
--- a/sbroad-core/src/ir/distribution/tests.rs
+++ b/sbroad-core/src/ir/distribution/tests.rs
@@ -1,5 +1,6 @@
 use super::*;
-use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type};
+use crate::ir::relation::{SpaceEngine, Table, Type};
+use crate::ir::tests::column_user_non_null;
 use crate::ir::transformation::helpers::sql_to_optimized_ir;
 use crate::ir::tree::traversal::{PostOrder, REL_CAPACITY};
 use crate::ir::{Node, Plan};
@@ -14,10 +15,10 @@ fn proj_preserve_dist_key() {
     let t = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
-            Column::new("c", Type::String, ColumnRole::User),
-            Column::new("d", Type::String, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Unsigned),
+            column_user_non_null(String::from("c"), Type::String),
+            column_user_non_null(String::from("d"), Type::String),
         ],
         &["b", "a"],
         &["b", "a"],
diff --git a/sbroad-core/src/ir/expression/tests.rs b/sbroad-core/src/ir/expression/tests.rs
index 946d8b333c..5489fcdaa7 100644
--- a/sbroad-core/src/ir/expression/tests.rs
+++ b/sbroad-core/src/ir/expression/tests.rs
@@ -1,6 +1,7 @@
+use crate::ir::tests::column_integer_user_non_null;
 use pretty_assertions::assert_eq;
 
-use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type};
+use crate::ir::relation::{SpaceEngine, Table};
 use crate::ir::value::Value;
 use crate::ir::{Plan, SbroadError};
 
@@ -28,7 +29,7 @@ fn rel_nodes_from_reference_in_scan() {
 
     let t = Table::new_seg(
         "t",
-        vec![Column::new("a", Type::Integer, ColumnRole::User)],
+        vec![column_integer_user_non_null(String::from("a"))],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -50,7 +51,7 @@ fn rel_nodes_from_reference_in_proj() {
 
     let t = Table::new_seg(
         "t",
-        vec![Column::new("a", Type::Integer, ColumnRole::User)],
+        vec![column_integer_user_non_null(String::from("a"))],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
diff --git a/sbroad-core/src/ir/operator/tests.rs b/sbroad-core/src/ir/operator/tests.rs
index 38d9de04f2..1b1df5bbc8 100644
--- a/sbroad-core/src/ir/operator/tests.rs
+++ b/sbroad-core/src/ir/operator/tests.rs
@@ -7,6 +7,8 @@ use crate::collection;
 use crate::errors::{Entity, SbroadError};
 use crate::ir::distribution::{Distribution, Key};
 use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type};
+use crate::ir::tests::column_integer_user_non_null;
+use crate::ir::tests::{column_user_non_null, sharding_column};
 use crate::ir::value::Value;
 use crate::ir::{Node, Plan};
 
@@ -19,10 +21,10 @@ fn scan_rel() {
     let t = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
-            Column::new("c", Type::String, ColumnRole::User),
-            Column::new("d", Type::String, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Unsigned),
+            column_user_non_null(String::from("c"), Type::String),
+            column_user_non_null(String::from("d"), Type::String),
         ],
         &["b", "a"],
         &["b", "a"],
@@ -57,10 +59,10 @@ fn scan_rel_serialized() {
     let t = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Number, ColumnRole::User),
-            Column::new("c", Type::String, ColumnRole::User),
-            Column::new("d", Type::String, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Number),
+            column_user_non_null(String::from("c"), Type::String),
+            column_user_non_null(String::from("d"), Type::String),
         ],
         &["b", "a"],
         &["b", "a"],
@@ -93,10 +95,10 @@ fn projection() {
     let t = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
-            Column::new("c", Type::String, ColumnRole::User),
-            Column::new("d", Type::String, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Unsigned),
+            column_user_non_null(String::from("c"), Type::String),
+            column_user_non_null(String::from("d"), Type::String),
         ],
         &["b", "a"],
         &["b", "a"],
@@ -150,10 +152,10 @@ fn selection() {
     let t = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
-            Column::new("c", Type::String, ColumnRole::User),
-            Column::new("d", Type::String, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Unsigned),
+            column_user_non_null(String::from("c"), Type::String),
+            column_user_non_null(String::from("d"), Type::String),
         ],
         &["b", "a"],
         &["b", "a"],
@@ -213,7 +215,7 @@ fn except() {
 
     let t1 = Table::new_seg(
         "t1",
-        vec![Column::new("a", Type::Unsigned, ColumnRole::User)],
+        vec![column_user_non_null(String::from("a"), Type::Unsigned)],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -225,7 +227,7 @@ fn except() {
 
     let t2 = Table::new_seg(
         "t2",
-        vec![Column::new("a", Type::Unsigned, ColumnRole::User)],
+        vec![column_user_non_null(String::from("a"), Type::Unsigned)],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -245,8 +247,8 @@ fn except() {
     let t3 = Table::new_seg(
         "t3",
         vec![
-            Column::new("a", Type::Unsigned, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Unsigned),
+            column_user_non_null(String::from("b"), Type::Unsigned),
         ],
         &["a"],
         &["a"],
@@ -271,7 +273,7 @@ fn insert() {
 
     let t1 = Table::new_seg(
         "t1",
-        vec![Column::new("a", Type::Unsigned, ColumnRole::User)],
+        vec![column_user_non_null(String::from("a"), Type::Unsigned)],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -284,9 +286,9 @@ fn insert() {
     let t2 = Table::new_seg(
         "t2",
         vec![
-            Column::new("a", Type::Unsigned, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
-            Column::new("c", Type::Unsigned, ColumnRole::Sharding),
+            column_user_non_null(String::from("a"), Type::Unsigned),
+            column_user_non_null(String::from("b"), Type::Unsigned),
+            Column::new("c", Type::Unsigned, ColumnRole::Sharding, true),
         ],
         &["a"],
         &["a"],
@@ -334,7 +336,7 @@ fn union_all() {
 
     let t1 = Table::new_seg(
         "t1",
-        vec![Column::new("a", Type::Unsigned, ColumnRole::User)],
+        vec![column_user_non_null(String::from("a"), Type::Unsigned)],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -345,7 +347,7 @@ fn union_all() {
 
     let t2 = Table::new_seg(
         "t2",
-        vec![Column::new("a", Type::Unsigned, ColumnRole::User)],
+        vec![column_user_non_null(String::from("a"), Type::Unsigned)],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -364,8 +366,8 @@ fn union_all_col_amount_mismatch() {
     let t1 = Table::new_seg(
         "t1",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Unsigned),
         ],
         &["a"],
         &["a"],
@@ -379,7 +381,7 @@ fn union_all_col_amount_mismatch() {
     // Check errors for children with different amount of column
     let t2 = Table::new_seg(
         "t2",
-        vec![Column::new("b", Type::Unsigned, ColumnRole::User)],
+        vec![column_user_non_null(String::from("b"), Type::Unsigned)],
         &["b"],
         &["b"],
         SpaceEngine::Memtx,
@@ -404,8 +406,8 @@ fn sub_query() {
     let t = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Unsigned),
         ],
         &["a"],
         &["b"],
@@ -452,7 +454,7 @@ fn selection_with_sub_query() {
 
     let t1 = Table::new_seg(
         "t1",
-        vec![Column::new("a", Type::Integer, ColumnRole::User)],
+        vec![column_integer_user_non_null(String::from("a"))],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -464,7 +466,7 @@ fn selection_with_sub_query() {
 
     let t2 = Table::new_seg(
         "t2",
-        vec![Column::new("b", Type::Integer, ColumnRole::User)],
+        vec![column_integer_user_non_null(String::from("b"))],
         &["b"],
         &["b"],
         SpaceEngine::Memtx,
@@ -509,9 +511,9 @@ fn join() {
     let t1 = Table::new_seg(
         "t1",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
-            Column::new("bucket_id", Type::Unsigned, ColumnRole::Sharding),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Unsigned),
+            sharding_column(),
         ],
         &["a"],
         &["a"],
@@ -524,9 +526,9 @@ fn join() {
     let t2 = Table::new_seg(
         "t2",
         vec![
-            Column::new("c", Type::Boolean, ColumnRole::User),
-            Column::new("d", Type::Unsigned, ColumnRole::User),
-            Column::new("bucket_id", Type::Unsigned, ColumnRole::Sharding),
+            column_user_non_null(String::from("c"), Type::Boolean),
+            column_user_non_null(String::from("d"), Type::Unsigned),
+            sharding_column(),
         ],
         &["d"],
         &["d"],
@@ -570,9 +572,9 @@ fn join_duplicate_columns() {
     let t1 = Table::new_seg(
         "t1",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
-            Column::new("bucket_id", Type::Unsigned, ColumnRole::Sharding),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Unsigned),
+            sharding_column(),
         ],
         &["a"],
         &["a"],
@@ -585,9 +587,9 @@ fn join_duplicate_columns() {
     let t2 = Table::new_seg(
         "t2",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("d", Type::Unsigned, ColumnRole::User),
-            Column::new("bucket_id", Type::Unsigned, ColumnRole::Sharding),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("d"), Type::Unsigned),
+            sharding_column(),
         ],
         &["d"],
         &["d"],
diff --git a/sbroad-core/src/ir/relation.rs b/sbroad-core/src/ir/relation.rs
index bf8f9c2339..4ed1805364 100644
--- a/sbroad-core/src/ir/relation.rs
+++ b/sbroad-core/src/ir/relation.rs
@@ -153,7 +153,7 @@ pub enum ColumnRole {
 }
 
 /// Table column.
-#[derive(Default, PartialEq, Debug, Eq, Clone)]
+#[derive(PartialEq, Debug, Eq, Clone)]
 pub struct Column {
     /// Column name.
     pub name: String,
@@ -161,6 +161,20 @@ pub struct Column {
     pub r#type: Type,
     /// Column role.
     pub role: ColumnRole,
+    /// Column is_nullable status.
+    /// Possibly `None` (e.g. in case it's taken from Tarantool local query execution metatada).
+    pub is_nullable: bool,
+}
+
+impl Default for Column {
+    fn default() -> Self {
+        Column {
+            name: String::default(),
+            r#type: Type::default(),
+            role: ColumnRole::default(),
+            is_nullable: true,
+        }
+    }
 }
 
 impl From<Column> for Field {
@@ -240,11 +254,13 @@ impl<'de> Visitor<'de> for ColumnVisitor {
         let mut column_name = String::new();
         let mut column_type = String::new();
         let mut column_role = String::new();
+        let mut column_is_nullable = String::new();
         while let Some((key, value)) = map.next_entry::<String, String>()? {
             match key.as_str() {
                 "name" => column_name.push_str(&value),
                 "type" => column_type.push_str(&value.to_lowercase()),
                 "role" => column_role.push_str(&value.to_lowercase()),
+                "is_nullable" => column_is_nullable.push_str(&value.to_lowercase()),
                 _ => return Err(Error::custom(&format!("invalid column param: {key}"))),
             }
         }
@@ -254,16 +270,20 @@ impl<'de> Visitor<'de> for ColumnVisitor {
             _ => ColumnRole::User,
         };
 
+        let is_nullable = matches!(column_is_nullable.as_str(), "true");
+
         match column_type.as_str() {
-            "boolean" => Ok(Column::new(&column_name, Type::Boolean, role)),
-            "decimal" => Ok(Column::new(&column_name, Type::Decimal, role)),
-            "double" => Ok(Column::new(&column_name, Type::Double, role)),
-            "integer" => Ok(Column::new(&column_name, Type::Integer, role)),
-            "number" | "numeric" => Ok(Column::new(&column_name, Type::Number, role)),
-            "scalar" => Ok(Column::new(&column_name, Type::Scalar, role)),
-            "string" | "text" | "varchar" => Ok(Column::new(&column_name, Type::String, role)),
-            "unsigned" => Ok(Column::new(&column_name, Type::Unsigned, role)),
-            "array" => Ok(Column::new(&column_name, Type::Array, role)),
+            "boolean" => Ok(Column::new(&column_name, Type::Boolean, role, is_nullable)),
+            "decimal" => Ok(Column::new(&column_name, Type::Decimal, role, is_nullable)),
+            "double" => Ok(Column::new(&column_name, Type::Double, role, is_nullable)),
+            "integer" => Ok(Column::new(&column_name, Type::Integer, role, is_nullable)),
+            "number" | "numeric" => Ok(Column::new(&column_name, Type::Number, role, is_nullable)),
+            "scalar" => Ok(Column::new(&column_name, Type::Scalar, role, is_nullable)),
+            "string" | "text" | "varchar" => {
+                Ok(Column::new(&column_name, Type::String, role, is_nullable))
+            }
+            "unsigned" => Ok(Column::new(&column_name, Type::Unsigned, role, is_nullable)),
+            "array" => Ok(Column::new(&column_name, Type::Array, role, is_nullable)),
             _ => Err(Error::custom("unsupported column type")),
         }
     }
@@ -281,11 +301,12 @@ impl<'de> Deserialize<'de> for Column {
 impl Column {
     /// Column constructor.
     #[must_use]
-    pub fn new(n: &str, t: Type, role: ColumnRole) -> Self {
+    pub fn new(n: &str, t: Type, role: ColumnRole, is_nullable: bool) -> Self {
         Column {
             name: n.into(),
             r#type: t,
             role,
+            is_nullable,
         }
     }
 
diff --git a/sbroad-core/src/ir/relation/tests.rs b/sbroad-core/src/ir/relation/tests.rs
index 6ae8c23e8e..28dd70be48 100644
--- a/sbroad-core/src/ir/relation/tests.rs
+++ b/sbroad-core/src/ir/relation/tests.rs
@@ -4,17 +4,14 @@ use std::path::Path;
 use pretty_assertions::{assert_eq, assert_ne};
 
 use super::*;
+use crate::ir::tests::column_user_non_null;
 
 #[test]
 fn column() {
-    let a = Column {
-        name: String::from("a"),
-        r#type: Type::Boolean,
-        role: ColumnRole::User,
-    };
-    assert_eq!(a, Column::new("a", Type::Boolean, ColumnRole::User));
-    assert_ne!(a, Column::new("a", Type::String, ColumnRole::User));
-    assert_ne!(a, Column::new("b", Type::Boolean, ColumnRole::User));
+    let a = column_user_non_null(String::from("a"), Type::Boolean);
+    assert_eq!(a, column_user_non_null(String::from("a"), Type::Boolean));
+    assert_ne!(a, column_user_non_null(String::from("a"), Type::String));
+    assert_ne!(a, column_user_non_null(String::from("b"), Type::Boolean));
 }
 
 #[test]
@@ -22,10 +19,10 @@ fn table_seg() {
     let t = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
-            Column::new("c", Type::String, ColumnRole::User),
-            Column::new("d", Type::String, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Unsigned),
+            column_user_non_null(String::from("c"), Type::String),
+            column_user_non_null(String::from("d"), Type::String),
         ],
         &["b", "a"],
         &["b", "a"],
@@ -42,7 +39,7 @@ fn table_seg() {
 fn table_seg_name() {
     let t = Table::new_seg(
         "t",
-        vec![Column::new("a", Type::Boolean, ColumnRole::User)],
+        vec![column_user_non_null(String::from("a"), Type::Boolean)],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -57,10 +54,10 @@ fn table_seg_duplicate_columns() {
         Table::new_seg(
             "t",
             vec![
-                Column::new("a", Type::Boolean, ColumnRole::User),
-                Column::new("b", Type::Unsigned, ColumnRole::User),
-                Column::new("c", Type::String, ColumnRole::User),
-                Column::new("a", Type::String, ColumnRole::User),
+                column_user_non_null(String::from("a"), Type::Boolean),
+                column_user_non_null(String::from("b"), Type::Unsigned),
+                column_user_non_null(String::from("c"), Type::String),
+                column_user_non_null(String::from("a"), Type::String),
             ],
             &["b", "a"],
             &["b", "a"],
@@ -76,9 +73,9 @@ fn table_seg_dno_bucket_id_column() {
     let t1 = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
-            Column::new("c", Type::String, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Unsigned),
+            column_user_non_null(String::from("c"), Type::String),
         ],
         &["b", "a"],
         &["b", "a"],
@@ -94,11 +91,11 @@ fn table_seg_dno_bucket_id_column() {
     let t2 = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
-            Column::new("c", Type::String, ColumnRole::User),
-            Column::new("bucket_id", Type::String, ColumnRole::Sharding),
-            Column::new("bucket_id2", Type::String, ColumnRole::Sharding),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Unsigned),
+            column_user_non_null(String::from("c"), Type::String),
+            Column::new("bucket_id", Type::String, ColumnRole::Sharding, false),
+            Column::new("bucket_id2", Type::String, ColumnRole::Sharding, false),
         ],
         &["b", "a"],
         &["b", "a"],
@@ -118,10 +115,10 @@ fn table_seg_wrong_key() {
         Table::new_seg(
             "t",
             vec![
-                Column::new("a", Type::Boolean, ColumnRole::User),
-                Column::new("b", Type::Unsigned, ColumnRole::User),
-                Column::new("c", Type::String, ColumnRole::User),
-                Column::new("d", Type::String, ColumnRole::User),
+                column_user_non_null(String::from("a"), Type::Boolean),
+                column_user_non_null(String::from("b"), Type::Unsigned),
+                column_user_non_null(String::from("c"), Type::String),
+                column_user_non_null(String::from("d"), Type::String),
             ],
             &["a", "e"],
             &["a", "e"],
@@ -138,8 +135,8 @@ fn table_seg_compound_type_in_key() {
         Table::new_seg(
             "t",
             vec![
-                Column::new("bucket_id", Type::Unsigned, ColumnRole::Sharding),
-                Column::new("a", Type::Array, ColumnRole::User),
+                Column::new("bucket_id", Type::Unsigned, ColumnRole::Sharding, false),
+                column_user_non_null(String::from("a"), Type::Array),
             ],
             &["a"],
             &["a"],
@@ -158,12 +155,12 @@ fn table_seg_serialized() {
     let t = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Number, ColumnRole::User),
-            Column::new("c", Type::String, ColumnRole::User),
-            Column::new("d", Type::String, ColumnRole::User),
-            Column::new("e", Type::Integer, ColumnRole::User),
-            Column::new("f", Type::Unsigned, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Number),
+            column_user_non_null(String::from("c"), Type::String),
+            column_user_non_null(String::from("d"), Type::String),
+            column_user_non_null(String::from("e"), Type::Integer),
+            column_user_non_null(String::from("f"), Type::Unsigned),
         ],
         &["a", "d"],
         &["a", "d"],
@@ -254,11 +251,7 @@ fn table_seg_serialized_no_columns() {
 
 #[test]
 fn column_msgpack_serialize() {
-    let c = Column {
-        name: "name".into(),
-        r#type: Type::Boolean,
-        role: ColumnRole::User,
-    };
+    let c = column_user_non_null(String::from("name"), Type::Boolean);
 
     assert_eq!(
         vec![
@@ -269,11 +262,7 @@ fn column_msgpack_serialize() {
         rmp_serde::to_vec(&c).unwrap()
     );
 
-    let c = Column {
-        name: "name".into(),
-        r#type: Type::String,
-        role: ColumnRole::User,
-    };
+    let c = column_user_non_null(String::from("name"), Type::String);
 
     assert_eq!(
         vec![
@@ -284,11 +273,7 @@ fn column_msgpack_serialize() {
         rmp_serde::to_vec(&c).unwrap()
     );
 
-    let c = Column {
-        name: "name".into(),
-        r#type: Type::Integer,
-        role: ColumnRole::User,
-    };
+    let c = column_user_non_null(String::from("name"), Type::Integer);
 
     assert_eq!(
         vec![
@@ -299,11 +284,7 @@ fn column_msgpack_serialize() {
         rmp_serde::to_vec(&c).unwrap()
     );
 
-    let c = Column {
-        name: "name".into(),
-        r#type: Type::Unsigned,
-        role: ColumnRole::User,
-    };
+    let c = column_user_non_null(String::from("name"), Type::Unsigned);
 
     assert_eq!(
         vec![
@@ -314,11 +295,7 @@ fn column_msgpack_serialize() {
         rmp_serde::to_vec(&c).unwrap()
     );
 
-    let c = Column {
-        name: "name".into(),
-        r#type: Type::Number,
-        role: ColumnRole::User,
-    };
+    let c = column_user_non_null(String::from("name"), Type::Number);
 
     assert_eq!(
         vec![
@@ -332,11 +309,7 @@ fn column_msgpack_serialize() {
 
 #[test]
 fn column_msgpack_deserialize() {
-    let c = Column {
-        name: "name".into(),
-        r#type: Type::Boolean,
-        role: ColumnRole::User,
-    };
+    let c = column_user_non_null(String::from("name"), Type::Boolean);
 
     let expected_msgpack = vec![
         0x83, 0xA4, 0x6E, 0x61, 0x6D, 0x65, 0xA4, 0x6E, 0x61, 0x6D, 0x65, 0xA4, 0x74, 0x79, 0x70,
@@ -357,10 +330,10 @@ fn table_converting() {
     let t = Table::new_seg(
         "t",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("b", Type::Unsigned, ColumnRole::User),
-            Column::new("c", Type::String, ColumnRole::User),
-            Column::new("d", Type::String, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("b"), Type::Unsigned),
+            column_user_non_null(String::from("c"), Type::String),
+            column_user_non_null(String::from("d"), Type::String),
         ],
         &["b", "a"],
         &["b", "a"],
diff --git a/sbroad-core/src/ir/tests.rs b/sbroad-core/src/ir/tests.rs
index 9a734c00cd..9572a738df 100644
--- a/sbroad-core/src/ir/tests.rs
+++ b/sbroad-core/src/ir/tests.rs
@@ -4,6 +4,54 @@ use pretty_assertions::assert_eq;
 use std::fs;
 use std::path::Path;
 
+/// Helper function to create `Column` object with given name and default:
+///
+/// * `type` = Integer
+/// * `is_nullable` = false
+/// * `role` = User
+/// Used only for tests purposes.
+#[must_use]
+#[cfg(test)]
+pub fn column_integer_user_non_null(name: String) -> Column {
+    Column {
+        name,
+        r#type: Type::Integer,
+        role: ColumnRole::User,
+        is_nullable: false,
+    }
+}
+
+/// Helper function to create `Column` object with given name, type and default
+/// * `is_nullable` = false
+/// * `role` = User
+/// Used only for tests purposes.
+#[must_use]
+#[cfg(test)]
+pub fn column_user_non_null(name: String, r#type: Type) -> Column {
+    Column {
+        name,
+        r#type,
+        role: ColumnRole::User,
+        is_nullable: false,
+    }
+}
+
+/// Helper function to create sharding `Column` object with default
+/// * `is_nullable` = true
+/// * `role` = Sharding
+/// * `type` = Unsigned
+/// Used only for tests purposes.
+#[must_use]
+#[cfg(test)]
+pub fn sharding_column() -> Column {
+    Column {
+        name: String::from("bucket_id"),
+        r#type: Type::Unsigned,
+        role: ColumnRole::Sharding,
+        is_nullable: true,
+    }
+}
+
 #[test]
 fn plan_no_top() {
     let path = Path::new("")
@@ -38,7 +86,7 @@ fn get_node() {
 
     let t = Table::new_seg(
         "t",
-        vec![Column::new("a", Type::Boolean, ColumnRole::User)],
+        vec![Column::new("a", Type::Boolean, ColumnRole::User, false)],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
diff --git a/sbroad-core/src/ir/transformation/redistribution/tests.rs b/sbroad-core/src/ir/transformation/redistribution/tests.rs
index 109c62109a..294da9d383 100644
--- a/sbroad-core/src/ir/transformation/redistribution/tests.rs
+++ b/sbroad-core/src/ir/transformation/redistribution/tests.rs
@@ -1,6 +1,7 @@
 use super::*;
 use crate::ir::operator::Relational;
-use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type};
+use crate::ir::relation::{SpaceEngine, Table};
+use crate::ir::tests::column_integer_user_non_null;
 use crate::ir::transformation::helpers::sql_to_ir;
 use crate::ir::Plan;
 use crate::ir::Slices;
@@ -18,7 +19,7 @@ fn full_motion_less_for_sub_query() {
 
     let t1 = Table::new_seg(
         "t1",
-        vec![Column::new("a", Type::Integer, ColumnRole::User)],
+        vec![column_integer_user_non_null(String::from("a"))],
         &["a"],
         &["a"],
         SpaceEngine::Vinyl,
@@ -31,8 +32,8 @@ fn full_motion_less_for_sub_query() {
     let t2 = Table::new_seg(
         "t2",
         vec![
-            Column::new("a", Type::Integer, ColumnRole::User),
-            Column::new("b", Type::Integer, ColumnRole::User),
+            column_integer_user_non_null(String::from("a")),
+            column_integer_user_non_null(String::from("b")),
         ],
         &["a"],
         &["a"],
@@ -82,8 +83,8 @@ fn full_motion_non_segment_outer_for_sub_query() {
     let t1 = Table::new_seg(
         "t1",
         vec![
-            Column::new("a", Type::Integer, ColumnRole::User),
-            Column::new("b", Type::Integer, ColumnRole::User),
+            column_integer_user_non_null(String::from("a")),
+            column_integer_user_non_null(String::from("b")),
         ],
         &["a"],
         &["a"],
@@ -96,7 +97,7 @@ fn full_motion_non_segment_outer_for_sub_query() {
 
     let t2 = Table::new_seg(
         "t2",
-        vec![Column::new("a", Type::Integer, ColumnRole::User)],
+        vec![column_integer_user_non_null(String::from("a"))],
         &["a"],
         &["a"],
         SpaceEngine::Vinyl,
@@ -144,7 +145,7 @@ fn local_sub_query() {
 
     let t1 = Table::new_seg(
         "t1",
-        vec![Column::new("a", Type::Integer, ColumnRole::User)],
+        vec![column_integer_user_non_null(String::from("a"))],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -156,7 +157,7 @@ fn local_sub_query() {
 
     let t2 = Table::new_seg(
         "t2",
-        vec![Column::new("a", Type::Integer, ColumnRole::User)],
+        vec![column_integer_user_non_null(String::from("a"))],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -203,7 +204,7 @@ fn multiple_sub_queries() {
 
     let t1 = Table::new_seg(
         "t1",
-        vec![Column::new("a", Type::Integer, ColumnRole::User)],
+        vec![column_integer_user_non_null(String::from("a"))],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -216,8 +217,8 @@ fn multiple_sub_queries() {
     let t2 = Table::new_seg(
         "t2",
         vec![
-            Column::new("a", Type::Integer, ColumnRole::User),
-            Column::new("b", Type::Integer, ColumnRole::User),
+            column_integer_user_non_null(String::from("a")),
+            column_integer_user_non_null(String::from("b")),
         ],
         &["a"],
         &["a"],
diff --git a/sbroad-core/src/ir/transformation/redistribution/tests/segment.rs b/sbroad-core/src/ir/transformation/redistribution/tests/segment.rs
index 856879838b..61fd6603c3 100644
--- a/sbroad-core/src/ir/transformation/redistribution/tests/segment.rs
+++ b/sbroad-core/src/ir/transformation/redistribution/tests/segment.rs
@@ -3,7 +3,8 @@ use crate::errors::{Entity, SbroadError};
 use crate::ir::distribution::{Distribution, Key};
 use crate::ir::helpers::RepeatableState;
 use crate::ir::operator::{Bool, Relational};
-use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type};
+use crate::ir::relation::{Column, SpaceEngine, Table};
+use crate::ir::tests::column_integer_user_non_null;
 use crate::ir::transformation::helpers::sql_to_ir;
 use crate::ir::transformation::redistribution::{MotionKey, MotionPolicy, Target};
 use crate::ir::{Node, Plan};
@@ -24,7 +25,7 @@ fn sub_query1() {
 
     let t1 = Table::new_seg(
         "t1",
-        vec![Column::new("a", Type::Integer, ColumnRole::User)],
+        vec![column_integer_user_non_null(String::from("a"))],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -37,8 +38,8 @@ fn sub_query1() {
     let t2 = Table::new_seg(
         "t2",
         vec![
-            Column::new("a", Type::Integer, ColumnRole::User),
-            Column::new("b", Type::Integer, ColumnRole::User),
+            column_integer_user_non_null(String::from("a")),
+            column_integer_user_non_null(String::from("b")),
         ],
         &["a"],
         &["a"],
@@ -334,7 +335,7 @@ fn insert4() {
 
 #[test]
 fn insert5() {
-    let query = r#"INSERT INTO "t" ("c", "d") SELECT "a", "b" FROM "t""#;
+    let query = r#"INSERT INTO "t" ("c", "d", "b") SELECT "a", "c", "b" FROM "t""#;
 
     let mut plan = sql_to_ir(query, vec![]);
     plan.add_motions().unwrap();
@@ -344,10 +345,7 @@ fn insert5() {
         assert_eq!(
             *policy,
             MotionPolicy::Segment(MotionKey {
-                targets: vec![
-                    Target::Value(Column::default_value()),
-                    Target::Value(Column::default_value()),
-                ]
+                targets: vec![Target::Value(Column::default_value()), Target::Reference(2),]
             })
         );
     } else {
@@ -357,7 +355,7 @@ fn insert5() {
 
 #[test]
 fn insert6() {
-    let query = r#"INSERT INTO "t" ("a", "c") SELECT "a", "b" FROM "t""#;
+    let query = r#"INSERT INTO "t" ("c", "b") SELECT "b", "c" FROM "t""#;
 
     let mut plan = sql_to_ir(query, vec![]);
     plan.add_motions().unwrap();
@@ -367,7 +365,7 @@ fn insert6() {
         assert_eq!(
             *policy,
             MotionPolicy::Segment(MotionKey {
-                targets: vec![Target::Reference(0), Target::Value(Column::default_value()),]
+                targets: vec![Target::Value(Column::default_value()), Target::Reference(1)]
             })
         );
     } else {
diff --git a/sbroad-core/src/ir/tree/tests.rs b/sbroad-core/src/ir/tree/tests.rs
index 59247ba6f0..9a4ae2478e 100644
--- a/sbroad-core/src/ir/tree/tests.rs
+++ b/sbroad-core/src/ir/tree/tests.rs
@@ -1,5 +1,6 @@
 use crate::ir::operator::Bool;
-use crate::ir::relation::{Column, ColumnRole, SpaceEngine, Table, Type};
+use crate::ir::relation::{SpaceEngine, Table, Type};
+use crate::ir::tests::column_user_non_null;
 use crate::ir::tree::traversal::{BreadthFirst, PostOrder, EXPR_CAPACITY, REL_CAPACITY};
 use crate::ir::value::Value;
 use crate::ir::{Expression, Plan};
@@ -55,7 +56,7 @@ fn relational_post() {
 
     let t1 = Table::new_seg(
         "t1",
-        vec![Column::new("a", Type::Boolean, ColumnRole::User)],
+        vec![column_user_non_null(String::from("a"), Type::Boolean)],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -66,7 +67,7 @@ fn relational_post() {
 
     let t2 = Table::new_seg(
         "t2",
-        vec![Column::new("a", Type::Boolean, ColumnRole::User)],
+        vec![column_user_non_null(String::from("a"), Type::Boolean)],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -119,7 +120,7 @@ fn selection_subquery_dfs_post() {
 
     let t1 = Table::new_seg(
         "t1",
-        vec![Column::new("a", Type::Boolean, ColumnRole::User)],
+        vec![column_user_non_null(String::from("a"), Type::Boolean)],
         &["a"],
         &["a"],
         SpaceEngine::Memtx,
@@ -132,8 +133,8 @@ fn selection_subquery_dfs_post() {
     let t2 = Table::new_seg(
         "t2",
         vec![
-            Column::new("b", Type::Boolean, ColumnRole::User),
-            Column::new("c", Type::Boolean, ColumnRole::User),
+            column_user_non_null(String::from("b"), Type::Boolean),
+            column_user_non_null(String::from("c"), Type::Boolean),
         ],
         &["b"],
         &["b"],
@@ -207,8 +208,8 @@ fn subtree_dfs_post() {
     let t1 = Table::new_seg(
         "t1",
         vec![
-            Column::new("a", Type::Boolean, ColumnRole::User),
-            Column::new("c", Type::Boolean, ColumnRole::User),
+            column_user_non_null(String::from("a"), Type::Boolean),
+            column_user_non_null(String::from("c"), Type::Boolean),
         ],
         &["a", "c"],
         &["a", "c"],
diff --git a/sbroad-core/tests/artifactory/backend/sql/tree/arbitrary_projection_plan.yaml b/sbroad-core/tests/artifactory/backend/sql/tree/arbitrary_projection_plan.yaml
index 4eacd2c991..e80d1875f9 100644
--- a/sbroad-core/tests/artifactory/backend/sql/tree/arbitrary_projection_plan.yaml
+++ b/sbroad-core/tests/artifactory/backend/sql/tree/arbitrary_projection_plan.yaml
@@ -176,18 +176,23 @@ relations:
         - name: a
           type: Integer
           role: User
+          is_nullable: false
         - name: b
           type: Integer
           role: User
+          is_nullable: false
         - name: c
           type: Integer
           role: User
+          is_nullable: false
         - name: d
           type: Integer
           role: User
+          is_nullable: false
         - name: bucket_id
           type: Unsigned
           role: Sharding
+          is_nullable: true
       shard_key:
         positions:
           - 0
diff --git a/sbroad-core/tests/artifactory/backend/sql/tree/arithmetic_projection_plan.yaml b/sbroad-core/tests/artifactory/backend/sql/tree/arithmetic_projection_plan.yaml
index b1b4bc3de5..5ccfc4e467 100644
--- a/sbroad-core/tests/artifactory/backend/sql/tree/arithmetic_projection_plan.yaml
+++ b/sbroad-core/tests/artifactory/backend/sql/tree/arithmetic_projection_plan.yaml
@@ -241,24 +241,31 @@ relations:
         - name: a
           type: Integer
           role: User
+          is_nullable: false
         - name: b
           type: Integer
           role: User
+          is_nullable: false
         - name: c
           type: Integer
           role: User
+          is_nullable: false
         - name: d
           type: Integer
           role: User
+          is_nullable: false
         - name: e
           type: Integer
           role: User
+          is_nullable: false
         - name: f
           type: Integer
           role: User
+          is_nullable: false
         - name: bucket_id
           type: Unsigned
           role: Sharding
+          is_nullable: true
       shard_key:
         positions:
           - 0
diff --git a/sbroad-core/tests/artifactory/backend/sql/tree/arithmetic_selection_plan.yaml b/sbroad-core/tests/artifactory/backend/sql/tree/arithmetic_selection_plan.yaml
index 6fe16c181f..4072a4975c 100644
--- a/sbroad-core/tests/artifactory/backend/sql/tree/arithmetic_selection_plan.yaml
+++ b/sbroad-core/tests/artifactory/backend/sql/tree/arithmetic_selection_plan.yaml
@@ -373,24 +373,31 @@ relations:
         - name: a
           type: Integer
           role: User
+          is_nullable: false
         - name: b
           type: Integer
           role: User
+          is_nullable: false
         - name: c
           type: Integer
           role: User
+          is_nullable: false
         - name: d
           type: Integer
           role: User
+          is_nullable: false
         - name: e
           type: Integer
           role: User
+          is_nullable: false
         - name: f
           type: Integer
           role: User
+          is_nullable: false
         - name: bucket_id
           type: Unsigned
           role: Sharding
+          is_nullable: true
       shard_key:
         positions:
           - 0
-- 
GitLab