generate self-inserts with nested subqueries

This commit is contained in:
Mikaël Francoeur
2025-11-10 19:27:58 -05:00
parent 23d6080531
commit d309e6ddb3
3 changed files with 49 additions and 16 deletions

View File

@@ -7,12 +7,12 @@ use serde::{Deserialize, Serialize};
use sql_generation::model::query::select::SelectTable;
use sql_generation::model::{
query::{
alter_table::{AlterTable, AlterTableType}, pragma::Pragma, select::{CompoundOperator, FromClause, ResultColumn, SelectInner}, transaction::{Begin, Commit, Rollback}, update::Update, Create, CreateIndex,
Delete,
Drop,
DropIndex,
Insert,
Select,
Create, CreateIndex, Delete, Drop, DropIndex, Insert, Select,
alter_table::{AlterTable, AlterTableType},
pragma::Pragma,
select::{CompoundOperator, FromClause, ResultColumn, SelectInner},
transaction::{Begin, Commit, Rollback},
update::Update,
},
table::{Index, JoinTable, JoinType, SimValue, Table, TableContext},
};
@@ -323,6 +323,7 @@ impl Shadow for Drop {
impl Shadow for Insert {
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
//FIXME this doesn't handle type affinity
fn shadow(&self, tables: &mut ShadowTablesMut) -> Self::Result {
match self {
Insert::Values { table, values } => {
@@ -381,7 +382,6 @@ impl Shadow for FromClause {
}
};
for join in &self.joins {
let joined_table = tables
.iter()

View File

@@ -184,6 +184,7 @@ pub fn gen_random_text<R: Rng + ?Sized>(rng: &mut R) -> String {
}
}
//FIXME this can hang if count > items.len() or if there are duplicates
pub fn pick_unique<'a, T: PartialEq, R: Rng + ?Sized>(
items: &'a [T],
count: usize,

View File

@@ -4,7 +4,10 @@ use crate::generation::{
};
use crate::model::query::alter_table::{AlterTable, AlterTableType, AlterTableTypeDiscriminants};
use crate::model::query::predicate::Predicate;
use crate::model::query::select::{CompoundOperator, CompoundSelect, Distinctness, FromClause, OrderBy, ResultColumn, SelectBody, SelectInner, SelectTable};
use crate::model::query::select::{
CompoundOperator, CompoundSelect, Distinctness, FromClause, OrderBy, ResultColumn, SelectBody,
SelectInner, SelectTable,
};
use crate::model::query::update::Update;
use crate::model::query::{Create, CreateIndex, Delete, Drop, DropIndex, Insert, Select};
use crate::model::table::{
@@ -81,7 +84,10 @@ impl Arbitrary for FromClause {
})
})
.collect();
FromClause { table: SelectTable::Table(name), joins }
FromClause {
table: SelectTable::Table(name),
joins,
}
}
}
@@ -146,6 +152,7 @@ impl Arbitrary for SelectInner {
}
impl ArbitrarySized for SelectInner {
//FIXME this can generate SELECT statements containing fewer columns than the num_result_columns parameter.
fn arbitrary_sized<R: Rng + ?Sized, C: GenerationContext>(
rng: &mut R,
env: &C,
@@ -282,13 +289,35 @@ impl Arbitrary for Insert {
})
};
let gen_self_select = |rng: &mut R| {
let gen_nested_self_insert = |rng: &mut R| {
let table = pick(env.tables(), rng);
if table.rows.is_empty() {
return None;
const MAX_SELF_INSERT_DEPTH: i32 = 5;
let nesting_depth = rng.random_range(1..=MAX_SELF_INSERT_DEPTH);
let mut select = Select::simple(
table.name.clone(),
Predicate::arbitrary_from(rng, env, table),
);
for _ in 1..nesting_depth {
select = Select {
body: SelectBody {
select: Box::new(SelectInner {
distinctness: Distinctness::All,
columns: vec![ResultColumn::Star],
from: Some(FromClause {
table: SelectTable::Select(select),
joins: Vec::new(),
}),
where_clause: Predicate::true_(),
order_by: None,
}),
compounds: Vec::new(),
},
limit: None,
};
}
let predicate = Predicate::true_();
let select = Select::simple(table.name.clone(), predicate);
Some(Insert::Select {
table: table.name.clone(),
@@ -297,10 +326,13 @@ impl Arbitrary for Insert {
};
backtrack(
vec![(1, Box::new(gen_values)), (1, Box::new(gen_self_select))],
vec![
(1, Box::new(gen_values)),
(1, Box::new(gen_nested_self_insert)),
],
rng,
)
.expect("backtrack with these arguments should not return None")
.expect("backtrack with these arguments should not return None")
}
}