use crate::value::ColumnMeta;
use crate::wire::consts::{blr, sql_type};
pub fn message_blr(columns: &[ColumnMeta]) -> Vec<u8> {
message_blr_impl(columns, true)
}
pub fn input_blr(columns: &[ColumnMeta]) -> Vec<u8> {
message_blr_impl(columns, false)
}
fn message_blr_impl(columns: &[ColumnMeta], for_output: bool) -> Vec<u8> {
let mut b = Vec::with_capacity(16 + columns.len() * 6);
b.push(blr::VERSION5);
b.push(blr::BEGIN);
b.push(blr::MESSAGE);
b.push(0); let field_count = (columns.len() * 2) as u16; b.extend_from_slice(&field_count.to_le_bytes());
for col in columns {
push_type(&mut b, col, for_output);
b.push(blr::SHORT);
b.push(0);
}
b.push(blr::END);
b.push(blr::EOC);
b
}
fn push_type(b: &mut Vec<u8>, col: &ColumnMeta, for_output: bool) {
let scale = col.scale as i8 as u8;
match sql_type::base(col.sql_type) {
sql_type::TEXT => {
b.push(blr::TEXT);
b.extend_from_slice(&(col.length as u16).to_le_bytes());
}
sql_type::VARYING => {
b.push(blr::VARYING);
b.extend_from_slice(&(col.length as u16).to_le_bytes());
}
sql_type::SHORT => {
b.push(blr::SHORT);
b.push(scale);
}
sql_type::LONG => {
b.push(blr::LONG);
b.push(scale);
}
sql_type::INT64 => {
b.push(blr::INT64);
b.push(scale);
}
sql_type::INT128 => {
b.push(blr::INT128);
b.push(scale);
}
sql_type::QUAD => {
b.push(blr::QUAD);
b.push(scale);
}
sql_type::FLOAT => b.push(blr::FLOAT),
sql_type::DOUBLE | sql_type::D_FLOAT => b.push(blr::DOUBLE),
sql_type::TYPE_DATE => b.push(blr::SQL_DATE),
sql_type::TYPE_TIME => b.push(blr::SQL_TIME),
sql_type::TIMESTAMP => b.push(blr::TIMESTAMP),
sql_type::BLOB => {
b.push(blr::BLOB2);
b.extend_from_slice(&(col.sub_type as u16).to_le_bytes());
b.extend_from_slice(&0u16.to_le_bytes());
}
sql_type::BOOLEAN => b.push(blr::BOOL),
sql_type::DEC16 => b.push(blr::DEC64),
sql_type::DEC34 => b.push(blr::DEC128),
sql_type::TIME_TZ | sql_type::TIME_TZ_EX => {
b.push(if for_output {
blr::EX_TIME_TZ
} else {
blr::SQL_TIME_TZ
});
}
sql_type::TIMESTAMP_TZ | sql_type::TIMESTAMP_TZ_EX => {
b.push(if for_output {
blr::EX_TIMESTAMP_TZ
} else {
blr::TIMESTAMP_TZ
});
}
other => {
let _ = other;
b.push(blr::QUAD);
b.push(0);
}
}
}
pub fn prepare_info_items() -> &'static [u8] {
use crate::wire::consts::isql::*;
&[
STMT_TYPE,
BIND,
DESCRIBE_VARS,
SQLDA_SEQ,
TYPE,
SUB_TYPE,
SCALE,
LENGTH,
FIELD,
RELATION,
ALIAS,
OWNER,
DESCRIBE_END,
SELECT,
DESCRIBE_VARS,
SQLDA_SEQ,
TYPE,
SUB_TYPE,
SCALE,
LENGTH,
FIELD,
RELATION,
ALIAS,
OWNER,
DESCRIBE_END,
]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn blr_for_smallint_and_varchar() {
let cols = vec![
ColumnMeta {
sql_type: sql_type::SHORT,
scale: 0,
..Default::default()
},
ColumnMeta {
sql_type: sql_type::VARYING,
length: 15,
..Default::default()
},
];
let blr_bytes = message_blr(&cols);
assert_eq!(
blr_bytes,
vec![5, 2, 4, 0, 4, 0, 7, 0, 7, 0, 37, 15, 0, 7, 0, 255, 76]
);
}
}