From 7eb504baefcfc71b6e00c8445773571151a5a394 Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Mon, 6 Oct 2025 14:00:38 -0300 Subject: [PATCH] certain properties cannot be generated if there are no tables in the current context --- simulator/generation/plan.rs | 3 +- simulator/generation/property.rs | 48 ++++++++++++++++++++++++-------- simulator/generation/query.rs | 2 +- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/simulator/generation/plan.rs b/simulator/generation/plan.rs index 05373312f..3e6e1ab9e 100644 --- a/simulator/generation/plan.rs +++ b/simulator/generation/plan.rs @@ -1097,8 +1097,7 @@ impl ArbitraryFrom<(&SimulatorEnv, InteractionStats, usize)> for Interactions { let queries = possible_queries(conn_ctx.tables()); let query_distr = QueryDistribution::new(queries, &remaining_); - let property_distr = - PropertyDistribution::new(env, &remaining_, &query_distr, conn_ctx.opts()); + let property_distr = PropertyDistribution::new(env, &remaining_, &query_distr, conn_ctx); frequency( vec![ diff --git a/simulator/generation/property.rs b/simulator/generation/property.rs index 3fef90b51..b82eab8bf 100644 --- a/simulator/generation/property.rs +++ b/simulator/generation/property.rs @@ -1248,6 +1248,7 @@ fn property_insert_values_select( ctx: &impl GenerationContext, mvcc: bool, ) -> Property { + assert!(!ctx.tables().is_empty()); // Get a random table let table = pick(ctx.tables(), rng); // Generate rows to insert @@ -1373,6 +1374,7 @@ fn property_table_has_expected_content( ctx: &impl GenerationContext, _mvcc: bool, ) -> Property { + assert!(!ctx.tables().is_empty()); // Get a random table let table = pick(ctx.tables(), rng); Property::TableHasExpectedContent { @@ -1386,6 +1388,7 @@ fn property_select_limit( ctx: &impl GenerationContext, _mvcc: bool, ) -> Property { + assert!(!ctx.tables().is_empty()); // Get a random table let table = pick(ctx.tables(), rng); // Select the table @@ -1442,6 +1445,7 @@ fn property_delete_select( ctx: &impl GenerationContext, _mvcc: bool, ) -> Property { + assert!(!ctx.tables().is_empty()); // Get a random table let table = pick(ctx.tables(), rng); // Generate a random predicate @@ -1503,6 +1507,7 @@ fn property_drop_select( ctx: &impl GenerationContext, _mvcc: bool, ) -> Property { + assert!(!ctx.tables().is_empty()); // Get a random table let table = pick(ctx.tables(), rng); @@ -1545,6 +1550,7 @@ fn property_select_select_optimizer( ctx: &impl GenerationContext, _mvcc: bool, ) -> Property { + assert!(!ctx.tables().is_empty()); // Get a random table let table = pick(ctx.tables(), rng); // Generate a random predicate @@ -1568,6 +1574,7 @@ fn property_where_true_false_null( ctx: &impl GenerationContext, _mvcc: bool, ) -> Property { + assert!(!ctx.tables().is_empty()); // Get a random table let table = pick(ctx.tables(), rng); // Generate a random predicate @@ -1589,6 +1596,7 @@ fn property_union_all_preserves_cardinality( ctx: &impl GenerationContext, _mvcc: bool, ) -> Property { + assert!(!ctx.tables().is_empty()); // Get a random table let table = pick(ctx.tables(), rng); // Generate a random predicate @@ -1663,10 +1671,16 @@ impl PropertyDiscriminants { } } - pub fn weight(&self, env: &SimulatorEnv, remaining: &Remaining, opts: &Opts) -> u32 { + pub fn weight( + &self, + env: &SimulatorEnv, + remaining: &Remaining, + ctx: &impl GenerationContext, + ) -> u32 { + let opts = ctx.opts(); match self { PropertyDiscriminants::InsertValuesSelect => { - if !env.opts.disable_insert_values_select { + if !env.opts.disable_insert_values_select && !ctx.tables().is_empty() { u32::min(remaining.select, remaining.insert).max(1) } else { 0 @@ -1675,7 +1689,13 @@ impl PropertyDiscriminants { PropertyDiscriminants::ReadYourUpdatesBack => { u32::min(remaining.select, remaining.insert).max(1) } - PropertyDiscriminants::TableHasExpectedContent => remaining.select.max(1), + PropertyDiscriminants::TableHasExpectedContent => { + if !ctx.tables().is_empty() { + remaining.select.max(1) + } else { + 0 + } + } PropertyDiscriminants::DoubleCreateFailure => { if !env.opts.disable_double_create_failure { remaining.create / 2 @@ -1684,42 +1704,48 @@ impl PropertyDiscriminants { } } PropertyDiscriminants::SelectLimit => { - if !env.opts.disable_select_limit { + if !env.opts.disable_select_limit && !ctx.tables().is_empty() { remaining.select } else { 0 } } PropertyDiscriminants::DeleteSelect => { - if !env.opts.disable_delete_select { + if !env.opts.disable_delete_select && !ctx.tables().is_empty() { u32::min(remaining.select, remaining.insert).min(remaining.delete) } else { 0 } } PropertyDiscriminants::DropSelect => { - if !env.opts.disable_drop_select { + if !env.opts.disable_drop_select && !ctx.tables().is_empty() { remaining.drop } else { 0 } } PropertyDiscriminants::SelectSelectOptimizer => { - if !env.opts.disable_select_optimizer { + if !env.opts.disable_select_optimizer && !ctx.tables().is_empty() { remaining.select / 2 } else { 0 } } PropertyDiscriminants::WhereTrueFalseNull => { - if opts.indexes && !env.opts.disable_where_true_false_null { + if opts.indexes + && !env.opts.disable_where_true_false_null + && !ctx.tables().is_empty() + { remaining.select / 2 } else { 0 } } PropertyDiscriminants::UNIONAllPreservesCardinality => { - if opts.indexes && !env.opts.disable_union_all_preserves_cardinality { + if opts.indexes + && !env.opts.disable_union_all_preserves_cardinality + && !ctx.tables().is_empty() + { remaining.select / 3 } else { 0 @@ -1803,13 +1829,13 @@ impl<'a> PropertyDistribution<'a> { env: &SimulatorEnv, remaining: &Remaining, query_distr: &'a QueryDistribution, - opts: &Opts, + ctx: &impl GenerationContext, ) -> Self { let properties = PropertyDiscriminants::can_generate(query_distr.items()); let weights = WeightedIndex::new( properties .iter() - .map(|property| property.weight(env, remaining, opts)), + .map(|property| property.weight(env, remaining, ctx)), ) .unwrap(); diff --git a/simulator/generation/query.rs b/simulator/generation/query.rs index a78df68c6..068e4f5e7 100644 --- a/simulator/generation/query.rs +++ b/simulator/generation/query.rs @@ -29,7 +29,7 @@ fn random_create(rng: &mut R, conn_ctx: &impl GenerationC } fn random_select(rng: &mut R, conn_ctx: &impl GenerationContext) -> Query { - if rng.random_bool(0.7) { + if !conn_ctx.tables().is_empty() && rng.random_bool(0.7) { Query::Select(Select::arbitrary(rng, conn_ctx)) } else { // Random expression