1use crate::value::ColumnMeta;
10use crate::wire::consts::{blr, sql_type};
11
12pub fn message_blr(columns: &[ColumnMeta]) -> Vec<u8> {
17 message_blr_impl(columns, true)
18}
19
20pub fn input_blr(columns: &[ColumnMeta]) -> Vec<u8> {
24 message_blr_impl(columns, false)
25}
26
27fn message_blr_impl(columns: &[ColumnMeta], for_output: bool) -> Vec<u8> {
28 let mut b = Vec::with_capacity(16 + columns.len() * 6);
29 b.push(blr::VERSION5);
30 b.push(blr::BEGIN);
31 b.push(blr::MESSAGE);
32 b.push(0); let field_count = (columns.len() * 2) as u16; b.extend_from_slice(&field_count.to_le_bytes());
35
36 for col in columns {
37 push_type(&mut b, col, for_output);
38 b.push(blr::SHORT);
40 b.push(0);
41 }
42
43 b.push(blr::END);
44 b.push(blr::EOC);
45 b
46}
47
48fn push_type(b: &mut Vec<u8>, col: &ColumnMeta, for_output: bool) {
49 let scale = col.scale as i8 as u8;
50 match sql_type::base(col.sql_type) {
51 sql_type::TEXT => {
52 b.push(blr::TEXT);
53 b.extend_from_slice(&(col.length as u16).to_le_bytes());
54 }
55 sql_type::VARYING => {
56 b.push(blr::VARYING);
57 b.extend_from_slice(&(col.length as u16).to_le_bytes());
58 }
59 sql_type::SHORT => {
60 b.push(blr::SHORT);
61 b.push(scale);
62 }
63 sql_type::LONG => {
64 b.push(blr::LONG);
65 b.push(scale);
66 }
67 sql_type::INT64 => {
68 b.push(blr::INT64);
69 b.push(scale);
70 }
71 sql_type::INT128 => {
72 b.push(blr::INT128);
73 b.push(scale);
74 }
75 sql_type::QUAD => {
76 b.push(blr::QUAD);
77 b.push(scale);
78 }
79 sql_type::FLOAT => b.push(blr::FLOAT),
80 sql_type::DOUBLE | sql_type::D_FLOAT => b.push(blr::DOUBLE),
81 sql_type::TYPE_DATE => b.push(blr::SQL_DATE),
82 sql_type::TYPE_TIME => b.push(blr::SQL_TIME),
83 sql_type::TIMESTAMP => b.push(blr::TIMESTAMP),
84 sql_type::BLOB => {
85 b.push(blr::BLOB2);
90 b.extend_from_slice(&(col.sub_type as u16).to_le_bytes());
91 b.extend_from_slice(&0u16.to_le_bytes());
92 }
93 sql_type::BOOLEAN => b.push(blr::BOOL),
94 sql_type::DEC16 => b.push(blr::DEC64),
95 sql_type::DEC34 => b.push(blr::DEC128),
96 sql_type::TIME_TZ | sql_type::TIME_TZ_EX => {
97 b.push(if for_output {
98 blr::EX_TIME_TZ
99 } else {
100 blr::SQL_TIME_TZ
101 });
102 }
103 sql_type::TIMESTAMP_TZ | sql_type::TIMESTAMP_TZ_EX => {
104 b.push(if for_output {
105 blr::EX_TIMESTAMP_TZ
106 } else {
107 blr::TIMESTAMP_TZ
108 });
109 }
110 other => {
111 let _ = other;
114 b.push(blr::QUAD);
115 b.push(0);
116 }
117 }
118}
119
120pub fn prepare_info_items() -> &'static [u8] {
124 use crate::wire::consts::isql::*;
125 &[
126 STMT_TYPE,
127 BIND,
129 DESCRIBE_VARS,
130 SQLDA_SEQ,
131 TYPE,
132 SUB_TYPE,
133 SCALE,
134 LENGTH,
135 FIELD,
136 RELATION,
137 ALIAS,
138 OWNER,
139 DESCRIBE_END,
140 SELECT,
142 DESCRIBE_VARS,
143 SQLDA_SEQ,
144 TYPE,
145 SUB_TYPE,
146 SCALE,
147 LENGTH,
148 FIELD,
149 RELATION,
150 ALIAS,
151 OWNER,
152 DESCRIBE_END,
153 ]
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159
160 #[test]
161 fn blr_for_smallint_and_varchar() {
162 let cols = vec![
163 ColumnMeta {
164 sql_type: sql_type::SHORT,
165 scale: 0,
166 ..Default::default()
167 },
168 ColumnMeta {
169 sql_type: sql_type::VARYING,
170 length: 15,
171 ..Default::default()
172 },
173 ];
174 let blr_bytes = message_blr(&cols);
175 assert_eq!(
178 blr_bytes,
179 vec![5, 2, 4, 0, 4, 0, 7, 0, 7, 0, 37, 15, 0, 7, 0, 255, 76]
180 );
181 }
182}