Merge 'Direct schema mutation – add instruction' from Levy A.

<img width="960" height="205" alt="image" src="https://github.com/user-
attachments/assets/f60a2133-dfe4-4411-9a7c-7283eb073875" />
<img width="944" height="504" alt="image" src="https://github.com/user-
attachments/assets/9383c8e2-4d8d-40b9-8ace-825ca3cf8682" />
```
`ALTER TABLE _ ADD COLUMN _`/limbo_add_column/
                        time:   [2.1199 ms 2.1921 ms 2.2756 ms]
                        change: [-85.983% -85.416% -84.716%] (p = 0.00 < 0.05)
                        Performance has improved.
Found 13 outliers among 100 measurements (13.00%)
  6 (6.00%) high mild
  7 (7.00%) high severe
`ALTER TABLE _ ADD COLUMN _`/sqlite_add_column/
                        time:   [10.358 ms 10.404 ms 10.469 ms]
                        change: [-6.2566% -2.3515% +0.2046%] (p = 0.21 > 0.05)
                        No change in performance detected.
Found 14 outliers among 100 measurements (14.00%)
  2 (2.00%) high mild
  12 (12.00%) high severe
  ```

Reviewed-by: Preston Thorpe <preston@turso.tech>

Closes #2482
This commit is contained in:
Preston Thorpe
2025-08-07 21:31:49 -04:00
committed by GitHub
4 changed files with 63 additions and 20 deletions

View File

@@ -181,7 +181,7 @@ pub fn translate_alter_table(
}
}
btree.columns.push(column);
btree.columns.push(column.clone());
let sql = btree.to_sql();
let mut escaped = String::with_capacity(sql.len());
@@ -219,9 +219,9 @@ pub fn translate_alter_table(
value: schema.schema_version as i32 + 1,
p5: 0,
});
program.emit_insn(Insn::ParseSchema {
db: usize::MAX, // TODO: This value is unused, change when we do something with it
where_clause: None,
program.emit_insn(Insn::AddColumn {
table: table_name.to_owned(),
column,
});
},
)?

View File

@@ -6871,13 +6871,13 @@ pub fn op_drop_column(
pager: &Rc<Pager>,
mv_store: Option<&Arc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
let Insn::DropColumn {
table,
column_index,
} = insn
else {
unreachable!("unexpected Insn {:?}", insn)
};
load_insn!(
DropColumn {
table,
column_index
},
insn
);
let conn = program.connection.clone();
@@ -6887,16 +6887,45 @@ pub fn op_drop_column(
.get_mut(table)
.expect("table being renamed should be in schema");
{
let table = Arc::make_mut(table);
let table = Arc::make_mut(table);
let Table::BTree(btree) = table else {
panic!("only btree tables can be renamed");
};
let Table::BTree(btree) = table else {
panic!("only btree tables can be renamed");
};
let btree = Arc::make_mut(btree);
btree.columns.remove(*column_index)
}
let btree = Arc::make_mut(btree);
btree.columns.remove(*column_index)
});
state.pc += 1;
Ok(InsnFunctionStepResult::Step)
}
pub fn op_add_column(
program: &Program,
state: &mut ProgramState,
insn: &Insn,
pager: &Rc<Pager>,
mv_store: Option<&Arc<MvStore>>,
) -> Result<InsnFunctionStepResult> {
load_insn!(AddColumn { table, column }, insn);
let conn = program.connection.clone();
conn.with_schema_mut(|schema| {
let table = schema
.tables
.get_mut(table)
.expect("table being renamed should be in schema");
let table = Arc::make_mut(table);
let Table::BTree(btree) = table else {
panic!("only btree tables can be renamed");
};
let btree = Arc::make_mut(btree);
btree.columns.push(column.clone())
});
state.pc += 1;

View File

@@ -1645,6 +1645,15 @@ pub fn insn_to_str(
0,
format!("drop_column({table}, {column_index})"),
),
Insn::AddColumn { table, column } => (
"AddColumn",
0,
0,
0,
Value::build_text(""),
0,
format!("add_column({table}, {column:?})"),
),
Insn::MaxPgcnt { db, dest, new_max } => (
"MaxPgcnt",
*db as i32,

View File

@@ -5,7 +5,7 @@ use std::{
use super::{execute, AggFunc, BranchOffset, CursorID, FuncCtx, InsnFunction, PageIdx};
use crate::{
schema::{Affinity, BTreeTable, Index},
schema::{Affinity, BTreeTable, Column, Index},
storage::{pager::CreateBTreeFlags, wal::CheckpointMode},
translate::collate::CollationSeq,
Value,
@@ -1034,6 +1034,10 @@ pub enum Insn {
table: String,
column_index: usize,
},
AddColumn {
table: String,
column: Column,
},
/// Try to set the maximum page count for database P1 to the value in P3.
/// Do not let the maximum page count fall below the current page count and
/// do not change the maximum page count value if P3==0.
@@ -1182,6 +1186,7 @@ impl Insn {
Insn::IntegrityCk { .. } => execute::op_integrity_check,
Insn::RenameTable { .. } => execute::op_rename_table,
Insn::DropColumn { .. } => execute::op_drop_column,
Insn::AddColumn { .. } => execute::op_add_column,
Insn::MaxPgcnt { .. } => execute::op_max_pgcnt,
Insn::JournalMode { .. } => execute::op_journal_mode,
}