diff --git a/limbo_sim b/limbo_sim new file mode 100644 index 000000000..a7582c3c9 Binary files /dev/null and b/limbo_sim differ diff --git a/simulator.log b/simulator.log new file mode 100644 index 000000000..04be8f663 --- /dev/null +++ b/simulator.log @@ -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 diff --git a/simulator/generation/predicate.rs b/simulator/generation/predicate.rs index e87ee7c3e..39f6a6f96 100644 --- a/simulator/generation/predicate.rs +++ b/simulator/generation/predicate.rs @@ -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(rng: &mut R, (t, row): (&Table, &Vec)) 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(rng: &mut R, (t, row): (&Table, &Vec)) } 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(rng: &mut R, (t, row): (&Table, &Vec)) 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(rng: &mut R, (t, row): (&Table, &Vec)) 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(rng: &mut R, (t, row): (&Table, &Vec)) 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(rng: &mut R, (t, row): (&Table, &Vec)) 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(rng: &mut R, (t, row): (&Table, &Vec)) }; 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(rng: &mut R, (t, row): (&Table, &Vec)) 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(rng: &mut R, (t, row): (&Table, &Vec)) 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, diff --git a/simulator/model/query/predicate.rs b/simulator/model/query/predicate.rs index 21f52b516..7d1ca3591 100644 --- a/simulator/model/query/predicate.rs +++ b/simulator/model/query/predicate.rs @@ -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 { - 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), } } diff --git a/simulator/model/table.rs b/simulator/model/table.rs index a1e5f6948..ffe779f5e 100644 --- a/simulator/model/table.rs +++ b/simulator/model/table.rs @@ -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