Merge 'simulator: add DROP TABLE <t> support' from Alperen Keleş

I wanted to assist the current development in an up-to-date fashion,
this PR adds drop table(which is being implemented currently in
https://github.com/tursodatabase/limbo/pull/897) testing support to the
generator.
Unfortunately, we don't have feature flags in the simulator yet, so the
users should manually fix the generation probability in
`simulator/generation/plan.rs#L644` and
`simulator/generation/property.rs#L629`.

Closes #949
This commit is contained in:
Pekka Enberg
2025-02-11 17:44:49 +02:00
11 changed files with 505 additions and 240 deletions

View File

@@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
use crate::{
model::{
query::{Create, Delete, Distinctness, Insert, Query, Select},
query::{select::Distinctness, Create, Delete, Drop, Insert, Query, Select},
table::Value,
},
runner::env::SimConnection,
@@ -201,14 +201,19 @@ pub(crate) struct InteractionStats {
pub(crate) write_count: usize,
pub(crate) delete_count: usize,
pub(crate) create_count: usize,
pub(crate) drop_count: usize,
}
impl Display for InteractionStats {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Read: {}, Write: {}, Delete: {}, Create: {}",
self.read_count, self.write_count, self.delete_count, self.create_count
"Read: {}, Write: {}, Delete: {}, Create: {}, Drop: {}",
self.read_count,
self.write_count,
self.delete_count,
self.create_count,
self.drop_count
)
}
}
@@ -307,37 +312,40 @@ impl Interactions {
}
select.shadow(env);
}
Property::DropSelect {
table,
queries,
select,
} => {
let drop = Query::Drop(Drop {
table: table.clone(),
});
drop.shadow(env);
for query in queries {
query.shadow(env);
}
select.shadow(env);
}
}
for interaction in property.interactions() {
match interaction {
Interaction::Query(query) => match query {
Query::Create(create) => {
if !env.tables.iter().any(|t| t.name == create.table.name) {
env.tables.push(create.table.clone());
}
create.shadow(env);
}
Query::Insert(insert) => {
let values = match &insert {
Insert::Values { values, .. } => values.clone(),
Insert::Select { select, .. } => select.shadow(env),
};
let table = env
.tables
.iter_mut()
.find(|t| t.name == insert.table())
.unwrap();
table.rows.extend(values);
insert.shadow(env);
}
Query::Delete(delete) => {
let table = env
.tables
.iter_mut()
.find(|t| t.name == delete.table)
.unwrap();
let t2 = &table.clone();
table.rows.retain_mut(|r| delete.predicate.test(r, t2));
delete.shadow(env);
}
Query::Drop(drop) => {
drop.shadow(env);
}
Query::Select(select) => {
select.shadow(env);
}
Query::Select(_) => {}
},
Interaction::Assertion(_) => {}
Interaction::Assumption(_) => {}
@@ -363,6 +371,7 @@ impl InteractionPlan {
let mut write = 0;
let mut delete = 0;
let mut create = 0;
let mut drop = 0;
for interactions in &self.plan {
match interactions {
@@ -374,6 +383,7 @@ impl InteractionPlan {
Query::Insert(_) => write += 1,
Query::Delete(_) => delete += 1,
Query::Create(_) => create += 1,
Query::Drop(_) => drop += 1,
}
}
}
@@ -383,6 +393,7 @@ impl InteractionPlan {
Query::Insert(_) => write += 1,
Query::Delete(_) => delete += 1,
Query::Create(_) => create += 1,
Query::Drop(_) => drop += 1,
},
Interactions::Fault(_) => {}
}
@@ -393,6 +404,7 @@ impl InteractionPlan {
write_count: write,
delete_count: delete,
create_count: create,
drop_count: drop,
}
}
}
@@ -579,7 +591,7 @@ impl Interaction {
}
}
fn create_table<R: rand::Rng>(rng: &mut R, _env: &SimulatorEnv) -> Interactions {
fn random_create<R: rand::Rng>(rng: &mut R, _env: &SimulatorEnv) -> Interactions {
Interactions::Query(Query::Create(Create::arbitrary(rng)))
}
@@ -588,8 +600,15 @@ fn random_read<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv) -> Interactions {
}
fn random_write<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv) -> Interactions {
let insert_query = Query::Insert(Insert::arbitrary_from(rng, env));
Interactions::Query(insert_query)
Interactions::Query(Query::Insert(Insert::arbitrary_from(rng, env)))
}
fn random_delete<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv) -> Interactions {
Interactions::Query(Query::Delete(Delete::arbitrary_from(rng, env)))
}
fn random_drop<R: rand::Rng>(rng: &mut R, env: &SimulatorEnv) -> Interactions {
Interactions::Query(Query::Drop(Drop::arbitrary_from(rng, env)))
}
fn random_fault<R: rand::Rng>(_rng: &mut R, _env: &SimulatorEnv) -> Interactions {
@@ -620,7 +639,16 @@ impl ArbitraryFrom<(&SimulatorEnv, InteractionStats)> for Interactions {
),
(
remaining_.create,
Box::new(|rng: &mut R| create_table(rng, env)),
Box::new(|rng: &mut R| random_create(rng, env)),
),
(
remaining_.delete,
Box::new(|rng: &mut R| random_delete(rng, env)),
),
(
// remaining_.drop,
0.0,
Box::new(|rng: &mut R| random_drop(rng, env)),
),
(
remaining_

View File

@@ -3,7 +3,10 @@ use serde::{Deserialize, Serialize};
use crate::{
model::{
query::{Create, Delete, Distinctness, Insert, Predicate, Query, Select},
query::{
select::{Distinctness, Predicate},
Create, Delete, Drop, Insert, Query, Select,
},
table::Value,
},
runner::env::SimulatorEnv,
@@ -94,6 +97,23 @@ pub(crate) enum Property {
predicate: Predicate,
queries: Vec<Query>,
},
// Drop-Select is a property in which selecting from a dropped table
// should result in an error.
// The execution of the property is as follows
// DROP TABLE <t>
// I_0
// I_1
// ...
// I_n
// SELECT * FROM <t> WHERE <predicate> -> Error
// The interactions in the middle has the following constraints;
// - There will be no errors in the middle interactions.
// - The table `t` will not be created, no table will be renamed to `t`.
DropSelect {
table: String,
queries: Vec<Query>,
select: Select,
},
}
impl Property {
@@ -103,6 +123,7 @@ impl Property {
Property::DoubleCreateFailure { .. } => "Double-Create-Failure".to_string(),
Property::SelectLimit { .. } => "Select-Limit".to_string(),
Property::DeleteSelect { .. } => "Delete-Select".to_string(),
Property::DropSelect { .. } => "Drop-Select".to_string(),
}
}
/// interactions construct a list of interactions, which is an executable representation of the property.
@@ -287,6 +308,55 @@ impl Property {
interactions.push(select);
interactions.push(assertion);
interactions
}
Property::DropSelect {
table,
queries,
select,
} => {
let assumption = Interaction::Assumption(Assertion {
message: format!("table {} exists", table),
func: Box::new({
let table = table.clone();
move |_: &Vec<ResultSet>, env: &SimulatorEnv| {
Ok(env.tables.iter().any(|t| t.name == table))
}
}),
});
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| {
let last = stack.last().unwrap();
match last {
Ok(_) => Ok(false),
Err(e) => Ok(e
.to_string()
.contains(&format!("Table {table_name} does not exist"))),
}
}),
});
let drop = Interaction::Query(Query::Drop(Drop {
table: table.clone(),
}));
let select = Interaction::Query(Query::Select(select.clone()));
let mut interactions = Vec::new();
interactions.push(assumption);
interactions.push(drop);
interactions.extend(queries.clone().into_iter().map(Interaction::Query));
interactions.push(select);
interactions.push(assertion);
interactions
}
}
@@ -298,6 +368,8 @@ pub(crate) struct Remaining {
pub(crate) read: f64,
pub(crate) write: f64,
pub(crate) create: f64,
pub(crate) delete: f64,
pub(crate) drop: f64,
}
pub(crate) fn remaining(env: &SimulatorEnv, stats: &InteractionStats) -> Remaining {
@@ -310,11 +382,19 @@ pub(crate) fn remaining(env: &SimulatorEnv, stats: &InteractionStats) -> Remaini
let remaining_create = ((env.opts.max_interactions as f64 * env.opts.create_percent / 100.0)
- (stats.create_count as f64))
.max(0.0);
let remaining_delete = ((env.opts.max_interactions as f64 * env.opts.delete_percent / 100.0)
- (stats.delete_count as f64))
.max(0.0);
let remaining_drop = ((env.opts.max_interactions as f64 * env.opts.drop_percent / 100.0)
- (stats.drop_count as f64))
.max(0.0);
Remaining {
read: remaining_read,
write: remaining_write,
create: remaining_create,
delete: remaining_delete,
drop: remaining_drop,
}
}
@@ -479,6 +559,47 @@ fn property_delete_select<R: rand::Rng>(
queries,
}
}
fn property_drop_select<R: rand::Rng>(
rng: &mut R,
env: &SimulatorEnv,
remaining: &Remaining,
) -> Property {
// Get a random table
let table = pick(&env.tables, rng);
// Create random queries respecting the constraints
let mut queries = Vec::new();
// - [x] There will be no errors in the middle interactions. (this constraint is impossible to check, so this is just best effort)
// - [-] The table `t` will not be created, no table will be renamed to `t`. (todo: update this constraint once ALTER is implemented)
for _ in 0..rng.gen_range(0..3) {
let query = Query::arbitrary_from(rng, (env, remaining));
match &query {
Query::Create(Create { table: t }) => {
// - The table `t` will not be created
if t.name == table.name {
continue;
}
}
_ => (),
}
queries.push(query);
}
let select = Select {
table: table.name.clone(),
predicate: Predicate::arbitrary_from(rng, table),
limit: None,
distinct: Distinctness::All,
};
Property::DropSelect {
table: table.name.clone(),
queries,
select,
}
}
impl ArbitraryFrom<(&SimulatorEnv, &InteractionStats)> for Property {
fn arbitrary_from<R: rand::Rng>(
rng: &mut R,
@@ -503,6 +624,11 @@ impl ArbitraryFrom<(&SimulatorEnv, &InteractionStats)> for Property {
f64::min(remaining_.read, remaining_.write),
Box::new(|rng: &mut R| property_delete_select(rng, env, &remaining_)),
),
(
// remaining_.drop,
0.0,
Box::new(|rng: &mut R| property_drop_select(rng, env, &remaining_)),
),
],
rng,
)

View File

@@ -1,7 +1,8 @@
use crate::generation::table::{GTValue, LTValue};
use crate::generation::{one_of, Arbitrary, ArbitraryFrom};
use crate::model::query::{Create, Delete, Distinctness, Insert, Predicate, Query, Select};
use crate::model::query::select::{Distinctness, Predicate};
use crate::model::query::{Create, Delete, Drop, Insert, Query, Select};
use crate::model::table::{Table, Value};
use crate::SimulatorEnv;
use rand::seq::SliceRandom as _;
@@ -96,6 +97,15 @@ impl ArbitraryFrom<&SimulatorEnv> for Delete {
}
}
impl ArbitraryFrom<&SimulatorEnv> for Drop {
fn arbitrary_from<R: Rng>(rng: &mut R, env: &SimulatorEnv) -> Self {
let table = pick(&env.tables, rng);
Self {
table: table.name.clone(),
}
}
}
impl ArbitraryFrom<(&SimulatorEnv, &Remaining)> for Query {
fn arbitrary_from<R: Rng>(rng: &mut R, (env, remaining): (&SimulatorEnv, &Remaining)) -> Self {
frequency(

View File

@@ -0,0 +1,38 @@
use std::fmt::Display;
use serde::{Deserialize, Serialize};
use crate::{
model::table::{Table, Value},
SimulatorEnv,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct Create {
pub(crate) table: Table,
}
impl Create {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<Value>> {
if !env.tables.iter().any(|t| t.name == self.table.name) {
env.tables.push(self.table.clone());
}
vec![]
}
}
impl Display for Create {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "CREATE TABLE {} (", self.table.name)?;
for (i, column) in self.table.columns.iter().enumerate() {
if i != 0 {
write!(f, ",")?;
}
write!(f, "{} {}", column.name, column.column_type)?;
}
write!(f, ")")
}
}

View File

@@ -0,0 +1,35 @@
use std::fmt::Display;
use serde::{Deserialize, Serialize};
use crate::{model::table::Value, SimulatorEnv};
use super::select::Predicate;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct Delete {
pub(crate) table: String,
pub(crate) predicate: Predicate,
}
impl Delete {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<Value>> {
let table = env
.tables
.iter_mut()
.find(|t| t.name == self.table)
.unwrap();
let t2 = table.clone();
table.rows.retain_mut(|r| self.predicate.test(r, &t2));
vec![]
}
}
impl Display for Delete {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "DELETE FROM {} WHERE {}", self.table, self.predicate)
}
}

View File

@@ -0,0 +1,23 @@
use std::fmt::Display;
use serde::{Deserialize, Serialize};
use crate::{model::table::Value, SimulatorEnv};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct Drop {
pub(crate) table: String,
}
impl Drop {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<Value>> {
env.tables.retain(|t| t.name != self.table);
vec![]
}
}
impl Display for Drop {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "DROP TABLE {}", self.table)
}
}

View File

@@ -0,0 +1,73 @@
use std::fmt::Display;
use serde::{Deserialize, Serialize};
use crate::{model::table::Value, SimulatorEnv};
use super::select::Select;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) enum Insert {
Values {
table: String,
values: Vec<Vec<Value>>,
},
Select {
table: String,
select: Box<Select>,
},
}
impl Insert {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<Value>> {
match self {
Insert::Values { table, values } => {
if let Some(t) = env.tables.iter_mut().find(|t| &t.name == table) {
t.rows.extend(values.clone());
}
}
Insert::Select { table, select } => {
let rows = select.shadow(env);
if let Some(t) = env.tables.iter_mut().find(|t| &t.name == table) {
t.rows.extend(rows);
}
}
}
vec![]
}
pub(crate) fn table(&self) -> &str {
match self {
Insert::Values { table, .. } | Insert::Select { table, .. } => table,
}
}
}
impl Display for Insert {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Insert::Values { table, values } => {
write!(f, "INSERT INTO {} VALUES ", table)?;
for (i, row) in values.iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "(")?;
for (j, value) in row.iter().enumerate() {
if j != 0 {
write!(f, ", ")?;
}
write!(f, "{}", value)?;
}
write!(f, ")")?;
}
Ok(())
}
Insert::Select { table, select } => {
write!(f, "INSERT INTO {} ", table)?;
write!(f, "{}", select)
}
}
}
}

View File

@@ -0,0 +1,71 @@
use std::fmt::Display;
pub(crate) use create::Create;
pub(crate) use delete::Delete;
pub(crate) use drop::Drop;
pub(crate) use insert::Insert;
pub(crate) use select::Select;
use serde::{Deserialize, Serialize};
use crate::{model::table::Value, runner::env::SimulatorEnv};
pub mod create;
pub mod delete;
pub mod drop;
pub mod insert;
pub mod select;
// This type represents the potential queries on the database.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) enum Query {
Create(Create),
Select(Select),
Insert(Insert),
Delete(Delete),
Drop(Drop),
}
impl Query {
pub(crate) fn dependencies(&self) -> Vec<String> {
match self {
Query::Create(_) => vec![],
Query::Select(Select { table, .. })
| Query::Insert(Insert::Select { table, .. })
| Query::Insert(Insert::Values { table, .. })
| Query::Delete(Delete { table, .. })
| Query::Drop(Drop { table, .. }) => vec![table.clone()],
}
}
pub(crate) fn uses(&self) -> Vec<String> {
match self {
Query::Create(Create { table }) => vec![table.name.clone()],
Query::Select(Select { table, .. })
| Query::Insert(Insert::Select { table, .. })
| Query::Insert(Insert::Values { table, .. })
| Query::Delete(Delete { table, .. })
| Query::Drop(Drop { table, .. }) => vec![table.clone()],
}
}
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<Value>> {
match self {
Query::Create(create) => create.shadow(env),
Query::Insert(insert) => insert.shadow(env),
Query::Delete(delete) => delete.shadow(env),
Query::Select(select) => select.shadow(env),
Query::Drop(drop) => drop.shadow(env),
}
}
}
impl Display for Query {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Create(create) => write!(f, "{}", create),
Self::Select(select) => write!(f, "{}", select),
Self::Insert(insert) => write!(f, "{}", insert),
Self::Delete(delete) => write!(f, "{}", delete),
Self::Drop(drop) => write!(f, "{}", drop),
}
}
}

View File

@@ -5,9 +5,55 @@ use serde::{Deserialize, Serialize};
use crate::{
model::table::{Table, Value},
runner::env::SimulatorEnv,
SimulatorEnv,
};
/// `SELECT` distinctness
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Distinctness {
/// `DISTINCT`
Distinct,
/// `ALL`
All,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct Select {
pub(crate) table: String,
pub(crate) predicate: Predicate,
pub(crate) distinct: Distinctness,
pub(crate) limit: Option<usize>,
}
impl Select {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<Value>> {
let table = env.tables.iter().find(|t| t.name == self.table.as_str());
if let Some(table) = table {
table
.rows
.iter()
.filter(|row| self.predicate.test(row, table))
.cloned()
.collect()
} else {
vec![]
}
}
}
impl Display for Select {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"SELECT * FROM {} WHERE {}{}",
self.table,
self.predicate,
self.limit
.map_or("".to_string(), |l| format!(" LIMIT {}", l))
)
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) enum Predicate {
And(Vec<Predicate>), // p1 AND p2 AND p3... AND pn
@@ -127,201 +173,3 @@ impl Display for Predicate {
}
}
}
// This type represents the potential queries on the database.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) enum Query {
Create(Create),
Select(Select),
Insert(Insert),
Delete(Delete),
}
impl Query {
pub(crate) fn dependencies(&self) -> Vec<String> {
match self {
Query::Create(_) => vec![],
Query::Select(Select { table, .. })
| Query::Insert(Insert::Select { table, .. })
| Query::Insert(Insert::Values { table, .. })
| Query::Delete(Delete { table, .. }) => vec![table.clone()],
}
}
pub(crate) fn uses(&self) -> Vec<String> {
match self {
Query::Create(Create { table }) => vec![table.name.clone()],
Query::Select(Select { table, .. })
| Query::Insert(Insert::Select { table, .. })
| Query::Insert(Insert::Values { table, .. })
| Query::Delete(Delete { table, .. }) => vec![table.clone()],
}
}
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<Value>> {
match self {
Query::Create(create) => create.shadow(env),
Query::Insert(insert) => insert.shadow(env),
Query::Delete(delete) => delete.shadow(env),
Query::Select(select) => select.shadow(env),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct Create {
pub(crate) table: Table,
}
impl Create {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<Value>> {
if !env.tables.iter().any(|t| t.name == self.table.name) {
env.tables.push(self.table.clone());
}
vec![]
}
}
impl Display for Create {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "CREATE TABLE {} (", self.table.name)?;
for (i, column) in self.table.columns.iter().enumerate() {
if i != 0 {
write!(f, ",")?;
}
write!(f, "{} {}", column.name, column.column_type)?;
}
write!(f, ")")
}
}
/// `SELECT` distinctness
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Distinctness {
/// `DISTINCT`
Distinct,
/// `ALL`
All,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct Select {
pub(crate) table: String,
pub(crate) predicate: Predicate,
pub(crate) distinct: Distinctness,
pub(crate) limit: Option<usize>,
}
impl Select {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<Value>> {
let table = env.tables.iter().find(|t| t.name == self.table.as_str());
if let Some(table) = table {
table
.rows
.iter()
.filter(|row| self.predicate.test(row, table))
.cloned()
.collect()
} else {
vec![]
}
}
}
impl Display for Select {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"SELECT * FROM {} WHERE {}{}",
self.table,
self.predicate,
self.limit
.map_or("".to_string(), |l| format!(" LIMIT {}", l))
)
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) enum Insert {
Values {
table: String,
values: Vec<Vec<Value>>,
},
Select {
table: String,
select: Box<Select>,
},
}
impl Insert {
pub(crate) fn shadow(&self, env: &mut SimulatorEnv) -> Vec<Vec<Value>> {
match self {
Insert::Values { table, values } => {
if let Some(t) = env.tables.iter_mut().find(|t| &t.name == table) {
t.rows.extend(values.clone());
}
}
Insert::Select { table, select } => {
let rows = select.shadow(env);
if let Some(t) = env.tables.iter_mut().find(|t| &t.name == table) {
t.rows.extend(rows);
}
}
}
vec![]
}
pub(crate) fn table(&self) -> &str {
match self {
Insert::Values { table, .. } | Insert::Select { table, .. } => table,
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub(crate) struct Delete {
pub(crate) table: String,
pub(crate) predicate: Predicate,
}
impl Delete {
pub(crate) fn shadow(&self, _env: &mut SimulatorEnv) -> Vec<Vec<Value>> {
vec![]
}
}
impl Display for Query {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Create(create) => write!(f, "{}", create),
Self::Select(select) => write!(f, "{}", select),
Self::Insert(Insert::Values { table, values }) => {
write!(f, "INSERT INTO {} VALUES ", table)?;
for (i, row) in values.iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "(")?;
for (j, value) in row.iter().enumerate() {
if j != 0 {
write!(f, ", ")?;
}
write!(f, "{}", value)?;
}
write!(f, ")")?;
}
Ok(())
}
Self::Insert(Insert::Select { table, select }) => {
write!(f, "INSERT INTO {} ", table)?;
write!(f, "{}", select)
}
Self::Delete(Delete {
table,
predicate: guard,
}) => write!(f, "DELETE FROM {} WHERE {}", table, guard),
}
}
}

View File

@@ -26,18 +26,28 @@ impl SimulatorEnv {
pub(crate) fn new(seed: u64, cli_opts: &SimulatorCLI, db_path: &Path) -> Self {
let mut rng = ChaCha8Rng::seed_from_u64(seed);
let (create_percent, read_percent, write_percent, delete_percent) = {
let mut remaining = 100.0;
let read_percent = rng.gen_range(0.0..=remaining);
remaining -= read_percent;
let write_percent = rng.gen_range(0.0..=remaining);
remaining -= write_percent;
let delete_percent = remaining;
let (create_percent, read_percent, write_percent, delete_percent, drop_percent) = {
let total = 100.0;
let create_percent = write_percent / 10.0;
let write_percent = write_percent - create_percent;
let read_percent = rng.gen_range(0.0..=total);
let write_percent = total - read_percent;
(create_percent, read_percent, write_percent, delete_percent)
// Create percent should be 5-15% of the write percent
let create_percent = rng.gen_range(0.05..=0.15) * write_percent;
// Drop percent should be 2-5% of the write percent
let drop_percent = rng.gen_range(0.02..=0.05) * write_percent;
// Delete percent should be 10-20% of the write percent
let delete_percent = rng.gen_range(0.1..=0.2) * write_percent;
let write_percent = write_percent - create_percent - delete_percent - drop_percent;
(
create_percent,
read_percent,
write_percent,
delete_percent,
drop_percent,
)
};
let opts = SimulatorOpts {
@@ -49,6 +59,7 @@ impl SimulatorEnv {
read_percent,
write_percent,
delete_percent,
drop_percent,
page_size: 4096, // TODO: randomize this too
max_interactions: rng.gen_range(cli_opts.minimum_size..=cli_opts.maximum_size),
max_time_simulation: cli_opts.maximum_time,
@@ -98,6 +109,7 @@ pub(crate) struct SimulatorOpts {
pub(crate) read_percent: f64,
pub(crate) write_percent: f64,
pub(crate) delete_percent: f64,
pub(crate) drop_percent: f64,
pub(crate) max_interactions: usize,
pub(crate) page_size: usize,
pub(crate) max_time_simulation: usize,

View File

@@ -32,7 +32,8 @@ impl InteractionPlan {
match p {
Property::InsertValuesSelect { queries, .. }
| Property::DoubleCreateFailure { queries, .. }
| Property::DeleteSelect { queries, .. } => {
| Property::DeleteSelect { queries, .. }
| Property::DropSelect { queries, .. } => {
queries.clear();
}
Property::SelectLimit { .. } => {}