mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-26 17:04:10 +00:00
Add support for DEFERRED, IMMEDIATE, and EXCLUSIVE in SQLite's BEGIN TRANSACTION command (#1067)
This commit is contained in:
parent
40bc407799
commit
1baec96685
7 changed files with 94 additions and 2 deletions
|
@ -1905,6 +1905,8 @@ pub enum Statement {
|
|||
StartTransaction {
|
||||
modes: Vec<TransactionMode>,
|
||||
begin: bool,
|
||||
/// Only for SQLite
|
||||
modifier: Option<TransactionModifier>,
|
||||
},
|
||||
/// ```sql
|
||||
/// SET TRANSACTION ...
|
||||
|
@ -3253,9 +3255,14 @@ impl fmt::Display for Statement {
|
|||
Statement::StartTransaction {
|
||||
modes,
|
||||
begin: syntax_begin,
|
||||
modifier,
|
||||
} => {
|
||||
if *syntax_begin {
|
||||
if let Some(modifier) = *modifier {
|
||||
write!(f, "BEGIN {} TRANSACTION", modifier)?;
|
||||
} else {
|
||||
write!(f, "BEGIN TRANSACTION")?;
|
||||
}
|
||||
} else {
|
||||
write!(f, "START TRANSACTION")?;
|
||||
}
|
||||
|
@ -4444,6 +4451,29 @@ impl fmt::Display for TransactionIsolationLevel {
|
|||
}
|
||||
}
|
||||
|
||||
/// SQLite specific syntax
|
||||
///
|
||||
/// <https://sqlite.org/lang_transaction.html>
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub enum TransactionModifier {
|
||||
Deferred,
|
||||
Immediate,
|
||||
Exclusive,
|
||||
}
|
||||
|
||||
impl fmt::Display for TransactionModifier {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use TransactionModifier::*;
|
||||
f.write_str(match self {
|
||||
Deferred => "DEFERRED",
|
||||
Immediate => "IMMEDIATE",
|
||||
Exclusive => "EXCLUSIVE",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
|
|
|
@ -38,4 +38,8 @@ impl Dialect for GenericDialect {
|
|||
fn supports_group_by_expr(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn supports_start_transaction_modifier(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,6 +137,10 @@ pub trait Dialect: Debug + Any {
|
|||
fn supports_in_empty_list(&self) -> bool {
|
||||
false
|
||||
}
|
||||
/// Returns true if the dialect supports `BEGIN {DEFERRED | IMMEDIATE | EXCLUSIVE} [TRANSACTION]` statements
|
||||
fn supports_start_transaction_modifier(&self) -> bool {
|
||||
false
|
||||
}
|
||||
/// Returns true if the dialect has a CONVERT function which accepts a type first
|
||||
/// and an expression second, e.g. `CONVERT(varchar, 1)`
|
||||
fn convert_type_before_value(&self) -> bool {
|
||||
|
|
|
@ -40,6 +40,10 @@ impl Dialect for SQLiteDialect {
|
|||
true
|
||||
}
|
||||
|
||||
fn supports_start_transaction_modifier(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn is_identifier_part(&self, ch: char) -> bool {
|
||||
self.is_identifier_start(ch) || ch.is_ascii_digit()
|
||||
}
|
||||
|
|
|
@ -209,6 +209,7 @@ define_keywords!(
|
|||
DECIMAL,
|
||||
DECLARE,
|
||||
DEFAULT,
|
||||
DEFERRED,
|
||||
DELETE,
|
||||
DELIMITED,
|
||||
DELIMITER,
|
||||
|
@ -255,6 +256,7 @@ define_keywords!(
|
|||
EVERY,
|
||||
EXCEPT,
|
||||
EXCLUDE,
|
||||
EXCLUSIVE,
|
||||
EXEC,
|
||||
EXECUTE,
|
||||
EXISTS,
|
||||
|
@ -322,6 +324,7 @@ define_keywords!(
|
|||
IF,
|
||||
IGNORE,
|
||||
ILIKE,
|
||||
IMMEDIATE,
|
||||
IMMUTABLE,
|
||||
IN,
|
||||
INCLUDE,
|
||||
|
|
|
@ -7961,14 +7961,27 @@ impl<'a> Parser<'a> {
|
|||
Ok(Statement::StartTransaction {
|
||||
modes: self.parse_transaction_modes()?,
|
||||
begin: false,
|
||||
modifier: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_begin(&mut self) -> Result<Statement, ParserError> {
|
||||
let modifier = if !self.dialect.supports_start_transaction_modifier() {
|
||||
None
|
||||
} else if self.parse_keyword(Keyword::DEFERRED) {
|
||||
Some(TransactionModifier::Deferred)
|
||||
} else if self.parse_keyword(Keyword::IMMEDIATE) {
|
||||
Some(TransactionModifier::Immediate)
|
||||
} else if self.parse_keyword(Keyword::EXCLUSIVE) {
|
||||
Some(TransactionModifier::Exclusive)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let _ = self.parse_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK]);
|
||||
Ok(Statement::StartTransaction {
|
||||
modes: self.parse_transaction_modes()?,
|
||||
begin: true,
|
||||
modifier,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ use test_utils::*;
|
|||
use sqlparser::ast::SelectItem::UnnamedExpr;
|
||||
use sqlparser::ast::*;
|
||||
use sqlparser::dialect::{GenericDialect, SQLiteDialect};
|
||||
use sqlparser::parser::ParserOptions;
|
||||
use sqlparser::parser::{ParserError, ParserOptions};
|
||||
use sqlparser::tokenizer::Token;
|
||||
|
||||
#[test]
|
||||
|
@ -435,6 +435,40 @@ fn invalid_empty_list() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_start_transaction_with_modifier() {
|
||||
sqlite_and_generic().verified_stmt("BEGIN DEFERRED TRANSACTION");
|
||||
sqlite_and_generic().verified_stmt("BEGIN IMMEDIATE TRANSACTION");
|
||||
sqlite_and_generic().verified_stmt("BEGIN EXCLUSIVE TRANSACTION");
|
||||
sqlite_and_generic().one_statement_parses_to("BEGIN DEFERRED", "BEGIN DEFERRED TRANSACTION");
|
||||
sqlite_and_generic().one_statement_parses_to("BEGIN IMMEDIATE", "BEGIN IMMEDIATE TRANSACTION");
|
||||
sqlite_and_generic().one_statement_parses_to("BEGIN EXCLUSIVE", "BEGIN EXCLUSIVE TRANSACTION");
|
||||
|
||||
let unsupported_dialects = TestedDialects {
|
||||
dialects: all_dialects()
|
||||
.dialects
|
||||
.into_iter()
|
||||
.filter(|x| !(x.is::<SQLiteDialect>() || x.is::<GenericDialect>()))
|
||||
.collect(),
|
||||
options: None,
|
||||
};
|
||||
let res = unsupported_dialects.parse_sql_statements("BEGIN DEFERRED");
|
||||
assert_eq!(
|
||||
ParserError::ParserError("Expected end of statement, found: DEFERRED".to_string()),
|
||||
res.unwrap_err(),
|
||||
);
|
||||
let res = unsupported_dialects.parse_sql_statements("BEGIN IMMEDIATE");
|
||||
assert_eq!(
|
||||
ParserError::ParserError("Expected end of statement, found: IMMEDIATE".to_string()),
|
||||
res.unwrap_err(),
|
||||
);
|
||||
let res = unsupported_dialects.parse_sql_statements("BEGIN EXCLUSIVE");
|
||||
assert_eq!(
|
||||
ParserError::ParserError("Expected end of statement, found: EXCLUSIVE".to_string()),
|
||||
res.unwrap_err(),
|
||||
);
|
||||
}
|
||||
|
||||
fn sqlite() -> TestedDialects {
|
||||
TestedDialects {
|
||||
dialects: vec![Box::new(SQLiteDialect {})],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue