From 1f24b51bfd705bd0e06bc5e165942c462d67ca77 Mon Sep 17 00:00:00 2001 From: Denis Smirnov <sd@picodata.io> Date: Mon, 5 Feb 2024 16:47:52 +0700 Subject: [PATCH] feat: introduce a new node type - code block --- sbroad-core/src/backend/sql/ir.rs | 9 ++++ sbroad-core/src/backend/sql/tree.rs | 6 +++ sbroad-core/src/errors.rs | 3 ++ sbroad-core/src/executor.rs | 12 ++++- sbroad-core/src/executor/ir.rs | 4 ++ sbroad-core/src/ir.rs | 58 +++++++++++++++-------- sbroad-core/src/ir/api/parameter.rs | 4 +- sbroad-core/src/ir/block.rs | 64 ++++++++++++++++++++++++++ sbroad-core/src/ir/distribution.rs | 4 ++ sbroad-core/src/ir/expression/types.rs | 4 ++ sbroad-core/src/ir/tree/expression.rs | 3 +- sbroad-core/src/ir/tree/relation.rs | 3 +- sbroad-core/src/ir/tree/subtree.rs | 2 +- 13 files changed, 150 insertions(+), 26 deletions(-) create mode 100644 sbroad-core/src/ir/block.rs diff --git a/sbroad-core/src/backend/sql/ir.rs b/sbroad-core/src/backend/sql/ir.rs index 022374d1ca..aa8c94c4c0 100644 --- a/sbroad-core/src/backend/sql/ir.rs +++ b/sbroad-core/src/backend/sql/ir.rs @@ -297,6 +297,15 @@ impl ExecutionPlan { Some("ACL nodes are not supported in the generated SQL".into()), )); } + Node::Block(_) => { + return Err(SbroadError::Unsupported( + Entity::Node, + Some( + "Code block nodes are not supported in the generated SQL" + .into(), + ), + )); + } Node::Parameter => { return Err(SbroadError::Unsupported( Entity::Node, diff --git a/sbroad-core/src/backend/sql/tree.rs b/sbroad-core/src/backend/sql/tree.rs index e1c609029d..dc67aba054 100644 --- a/sbroad-core/src/backend/sql/tree.rs +++ b/sbroad-core/src/backend/sql/tree.rs @@ -665,6 +665,12 @@ impl<'p> SyntaxPlan<'p> { "ACL node {node:?} is not supported in the syntax plan" )), )), + Node::Block(..) => Err(SbroadError::Invalid( + Entity::SyntaxPlan, + Some(format!( + "Block node {node:?} is not supported in the syntax plan" + )), + )), Node::Parameter => { let sn = SyntaxNode::new_parameter(id); Ok(self.nodes.push_syntax_node(sn)) diff --git a/sbroad-core/src/errors.rs b/sbroad-core/src/errors.rs index da6b1472af..6161b5f996 100644 --- a/sbroad-core/src/errors.rs +++ b/sbroad-core/src/errors.rs @@ -88,6 +88,8 @@ pub enum Entity { OptionSpec, /// corresponds to struct ReferredNodes ReferredNodes, + /// Routine + Routine, /// parser rule Rule, /// corresponds to struct RouterRuntime @@ -182,6 +184,7 @@ impl fmt::Display for Entity { Entity::Relational => "relational".to_string(), Entity::RequiredData => "required data".to_string(), Entity::ReferredNodes => "referred nodes".to_string(), + Entity::Routine => "routine".to_string(), Entity::Rule => "rule".to_string(), Entity::Runtime => "runtime".to_string(), Entity::Option => "option".to_string(), diff --git a/sbroad-core/src/executor.rs b/sbroad-core/src/executor.rs index 7e27a6c5af..cb9ccca14e 100644 --- a/sbroad-core/src/executor.rs +++ b/sbroad-core/src/executor.rs @@ -141,11 +141,11 @@ where } plan.version_map = table_version_map; } - if !plan.is_ddl()? && !plan.is_acl()? { + if !plan.is_ddl()? && !plan.is_acl()? && !plan.is_block()? { cache.put(key, plan.clone())?; } } - if !plan.is_ddl()? && !plan.is_acl()? { + if !plan.is_ddl()? && !plan.is_acl()? && !plan.is_block()? { plan.bind_params(params)?; plan.apply_options()?; plan.optimize()?; @@ -265,6 +265,14 @@ where self.is_explain } + /// Checks that query is a statement block. + /// + /// # Errors + /// - plan is invalid + pub fn is_block(&self) -> Result<bool, SbroadError> { + self.exec_plan.get_ir_plan().is_block() + } + /// Checks that query is DDL. /// /// # Errors diff --git a/sbroad-core/src/executor/ir.rs b/sbroad-core/src/executor/ir.rs index 86c30a86d7..7f2eb82656 100644 --- a/sbroad-core/src/executor/ir.rs +++ b/sbroad-core/src/executor/ir.rs @@ -616,6 +616,10 @@ impl ExecutionPlan { Entity::SubTree, Some("ACL node".to_string()), ))?, + Node::Block { .. } => Err(SbroadError::Invalid( + Entity::SubTree, + Some("code block node".to_string()), + ))?, } new_plan.nodes.push(node); translation.insert(node_id, next_id); diff --git a/sbroad-core/src/ir.rs b/sbroad-core/src/ir.rs index 0ded073e7c..1996287173 100644 --- a/sbroad-core/src/ir.rs +++ b/sbroad-core/src/ir.rs @@ -12,6 +12,7 @@ use std::slice::Iter; use tarantool::tlua; use acl::Acl; +use block::Block; use ddl::Ddl; use expression::Expression; use operator::{Arithmetic, Relational}; @@ -38,6 +39,7 @@ use self::relation::Relations; #[allow(elided_lifetimes_in_associated_constant)] pub mod acl; pub mod aggregates; +pub mod block; pub mod ddl; pub mod distribution; pub mod expression; @@ -69,6 +71,7 @@ const DEFAULT_VDBE_MAX_STEPS: u64 = 45000; #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub enum Node { Acl(Acl), + Block(Block), Ddl(Ddl), Expression(Expression), Relational(Relational), @@ -804,6 +807,15 @@ impl Plan { self.is_explain } + /// Checks that plan is a block of queries. + /// + /// # Errors + /// - top node doesn't exist in the plan or is invalid. + pub fn is_block(&self) -> Result<bool, SbroadError> { + let top_id = self.get_top()?; + Ok(matches!(self.get_node(top_id)?, Node::Block(..))) + } + /// Checks that plan is DDL query /// /// # Errors @@ -840,12 +852,14 @@ impl Plan { let node = self.get_node(node_id)?; match node { Node::Relational(rel) => Ok(rel), - Node::Expression(_) | Node::Parameter | Node::Ddl(..) | Node::Acl(..) => { - Err(SbroadError::Invalid( - Entity::Node, - Some(format!("node is not Relational type: {node:?}")), - )) - } + Node::Expression(_) + | Node::Parameter + | Node::Ddl(..) + | Node::Acl(..) + | Node::Block(..) => Err(SbroadError::Invalid( + Entity::Node, + Some(format!("node is not Relational type: {node:?}")), + )), } } @@ -860,9 +874,14 @@ impl Plan { ) -> Result<&mut Relational, SbroadError> { match self.get_mut_node(node_id)? { Node::Relational(rel) => Ok(rel), - Node::Expression(_) | Node::Parameter | Node::Ddl(..) | Node::Acl(..) => Err( - SbroadError::Invalid(Entity::Node, Some("Node is not relational".into())), - ), + Node::Expression(_) + | Node::Parameter + | Node::Ddl(..) + | Node::Acl(..) + | Node::Block(..) => Err(SbroadError::Invalid( + Entity::Node, + Some("Node is not relational".into()), + )), } } @@ -885,10 +904,9 @@ impl Plan { )) } } - Node::Relational(_) | Node::Ddl(..) | Node::Acl(..) => Err(SbroadError::Invalid( - Entity::Node, - Some("node is not Expression type".into()), - )), + Node::Relational(_) | Node::Ddl(..) | Node::Acl(..) | Node::Block(..) => Err( + SbroadError::Invalid(Entity::Node, Some("node is not Expression type".into())), + ), } } @@ -904,12 +922,14 @@ impl Plan { let node = self.get_mut_node(node_id)?; match node { Node::Expression(exp) => Ok(exp), - Node::Relational(_) | Node::Parameter | Node::Ddl(..) | Node::Acl(..) => { - Err(SbroadError::Invalid( - Entity::Node, - Some(format!("node ({node_id}) is not expression type: {node:?}")), - )) - } + Node::Relational(_) + | Node::Parameter + | Node::Ddl(..) + | Node::Acl(..) + | Node::Block(..) => Err(SbroadError::Invalid( + Entity::Node, + Some(format!("node ({node_id}) is not expression type: {node:?}")), + )), } } diff --git a/sbroad-core/src/ir/api/parameter.rs b/sbroad-core/src/ir/api/parameter.rs index a15a34f2d3..0683099344 100644 --- a/sbroad-core/src/ir/api/parameter.rs +++ b/sbroad-core/src/ir/api/parameter.rs @@ -247,7 +247,7 @@ impl Plan { | Expression::Constant { .. } | Expression::CountAsterisk => {} }, - Node::Parameter | Node::Ddl(..) | Node::Acl(..) => {} + Node::Parameter | Node::Ddl(..) | Node::Acl(..) | Node::Block(..) => {} } } @@ -360,7 +360,7 @@ impl Plan { | Expression::Constant { .. } | Expression::CountAsterisk => {} }, - Node::Parameter | Node::Ddl(..) | Node::Acl(..) => {} + Node::Parameter | Node::Ddl(..) | Node::Acl(..) | Node::Block(..) => {} } } diff --git a/sbroad-core/src/ir/block.rs b/sbroad-core/src/ir/block.rs new file mode 100644 index 0000000000..be8d4e140b --- /dev/null +++ b/sbroad-core/src/ir/block.rs @@ -0,0 +1,64 @@ +use crate::errors::{Entity, SbroadError}; +use crate::ir::{Node, NodeId, Plan}; + +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub enum Block { + /// Procedure body. + Procedure { + /// The name of the procedure. + name: String, + /// Passed values to the procedure. + values: Vec<NodeId>, + }, +} + +impl Default for Block { + fn default() -> Self { + Block::Procedure { + name: String::new(), + values: vec![], + } + } +} + +impl Plan { + /// Get a reference to a block node. + /// + /// # Errors + /// - the node is not a block node. + pub fn get_block_node(&self, node_id: NodeId) -> Result<&Block, SbroadError> { + let node = self.get_node(node_id)?; + match node { + Node::Block(block) => Ok(block), + Node::Expression(_) + | Node::Relational(_) + | Node::Ddl(..) + | Node::Acl(..) + | Node::Parameter => Err(SbroadError::Invalid( + Entity::Node, + Some(format!("node {node:?} (id {node_id}) is not Block type")), + )), + } + } + + /// Get a mutable reference to a block node. + /// + /// # Errors + /// - the node is not a block node. + pub fn get_mut_block_node(&mut self, node_id: NodeId) -> Result<&mut Block, SbroadError> { + let node = self.get_mut_node(node_id)?; + match node { + Node::Block(block) => Ok(block), + Node::Expression(_) + | Node::Relational(_) + | Node::Ddl(..) + | Node::Acl(..) + | Node::Parameter => Err(SbroadError::Invalid( + Entity::Node, + Some(format!("node {node:?} (id {node_id}) is not Block type")), + )), + } + } +} diff --git a/sbroad-core/src/ir/distribution.rs b/sbroad-core/src/ir/distribution.rs index e865b3d4b0..832d16d0d7 100644 --- a/sbroad-core/src/ir/distribution.rs +++ b/sbroad-core/src/ir/distribution.rs @@ -798,6 +798,10 @@ impl Plan { Entity::Distribution, Some("Failed to get distribution for a ACL node.".to_string()), )), + Node::Block(_) => Err(SbroadError::Invalid( + Entity::Distribution, + Some("Failed to get distribution for a code block node.".to_string()), + )), } } diff --git a/sbroad-core/src/ir/expression/types.rs b/sbroad-core/src/ir/expression/types.rs index 08e231eed2..38bffe7386 100644 --- a/sbroad-core/src/ir/expression/types.rs +++ b/sbroad-core/src/ir/expression/types.rs @@ -22,6 +22,10 @@ impl Plan { Entity::Node, Some("ACL node has no type".to_string()), )), + Node::Block(_) => Err(SbroadError::Invalid( + Entity::Node, + Some("code block node has no type".to_string()), + )), } } } diff --git a/sbroad-core/src/ir/tree/expression.rs b/sbroad-core/src/ir/tree/expression.rs index d31efa4446..5337a7fee3 100644 --- a/sbroad-core/src/ir/tree/expression.rs +++ b/sbroad-core/src/ir/tree/expression.rs @@ -181,7 +181,8 @@ fn expression_next<'nodes>( | Node::Relational(_) | Node::Parameter | Node::Ddl(_) - | Node::Acl(_), + | Node::Acl(_) + | Node::Block(_), ) | None => None, } diff --git a/sbroad-core/src/ir/tree/relation.rs b/sbroad-core/src/ir/tree/relation.rs index c5366fb6ac..813874718b 100644 --- a/sbroad-core/src/ir/tree/relation.rs +++ b/sbroad-core/src/ir/tree/relation.rs @@ -100,7 +100,8 @@ fn relational_next<'nodes>( | Node::Expression(_) | Node::Parameter | Node::Ddl(_) - | Node::Acl(_), + | Node::Acl(_) + | Node::Block(_), ) | None => None, } diff --git a/sbroad-core/src/ir/tree/subtree.rs b/sbroad-core/src/ir/tree/subtree.rs index b0938f9632..4fca332c72 100644 --- a/sbroad-core/src/ir/tree/subtree.rs +++ b/sbroad-core/src/ir/tree/subtree.rs @@ -195,7 +195,7 @@ fn subtree_next<'plan>( ) -> Option<&'plan usize> { if let Some(child) = iter.get_nodes().arena.get(iter.get_current()) { return match child { - Node::Parameter | Node::Ddl(..) | Node::Acl(..) => None, + Node::Parameter | Node::Ddl(..) | Node::Acl(..) | Node::Block(..) => None, Node::Expression(exp) => match exp { Expression::Alias { child, .. } | Expression::Cast { child, .. } -- GitLab