Merge 'core: constraint check uniqueness' from Pere Diaz Bou

```bash
limbo> insert into products values (1, 'asdf', 432);
Runtime error: UNIQUE constraint failed: products.id (19)
```

Closes #336
This commit is contained in:
Pekka Enberg 2024-09-20 13:27:10 +03:00
commit b67640c437
6 changed files with 56 additions and 9 deletions

View file

@ -36,6 +36,8 @@ pub enum LimboError {
InvalidTime(String),
#[error("Modifier parsing error: {0}")]
InvalidModifier(String),
#[error("Runtime error: {0}")]
Constraint(String),
}
#[macro_export]
@ -51,3 +53,6 @@ macro_rules! bail_corrupt_error {
return Err($crate::error::LimboError::Corrupt(format!($($arg)*)))
};
}
pub const SQLITE_CONSTRAINT: usize = 19;
pub const SQLITE_CONSTRAINT_PRIMARYKEY: usize = SQLITE_CONSTRAINT | (6 << 8);

View file

@ -1453,7 +1453,10 @@ fn epilogue(
start_offset: BranchOffset,
) -> Result<()> {
program.resolve_label(halt_label, program.offset());
program.emit_insn(Insn::Halt);
program.emit_insn(Insn::Halt {
err_code: 0,
description: String::new(),
});
program.resolve_label(init_label, program.offset());
program.emit_insn(Insn::Transaction);

View file

@ -4,6 +4,7 @@ use sqlite3_parser::ast::{
DistinctNames, InsertBody, QualifiedName, ResolveType, ResultColumn, With,
};
use crate::error::SQLITE_CONSTRAINT_PRIMARYKEY;
use crate::Result;
use crate::{
schema::{Schema, Table},
@ -167,7 +168,15 @@ pub fn translate_insert(
},
make_record_label,
);
program.emit_insn(Insn::Halt); // Add error code 1555 and rollback
// TODO: rollback
program.emit_insn(Insn::Halt {
err_code: SQLITE_CONSTRAINT_PRIMARYKEY,
description: format!(
"{}.{}",
table.get_name(),
table.column_index_to_name(0).unwrap()
),
});
program.resolve_label(make_record_label, program.offset());
program.emit_insn(Insn::MakeRecord {
start_reg: column_registers_start + 1,
@ -188,7 +197,10 @@ pub fn translate_insert(
});
program.resolve_label(halt_label, program.offset());
program.emit_insn(Insn::Halt);
program.emit_insn(Insn::Halt {
err_code: 0,
description: String::new(),
});
program.resolve_label(init_label, program.offset());
program.emit_insn(Insn::Transaction);
program.emit_constant_insns();

View file

@ -135,7 +135,10 @@ fn translate_pragma(
todo!()
}
};
program.emit_insn(Insn::Halt);
program.emit_insn(Insn::Halt {
err_code: 0,
description: String::new(),
});
program.resolve_label(init_label, program.offset());
program.emit_insn(Insn::Transaction);
program.emit_constant_insns();

View file

@ -383,9 +383,12 @@ pub fn insn_to_str(
0,
"".to_string(),
),
Insn::Halt => (
Insn::Halt {
err_code,
description: _,
} => (
"Halt",
0,
*err_code as i32,
0,
0,
OwnedValue::Text(Rc::new("".to_string())),

View file

@ -23,7 +23,7 @@ pub mod sorter;
mod datetime;
use crate::error::LimboError;
use crate::error::{LimboError, SQLITE_CONSTRAINT_PRIMARYKEY};
use crate::function::{AggFunc, FuncCtx, JsonFunc, ScalarFunc};
use crate::json::get_json;
use crate::pseudo::PseudoCursor;
@ -232,7 +232,10 @@ pub enum Insn {
},
// Halt the program.
Halt,
Halt {
err_code: usize,
description: String,
},
// Start a transaction.
Transaction,
@ -1001,7 +1004,25 @@ impl Program {
state.pc += 1;
}
}
Insn::Halt => {
Insn::Halt {
err_code,
description,
} => {
match *err_code {
0 => {}
SQLITE_CONSTRAINT_PRIMARYKEY => {
return Err(LimboError::Constraint(format!(
"UNIQUE constraint failed: {} (19)",
description
)));
}
_ => {
return Err(LimboError::Constraint(format!(
"undocumented halt error code {}",
description
)));
}
}
pager.end_read_tx()?;
return Ok(StepResult::Done);
}