mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-23 17:05:36 +01:00
Remove old unused data structures and functions
This commit is contained in:
@@ -6,7 +6,7 @@ use turso_sqlite3_parser::ast::{
|
||||
};
|
||||
|
||||
use crate::error::{SQLITE_CONSTRAINT_NOTNULL, SQLITE_CONSTRAINT_PRIMARYKEY};
|
||||
use crate::schema::{self, IndexColumn, Table};
|
||||
use crate::schema::{self, Table};
|
||||
use crate::translate::emitter::{
|
||||
emit_cdc_insns, emit_cdc_patch_record, prepare_cdc_if_necessary, OperationMode,
|
||||
};
|
||||
@@ -586,19 +586,6 @@ pub fn translate_insert(
|
||||
Ok(program)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Represents how a column should be populated during an INSERT.
|
||||
/// Contains both the column definition and optionally the index into the VALUES tuple.
|
||||
struct ColumnMapping<'a> {
|
||||
/// Reference to the column definition from the table schema
|
||||
column: &'a Column,
|
||||
/// If Some(i), use the i-th value from the VALUES tuple
|
||||
/// If None, use NULL (column was not specified in INSERT statement)
|
||||
value_index: Option<usize>,
|
||||
/// The default value for the column, if defined
|
||||
default_value: Option<&'a Expr>,
|
||||
}
|
||||
|
||||
pub const ROWID_COLUMN: &Column = &Column {
|
||||
name: None,
|
||||
ty: schema::Type::Integer,
|
||||
@@ -612,302 +599,6 @@ pub const ROWID_COLUMN: &Column = &Column {
|
||||
hidden: false,
|
||||
};
|
||||
|
||||
/// Resolves how each column in a table should be populated during an INSERT.
|
||||
/// Returns a Vec of ColumnMapping, one for each column in the table's schema.
|
||||
///
|
||||
/// For each column, specifies:
|
||||
/// 1. The column definition (type, constraints, etc)
|
||||
/// 2. Where to get the value from:
|
||||
/// - Some(i) -> use i-th value from the VALUES tuple
|
||||
/// - None -> use NULL (column wasn't specified in INSERT)
|
||||
///
|
||||
/// Two cases are handled:
|
||||
/// 1. No column list specified (INSERT INTO t VALUES ...):
|
||||
/// - Values are assigned to columns in table definition order
|
||||
/// - If fewer values than columns, remaining columns map to None
|
||||
/// 2. Column list specified (INSERT INTO t (col1, col3) VALUES ...):
|
||||
/// - Named columns map to their corresponding value index
|
||||
/// - Unspecified columns map to None
|
||||
fn resolve_columns_for_insert<'a>(
|
||||
table: &'a Table,
|
||||
columns: &Option<DistinctNames>,
|
||||
num_values: usize,
|
||||
) -> Result<Vec<ColumnMapping<'a>>> {
|
||||
let table_columns = table.columns();
|
||||
|
||||
// +1 for rowid implicit ROWID column
|
||||
let mut column_mappings = Vec::with_capacity(table_columns.len() + 1);
|
||||
column_mappings.push(ColumnMapping {
|
||||
column: ROWID_COLUMN,
|
||||
value_index: None,
|
||||
default_value: None,
|
||||
});
|
||||
for column in table_columns {
|
||||
column_mappings.push(ColumnMapping {
|
||||
column,
|
||||
value_index: None,
|
||||
default_value: column.default.as_ref(),
|
||||
});
|
||||
}
|
||||
|
||||
if columns.is_none() {
|
||||
// Case 1: No columns specified - map values to columns in order
|
||||
let mut value_idx = 0;
|
||||
for (i, col) in table_columns.iter().enumerate() {
|
||||
column_mappings[i + 1].value_index = if col.hidden { None } else { Some(value_idx) };
|
||||
if !col.hidden {
|
||||
value_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if num_values != value_idx {
|
||||
crate::bail_parse_error!(
|
||||
"table {} has {} columns but {} values were supplied",
|
||||
&table.get_name(),
|
||||
value_idx,
|
||||
num_values
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Case 2: Columns specified - map named columns to their values
|
||||
// Map each named column to its value index
|
||||
for (value_index, column_name) in columns.as_ref().unwrap().iter().enumerate() {
|
||||
let column_name = normalize_ident(column_name.as_str());
|
||||
let table_index = if column_name == ROWID {
|
||||
Some(0)
|
||||
} else {
|
||||
column_mappings.iter().position(|c| {
|
||||
c.column
|
||||
.name
|
||||
.as_ref()
|
||||
.is_some_and(|name| name.eq_ignore_ascii_case(&column_name))
|
||||
})
|
||||
};
|
||||
|
||||
let Some(table_index) = table_index else {
|
||||
crate::bail_parse_error!(
|
||||
"table {} has no column named {}",
|
||||
&table.get_name(),
|
||||
column_name
|
||||
);
|
||||
};
|
||||
|
||||
column_mappings[table_index].value_index = Some(value_index);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(column_mappings)
|
||||
}
|
||||
|
||||
/// Represents how a column in an index should be populated during an INSERT.
|
||||
/// Similar to ColumnMapping above but includes the index name, as well as multiple
|
||||
/// possible value indices for each.
|
||||
#[derive(Debug, Default)]
|
||||
struct IndexColMapping {
|
||||
idx_name: String,
|
||||
columns: Vec<(usize, IndexColumn)>,
|
||||
value_indicies: Vec<Option<usize>>,
|
||||
}
|
||||
|
||||
impl IndexColMapping {
|
||||
fn new(name: String) -> Self {
|
||||
IndexColMapping {
|
||||
idx_name: name,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Example:
|
||||
/// Table 'test': (a, b, c);
|
||||
/// Index 'idx': test(a, b);
|
||||
///________________________________
|
||||
/// Insert (a, c): (2, 3)
|
||||
/// Record: (2, NULL, 3)
|
||||
/// IndexColMapping: (a, b) = (2, NULL)
|
||||
fn resolve_indicies_for_insert(
|
||||
schema: &Schema,
|
||||
table: &Table,
|
||||
columns: &[ColumnMapping<'_>],
|
||||
) -> Result<Vec<IndexColMapping>> {
|
||||
let mut index_col_mappings = Vec::new();
|
||||
// Iterate over all indices for this table
|
||||
for index in schema.get_indices(table.get_name()) {
|
||||
let mut idx_map = IndexColMapping::new(index.name.clone());
|
||||
// For each column in the index (in the order defined by the index),
|
||||
// try to find the corresponding column in the insert’s column mapping.
|
||||
for idx_col in &index.columns {
|
||||
let target_name = normalize_ident(idx_col.name.as_str());
|
||||
if let Some((i, col_mapping)) = columns.iter().enumerate().find(|(_, mapping)| {
|
||||
mapping
|
||||
.column
|
||||
.name
|
||||
.as_ref()
|
||||
.is_some_and(|name| name.eq_ignore_ascii_case(&target_name))
|
||||
}) {
|
||||
idx_map.columns.push((i, idx_col.clone()));
|
||||
idx_map.value_indicies.push(col_mapping.value_index);
|
||||
} else {
|
||||
return Err(crate::LimboError::ParseError(format!(
|
||||
"Column {} not found in index {}",
|
||||
target_name, index.name
|
||||
)));
|
||||
}
|
||||
}
|
||||
// Add the mapping if at least one column was found.
|
||||
if !idx_map.columns.is_empty() {
|
||||
index_col_mappings.push(idx_map);
|
||||
}
|
||||
}
|
||||
Ok(index_col_mappings)
|
||||
}
|
||||
|
||||
fn populate_columns_multiple_rows(
|
||||
program: &mut ProgramBuilder,
|
||||
column_mappings: &[ColumnMapping], // columns in order of table definition
|
||||
column_registers_start: usize,
|
||||
yield_reg: usize,
|
||||
resolver: &Resolver,
|
||||
temp_table_ctx: &Option<TempTableCtx>,
|
||||
) -> Result<()> {
|
||||
// In case when both rowid and rowid-alias column provided in the query - turso-db overwrite rowid with **latest** value from the list
|
||||
// As we iterate by column in natural order of their definition in scheme,
|
||||
// we need to track last value_index we wrote to the rowid and overwrite rowid register only if new value_index is greater
|
||||
let mut last_rowid_explicit_value = None;
|
||||
for (i, mapping) in column_mappings.iter().enumerate() {
|
||||
let column_register = column_registers_start + i;
|
||||
|
||||
if let Some(value_index) = mapping.value_index {
|
||||
let write_directly_to_rowid_reg = mapping.column.is_rowid_alias;
|
||||
let write_reg = if write_directly_to_rowid_reg {
|
||||
if last_rowid_explicit_value.is_some_and(|x| x > value_index) {
|
||||
continue;
|
||||
}
|
||||
last_rowid_explicit_value = Some(value_index);
|
||||
column_registers_start // rowid always the first register in the array for insertion record
|
||||
} else {
|
||||
column_register
|
||||
};
|
||||
if let Some(temp_table_ctx) = temp_table_ctx {
|
||||
program.emit_column_or_rowid(temp_table_ctx.cursor_id, value_index, write_reg);
|
||||
} else {
|
||||
program.emit_insn(Insn::Copy {
|
||||
src_reg: yield_reg + value_index,
|
||||
dst_reg: write_reg,
|
||||
extra_amount: 0,
|
||||
});
|
||||
}
|
||||
// write_reg can be euqal to column_register if column list explicitly mention "rowid"
|
||||
if write_reg != column_register {
|
||||
program.emit_null(column_register, None);
|
||||
program.mark_last_insn_constant();
|
||||
}
|
||||
} else if mapping.column.is_rowid_alias {
|
||||
program.emit_insn(Insn::SoftNull {
|
||||
reg: column_register,
|
||||
});
|
||||
} else if let Some(default_expr) = mapping.default_value {
|
||||
translate_expr(program, None, default_expr, column_register, resolver)?;
|
||||
} else {
|
||||
// Column was not specified as has no DEFAULT - use NULL if it is nullable, otherwise error
|
||||
// Rowid alias columns can be NULL because we will autogenerate a rowid in that case.
|
||||
let is_nullable = !mapping.column.primary_key || mapping.column.is_rowid_alias;
|
||||
if is_nullable {
|
||||
program.emit_insn(Insn::Null {
|
||||
dest: column_register,
|
||||
dest_end: None,
|
||||
});
|
||||
} else {
|
||||
crate::bail_parse_error!(
|
||||
"column {} is not nullable",
|
||||
mapping.column.name.as_ref().expect("column name is None")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Populates the column registers with values for a single row
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn populate_column_registers(
|
||||
program: &mut ProgramBuilder,
|
||||
value: &[Expr],
|
||||
column_mappings: &[ColumnMapping],
|
||||
column_registers_start: usize,
|
||||
resolver: &Resolver,
|
||||
) -> Result<()> {
|
||||
// In case when both rowid and rowid-alias column provided in the query - turso-db overwrite rowid with **latest** value from the list
|
||||
// As we iterate by column in natural order of their definition in scheme,
|
||||
// we need to track last value_index we wrote to the rowid and overwrite rowid register only if new value_index is greater
|
||||
let mut last_rowid_explicit_value = None;
|
||||
for (i, mapping) in column_mappings.iter().enumerate() {
|
||||
let column_register = column_registers_start + i;
|
||||
|
||||
// Column has a value in the VALUES tuple
|
||||
if let Some(value_index) = mapping.value_index {
|
||||
// When inserting a single row, SQLite writes the value provided for the rowid alias column (INTEGER PRIMARY KEY)
|
||||
// directly into the rowid register and writes a NULL into the rowid alias column.
|
||||
let write_directly_to_rowid_reg = mapping.column.is_rowid_alias;
|
||||
let write_reg = if write_directly_to_rowid_reg {
|
||||
if last_rowid_explicit_value.is_some_and(|x| x > value_index) {
|
||||
continue;
|
||||
}
|
||||
last_rowid_explicit_value = Some(value_index);
|
||||
column_registers_start // rowid always the first register in the array for insertion record
|
||||
} else {
|
||||
column_register
|
||||
};
|
||||
|
||||
translate_expr_no_constant_opt(
|
||||
program,
|
||||
None,
|
||||
value.get(value_index).expect("value index out of bounds"),
|
||||
write_reg,
|
||||
resolver,
|
||||
NoConstantOptReason::RegisterReuse,
|
||||
)?;
|
||||
// write_reg can be euqal to column_register if column list explicitly mention "rowid"
|
||||
if write_reg != column_register {
|
||||
program.emit_null(column_register, None);
|
||||
program.mark_last_insn_constant();
|
||||
}
|
||||
} else if mapping.column.hidden {
|
||||
program.emit_insn(Insn::Null {
|
||||
dest: column_register,
|
||||
dest_end: None,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
} else if let Some(default_expr) = mapping.default_value {
|
||||
translate_expr_no_constant_opt(
|
||||
program,
|
||||
None,
|
||||
default_expr,
|
||||
column_register,
|
||||
resolver,
|
||||
NoConstantOptReason::RegisterReuse,
|
||||
)?;
|
||||
} else {
|
||||
// Column was not specified as has no DEFAULT - use NULL if it is nullable, otherwise error
|
||||
// Rowid alias columns can be NULL because we will autogenerate a rowid in that case.
|
||||
let is_nullable = !mapping.column.primary_key || mapping.column.is_rowid_alias;
|
||||
if is_nullable {
|
||||
program.emit_insn(Insn::Null {
|
||||
dest: column_register,
|
||||
dest_end: None,
|
||||
});
|
||||
program.mark_last_insn_constant();
|
||||
} else {
|
||||
crate::bail_parse_error!(
|
||||
"column {} is not nullable",
|
||||
mapping.column.name.as_ref().expect("column name is None")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Represents how a table should be populated during an INSERT.
|
||||
#[derive(Debug)]
|
||||
struct Insertion<'a> {
|
||||
@@ -1149,7 +840,7 @@ fn translate_rows_multiple<'short, 'long: 'short>(
|
||||
let translate_value_fn =
|
||||
|prg: &mut ProgramBuilder, value_index: usize, column_register: usize| {
|
||||
if let Some(temp_table_ctx) = temp_table_ctx {
|
||||
prg.emit_column(temp_table_ctx.cursor_id, value_index, column_register);
|
||||
prg.emit_column_or_rowid(temp_table_ctx.cursor_id, value_index, column_register);
|
||||
} else {
|
||||
prg.emit_insn(Insn::Copy {
|
||||
src_reg: yield_reg + value_index,
|
||||
|
||||
Reference in New Issue
Block a user