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