fix code in order to not reset internal prepared statements created during DDL execution

This commit is contained in:
Nikita Sivukhin
2025-10-06 15:10:37 +04:00
parent 4877180784
commit 0ace1f9d90
3 changed files with 22 additions and 8 deletions

View File

@@ -47,6 +47,7 @@ use crate::types::{WalFrameInfo, WalState};
#[cfg(feature = "fs")]
use crate::util::{OpenMode, OpenOptions};
use crate::vdbe::metrics::ConnectionMetrics;
use crate::vdbe::PROGRAM_STATE_DONE;
use crate::vtab::VirtualTable;
use crate::{incremental::view::AllViewsTxState, translate::emitter::TransactionMode};
use core::str;
@@ -2572,6 +2573,7 @@ impl Statement {
fn reprepare(&mut self) -> Result<()> {
tracing::trace!("repreparing statement");
let conn = self.program.connection.clone();
*conn.schema.write() = conn.db.clone_schema();
self.program = {
let mut parser = Parser::new(self.program.sql.as_bytes());
@@ -2600,7 +2602,7 @@ impl Statement {
QueryMode::Explain => (EXPLAIN_COLUMNS.len(), 0),
QueryMode::ExplainQueryPlan => (EXPLAIN_QUERY_PLAN_COLUMNS.len(), 0),
};
self._reset(Some(max_registers), Some(cursor_count));
self.reset_internal(Some(max_registers), Some(cursor_count));
// Load the parameters back into the state
self.state.parameters = parameters;
Ok(())
@@ -2714,10 +2716,16 @@ impl Statement {
}
pub fn reset(&mut self) {
self._reset(None, None);
self.reset_internal(None, None);
}
pub fn _reset(&mut self, max_registers: Option<usize>, max_cursors: Option<usize>) {
pub(crate) fn mark_as_done(&self) {
self.program
.program_state
.store(PROGRAM_STATE_DONE, Ordering::SeqCst);
}
fn reset_internal(&mut self, max_registers: Option<usize>, max_cursors: Option<usize>) {
self.state.reset(max_registers, max_cursors);
self.program
.abort(self.mv_store.as_ref(), &self.pager, None);

View File

@@ -8018,12 +8018,15 @@ pub fn op_drop_column(
let schema = conn.schema.read();
for (view_name, view) in schema.views.iter() {
let view_select_sql = format!("SELECT * FROM {view_name}");
conn.prepare(view_select_sql.as_str()).map_err(|e| {
let stmt = conn.prepare(view_select_sql.as_str()).map_err(|e| {
LimboError::ParseError(format!(
"cannot drop column \"{}\": referenced in VIEW {view_name}: {}",
column_name, view.sql,
))
})?;
// this is internal statement running during active Program execution
// so, we must not interact with transaction state and explicitly mark this statement as done avoiding cleanup on reset
stmt.mark_as_done();
}
}
@@ -8149,12 +8152,15 @@ pub fn op_alter_column(
for (view_name, view) in schema.views.iter() {
let view_select_sql = format!("SELECT * FROM {view_name}");
// FIXME: this should rewrite the view to reference the new column name
conn.prepare(view_select_sql.as_str()).map_err(|e| {
let stmt = conn.prepare(view_select_sql.as_str()).map_err(|e| {
LimboError::ParseError(format!(
"cannot rename column \"{}\": referenced in VIEW {view_name}: {}",
old_column_name, view.sql,
))
})?;
// this is internal statement running during active Program execution
// so, we must not interact with transaction state and explicitly mark this statement as done avoiding cleanup on reset
stmt.mark_as_done();
}
}

View File

@@ -483,9 +483,9 @@ macro_rules! get_cursor {
};
}
const PROGRAM_STATE_ACTIVE: u32 = 0;
const PROGRAM_STATE_ABORTED: u32 = 1;
const PROGRAM_STATE_DONE: u32 = 2;
pub(crate) const PROGRAM_STATE_ACTIVE: u32 = 1;
pub(crate) const PROGRAM_STATE_ABORTED: u32 = 2;
pub(crate) const PROGRAM_STATE_DONE: u32 = 3;
pub struct Program {
pub max_registers: usize,