fix generation and expr evaluation

This commit is contained in:
pedrocarlo
2025-06-03 14:36:32 -03:00
parent 9f2608bded
commit fac4b4e6fb
5 changed files with 105 additions and 74 deletions

BIN
limbo_sim Normal file

Binary file not shown.

53
simulator.log Normal file
View File

@@ -0,0 +1,53 @@
INFO limbo_sim: 624: seed=8825480009738779594
INFO limbo_sim: 643: Generating database interaction plan...
INFO limbo_sim::generation::plan: 471: Generated plan with 2522 interactions
INFO limbo_sim: 651: Read: 749, Write: 1284, Delete: 314, Update: 280, Create: 145, Drop: 0
INFO limbo_sim: 668: Executing database interaction plan...
ERROR limbo_sim::runner::execution: 155: error Internal error: row [["-8764217988.231829", "1058607710.2615395", "600358361.8981647", "X'696E7175697369746976655F6D617274696E64616C65'", "'technological_deutscher'", "-8084940719.693194", "'gorgeous_ervin'", "-2573272842.7607965", "8759121979743080371"]] not found in table glimmering_edinburgh. Inner error: Internal error: Parse error: Column stunning_farrow not found
INFO limbo_sim::runner::io: 46: run_once faults: 0
INFO limbo_sim::runner::io: 48:
INFO limbo_sim::runner::io: 49: ===========================
INFO limbo_sim::runner::file: 35: op calls faults
INFO limbo_sim::runner::file: 36: --------- -------- --------
INFO limbo_sim::runner::file: 37: pread 5 0
INFO limbo_sim::runner::file: 42: pwrite 3 0
INFO limbo_sim::runner::file: 47: sync 1 0
INFO limbo_sim::runner::file: 52: --------- -------- --------
INFO limbo_sim::runner::file: 57: total 9 0
INFO limbo_sim::runner::io: 48:
INFO limbo_sim::runner::io: 49: ===========================
INFO limbo_sim::runner::file: 35: op calls faults
INFO limbo_sim::runner::file: 36: --------- -------- --------
INFO limbo_sim::runner::file: 37: pread 5 0
INFO limbo_sim::runner::file: 42: pwrite 4 0
INFO limbo_sim::runner::file: 47: sync 5 0
INFO limbo_sim::runner::file: 52: --------- -------- --------
INFO limbo_sim::runner::file: 57: total 14 0
INFO limbo_sim: 683: Simulation completed
ERROR limbo_sim: 311: simulation failed: 'InternalError("row [[\"-8764217988.231829\", \"1058607710.2615395\", \"600358361.8981647\", \"X'696E7175697369746976655F6D617274696E64616C65'\", \"'technological_deutscher'\", \"-8084940719.693194\", \"'gorgeous_ervin'\", \"-2573272842.7607965\", \"8759121979743080371\"]] not found in table glimmering_edinburgh. Inner error: Internal error: Parse error: Column stunning_farrow not found")'
INFO limbo_sim: 312: Starting to shrink
INFO limbo_sim::shrink::plan: 49: Shrinking interaction plan from 2522 to 4 properties
INFO limbo_sim: 318: Read: 2, Write: 1, Delete: 1, Update: 0, Create: 1, Drop: 0
INFO limbo_sim: 668: Executing database interaction plan...
ERROR limbo_sim::runner::execution: 155: error Internal error: row [["-8764217988.231829", "1058607710.2615395", "600358361.8981647", "X'696E7175697369746976655F6D617274696E64616C65'", "'technological_deutscher'", "-8084940719.693194", "'gorgeous_ervin'", "-2573272842.7607965", "8759121979743080371"]] not found in table glimmering_edinburgh. Inner error: Internal error: Parse error: Column stunning_farrow not found
INFO limbo_sim::runner::io: 46: run_once faults: 0
INFO limbo_sim::runner::io: 48:
INFO limbo_sim::runner::io: 49: ===========================
INFO limbo_sim::runner::file: 35: op calls faults
INFO limbo_sim::runner::file: 36: --------- -------- --------
INFO limbo_sim::runner::file: 37: pread 3 0
INFO limbo_sim::runner::file: 42: pwrite 1 0
INFO limbo_sim::runner::file: 47: sync 0 0
INFO limbo_sim::runner::file: 52: --------- -------- --------
INFO limbo_sim::runner::file: 57: total 4 0
INFO limbo_sim::runner::io: 48:
INFO limbo_sim::runner::io: 49: ===========================
INFO limbo_sim::runner::file: 35: op calls faults
INFO limbo_sim::runner::file: 36: --------- -------- --------
INFO limbo_sim::runner::file: 37: pread 2 0
INFO limbo_sim::runner::file: 42: pwrite 4 0
INFO limbo_sim::runner::file: 47: sync 3 0
INFO limbo_sim::runner::file: 52: --------- -------- --------
INFO limbo_sim::runner::file: 57: total 9 0
INFO limbo_sim: 683: Simulation completed
INFO limbo_sim: 362: shrinking succeeded, reduced the plan from 2522 to 4

View File

@@ -32,7 +32,7 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate {
Box::new(|rng| {
Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(table.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::Equals,
@@ -43,7 +43,7 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate {
let gt_value = GTValue::arbitrary_from(rng, &column_values).0;
Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(table.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::Greater,
@@ -54,7 +54,7 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate {
let lt_value = LTValue::arbitrary_from(rng, &column_values).0;
Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(table.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::Less,
@@ -69,7 +69,7 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate {
Box::new(|rng| {
Expr::Binary(
Box::new(Expr::Qualified(
ast::Name("".to_string()),
ast::Name(table.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::NotEquals,
@@ -80,7 +80,7 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate {
let lt_value = LTValue::arbitrary_from(rng, &column_values).0;
Expr::Binary(
Box::new(Expr::Qualified(
ast::Name("".to_string()),
ast::Name(table.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::Greater,
@@ -91,7 +91,7 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate {
let gt_value = GTValue::arbitrary_from(rng, &column_values).0;
Expr::Binary(
Box::new(Expr::Qualified(
ast::Name("".to_string()),
ast::Name(table.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::Less,
@@ -203,10 +203,7 @@ impl ArbitraryFrom<(&str, &Value)> for Predicate {
vec![
Box::new(|_| {
Predicate(Expr::Binary(
Box::new(Expr::Qualified(
ast::Name("".to_string()),
ast::Name(column_name.to_string()),
)),
Box::new(Expr::Id(ast::Id(column_name.to_string()))),
ast::Operator::Equals,
Box::new(Expr::Literal(value.into())),
))
@@ -214,10 +211,7 @@ impl ArbitraryFrom<(&str, &Value)> for Predicate {
Box::new(|rng| {
let gt_value = GTValue::arbitrary_from(rng, value).0;
Predicate(Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(column_name.to_string()),
)),
Box::new(Expr::Id(ast::Id(column_name.to_string()))),
ast::Operator::Greater,
Box::new(Expr::Literal(gt_value.into())),
))
@@ -225,10 +219,7 @@ impl ArbitraryFrom<(&str, &Value)> for Predicate {
Box::new(|rng| {
let lt_value = LTValue::arbitrary_from(rng, value).0;
Predicate(Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(column_name.to_string()),
)),
Box::new(Expr::Id(ast::Id(column_name.to_string()))),
ast::Operator::Less,
Box::new(Expr::Literal(lt_value.into())),
))
@@ -252,7 +243,7 @@ fn produce_true_predicate<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<Value>))
Box::new(|_| {
Some(Predicate(Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(t.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::Equals,
@@ -269,7 +260,7 @@ fn produce_true_predicate<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<Value>))
} else {
Some(Predicate(Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(t.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::NotEquals,
@@ -284,7 +275,7 @@ fn produce_true_predicate<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<Value>))
let lt_value = LTValue::arbitrary_from(rng, value).0;
Some(Predicate(Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(t.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::Greater,
@@ -298,7 +289,7 @@ fn produce_true_predicate<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<Value>))
let gt_value = GTValue::arbitrary_from(rng, value).0;
Some(Predicate(Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(t.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::Less,
@@ -312,7 +303,7 @@ fn produce_true_predicate<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<Value>))
LikeValue::arbitrary_from_maybe(rng, value).map(|like| {
Predicate(Expr::Like {
lhs: Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(t.name.clone()),
ast::Name(column.name.clone()),
)),
not: false, // TODO: also generate this value eventually
@@ -339,7 +330,7 @@ fn produce_false_predicate<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<Value>))
Box::new(|_| {
Predicate(Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(t.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::NotEquals,
@@ -355,7 +346,7 @@ fn produce_false_predicate<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<Value>))
};
Predicate(Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(t.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::Equals,
@@ -366,7 +357,7 @@ fn produce_false_predicate<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<Value>))
let gt_value = GTValue::arbitrary_from(rng, value).0;
Predicate(Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(t.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::Greater,
@@ -377,7 +368,7 @@ fn produce_false_predicate<R: Rng>(rng: &mut R, (t, row): (&Table, &Vec<Value>))
let lt_value = LTValue::arbitrary_from(rng, value).0;
Predicate(Expr::Binary(
Box::new(ast::Expr::Qualified(
ast::Name("".to_string()),
ast::Name(t.name.clone()),
ast::Name(column.name.clone()),
)),
ast::Operator::Less,

View File

@@ -8,15 +8,6 @@ use crate::model::{
table::{Table, Value},
};
macro_rules! assert_implemented_predicate_expr {
($val:expr) => {
assert!(matches!(
$val,
ast::Expr::DoublyQualified(..) | ast::Expr::Qualified(..) | ast::Expr::Literal(..)
))
};
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Predicate(pub ast::Expr);
@@ -30,39 +21,8 @@ impl Predicate {
}
pub(crate) fn test(&self, row: &[Value], table: &Table) -> bool {
match &self.0 {
ast::Expr::Binary(lhs, operator, rhs) => {
let lhs = expr_to_value(lhs, row, table);
let rhs = expr_to_value(rhs, row, table);
match (lhs, rhs) {
(Some(lhs), Some(rhs)) => lhs.binary_compare(&rhs, *operator),
_ => false,
}
}
ast::Expr::Like {
lhs,
not,
op,
rhs,
escape: _, // TODO: support escape
} => {
let lhs = expr_to_value(lhs, row, table);
let rhs = expr_to_value(rhs, row, table);
let res = match (lhs, rhs) {
(Some(lhs), Some(rhs)) => lhs.like_compare(&rhs, *op),
_ => false,
};
if *not {
!res
} else {
res
}
}
ast::Expr::Literal(literal) => Value::from(literal).into_bool(),
// TODO: next implement unary operator
ast::Expr::Unary(..) => todo!(),
expr => unimplemented!("{:?}", expr),
}
let value = expr_to_value(&self.0, row, table);
value.map_or(false, |value| value.into_bool())
}
}
@@ -71,17 +31,42 @@ impl Predicate {
// TODO: In the future, we can try to expand this computation if we want to support harder properties that require us
// to already know more values before hand
fn expr_to_value(expr: &ast::Expr, row: &[Value], table: &Table) -> Option<Value> {
assert_implemented_predicate_expr!(expr);
match expr {
ast::Expr::DoublyQualified(_, _, col_name) | ast::Expr::Qualified(_, col_name) => table
ast::Expr::DoublyQualified(_, _, ast::Name(col_name))
| ast::Expr::Qualified(_, ast::Name(col_name))
| ast::Expr::Id(ast::Id(col_name)) => table
.columns
.iter()
.zip(row.iter())
.find(|(column, _)| column.name == col_name.0)
.find(|(column, _)| column.name == *col_name)
.map(|(_, value)| value)
.cloned(),
ast::Expr::Literal(literal) => Some(literal.into()),
// TODO: add binary and unary
ast::Expr::Binary(lhs, op, rhs) => {
let lhs = expr_to_value(lhs, row, table);
let rhs = expr_to_value(rhs, row, table);
match (lhs, rhs) {
(Some(lhs), Some(rhs)) => Some(lhs.binary_compare(&rhs, *op)),
_ => None,
}
}
ast::Expr::Like {
lhs,
not,
op,
rhs,
escape: _, // TODO: support escape
} => {
let lhs = expr_to_value(lhs, row, table);
let rhs = expr_to_value(rhs, row, table);
let res = match (lhs, rhs) {
(Some(lhs), Some(rhs)) => lhs.like_compare(&rhs, *op),
_ => return None,
};
let value: Value = if *not { !res } else { res }.into();
Some(value)
}
// TODO: add unary
_ => unreachable!("{:?}", expr),
}
}

View File

@@ -127,7 +127,8 @@ impl Value {
}
// TODO: support more predicates
pub fn binary_compare(&self, other: &Self, operator: ast::Operator) -> bool {
/// Returns a Value::TRUE or VALUE::FALSE
pub fn binary_compare(&self, other: &Self, operator: ast::Operator) -> Value {
match operator {
ast::Operator::Add => todo!(),
ast::Operator::And => self.into_bool() && other.into_bool(),
@@ -153,6 +154,7 @@ impl Value {
ast::Operator::RightShift => todo!(),
ast::Operator::Subtract => todo!(),
}
.into()
}
// TODO: support more operators. Copy the implementation for exec_glob