1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
use crate::*; pub use std::fmt::Write; #[derive(Debug, Default)] pub struct SqlWriter { pub counter: usize, pub string: String, } pub fn inject_parameters(sql: &str, params: Vec<Value>, query_builder: &dyn QueryBuilder) -> String { let tokenizer = Tokenizer::new(sql); let tokens: Vec<Token> = tokenizer.iter().collect(); let mut counter = 0; let mut output = Vec::new(); let mut i = 0; while i < tokens.len() { let token = &tokens[i]; match token { Token::Punctuation(mark) => { if mark == "?" { output.push(query_builder.value_to_string(¶ms[counter])); counter += 1; i += 1; continue; } else if mark == "$" && i + 1 < tokens.len() { if let Token::Unquoted(next) = &tokens[i + 1] { if let Ok(num) = next.parse::<usize>() { output.push(query_builder.value_to_string(¶ms[num - 1])); i += 2; continue; } } } output.push(mark.to_string()) }, _ => output.push(token.to_string()) } i += 1; } output.into_iter().collect() } impl SqlWriter { pub fn new() -> Self { Self::default() } pub fn push_param(&mut self, sign: &str, numbered: bool) { self.counter += 1; if numbered { write!(&mut self.string, "{}{}", sign, self.counter).unwrap(); } else { write!(&mut self.string, "{}", sign).unwrap(); } } pub fn result(self) -> String { self.string } } impl std::fmt::Write for SqlWriter { fn write_str(&mut self, s: &str) -> Result<(), std::fmt::Error> { write!(self.string, "{}", s) } } #[cfg(test)] mod tests { use super::*; #[test] fn inject_parameters_1() { assert_eq!(inject_parameters("WHERE A = ?", vec!["B".into()], &MysqlQueryBuilder), "WHERE A = 'B'"); } #[test] fn inject_parameters_2() { assert_eq!(inject_parameters("WHERE A = '?' AND B = ?", vec!["C".into()], &MysqlQueryBuilder), "WHERE A = '?' AND B = 'C'"); } #[test] fn inject_parameters_3() { assert_eq!(inject_parameters("WHERE A = ? AND C = ?", vec!["B".into(), "D".into()], &MysqlQueryBuilder), "WHERE A = 'B' AND C = 'D'"); } #[test] fn inject_parameters_4() { assert_eq!(inject_parameters("WHERE A = $1 AND C = $2", vec!["B".into(), "D".into()], &PostgresQueryBuilder), "WHERE A = 'B' AND C = 'D'"); } #[test] fn inject_parameters_5() { assert_eq!(inject_parameters("WHERE A = $2 AND C = $1", vec!["B".into(), "D".into()], &PostgresQueryBuilder), "WHERE A = 'D' AND C = 'B'"); } #[test] fn inject_parameters_6() { assert_eq!(inject_parameters("WHERE A = $1", vec!["B'C".into()], &PostgresQueryBuilder), "WHERE A = E'B\\'C'"); } #[test] fn inject_parameters_7() { assert_eq!(inject_parameters("?", vec![vec![0xABu8, 0xCD, 0xEF].into()], &MysqlQueryBuilder), "x'ABCDEF'"); } }