Emit Affinity instruction for unique index, and use no_constant_opt

This commit is contained in:
PThorpe92
2025-09-21 13:24:48 -04:00
parent 63177c42e4
commit e545e75e31

View File

@@ -1,6 +1,7 @@
// This module contains code for emitting bytecode instructions for SQL query execution.
// It handles translating high-level SQL operations into low-level bytecode that can be executed by the virtual machine.
use std::num::NonZeroUsize;
use std::sync::Arc;
use tracing::{instrument, Level};
@@ -25,8 +26,8 @@ use crate::function::Func;
use crate::schema::{BTreeTable, Column, Schema, Table};
use crate::translate::compound_select::emit_program_for_compound_select;
use crate::translate::expr::{
emit_returning_results, translate_condition_expr, translate_expr_no_constant_opt,
walk_expr_mut, ConditionMetadata, NoConstantOptReason, ReturningValueRegisters, WalkControl,
emit_returning_results, translate_expr_no_constant_opt, walk_expr_mut, NoConstantOptReason,
ReturningValueRegisters, WalkControl,
};
use crate::translate::plan::{DeletePlan, JoinedTable, Plan, QueryDestination, Search};
use crate::translate::result_row::try_fold_expr_to_i64;
@@ -578,17 +579,20 @@ fn emit_delete_insns(
.bind_where_expr(Some(table_references), connection)
.expect("where clause to exist");
let skip_label = program.allocate_label();
translate_condition_expr(
let reg = program.alloc_register();
translate_expr_no_constant_opt(
program,
table_references,
Some(table_references),
&where_copy,
ConditionMetadata {
jump_if_condition_is_true: false,
jump_target_when_false: skip_label,
jump_target_when_true: BranchOffset::Placeholder,
},
reg,
&t_ctx.resolver,
NoConstantOptReason::RegisterReuse,
)?;
program.emit_insn(Insn::IfNot {
reg,
jump_if_null: true,
target_pc: skip_label,
});
Some(skip_label)
} else {
None
@@ -1075,7 +1079,7 @@ fn emit_update_insns(
.bind_where_expr(Some(&mut plan.table_references), connection)
.expect("where clause to exist");
let old_satisfied_reg = program.alloc_register();
let old_satisfied_reg = translate_expr_no_constant_opt(
translate_expr_no_constant_opt(
program,
Some(&plan.table_references),
&where_clause,
@@ -1100,12 +1104,13 @@ fn emit_update_insns(
)?;
let new_satisfied_reg = program.alloc_register();
translate_expr(
translate_expr_no_constant_opt(
program,
None,
&new_where,
new_satisfied_reg,
&t_ctx.resolver,
NoConstantOptReason::RegisterReuse,
)?;
// now we have two registers that tell us whether or not the old and new values satisfy
@@ -1204,6 +1209,20 @@ fn emit_update_insns(
// Handle unique constraint
if index.unique {
let aff = index
.columns
.iter()
.map(|ic| {
unsafe { &*table_ref }.columns()[ic.pos_in_table]
.affinity()
.aff_mask()
})
.collect::<String>();
program.emit_insn(Insn::Affinity {
start_reg: idx_start_reg,
count: NonZeroUsize::new(num_cols).expect("nonzero col count"),
affinities: aff,
});
let constraint_check = program.allocate_label();
// check if the record already exists in the index for unique indexes and abort if so
program.emit_insn(Insn::NoConflict {
@@ -1782,24 +1801,32 @@ fn rewrite_where_for_update_registers(
match e {
Expr::Qualified(_, col) | Expr::DoublyQualified(_, _, col) => {
let normalized = normalize_ident(col.as_str());
if let Some((idx, _)) = columns.iter().enumerate().find(|(_, c)| {
if let Some((idx, c)) = columns.iter().enumerate().find(|(_, c)| {
c.name
.as_ref()
.is_some_and(|n| n.eq_ignore_ascii_case(&normalized))
}) {
*e = Expr::Register(columns_start_reg + idx);
if c.is_rowid_alias {
*e = Expr::Register(rowid_reg);
} else {
*e = Expr::Register(columns_start_reg + idx);
}
}
}
Expr::Id(ast::Name::Ident(name)) | Expr::Id(ast::Name::Quoted(name)) => {
let normalized = normalize_ident(name.as_str());
if normalized.eq_ignore_ascii_case("rowid") {
*e = Expr::Register(rowid_reg);
} else if let Some((idx, _)) = columns.iter().enumerate().find(|(_, c)| {
} else if let Some((idx, c)) = columns.iter().enumerate().find(|(_, c)| {
c.name
.as_ref()
.is_some_and(|n| n.eq_ignore_ascii_case(&normalized))
}) {
*e = Expr::Register(columns_start_reg + idx);
if c.is_rowid_alias {
*e = Expr::Register(rowid_reg);
} else {
*e = Expr::Register(columns_start_reg + idx);
}
}
}
Expr::RowId { .. } => {