diff --git a/01.workspace/heave/src/fun/sqlite_build_params.rs b/01.workspace/heave/src/fun/sqlite_build_params.rs index 64e3c0c..877aed8 100644 --- a/01.workspace/heave/src/fun/sqlite_build_params.rs +++ b/01.workspace/heave/src/fun/sqlite_build_params.rs @@ -4,7 +4,8 @@ use rusqlite::*; pub fn run<'a>(filter: &'a Filter) -> Result>, FailedTo> { let mut params: Vec> = Vec::new(); for condition in filter.conditions() { - let (_, comparison, condition) = condition; + let (name, comparison, condition) = condition; + params.push(Box::new(name)); match (comparison, condition) { // BOOL (Comparison::Equal, Condition::Bool(value)) => params.push(Box::new(value)), diff --git a/01.workspace/heave/src/fun/sqlite_build_statement.rs b/01.workspace/heave/src/fun/sqlite_build_statement.rs index 6d0be76..033613d 100644 --- a/01.workspace/heave/src/fun/sqlite_build_statement.rs +++ b/01.workspace/heave/src/fun/sqlite_build_statement.rs @@ -1,83 +1,82 @@ use crate::*; -// TODO: possible sql injection for attribute_id!!! - const BASE_SELECT: &str = r#"SELECT * FROM entity"#; const INNER_JOIN_FRAGMENT: &str = r#" INNER JOIN attribute as attribute_{index} ON entity.id = attribute_{index}.entity_id - AND attribute_{index}.id = '{attribute_id}' + AND attribute_{index}.id = ?{attribute_id_index} AND attribute_{index}.{field} {op} ?{index} "#; const WHERE: &str = r#" WHERE 1=1"#; -fn compose_fragment(name: &str, field: &str, op: &str, index: usize) -> String { +fn compose_fragment(field: &str, op: &str, index: usize) -> String { + let attribute_index = index * 2 - 1; + let field_index = index * 2; INNER_JOIN_FRAGMENT - .replace("{attribute_id}", name) .replace("{field}", field) .replace("{op}", op) - .replace("{index}", &index.to_string()) + .replace("{attribute_id_index}", &attribute_index.to_string()) + .replace("{index}", &field_index.to_string()) } fn from_condition( i: usize, - name: &str, comparison: &Comparison, condition: &Condition, ) -> Result { let fragment = match (comparison, condition) { // BOOL - (Comparison::Equal, Condition::Bool(_)) => compose_fragment(name, "value_bool", "=", i), + (Comparison::Equal, Condition::Bool(_)) => compose_fragment("value_bool", "=", i), (_, Condition::Bool(_)) => return Err(FailedTo::ComposeFilter), // SIGNED INT - (Comparison::Equal, Condition::SignedInt(_)) => compose_fragment(name, "value_int", "=", i), + (Comparison::Equal, Condition::SignedInt(_)) => compose_fragment("value_int", "=", i), (Comparison::Greater, Condition::SignedInt(_)) => { - compose_fragment(name, "value_int", ">", i) + compose_fragment("value_int", ">", i) } (Comparison::Lesser, Condition::SignedInt(_)) => { - compose_fragment(name, "value_int", "<", i) + compose_fragment("value_int", "<", i) } (Comparison::GreaterOrEqual, Condition::SignedInt(_)) => { - compose_fragment(name, "value_int", ">=", i) + compose_fragment("value_int", ">=", i) } (Comparison::LesserOrEqual, Condition::SignedInt(_)) => { - compose_fragment(name, "value_int", "<=", i) + compose_fragment("value_int", "<=", i) } (_, Condition::SignedInt(_)) => return Err(FailedTo::ComposeFilter), // UNSIGNED INT (Comparison::Equal, Condition::UnsignedInt(_)) => { - compose_fragment(name, "value_uint", "=", i) + compose_fragment("value_uint", "=", i) } (Comparison::Greater, Condition::UnsignedInt(_)) => { - compose_fragment(name, "value_uint", ">", i) + compose_fragment("value_uint", ">", i) } (Comparison::Lesser, Condition::UnsignedInt(_)) => { - compose_fragment(name, "value_uint", "<", i) + compose_fragment("value_uint", "<", i) } (Comparison::GreaterOrEqual, Condition::UnsignedInt(_)) => { - compose_fragment(name, "value_uint", ">=", i) + compose_fragment("value_uint", ">=", i) } (Comparison::LesserOrEqual, Condition::UnsignedInt(_)) => { - compose_fragment(name, "value_uint", "<=", i) + compose_fragment("value_uint", "<=", i) } (_, Condition::UnsignedInt(_)) => return Err(FailedTo::ComposeFilter), // REAL - (Comparison::Equal, Condition::Real(_)) => compose_fragment(name, "value_real", "=", i), - (Comparison::Greater, Condition::Real(_)) => compose_fragment(name, "value_real", ">", i), - (Comparison::Lesser, Condition::Real(_)) => compose_fragment(name, "value_real", "<", i), + (Comparison::Equal, Condition::Real(_)) => compose_fragment("value_real", "=", i), + (Comparison::Greater, Condition::Real(_)) => compose_fragment("value_real", ">", i), + (Comparison::Lesser, Condition::Real(_)) => compose_fragment("value_real", "<", i), (Comparison::GreaterOrEqual, Condition::Real(_)) => { - compose_fragment(name, "value_real", ">=", i) + compose_fragment("value_real", ">=", i) } (Comparison::LesserOrEqual, Condition::Real(_)) => { - compose_fragment(name, "value_real", "<=", i) + compose_fragment("value_real", "<=", i) } (_, Condition::Real(_)) => return Err(FailedTo::ComposeFilter), // TEXT - (Comparison::IsExactly, Condition::Text(_)) => compose_fragment(name, "value_text", "=", i), + (Comparison::IsExactly, Condition::Text(_)) => compose_fragment("value_text", "=", i), ( Comparison::StartsWith | Comparison::EndsWith | Comparison::Contains, Condition::Text(_), - ) => compose_fragment(name, "value_text", "LIKE", i), + ) => compose_fragment("value_text", "LIKE", i), (_, Condition::Text(_)) => return Err(FailedTo::ComposeFilter), }; Ok(fragment) @@ -88,9 +87,9 @@ pub fn run(filter: &Filter) -> Result { let mut statement = String::from(BASE_SELECT); let mut idx = 0; // for each condition add an inner join fragment - for (i, (name, comparison, condition)) in filter.conditions().enumerate() { + for (i, (_, comparison, condition)) in filter.conditions().enumerate() { idx = i + 1; - let fragment = from_condition(idx, name, comparison, condition)?; + let fragment = from_condition(idx, comparison, condition)?; statement.push_str(&fragment); } // add a neutral where condition