Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/bin/sqlite-rs/pragma_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ mod tests {
#[test]
fn primary_key_columns_inline_and_table_level() {
let mut schema = TableSchema {
unresolved_autoindex: false,
name: "t".to_string(),
root_page: 2,
columns: vec!["a".to_string(), "b".to_string()],
Expand Down
1 change: 1 addition & 0 deletions src/bin/sqlite-rs/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ pub(crate) fn compile_select_program(
return Err("EXPLAIN QUERY PLAN requires a FROM clause".to_string());
}
let no_table = TableSchema {
unresolved_autoindex: false,
name: String::new(),
root_page: 0,
columns: vec![],
Expand Down
1 change: 1 addition & 0 deletions src/bin/sqlite-rs/readline/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ mod tests {
fn schema(name: &str, columns: &[&str]) -> TableSchema {
let columns: Vec<String> = columns.iter().map(|s| s.to_string()).collect();
TableSchema {
unresolved_autoindex: false,
name: name.to_string(),
root_page: 2,
column_types: vec![String::new(); columns.len()],
Expand Down
1 change: 1 addition & 0 deletions src/codegen/analyze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ mod tests {

fn table(name: &str, root_page: u32, indexes: Vec<IndexSchema>) -> TableSchema {
TableSchema {
unresolved_autoindex: false,
name: name.to_string(),
root_page,
columns: vec!["a".to_string()],
Expand Down
1 change: 1 addition & 0 deletions src/codegen/ddl/create_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ mod tests {

fn schema() -> TableSchema {
TableSchema {
unresolved_autoindex: false,
name: "t".to_string(),
root_page: 2,
columns: vec!["a".to_string(), "b".to_string()],
Expand Down
1 change: 1 addition & 0 deletions src/codegen/ddl/drop_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ mod tests {

fn schema_with_index() -> TableSchema {
TableSchema {
unresolved_autoindex: false,
name: "t".to_string(),
root_page: 2,
columns: vec!["a".to_string()],
Expand Down
1 change: 1 addition & 0 deletions src/codegen/select/aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ fn compact_index_map(needed_order: &[usize], schema_len: usize) -> Vec<Option<us
/// directly — see [`compile_grouped_scan`]'s pass 2.
fn compact_schema(schema: &TableSchema, needed_order: &[usize]) -> TableSchema {
TableSchema {
unresolved_autoindex: false,
name: schema.name.clone(),
root_page: 0,
columns: needed_order
Expand Down
1 change: 1 addition & 0 deletions src/codegen/select/aggregate/accum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ where
let mut synthetic_types = schema.column_types.clone();
synthetic_types.extend(synthetic_names.iter().map(|_| String::new()));
let synthetic_schema = TableSchema {
unresolved_autoindex: false,
name: schema.name.clone(),
root_page: 0,
columns: synthetic_columns,
Expand Down
2 changes: 2 additions & 0 deletions src/codegen/select/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ pub(super) fn compile_select_no_from(
em.patch_p2(init_addr, body_start);

let no_table = TableSchema {
unresolved_autoindex: false,
name: String::new(),
root_page: 0,
columns: vec![],
Expand Down Expand Up @@ -460,6 +461,7 @@ pub fn compile_select_compound(
// trailing ORDER BY/LIMIT and its terms bind to the compound's
// result columns, never to any arm's table columns.
let output_schema = TableSchema {
unresolved_autoindex: false,
name: String::new(),
root_page: 0,
columns: output_column_names(first, first_schema),
Expand Down
1 change: 1 addition & 0 deletions src/codegen/select/join_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,7 @@ mod tests {

fn schema(name: &str, columns: &[&str], indexes: Vec<IndexSchema>) -> TableSchema {
TableSchema {
unresolved_autoindex: false,
name: name.to_string(),
root_page: 0,
columns: columns.iter().map(|c| (*c).to_string()).collect(),
Expand Down
1 change: 1 addition & 0 deletions src/codegen/select/join_order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ mod tests {

fn schema(name: &str, columns: &[&str], indexes: Vec<IndexSchema>) -> TableSchema {
TableSchema {
unresolved_autoindex: false,
name: name.to_string(),
root_page: 0,
columns: columns.iter().map(|c| (*c).to_string()).collect(),
Expand Down
14 changes: 14 additions & 0 deletions src/codegen/stmt/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ pub fn compile_delete_with_catalog(
reason: "WITHOUT ROWID tables are not supported by DELETE codegen yet".to_string(),
});
}
// #685: an on-disk `sqlite_autoindex_*` whose key columns could not
// be recovered from the table's DDL is absent from `schema.indexes`,
// so this codegen would neither enforce its uniqueness nor maintain
// it — the write would report success and leave the index stale.
// Refuse instead, per spec 010/Req 8 and spec 007/Req 1's precedent.
if schema.unresolved_autoindex {
return Err(CodegenError::Unsupported {
reason: format!(
"table {} carries an automatic index this reader could not \
interpret, so DELETE would corrupt it; the table is read-only",
schema.name
),
});
}

let mut em = Emitter::new();
let mut reg = RegAlloc::new();
Expand Down
31 changes: 30 additions & 1 deletion src/codegen/stmt/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,20 @@ pub fn compile_insert(
reason: "WITHOUT ROWID tables are not supported by INSERT codegen yet".to_string(),
});
}
// #685: an on-disk `sqlite_autoindex_*` whose key columns could not
// be recovered from the table's DDL is absent from `schema.indexes`,
// so this codegen would neither enforce its uniqueness nor maintain
// it — the write would report success and leave the index stale.
// Refuse instead, per spec 010/Req 8 and spec 007/Req 1's precedent.
if schema.unresolved_autoindex {
return Err(CodegenError::Unsupported {
reason: format!(
"table {} carries an automatic index this reader could not \
interpret, so INSERT would corrupt it; the table is read-only",
schema.name
),
});
}

let create = cached_create_table(schema)?;

Expand Down Expand Up @@ -367,6 +381,7 @@ pub fn compile_insert(
// support. Every `CHECK` column reference reads via ordinary
// `Opcode::Column` instead.
let check_schema = TableSchema {
unresolved_autoindex: false,
sql: String::new(),
rowid_alias: None,
..schema.clone()
Expand Down Expand Up @@ -964,7 +979,21 @@ fn emit_unique_check(
em.place(seek_ok);
}
ConflictAction::Abort | ConflictAction::Fail | ConflictAction::Rollback => {
let message = format!("UNIQUE constraint failed: {}.{}", schema.name, index.name);
// Stock SQLite names the *columns*, not the index:
// `UNIQUE constraint failed: t.a, t.b, t.c`. Naming the
// index instead diverged for every unique index (measured
// against 3.51.0), and #685 made it newly reachable for
// autoindexes, whose generated name would be meaningless in
// an application's error log.
let message = format!(
"UNIQUE constraint failed: {}",
index
.columns
.iter()
.map(|col| format!("{}.{}", schema.name, col.name))
.collect::<Vec<_>>()
.join(", ")
);
em.emit(Instruction::with_p4(
Opcode::Halt,
SQLITE_CONSTRAINT_UNIQUE,
Expand Down
15 changes: 15 additions & 0 deletions src/codegen/stmt/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,20 @@ pub fn compile_update_with_catalog(
reason: "WITHOUT ROWID tables are not supported by UPDATE codegen yet".to_string(),
});
}
// #685: an on-disk `sqlite_autoindex_*` whose key columns could not
// be recovered from the table's DDL is absent from `schema.indexes`,
// so this codegen would neither enforce its uniqueness nor maintain
// it — the write would report success and leave the index stale.
// Refuse instead, per spec 010/Req 8 and spec 007/Req 1's precedent.
if schema.unresolved_autoindex {
return Err(CodegenError::Unsupported {
reason: format!(
"table {} carries an automatic index this reader could not \
interpret, so UPDATE would corrupt it; the table is read-only",
schema.name
),
});
}

let create = cached_create_table(schema)?;

Expand All @@ -105,6 +119,7 @@ pub fn compile_update_with_catalog(
// for the rowid-alias column — cleared here alongside `sql`, and which the pseudo-cursor can't
// answer).
let check_schema = TableSchema {
unresolved_autoindex: false,
sql: String::new(),
rowid_alias: None,
..schema.clone()
Expand Down
2 changes: 2 additions & 0 deletions src/codegen/subquery/from_clause.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ fn subquery_result_schema(
) -> TableSchema {
let columns = subquery_output_columns(subquery, table_refs, schemas);
TableSchema {
unresolved_autoindex: false,
name: String::new(),
root_page: 0,
columns: columns.clone(),
Expand Down Expand Up @@ -386,6 +387,7 @@ mod tests {

fn table(name: &str, root_page: u32) -> TableSchema {
TableSchema {
unresolved_autoindex: false,
name: name.to_string(),
root_page,
columns: vec!["a".to_string(), "b".to_string()],
Expand Down
1 change: 1 addition & 0 deletions src/codegen/subquery/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,7 @@ mod tests {

fn table(name: &str, root_page: u32, columns: &[&str], sql: &str) -> TableSchema {
TableSchema {
unresolved_autoindex: false,
name: name.to_string(),
root_page,
columns: columns.iter().map(|c| c.to_string()).collect(),
Expand Down
1 change: 1 addition & 0 deletions src/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ mod tests {

fn schema(sql: &str) -> TableSchema {
TableSchema {
unresolved_autoindex: false,
name: "t".to_string(),
root_page: 1,
columns: vec![],
Expand Down
1 change: 1 addition & 0 deletions src/integrity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ mod tests {

fn table_schema(name: &str, root_page: u32, indexes: Vec<IndexSchema>) -> TableSchema {
TableSchema {
unresolved_autoindex: false,
name: name.to_string(),
root_page,
columns: vec![],
Expand Down
1 change: 1 addition & 0 deletions src/planner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ mod tests {
.unwrap();

let schemas = vec![TableSchema {
unresolved_autoindex: false,
name: "sqlite_stat1".to_string(),
root_page: stat1_root,
columns: vec!["tbl".to_string(), "idx".to_string(), "stat".to_string()],
Expand Down
Loading
Loading