1use crate::myc;
2use crate::{StatementData, Value};
3use std::collections::HashMap;
4use std::convert::TryFrom;
5
6pub struct ParamParser<'a> {
12 pub(crate) params: u16,
13 pub(crate) bytes: &'a [u8],
14 pub(crate) long_data: &'a HashMap<u16, Vec<u8>>,
15 pub(crate) bound_types: &'a mut Vec<(myc::constants::ColumnType, bool)>,
16}
17
18impl<'a> ParamParser<'a> {
19 pub(crate) fn new(input: &'a [u8], stmt: &'a mut StatementData) -> Self {
20 ParamParser {
21 params: stmt.params,
22 bytes: input,
23 long_data: &stmt.long_data,
24 bound_types: &mut stmt.bound_types,
25 }
26 }
27}
28
29impl<'a> IntoIterator for ParamParser<'a> {
30 type IntoIter = Params<'a>;
31 type Item = ParamValue<'a>;
32 fn into_iter(self) -> Params<'a> {
33 Params {
34 params: self.params,
35 input: self.bytes,
36 nullmap: None,
37 col: 0,
38 long_data: self.long_data,
39 bound_types: self.bound_types,
40 }
41 }
42}
43
44pub struct Params<'a> {
46 params: u16,
47 input: &'a [u8],
48 nullmap: Option<&'a [u8]>,
49 col: u16,
50 long_data: &'a HashMap<u16, Vec<u8>>,
51 bound_types: &'a mut Vec<(myc::constants::ColumnType, bool)>,
52}
53
54pub struct ParamValue<'a> {
56 pub value: Value<'a>,
58 pub coltype: myc::constants::ColumnType,
60}
61
62impl<'a> Iterator for Params<'a> {
63 type Item = ParamValue<'a>;
64 fn next(&mut self) -> Option<Self::Item> {
65 if self.nullmap.is_none() {
66 let nullmap_len = (self.params as usize + 7) / 8;
67 let (nullmap, rest) = self.input.split_at(nullmap_len);
68 self.nullmap = Some(nullmap);
69 self.input = rest;
70
71 if !rest.is_empty() && rest[0] != 0x00 {
72 let (typmap, rest) = rest[1..].split_at(2 * self.params as usize);
73 self.bound_types.clear();
74 for i in 0..self.params as usize {
75 self.bound_types.push((
76 myc::constants::ColumnType::try_from(typmap[2 * i]).unwrap_or_else(|e| {
77 panic!("bad column type 0x{:x}: {}", typmap[2 * i], e)
78 }),
79 (typmap[2 * i + 1] & 128) != 0,
80 ));
81 }
82 self.input = rest;
83 }
84 }
85
86 if self.col >= self.params {
87 return None;
88 }
89 let pt = &self.bound_types[self.col as usize];
90
91 if let Some(nullmap) = self.nullmap {
95 let byte = self.col as usize / 8;
96 if byte >= nullmap.len() {
97 return None;
98 }
99 if (nullmap[byte] & 1u8 << (self.col % 8)) != 0 {
100 self.col += 1;
101 return Some(ParamValue {
102 value: Value::null(),
103 coltype: pt.0,
104 });
105 }
106 } else {
107 unreachable!();
108 }
109
110 let v = if let Some(data) = self.long_data.get(&self.col) {
111 Value::bytes(&data[..])
112 } else {
113 Value::parse_from(&mut self.input, pt.0, pt.1).unwrap()
114 };
115 self.col += 1;
116 Some(ParamValue {
117 value: v,
118 coltype: pt.0,
119 })
120 }
121}