diff --git a/src/ir/explain.rs b/src/ir/explain.rs
index f20fa8f539cd0b9a39a13e8458b0d9e29ac6214d..98efad25fb319a014848bb2bbe041cc67f4711c4 100644
--- a/src/ir/explain.rs
+++ b/src/ir/explain.rs
@@ -450,6 +450,9 @@ impl Display for InnerJoin {
 enum ExplainNode {
     Except,
     InnerJoin(InnerJoin),
+    ValueRow(Row),
+    Value,
+    Insert(String),
     Projection(Projection),
     Scan(Scan),
     Selection(Selection),
@@ -463,6 +466,9 @@ impl Display for ExplainNode {
         let s = match &self {
             ExplainNode::Except => "except".to_string(),
             ExplainNode::InnerJoin(i) => i.to_string(),
+            ExplainNode::ValueRow(r) => format!("value row (data={})", r),
+            ExplainNode::Value => "values".to_string(),
+            ExplainNode::Insert(s) => format!("insert {}", s),
             ExplainNode::Projection(e) => e.to_string(),
             ExplainNode::Scan(s) => s.to_string(),
             ExplainNode::Selection(s) => format!("selection {}", s),
@@ -732,13 +738,52 @@ impl FullExplain {
                     let condition = Selection::new(ir, *condition, &sq_ref_map)?;
                     Some(ExplainNode::InnerJoin(InnerJoin { condition }))
                 }
-                Relational::Insert { .. }
-                | Relational::Values { .. }
-                | Relational::ValuesRow { .. } => {
-                    return Err(QueryPlannerError::CustomError(format!(
-                        "Explain hasn't supported node {:?} yet",
-                        node
-                    )))
+                Relational::ValuesRow { data, children, .. } => {
+                    let mut sq_ref_map: HashMap<usize, usize> =
+                        HashMap::with_capacity(children.len());
+
+                    for sq_id in children.iter().rev() {
+                        let sq_node = stack.pop().ok_or_else(|| {
+                            QueryPlannerError::CustomError(
+                                "Insert node failed to get a sub-query.".into(),
+                            )
+                        })?;
+
+                        result.subqueries.push(sq_node);
+                        let offset = result.subqueries.len() - 1;
+                        sq_ref_map.insert(*sq_id, offset);
+                    }
+
+                    let values = ir.get_expression_node(*data)?.get_row_list()?;
+                    let row = Row::from_ir_nodes(ir, values, &sq_ref_map)?;
+
+                    Some(ExplainNode::ValueRow(row))
+                }
+                Relational::Values { children, .. } => {
+                    let mut amount_values = children.len();
+
+                    while amount_values > 0 {
+                        let value_row = stack.pop().ok_or_else(|| {
+                            QueryPlannerError::CustomError(
+                                "Insert node failed to get a value row.".into(),
+                            )
+                        })?;
+
+                        current_node.children.insert(0, value_row);
+                        amount_values -= 1;
+                    }
+                    Some(ExplainNode::Value)
+                }
+                Relational::Insert { relation, .. } => {
+                    let values = stack.pop().ok_or_else(|| {
+                        QueryPlannerError::CustomError(
+                            "Insert node failed to get a value row.".into(),
+                        )
+                    })?;
+
+                    current_node.children.push(values);
+
+                    Some(ExplainNode::Insert(relation.into()))
                 }
             };
             stack.push(current_node);
diff --git a/src/ir/explain/tests.rs b/src/ir/explain/tests.rs
index 152049aa9fd08a5927e91126de577042e442aea8..d8a564bc488c913b380cf659629114e594bcddac 100644
--- a/src/ir/explain/tests.rs
+++ b/src/ir/explain/tests.rs
@@ -302,3 +302,90 @@ fn unary_condition_plan() {
 
     assert_eq!(actual_explain, explain_tree.to_string())
 }
+
+#[test]
+fn insert_plan() {
+    let query = r#"INSERT INTO "test_space" ("id", "FIRST_NAME") VALUES (1, '123')"#;
+
+    let plan = sql_to_optimized_ir(query, vec![]);
+
+    let top = &plan.get_top().unwrap();
+    let explain_tree = FullExplain::new(&plan, *top).unwrap();
+
+    let mut actual_explain = String::new();
+    actual_explain.push_str(
+        r#"insert "test_space"
+    motion [policy: segment([ref(COLUMN_1)]), generation: sharding_column]
+        values
+            value row (data=ROW(1, '123'))
+"#,
+    );
+
+    assert_eq!(actual_explain, explain_tree.to_string())
+}
+
+#[test]
+fn multiply_insert_plan() {
+    let query = r#"INSERT INTO "test_space" ("id", "FIRST_NAME") VALUES (1, '123'), (2, '456'), (3, '789')"#;
+
+    let plan = sql_to_optimized_ir(query, vec![]);
+
+    let top = &plan.get_top().unwrap();
+    let explain_tree = FullExplain::new(&plan, *top).unwrap();
+
+    let mut actual_explain = String::new();
+    actual_explain.push_str(
+        r#"insert "test_space"
+    motion [policy: segment([ref(COLUMN_5)]), generation: sharding_column]
+        values
+            value row (data=ROW(1, '123'))
+            value row (data=ROW(2, '456'))
+            value row (data=ROW(3, '789'))
+"#,
+    );
+
+    assert_eq!(actual_explain, explain_tree.to_string())
+}
+
+#[test]
+fn insert_select_plan() {
+    let query = r#"INSERT INTO "test_space" ("id", "FIRST_NAME")
+SELECT "identification_number", "product_code" FROM "hash_testing""#;
+
+    let plan = sql_to_optimized_ir(query, vec![]);
+
+    let top = &plan.get_top().unwrap();
+    let explain_tree = FullExplain::new(&plan, *top).unwrap();
+
+    let mut actual_explain = String::new();
+    actual_explain.push_str(
+        r#"insert "test_space"
+    motion [policy: segment([ref("identification_number")]), generation: sharding_column]
+        projection ("hash_testing"."identification_number" -> "identification_number", "hash_testing"."product_code" -> "product_code")
+            scan "hash_testing"
+"#,
+    );
+
+    assert_eq!(actual_explain, explain_tree.to_string())
+}
+
+#[test]
+fn select_value_plan() {
+    let query = r#"select * from (values (1))"#;
+
+    let plan = sql_to_optimized_ir(query, vec![]);
+
+    let top = &plan.get_top().unwrap();
+    let explain_tree = FullExplain::new(&plan, *top).unwrap();
+
+    let mut actual_explain = String::new();
+    actual_explain.push_str(
+        r#"projection (COLUMN_1 -> COLUMN_1)
+    scan
+        values
+            value row (data=ROW(1))
+"#,
+    );
+
+    assert_eq!(actual_explain, explain_tree.to_string())
+}