use crate::SqlError;
#[derive(Debug, Clone, Copy)]
pub struct QueryLimits {
pub max_input_bytes: usize,
pub max_mir_nodes: usize,
}
impl QueryLimits {
pub const DEFAULT: Self = Self {
max_input_bytes: 64 * 1024,
max_mir_nodes: 256,
};
}
impl Default for QueryLimits {
fn default() -> Self {
Self::DEFAULT
}
}
pub const fn enforce_input_size(sql: &str, limits: QueryLimits) -> Result<(), SqlError> {
let len = sql.len();
if len > limits.max_input_bytes {
Err(SqlError::QueryTooLarge {
len,
limit: limits.max_input_bytes,
})
} else {
Ok(())
}
}
pub const fn enforce_graph_size(nodes: usize, limits: QueryLimits) -> Result<(), SqlError> {
if nodes > limits.max_mir_nodes {
Err(SqlError::QueryTooComplex {
nodes,
limit: limits.max_mir_nodes,
})
} else {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::{enforce_graph_size, enforce_input_size, QueryLimits};
use crate::SqlError;
#[test]
fn input_at_limit_passes() {
let limits = QueryLimits {
max_input_bytes: 4,
max_mir_nodes: 8,
};
assert!(enforce_input_size("abcd", limits).is_ok());
}
#[test]
fn input_above_limit_rejects() {
let limits = QueryLimits {
max_input_bytes: 3,
max_mir_nodes: 8,
};
match enforce_input_size("abcd", limits) {
Err(SqlError::QueryTooLarge { len: 4, limit: 3 }) => {}
other => panic!("expected QueryTooLarge, got {other:?}"),
}
}
#[test]
fn graph_above_limit_rejects() {
let limits = QueryLimits {
max_input_bytes: 1024,
max_mir_nodes: 5,
};
match enforce_graph_size(10, limits) {
Err(SqlError::QueryTooComplex {
nodes: 10,
limit: 5,
}) => {}
other => panic!("expected QueryTooComplex, got {other:?}"),
}
}
}