use crate::conversion::ToParams;
use crate::error::Result;
use crate::protocol::codec::MessageBuilder;
use crate::protocol::types::{FormatCode, Oid, preferred_format};
pub fn write_parse(buf: &mut Vec<u8>, name: &str, query: &str, param_oids: &[Oid]) {
log::debug!("PARSE {query}");
let mut msg = MessageBuilder::new(buf, super::msg_type::PARSE);
msg.write_cstr(name);
msg.write_cstr(query);
msg.write_i16(param_oids.len() as i16);
for &oid in param_oids {
msg.write_i32(oid as i32);
}
msg.finish();
}
pub fn write_bind<P: ToParams>(
buf: &mut Vec<u8>,
portal: &str,
statement_name: &str,
params: &P,
target_oids: &[Oid],
) -> Result<()> {
log::debug!(
"BIND {} {}",
if statement_name.is_empty() {
"<unnamed statement>"
} else {
statement_name
},
if portal.is_empty() {
"<unnamed portal>"
} else {
portal
}
);
let mut msg = MessageBuilder::new(buf, super::msg_type::BIND);
msg.write_cstr(portal);
msg.write_cstr(statement_name);
let param_count = params.param_count();
msg.write_i16(param_count as i16);
for &oid in target_oids {
msg.write_i16(preferred_format(oid) as i16);
}
msg.write_i16(param_count as i16);
params.encode(target_oids, msg.buf())?;
msg.write_i16(1);
msg.write_i16(FormatCode::Binary as i16);
msg.finish();
Ok(())
}
pub fn write_execute(buf: &mut Vec<u8>, portal: &str, max_rows: u32) {
log::debug!(
"EXECUTE {} LIMIT {max_rows}",
if portal.is_empty() {
"<unnamed portal>"
} else {
portal
}
);
let mut msg = MessageBuilder::new(buf, super::msg_type::EXECUTE);
msg.write_cstr(portal);
msg.write_i32(max_rows as i32);
msg.finish();
}
pub fn write_describe(buf: &mut Vec<u8>, describe_type: u8, name: &str) {
log::debug!("DESCRIBE({}) {name}", describe_type as char);
let mut msg = MessageBuilder::new(buf, super::msg_type::DESCRIBE);
msg.write_u8(describe_type);
msg.write_cstr(name);
msg.finish();
}
pub fn write_describe_statement(buf: &mut Vec<u8>, name: &str) {
write_describe(buf, b'S', name);
}
pub fn write_describe_portal(buf: &mut Vec<u8>, name: &str) {
write_describe(buf, b'P', name);
}
pub fn write_close(buf: &mut Vec<u8>, close_type: u8, name: &str) {
log::debug!("CLOSE({}) {name}", close_type as char);
let mut msg = MessageBuilder::new(buf, super::msg_type::CLOSE);
msg.write_u8(close_type);
msg.write_cstr(name);
msg.finish();
}
pub fn write_close_statement(buf: &mut Vec<u8>, name: &str) {
write_close(buf, b'S', name);
}
pub fn write_close_portal(buf: &mut Vec<u8>, name: &str) {
write_close(buf, b'P', name);
}
pub fn write_sync(buf: &mut Vec<u8>) {
log::debug!("SYNC");
let msg = MessageBuilder::new(buf, super::msg_type::SYNC);
msg.finish();
}
pub fn write_flush(buf: &mut Vec<u8>) {
log::debug!("FLUSH");
let msg = MessageBuilder::new(buf, super::msg_type::FLUSH);
msg.finish();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse() {
let mut buf = Vec::new();
write_parse(&mut buf, "stmt1", "SELECT $1::int", &[0]);
assert_eq!(buf[0], b'P');
let len = i32::from_be_bytes([buf[1], buf[2], buf[3], buf[4]]);
assert_eq!(len as usize, buf.len() - 1);
}
#[test]
fn sync() {
let mut buf = Vec::new();
write_sync(&mut buf);
assert_eq!(buf.len(), 5);
assert_eq!(buf[0], b'S');
assert_eq!(&buf[1..5], &4_i32.to_be_bytes());
}
#[test]
fn flush() {
let mut buf = Vec::new();
write_flush(&mut buf);
assert_eq!(buf.len(), 5);
assert_eq!(buf[0], b'H');
assert_eq!(&buf[1..5], &4_i32.to_be_bytes());
}
#[test]
fn execute() {
let mut buf = Vec::new();
write_execute(&mut buf, "", 0);
assert_eq!(buf[0], b'E');
let len = i32::from_be_bytes([buf[1], buf[2], buf[3], buf[4]]);
assert_eq!(len, 9);
}
}