mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-09 18:24:20 +01:00
VDBE: handle subtransaction commits/aborts in op_halt
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
#![allow(unused_variables)]
|
||||
use crate::error::{SQLITE_CONSTRAINT_FOREIGNKEY, SQLITE_CONSTRAINT_UNIQUE};
|
||||
use crate::error::SQLITE_CONSTRAINT_UNIQUE;
|
||||
use crate::function::AlterTableFunc;
|
||||
use crate::mvcc::database::CheckpointStateMachine;
|
||||
use crate::numeric::{NullableInteger, Numeric};
|
||||
@@ -21,7 +21,7 @@ use crate::util::{
|
||||
normalize_ident, rewrite_column_references_if_needed, rewrite_fk_parent_cols_if_self_ref,
|
||||
};
|
||||
use crate::vdbe::insn::InsertFlags;
|
||||
use crate::vdbe::{registers_to_ref_values, TxnCleanup};
|
||||
use crate::vdbe::{registers_to_ref_values, EndStatement, TxnCleanup};
|
||||
use crate::vector::{vector32_sparse, vector_concat, vector_distance_jaccard, vector_slice};
|
||||
use crate::{
|
||||
error::{
|
||||
@@ -2149,8 +2149,8 @@ pub fn halt(
|
||||
description: &str,
|
||||
) -> Result<InsnFunctionStepResult> {
|
||||
if err_code > 0 {
|
||||
// invalidate page cache in case of error
|
||||
pager.clear_page_cache(false);
|
||||
// Any non-FK constraint violation causes the statement subtransaction to roll back.
|
||||
state.end_statement(&program.connection, &pager, EndStatement::RollbackSavepoint)?;
|
||||
}
|
||||
match err_code {
|
||||
0 => {}
|
||||
@@ -2169,9 +2169,6 @@ pub fn halt(
|
||||
"UNIQUE constraint failed: {description} (19)"
|
||||
)));
|
||||
}
|
||||
SQLITE_CONSTRAINT_FOREIGNKEY => {
|
||||
return Err(LimboError::Constraint(format!("{description} (19)")));
|
||||
}
|
||||
_ => {
|
||||
return Err(LimboError::Constraint(format!(
|
||||
"undocumented halt error code {description}"
|
||||
@@ -2181,23 +2178,46 @@ pub fn halt(
|
||||
|
||||
let auto_commit = program.connection.auto_commit.load(Ordering::SeqCst);
|
||||
tracing::trace!("halt(auto_commit={})", auto_commit);
|
||||
|
||||
// Check for immediate foreign key violations.
|
||||
// Any immediate violation causes the statement subtransaction to roll back.
|
||||
if program.connection.foreign_keys_enabled()
|
||||
&& state
|
||||
.fk_immediate_violations_during_stmt
|
||||
.load(Ordering::Acquire)
|
||||
> 0
|
||||
{
|
||||
state.end_statement(&program.connection, &pager, EndStatement::RollbackSavepoint)?;
|
||||
return Err(LimboError::Constraint(
|
||||
"foreign key constraint failed".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if auto_commit {
|
||||
// In autocommit mode, a statement that leaves deferred violations must fail here.
|
||||
if program.connection.foreign_keys_enabled()
|
||||
&& program
|
||||
// In autocommit mode, a statement that leaves deferred violations must fail here,
|
||||
// and it also ends the transaction.
|
||||
if program.connection.foreign_keys_enabled() {
|
||||
let deferred_violations = program
|
||||
.connection
|
||||
.fk_deferred_violations
|
||||
.swap(0, Ordering::AcqRel)
|
||||
> 0
|
||||
{
|
||||
return Err(LimboError::Constraint(
|
||||
"foreign key constraint failed".to_string(),
|
||||
));
|
||||
.swap(0, Ordering::AcqRel);
|
||||
if deferred_violations > 0 {
|
||||
pager.rollback_tx(&program.connection);
|
||||
program.connection.set_tx_state(TransactionState::None);
|
||||
program.connection.auto_commit.store(true, Ordering::SeqCst);
|
||||
return Err(LimboError::Constraint(
|
||||
"foreign key constraint failed".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
state.end_statement(&program.connection, &pager, EndStatement::ReleaseSavepoint)?;
|
||||
program
|
||||
.commit_txn(pager.clone(), state, mv_store, false)
|
||||
.map(Into::into)
|
||||
} else {
|
||||
// Even if deferred violations are present, the statement subtransaction completes successfully when
|
||||
// it is part of an interactive transaction.
|
||||
state.end_statement(&program.connection, &pager, EndStatement::ReleaseSavepoint)?;
|
||||
Ok(InsnFunctionStepResult::Done)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user