fix the merge conflicts

This commit is contained in:
alpaylan
2025-07-11 02:04:14 -04:00
parent 8f46bbc77e
commit 65fe60ba57
15 changed files with 137 additions and 98 deletions

View File

@@ -3,7 +3,7 @@ use std::{iter::Sum, ops::SubAssign};
use anarchist_readable_name_generator_lib::readable_name_custom;
use rand::{distributions::uniform::SampleUniform, Rng};
use crate::model::table::Table;
use crate::runner::env::SimulatorTables;
mod expr;
pub mod plan;
@@ -50,7 +50,7 @@ pub trait ArbitraryFromMaybe<T> {
/// might return a vector of rows that were inserted into the table.
pub(crate) trait Shadow {
type Result;
fn shadow(&self, tables: &mut Vec<Table>) -> Self::Result;
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result;
}
/// Frequency is a helper function for composing different generators with different frequency

View File

@@ -8,16 +8,16 @@ use std::{
use serde::{Deserialize, Serialize};
use turso_core::{Connection, Result, StepResult, IO};
use turso_core::{Connection, Result, StepResult};
use crate::{
generation::Shadow,
model::{
query::{update::Update, Create, CreateIndex, Delete, Drop, Insert, Query, Select},
table::{SimValue, Table},
table::SimValue,
},
runner::{
env::{SimConnection, SimulationType},
env::{SimConnection, SimulationType, SimulatorTables},
io::SimulatorIO,
},
SimulatorEnv,
@@ -114,7 +114,7 @@ pub(crate) enum Interactions {
impl Shadow for Interactions {
type Result = ();
fn shadow(&self, tables: &mut Vec<Table>) {
fn shadow(&self, tables: &mut SimulatorTables) {
match self {
Interactions::Property(property) => {
let initial_tables = tables.clone();
@@ -423,7 +423,7 @@ impl ArbitraryFrom<&mut SimulatorEnv> for InteractionPlan {
impl Shadow for Interaction {
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
fn shadow(&self, env: &mut Vec<Table>) -> Self::Result {
fn shadow(&self, env: &mut SimulatorTables) -> Self::Result {
match self {
Self::Query(query) => query.shadow(env),
Self::FsyncQuery(query) => {
@@ -438,7 +438,7 @@ impl Shadow for Interaction {
}
}
impl Interaction {
pub(crate) fn execute_query(&self, conn: &mut Arc<Connection>, io: &SimulatorIO) -> ResultSet {
pub(crate) fn execute_query(&self, conn: &mut Arc<Connection>, _io: &SimulatorIO) -> ResultSet {
if let Self::Query(query) = self {
let query_str = query.to_string();
let rows = conn.query(&query_str);
@@ -737,7 +737,7 @@ fn random_create<R: rand::Rng>(rng: &mut R, _env: &SimulatorEnv) -> Interactions
}
fn random_read<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv) -> Interactions {
Interactions::Query(Query::Select(Select::arbitrary_from(rng, &env.tables)))
Interactions::Query(Query::Select(Select::arbitrary_from(rng, &env.tables.tables)))
}
fn random_write<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv) -> Interactions {

View File

@@ -3,22 +3,16 @@ use turso_core::LimboError;
use turso_sqlite3_parser::ast::{self};
use crate::{
model::{
generation::Shadow as _, model::{
query::{
predicate::Predicate,
select::{
predicate::Predicate, select::{
CompoundOperator, CompoundSelect, Distinctness, ResultColumn, SelectBody,
SelectInner,
},
select::{Distinctness, ResultColumn},
transaction::{Begin, Commit, Rollback},
update::Update,
Create, Delete, Drop, Insert, Query, Select,
}, transaction::{Begin, Commit, Rollback}, update::Update, Create, Delete, Drop, Insert, Query, Select
},
table::SimValue,
FAULT_ERROR_MSG,
},
runner::env::SimulatorEnv,
}, runner::env::SimulatorEnv
};
use super::{
@@ -285,17 +279,17 @@ impl Property {
let table_name = create.table.name.clone();
let assertion = Interaction::Assertion(Assertion {
message:
"creating two tables with the name should result in a failure for the second query"
.to_string(),
func: Box::new(move |stack: &Vec<ResultSet>, _: &SimulatorEnv| {
let last = stack.last().unwrap();
match last {
Ok(_) => Ok(false),
Err(e) => Ok(e.to_string().to_lowercase().contains(&format!("table {table_name} already exists"))),
}
}),
});
message:
"creating two tables with the name should result in a failure for the second query"
.to_string(),
func: Box::new(move |stack: &Vec<ResultSet>, _| {
let last = stack.last().unwrap();
match last {
Ok(_) => Ok(false),
Err(e) => Ok(e.to_string().to_lowercase().contains(&format!("table {table_name} already exists"))),
}
}),
});
let mut interactions = Vec::new();
interactions.push(assumption);
@@ -318,7 +312,7 @@ impl Property {
),
func: Box::new({
let table_name = select.dependencies();
move |_: &Vec<ResultSet>, env: &SimulatorEnv| {
move |_: &Vec<ResultSet>, env: &mut SimulatorEnv| {
Ok(table_name
.iter()
.all(|table| env.tables.iter().any(|t| t.name == *table)))
@@ -373,8 +367,8 @@ impl Property {
)));
let assertion = Interaction::Assertion(Assertion {
message: format!("`{select}` should return no values for table `{table}`",),
func: Box::new(move |stack: &Vec<ResultSet>, _: &SimulatorEnv| {
message: format!("`{}` should return no values for table `{}`", select, table,),
func: Box::new(move |stack: &Vec<ResultSet>, _| {
let rows = stack.last().unwrap();
match rows {
Ok(rows) => Ok(rows.is_empty()),
@@ -410,8 +404,11 @@ impl Property {
let table_name = table.clone();
let assertion = Interaction::Assertion(Assertion {
message: format!("select query should result in an error for table '{table}'"),
func: Box::new(move |stack: &Vec<ResultSet>, _: &SimulatorEnv| {
message: format!(
"select query should result in an error for table '{}'",
table
),
func: Box::new(move |stack: &Vec<ResultSet>, _| {
let last = stack.last().unwrap();
match last {
Ok(_) => Ok(false),
@@ -471,8 +468,8 @@ impl Property {
// If rows1 results have more than 1 column, there is a problem
if rows1.iter().any(|vs| vs.len() > 1) {
return Err(LimboError::InternalError(
"Select query without the star should return only one column".to_string(),
));
"Select query without the star should return only one column".to_string(),
));
}
// Count the 1s in the select query without the star
let rows1_count = rows1
@@ -517,11 +514,11 @@ impl Property {
// then when IO is called the fault triggers. It may happen that a fault is injected
// but no IO happens right after it
message: "fault occured".to_string(),
func: Box::new(move |stack, env| {
func: Box::new(move |stack, env: &mut SimulatorEnv| {
let last = stack.last().unwrap();
match last {
Ok(_) => {
query_clone.shadow(env);
let _ = query_clone.shadow(&mut env.tables);
Ok(true)
}
Err(err) => {
@@ -554,7 +551,7 @@ impl Property {
),
func: Box::new({
let tables = select.dependencies();
move |_: &Vec<ResultSet>, env: &SimulatorEnv| {
move |_: &Vec<ResultSet>, env: &mut SimulatorEnv| {
Ok(tables
.iter()
.all(|table| env.tables.iter().any(|t| t.name == *table)))
@@ -612,7 +609,7 @@ impl Property {
// select and select_tlp should return the same rows
let assertion = Interaction::Assertion(Assertion {
message: "select and select_tlp should return the same rows".to_string(),
func: Box::new(move |stack: &Vec<ResultSet>, _: &SimulatorEnv| {
func: Box::new(move |stack: &Vec<ResultSet>, _: &mut SimulatorEnv| {
if stack.len() < 2 {
return Err(LimboError::InternalError(
"Not enough result sets on the stack".to_string(),
@@ -681,7 +678,7 @@ impl Property {
Interaction::Query(Query::Select(s3.clone())),
Interaction::Assertion(Assertion {
message: "UNION ALL should preserve cardinality".to_string(),
func: Box::new(move |stack: &Vec<ResultSet>, _: &SimulatorEnv| {
func: Box::new(move |stack: &Vec<ResultSet>, _: &mut SimulatorEnv| {
if stack.len() < 3 {
return Err(LimboError::InternalError(
"Not enough result sets on the stack".to_string(),
@@ -720,15 +717,14 @@ fn assert_all_table_values(tables: &[String]) -> impl Iterator<Item = Interactio
)));
let assertion = Interaction::Assertion(Assertion {
message: format!(
"table {table} should contain all of its values after the wal reopened"
),
message: format!("table {} should contain all of its values", table),
func: Box::new({
let table = table.clone();
move |stack: &Vec<ResultSet>, env: &mut SimulatorEnv| {
let table = env.tables.iter().find(|t| t.name == table).ok_or_else(|| {
LimboError::InternalError(format!(
"table {table} should exist in simulator env",
"table {} should exist in simulator env",
table
))
})?;
let last = stack.last().unwrap();

View File

@@ -7,6 +7,7 @@ use crate::model::query::select::{
use crate::model::query::update::Update;
use crate::model::query::{Create, Delete, Drop, Insert, Query, Select};
use crate::model::table::{SimValue, Table};
use crate::runner::env::SimulatorTables;
use crate::SimulatorEnv;
use itertools::Itertools;
use rand::Rng;
@@ -77,7 +78,10 @@ impl ArbitraryFrom<&Vec<Table>> for FromClause {
impl ArbitraryFrom<&Vec<Table>> for SelectInner {
fn arbitrary_from<R: Rng>(rng: &mut R, tables: &Vec<Table>) -> Self {
let from = FromClause::arbitrary_from(rng, tables);
let mut tables = tables.clone();
let mut tables = SimulatorTables {
tables: tables.clone(),
snapshot: None,
};
// todo: this is a temporary hack because env is not separated from the tables
let join_table = from
.shadow(&mut tables)
@@ -180,7 +184,10 @@ impl ArbitraryFrom<&SimulatorEnv> for Insert {
// Backtrack here cannot return None
backtrack(
vec![(1, Box::new(gen_values)), (1, Box::new(gen_select))],
vec![
(1, Box::new(gen_values)),
(1, Box::new(|rng| gen_select(rng))),
],
rng,
)
.unwrap()
@@ -259,14 +266,15 @@ impl ArbitraryFrom<&SimulatorEnv> for Update {
#[cfg(test)]
mod query_generation_tests {
use rand::RngCore;
use turso_core::Value;
use turso_sqlite3_parser::to_sql_string::ToSqlString;
use super::*;
use crate::model::query::predicate::Predicate;
use crate::model::query::EmptyContext;
use crate::model::table::{Column, ColumnType};
use crate::SimulatorEnv;
#[test]
fn test_select_query_generation() {

View File

@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use crate::{
generation::Shadow,
model::table::{SimValue, Table},
model::table::{SimValue, Table}, runner::env::SimulatorTables,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -15,7 +15,7 @@ pub(crate) struct Create {
impl Shadow for Create {
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
fn shadow(&self, tables: &mut Vec<Table>) -> Self::Result {
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
if !tables.iter().any(|t| t.name == self.table.name) {
tables.push(self.table.clone());
Ok(vec![])

View File

@@ -1,7 +1,7 @@
use crate::{
generation::{gen_random_text, pick, pick_n_unique, ArbitraryFrom, Shadow},
model::table::{SimValue, Table},
runner::env::SimulatorEnv,
model::table::SimValue,
runner::env::{SimulatorEnv, SimulatorTables},
};
use rand::Rng;
use serde::{Deserialize, Serialize};
@@ -30,7 +30,7 @@ pub(crate) struct CreateIndex {
impl Shadow for CreateIndex {
type Result = Vec<Vec<SimValue>>;
fn shadow(&self, _env: &mut Vec<Table>) -> Vec<Vec<SimValue>> {
fn shadow(&self, _env: &mut SimulatorTables) -> Vec<Vec<SimValue>> {
// CREATE INDEX doesn't require any shadowing; we don't need to keep track
// in the simulator what indexes exist.
vec![]

View File

@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use crate::{
generation::Shadow,
model::table::{SimValue, Table},
model::table::SimValue, runner::env::SimulatorTables,
};
use super::predicate::Predicate;
@@ -18,8 +18,8 @@ pub(crate) struct Delete {
impl Shadow for Delete {
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
fn shadow(&self, tables: &mut Vec<Table>) -> Self::Result {
let table = tables.iter_mut().find(|t| t.name == self.table);
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
let table = tables.tables.iter_mut().find(|t| t.name == self.table);
if let Some(table) = table {
// If the table exists, we can delete from it

View File

@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use crate::{
generation::Shadow,
model::table::{SimValue, Table},
model::table::SimValue, runner::env::SimulatorTables,
};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@@ -15,7 +15,7 @@ pub(crate) struct Drop {
impl Shadow for Drop {
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
fn shadow(&self, tables: &mut Vec<Table>) -> Self::Result {
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
if !tables.iter().any(|t| t.name == self.table) {
// If the table does not exist, we return an error
return Err(anyhow::anyhow!(
@@ -24,7 +24,7 @@ impl Shadow for Drop {
));
}
tables.retain(|t| t.name != self.table);
tables.tables.retain(|t| t.name != self.table);
Ok(vec![])
}

View File

@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use crate::{
generation::Shadow,
model::table::{SimValue, Table},
model::table::SimValue, runner::env::SimulatorTables,
};
use super::select::Select;
@@ -24,10 +24,10 @@ pub(crate) enum Insert {
impl Shadow for Insert {
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
fn shadow(&self, tables: &mut Vec<Table>) -> Self::Result {
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
match self {
Insert::Values { table, values } => {
if let Some(t) = tables.iter_mut().find(|t| &t.name == table) {
if let Some(t) = tables.tables.iter_mut().find(|t| &t.name == table) {
t.rows.extend(values.clone());
} else {
return Err(anyhow::anyhow!(
@@ -38,7 +38,7 @@ impl Shadow for Insert {
}
Insert::Select { table, select } => {
let rows = select.shadow(tables)?;
if let Some(t) = tables.iter_mut().find(|t| &t.name == table) {
if let Some(t) = tables.tables.iter_mut().find(|t| &t.name == table) {
t.rows.extend(rows);
} else {
return Err(anyhow::anyhow!(

View File

@@ -12,12 +12,8 @@ use update::Update;
use crate::{
generation::Shadow,
model::table::{SimValue, Table},
model::{
query::transaction::{Begin, Commit, Rollback},
table::SimValue,
},
runner::env::SimulatorEnv,
model::{query::transaction::{Begin, Commit, Rollback}, table::SimValue},
runner::env::SimulatorTables,
};
pub mod create;
@@ -79,7 +75,7 @@ impl Query {
impl Shadow for Query {
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
fn shadow(&self, env: &mut Vec<Table>) -> Self::Result {
fn shadow(&self, env: &mut SimulatorTables) -> Self::Result {
match self {
Query::Create(create) => create.shadow(env),
Query::Insert(insert) => insert.shadow(env),
@@ -88,9 +84,9 @@ impl Shadow for Query {
Query::Update(update) => update.shadow(env),
Query::Drop(drop) => drop.shadow(env),
Query::CreateIndex(create_index) => Ok(create_index.shadow(env)),
Query::Begin(begin) => begin.shadow(env),
Query::Commit(commit) => commit.shadow(env),
Query::Rollback(rollback) => rollback.shadow(env),
Query::Begin(begin) => Ok(begin.shadow(env)),
Query::Commit(commit) => Ok(commit.shadow(env)),
Query::Rollback(rollback) => Ok(rollback.shadow(env)),
}
}
}

View File

@@ -11,7 +11,7 @@ use crate::{
model::{
query::EmptyContext,
table::{SimValue, Table},
},
}, runner::env::SimulatorTables,
};
use super::predicate::Predicate;
@@ -253,7 +253,9 @@ impl JoinTable {
impl Shadow for FromClause {
type Result = anyhow::Result<JoinTable>;
fn shadow(&self, tables: &mut Vec<Table>) -> Self::Result {
fn shadow(&self, env: &mut SimulatorTables) -> Self::Result {
let tables = &mut env.tables;
let first_table = tables
.iter()
.find(|t| t.name == self.table)
@@ -309,7 +311,7 @@ impl Shadow for FromClause {
impl Shadow for SelectInner {
type Result = anyhow::Result<JoinTable>;
fn shadow(&self, env: &mut Vec<Table>) -> Self::Result {
fn shadow(&self, env: &mut SimulatorTables) -> Self::Result {
let mut join_table = self.from.shadow(env)?;
let as_table = join_table.clone().into_table();
for row in &mut join_table.rows {
@@ -336,7 +338,7 @@ impl Shadow for SelectInner {
impl Shadow for Select {
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
fn shadow(&self, env: &mut Vec<Table>) -> Self::Result {
fn shadow(&self, env: &mut SimulatorTables) -> Self::Result {
let first_result = self.body.select.shadow(env)?;
let mut rows = first_result.into_table().rows;

View File

@@ -2,7 +2,11 @@ use std::fmt::Display;
use serde::{Deserialize, Serialize};
use crate::{model::table::SimValue, runner::env::SimulatorEnv};
use crate::{
generation::Shadow,
model::table::SimValue,
runner::env::SimulatorTables,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct Begin {
@@ -15,24 +19,27 @@ pub(crate) struct Commit;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct Rollback;
impl Begin {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<SimValue>> {
env.tables_snapshot = Some(env.tables.clone());
impl Shadow for Begin {
type Result = Vec<Vec<SimValue>>;
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
tables.snapshot = Some(tables.tables.clone());
vec![]
}
}
impl Commit {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<SimValue>> {
env.tables_snapshot = None;
impl Shadow for Commit {
type Result = Vec<Vec<SimValue>>;
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
tables.snapshot = None;
vec![]
}
}
impl Rollback {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<SimValue>> {
if let Some(tables) = env.tables_snapshot.take() {
env.tables = tables;
impl Shadow for Rollback {
type Result = Vec<Vec<SimValue>>;
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
if let Some(tables_) = tables.snapshot.take() {
tables.tables = tables_;
}
vec![]
}

View File

@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use crate::{
generation::Shadow,
model::table::{SimValue, Table},
model::table::SimValue, runner::env::SimulatorTables,
};
use super::predicate::Predicate;
@@ -19,8 +19,8 @@ pub(crate) struct Update {
impl Shadow for Update {
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
fn shadow(&self, tables: &mut Vec<Table>) -> Self::Result {
let table = tables.iter_mut().find(|t| t.name == self.table);
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
let table = tables.tables.iter_mut().find(|t| t.name == self.table);
let table = if let Some(table) = table {
table

View File

@@ -1,5 +1,6 @@
use std::fmt::Display;
use std::mem;
use std::ops::Deref;
use std::panic::UnwindSafe;
use std::path::{Path, PathBuf};
use std::sync::Arc;
@@ -27,9 +28,39 @@ pub(crate) enum SimulationPhase {
Shrink,
}
#[derive(Debug, Clone)]
pub(crate) struct SimulatorTables {
pub(crate) tables: Vec<Table>,
pub(crate) snapshot: Option<Vec<Table>>,
}
impl SimulatorTables {
pub(crate) fn new() -> Self {
Self {
tables: Vec::new(),
snapshot: None,
}
}
pub(crate) fn clear(&mut self) {
self.tables.clear();
self.snapshot = None;
}
pub(crate) fn push(&mut self, table: Table) {
self.tables.push(table);
}
}
impl Deref for SimulatorTables {
type Target = Vec<Table>;
fn deref(&self) -> &Self::Target {
&self.tables
}
}
pub(crate) struct SimulatorEnv {
pub(crate) opts: SimulatorOpts,
pub(crate) tables: Vec<Table>,
pub(crate) connections: Vec<SimConnection>,
pub(crate) io: Arc<SimulatorIO>,
pub(crate) db: Arc<Database>,
@@ -37,7 +68,7 @@ pub(crate) struct SimulatorEnv {
pub(crate) paths: Paths,
pub(crate) type_: SimulationType,
pub(crate) phase: SimulationPhase,
pub tables_snapshot: Option<Vec<Table>>,
pub(crate) tables: SimulatorTables,
}
impl UnwindSafe for SimulatorEnv {}
@@ -56,7 +87,6 @@ impl SimulatorEnv {
paths: self.paths.clone(),
type_: self.type_,
phase: self.phase,
tables_snapshot: None,
}
}
@@ -246,7 +276,7 @@ impl SimulatorEnv {
SimulatorEnv {
opts,
tables: Vec::new(),
tables: SimulatorTables::new(),
connections,
paths,
rng,
@@ -254,7 +284,6 @@ impl SimulatorEnv {
db,
type_: simulation_type,
phase: SimulationPhase::Test,
tables_snapshot: None,
}
}

View File

@@ -896,6 +896,7 @@ pub struct FromClause {
pub select: Option<Box<SelectTable>>, // FIXME mandatory
/// `JOIN`ed tabled
pub joins: Option<Vec<JoinedSelectTable>>,
/// A default join operator
pub op: Option<JoinOperator>, // FIXME transient
}
impl FromClause {