diff --git a/lib/src/dbs/executor.rs b/lib/src/dbs/executor.rs index 87c35373..c171a4ee 100644 --- a/lib/src/dbs/executor.rs +++ b/lib/src/dbs/executor.rs @@ -35,10 +35,10 @@ impl<'a> Executor<'a> { } } - async fn begin(&mut self) -> bool { + async fn begin(&mut self, write: bool) -> bool { match self.txn.as_ref() { Some(_) => false, - None => match self.kvs.transaction(true, false).await { + None => match self.kvs.transaction(write, false).await { Ok(v) => { self.txn = Some(Arc::new(Mutex::new(v))); true @@ -155,7 +155,7 @@ impl<'a> Executor<'a> { } // Begin a new transaction Statement::Begin(_) => { - self.begin().await; + self.begin(true).await; continue; } // Cancel a running transaction @@ -208,7 +208,7 @@ impl<'a> Executor<'a> { // Process param definition statements Statement::Set(stm) => { // Create a transaction - let loc = self.begin().await; + let loc = self.begin(stm.writeable()).await; // Process the statement match stm.compute(&ctx, &opt, &self.txn(), None).await { Ok(val) => { @@ -228,7 +228,7 @@ impl<'a> Executor<'a> { // Compute the statement normally false => { // Create a transaction - let loc = self.begin().await; + let loc = self.begin(stm.writeable()).await; // Process the statement let res = match stm.timeout() { // There is a timeout clause diff --git a/lib/src/sql/statement.rs b/lib/src/sql/statement.rs index 044a6d9c..0cdaf4a4 100644 --- a/lib/src/sql/statement.rs +++ b/lib/src/sql/statement.rs @@ -59,8 +59,8 @@ pub fn statements(i: &str) -> IResult<&str, Statements> { #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum Statement { - Set(SetStatement), Use(UseStatement), + Set(SetStatement), Info(InfoStatement), Live(LiveStatement), Kill(KillStatement), @@ -92,9 +92,29 @@ impl Statement { _ => None, } } -} -impl Statement { + pub(crate) fn writeable(&self) -> bool { + match self { + Statement::Use(_) => false, + Statement::Set(v) => v.writeable(), + Statement::Info(_) => false, + Statement::Live(_) => true, + Statement::Kill(_) => true, + Statement::Output(v) => v.writeable(), + Statement::Ifelse(v) => v.writeable(), + Statement::Select(v) => v.writeable(), + Statement::Create(v) => v.writeable(), + Statement::Update(v) => v.writeable(), + Statement::Relate(v) => v.writeable(), + Statement::Delete(v) => v.writeable(), + Statement::Insert(v) => v.writeable(), + Statement::Define(_) => true, + Statement::Remove(_) => true, + Statement::Option(_) => false, + _ => unreachable!(), + } + } + pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/create.rs b/lib/src/sql/statements/create.rs index 43a1cadd..a2166f0d 100644 --- a/lib/src/sql/statements/create.rs +++ b/lib/src/sql/statements/create.rs @@ -28,6 +28,10 @@ pub struct CreateStatement { } impl CreateStatement { + pub(crate) fn writeable(&self) -> bool { + true + } + pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/delete.rs b/lib/src/sql/statements/delete.rs index 38474c99..bcffcbbf 100644 --- a/lib/src/sql/statements/delete.rs +++ b/lib/src/sql/statements/delete.rs @@ -29,6 +29,10 @@ pub struct DeleteStatement { } impl DeleteStatement { + pub(crate) fn writeable(&self) -> bool { + true + } + pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/ifelse.rs b/lib/src/sql/statements/ifelse.rs index 3860ebd5..8b966b25 100644 --- a/lib/src/sql/statements/ifelse.rs +++ b/lib/src/sql/statements/ifelse.rs @@ -19,6 +19,15 @@ pub struct IfelseStatement { } impl IfelseStatement { + pub(crate) fn writeable(&self) -> bool { + for (cond, then) in self.exprs.iter() { + if cond.writeable() || then.writeable() { + return true; + } + } + self.close.as_ref().map_or(false, |v| v.writeable()) + } + pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/insert.rs b/lib/src/sql/statements/insert.rs index 23caedcd..b59d47dd 100644 --- a/lib/src/sql/statements/insert.rs +++ b/lib/src/sql/statements/insert.rs @@ -32,6 +32,10 @@ pub struct InsertStatement { } impl InsertStatement { + pub(crate) fn writeable(&self) -> bool { + true + } + pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/output.rs b/lib/src/sql/statements/output.rs index 6f5f46a7..64a8b9d5 100644 --- a/lib/src/sql/statements/output.rs +++ b/lib/src/sql/statements/output.rs @@ -16,6 +16,10 @@ pub struct OutputStatement { } impl OutputStatement { + pub(crate) fn writeable(&self) -> bool { + self.what.writeable() + } + pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/relate.rs b/lib/src/sql/statements/relate.rs index ee3aa66c..97265c9d 100644 --- a/lib/src/sql/statements/relate.rs +++ b/lib/src/sql/statements/relate.rs @@ -35,6 +35,10 @@ pub struct RelateStatement { } impl RelateStatement { + pub(crate) fn writeable(&self) -> bool { + true + } + pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/select.rs b/lib/src/sql/statements/select.rs index d4ca8fdb..05db314c 100644 --- a/lib/src/sql/statements/select.rs +++ b/lib/src/sql/statements/select.rs @@ -9,7 +9,7 @@ use crate::sql::comment::shouldbespace; use crate::sql::cond::{cond, Cond}; use crate::sql::error::IResult; use crate::sql::fetch::{fetch, Fetchs}; -use crate::sql::field::{fields, Fields}; +use crate::sql::field::{fields, Field, Fields}; use crate::sql::group::{group, Groups}; use crate::sql::limit::{limit, Limit}; use crate::sql::order::{order, Orders}; @@ -42,21 +42,36 @@ pub struct SelectStatement { } impl SelectStatement { + /// Return the statement limit number or 0 if not set pub fn limit(&self) -> usize { match self.limit { Some(Limit(v)) => v, None => 0, } } + + /// Return the statement start number or 0 if not set pub fn start(&self) -> usize { match self.start { Some(Start(v)) => v, None => 0, } } -} -impl SelectStatement { + pub(crate) fn writeable(&self) -> bool { + if self.expr.iter().any(|v| match v { + Field::All => false, + Field::Alone(v) => v.writeable(), + Field::Alias(v, _) => v.writeable(), + }) { + return true; + } + if self.what.iter().any(|v| v.writeable()) { + return true; + } + self.cond.as_ref().map_or(false, |v| v.writeable()) + } + pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/set.rs b/lib/src/sql/statements/set.rs index 9958b40b..c96e49b1 100644 --- a/lib/src/sql/statements/set.rs +++ b/lib/src/sql/statements/set.rs @@ -21,6 +21,10 @@ pub struct SetStatement { } impl SetStatement { + pub(crate) fn writeable(&self) -> bool { + self.what.writeable() + } + pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/statements/update.rs b/lib/src/sql/statements/update.rs index a5ed9ebe..ee1516ed 100644 --- a/lib/src/sql/statements/update.rs +++ b/lib/src/sql/statements/update.rs @@ -30,6 +30,10 @@ pub struct UpdateStatement { } impl UpdateStatement { + pub(crate) fn writeable(&self) -> bool { + true + } + pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/subquery.rs b/lib/src/sql/subquery.rs index 6ba5da0f..81dcbbb2 100644 --- a/lib/src/sql/subquery.rs +++ b/lib/src/sql/subquery.rs @@ -38,6 +38,19 @@ impl PartialOrd for Subquery { } impl Subquery { + pub(crate) fn writeable(&self) -> bool { + match self { + Subquery::Value(v) => v.writeable(), + Subquery::Ifelse(v) => v.writeable(), + Subquery::Select(v) => v.writeable(), + Subquery::Create(v) => v.writeable(), + Subquery::Update(v) => v.writeable(), + Subquery::Delete(v) => v.writeable(), + Subquery::Relate(v) => v.writeable(), + Subquery::Insert(v) => v.writeable(), + } + } + pub(crate) async fn compute( &self, ctx: &Context<'_>, diff --git a/lib/src/sql/value/value.rs b/lib/src/sql/value/value.rs index 57fe55d0..f96f024a 100644 --- a/lib/src/sql/value/value.rs +++ b/lib/src/sql/value/value.rs @@ -967,6 +967,17 @@ impl fmt::Display for Value { } impl Value { + pub(crate) fn writeable(&self) -> bool { + match self { + Value::Array(v) => v.iter().any(|v| v.writeable()), + Value::Object(v) => v.iter().any(|(_, v)| v.writeable()), + Value::Function(v) => v.args().iter().any(|v| v.writeable()), + Value::Subquery(v) => v.writeable(), + Value::Expression(v) => v.l.writeable() || v.r.writeable(), + _ => false, + } + } + #[cfg_attr(feature = "parallel", async_recursion)] #[cfg_attr(not(feature = "parallel"), async_recursion(?Send))] pub(crate) async fn compute(