diff --git a/simulator/generation/plan.rs b/simulator/generation/plan.rs index c8925cd59..d0c09cd8a 100644 --- a/simulator/generation/plan.rs +++ b/simulator/generation/plan.rs @@ -181,6 +181,7 @@ impl InteractionPlan { begin_count: 0, commit_count: 0, rollback_count: 0, + pragma_count: 0, }; fn query_stat(q: &Query, stats: &mut InteractionStats) { @@ -196,6 +197,7 @@ impl InteractionPlan { Query::Commit(_) => stats.commit_count += 1, Query::Rollback(_) => stats.rollback_count += 1, Query::Placeholder => {} + Query::Pragma(_) => stats.pragma_count += 1, } } for interactions in &self.plan { @@ -724,6 +726,7 @@ pub(crate) struct InteractionStats { pub(crate) begin_count: u32, pub(crate) commit_count: u32, pub(crate) rollback_count: u32, + pub(crate) pragma_count: u32, } impl InteractionStats { diff --git a/simulator/generation/property.rs b/simulator/generation/property.rs index 47b352406..26448d471 100644 --- a/simulator/generation/property.rs +++ b/simulator/generation/property.rs @@ -326,7 +326,6 @@ impl Property { let rows = insert.rows(); let row = &rows[*row_index]; - match &query { Query::Delete(Delete { table: t, @@ -1385,6 +1384,7 @@ pub(crate) struct Remaining { pub(crate) delete: u32, pub(crate) update: u32, pub(crate) drop: u32, + pub(crate) pragma: u32, } pub(crate) fn remaining( @@ -1408,6 +1408,7 @@ pub(crate) fn remaining( let total_delete = (max_interactions * opts.delete_weight) / total_weight; let total_update = (max_interactions * opts.update_weight) / total_weight; let total_drop = (max_interactions * opts.drop_table_weight) / total_weight; + let total_pragma = (max_interactions * opts.pragma_weight) / total_weight; let remaining_select = total_select .checked_sub(stats.select_count) @@ -1428,6 +1429,9 @@ pub(crate) fn remaining( .checked_sub(stats.update_count) .unwrap_or_default(); let remaining_drop = total_drop.checked_sub(stats.drop_count).unwrap_or_default(); + let remaining_pragma = total_pragma + .checked_sub(stats.pragma_count) + .unwrap_or_default(); if mvcc { // TODO: index not supported yet for mvcc @@ -1442,6 +1446,7 @@ pub(crate) fn remaining( delete: remaining_delete, drop: remaining_drop, update: remaining_update, + pragma: remaining_pragma, } } diff --git a/simulator/generation/query.rs b/simulator/generation/query.rs index 914b44b35..3c8f148dd 100644 --- a/simulator/generation/query.rs +++ b/simulator/generation/query.rs @@ -5,11 +5,16 @@ use crate::{ use rand::{ Rng, distr::{Distribution, weighted::WeightedIndex}, + seq::IndexedRandom, }; use sql_generation::{ generation::{Arbitrary, ArbitraryFrom, GenerationContext, query::SelectFree}, model::{ - query::{Create, CreateIndex, Delete, Insert, Select, update::Update}, + query::{ + Create, CreateIndex, Delete, Insert, Select, + pragma::{Pragma, VacuumMode}, + update::Update, + }, table::Table, }, }; @@ -79,6 +84,18 @@ fn random_create_index( Query::CreateIndex(create_index) } +fn random_pragma(rng: &mut R, _conn_ctx: &impl GenerationContext) -> Query { + const ALL_MODES: [VacuumMode; 2] = [ + VacuumMode::None, + // VacuumMode::Incremental, not implemented yer + VacuumMode::Full, + ]; + + let mode = ALL_MODES.choose(rng).unwrap(); + + Query::Pragma(Pragma::AutoVacuumMode(mode.clone())) +} + /// Possible queries that can be generated given the table state /// /// Does not take into account transactional statements @@ -114,14 +131,13 @@ impl QueryDiscriminants { QueryDiscriminants::Placeholder => { unreachable!("Query Placeholders should not be generated") } + QueryDiscriminants::Pragma => random_pragma, } } pub fn weight(&self, remaining: &Remaining) -> u32 { match self { QueryDiscriminants::Create => remaining.create, - // remaining.select / 3 is for the random_expr generation - // have a max of 1 so that we always generate at least a non zero weight for `QueryDistribution` QueryDiscriminants::Select => (remaining.select + remaining.select / 3).max(1), QueryDiscriminants::Insert => remaining.insert, QueryDiscriminants::Delete => remaining.delete, @@ -136,6 +152,7 @@ impl QueryDiscriminants { QueryDiscriminants::Placeholder => { unreachable!("Query Placeholders should not be generated") } + QueryDiscriminants::Pragma => remaining.pragma, } } } diff --git a/simulator/model/mod.rs b/simulator/model/mod.rs index 9e3d29db2..d6871623a 100644 --- a/simulator/model/mod.rs +++ b/simulator/model/mod.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; use sql_generation::model::{ query::{ Create, CreateIndex, Delete, Drop, Insert, Select, + pragma::Pragma, select::{CompoundOperator, FromClause, ResultColumn, SelectInner}, transaction::{Begin, Commit, Rollback}, update::Update, @@ -32,6 +33,7 @@ pub enum Query { Begin(Begin), Commit(Commit), Rollback(Rollback), + Pragma(Pragma), /// Placeholder query that still needs to be generated Placeholder, } @@ -71,8 +73,11 @@ impl Query { Query::CreateIndex(CreateIndex { table_name, .. }) => { IndexSet::from_iter([table_name.clone()]) } - Query::Begin(_) | Query::Commit(_) | Query::Rollback(_) => IndexSet::new(), - Query::Placeholder => IndexSet::new(), + Query::Begin(_) + | Query::Commit(_) + | Query::Rollback(_) + | Query::Placeholder + | Query::Pragma(_) => IndexSet::new(), } } pub fn uses(&self) -> Vec { @@ -80,13 +85,14 @@ impl Query { Query::Create(Create { table }) => vec![table.name.clone()], Query::Select(select) => select.dependencies().into_iter().collect(), Query::Insert(Insert::Select { table, .. }) - | Query::Insert(Insert::Values { table, .. }) - | Query::Delete(Delete { table, .. }) - | Query::Update(Update { table, .. }) - | Query::Drop(Drop { table, .. }) => vec![table.clone()], + | Query::Insert(Insert::Values { table, .. }) + | Query::Delete(Delete { table, .. }) + | Query::Update(Update { table, .. }) + | Query::Drop(Drop { table, .. }) => vec![table.clone()], Query::CreateIndex(CreateIndex { table_name, .. }) => vec![table_name.clone()], Query::Begin(..) | Query::Commit(..) | Query::Rollback(..) => vec![], Query::Placeholder => vec![], + Query::Pragma(_) => vec![], } } @@ -121,6 +127,7 @@ impl Display for Query { Self::Commit(commit) => write!(f, "{commit}"), Self::Rollback(rollback) => write!(f, "{rollback}"), Self::Placeholder => Ok(()), + Query::Pragma(pragma) => write!(f, "{pragma}"), } } } @@ -141,12 +148,14 @@ impl Shadow for Query { Query::Commit(commit) => Ok(commit.shadow(env)), Query::Rollback(rollback) => Ok(rollback.shadow(env)), Query::Placeholder => Ok(vec![]), + Query::Pragma(Pragma::AutoVacuumMode(_)) => Ok(vec![]), } } } bitflags! { pub struct QueryCapabilities: u32 { + const NONE = 0; const CREATE = 1 << 0; const SELECT = 1 << 1; const INSERT = 1 << 2; @@ -190,6 +199,7 @@ impl From for QueryCapabilities { QueryDiscriminants::Placeholder => { unreachable!("QueryCapabilities do not apply to query Placeholder") } + QueryDiscriminants::Pragma => QueryCapabilities::NONE, } } } @@ -203,6 +213,7 @@ impl QueryDiscriminants { QueryDiscriminants::Delete, QueryDiscriminants::Drop, QueryDiscriminants::CreateIndex, + QueryDiscriminants::Pragma, ]; #[inline] diff --git a/simulator/profiles/query.rs b/simulator/profiles/query.rs index a58c983e0..81f433a02 100644 --- a/simulator/profiles/query.rs +++ b/simulator/profiles/query.rs @@ -22,6 +22,8 @@ pub struct QueryProfile { pub delete_weight: u32, #[garde(skip)] pub drop_table_weight: u32, + #[garde(skip)] + pub pragma_weight: u32, } impl Default for QueryProfile { @@ -35,6 +37,7 @@ impl Default for QueryProfile { update_weight: 20, delete_weight: 20, drop_table_weight: 2, + pragma_weight: 100,//TODO change this back to 2 } } } diff --git a/sql_generation/model/query/mod.rs b/sql_generation/model/query/mod.rs index 98ec2bdfd..26aedb6a3 100644 --- a/sql_generation/model/query/mod.rs +++ b/sql_generation/model/query/mod.rs @@ -16,3 +16,4 @@ pub mod predicate; pub mod select; pub mod transaction; pub mod update; +pub mod pragma; diff --git a/sql_generation/model/query/pragma.rs b/sql_generation/model/query/pragma.rs new file mode 100644 index 000000000..2bf8fca2a --- /dev/null +++ b/sql_generation/model/query/pragma.rs @@ -0,0 +1,28 @@ +use std::fmt::Display; + +pub enum Pragma { + AutoVacuumMode(VacuumMode), +} + +pub enum VacuumMode { + None, + Incremental, + Full, +} + +impl Display for Pragma { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Pragma::AutoVacuumMode(vacuum_mode) => { + let mode = match vacuum_mode { + VacuumMode::None => "none", + VacuumMode::Incremental => "incremental", + VacuumMode::Full => "full", + }; + + write!(f, "PRAGMA auto_vacuum={mode} ")?; + Ok(()) + } + } + } +}