use bytes::{Buf, BufMut, BytesMut};
use super::{DecodeContext, Message, codec};
use crate::error::PgWireResult;
pub const FORMAT_CODE_TEXT: i16 = 0;
pub const FORMAT_CODE_BINARY: i16 = 1;
#[non_exhaustive]
#[derive(PartialEq, Eq, Debug, Default, new)]
pub struct FieldDescription {
pub name: String,
pub table_id: i32,
pub column_id: i16,
pub type_id: u32,
pub type_size: i16,
pub type_modifier: i32,
pub format_code: i16,
}
#[non_exhaustive]
#[derive(PartialEq, Eq, Debug, Default, new)]
pub struct RowDescription {
pub fields: Vec<FieldDescription>,
}
pub const MESSAGE_TYPE_BYTE_ROW_DESCRITION: u8 = b'T';
impl Message for RowDescription {
#[inline]
fn message_type() -> Option<u8> {
Some(MESSAGE_TYPE_BYTE_ROW_DESCRITION)
}
#[inline]
fn max_message_length() -> usize {
super::LONG_BACKEND_PACKET_SIZE_LIMIT
}
fn message_length(&self) -> usize {
4 + 2
+ self
.fields
.iter()
.map(|f| f.name.len() + 1 + 4 + 2 + 4 + 2 + 4 + 2)
.sum::<usize>()
}
fn encode_body(&self, buf: &mut BytesMut) -> PgWireResult<()> {
buf.put_i16(self.fields.len() as i16);
for field in &self.fields {
codec::put_cstring(buf, &field.name);
buf.put_i32(field.table_id);
buf.put_i16(field.column_id);
buf.put_u32(field.type_id);
buf.put_i16(field.type_size);
buf.put_i32(field.type_modifier);
buf.put_i16(field.format_code);
}
Ok(())
}
fn decode_body(buf: &mut BytesMut, _: usize, _ctx: &DecodeContext) -> PgWireResult<Self> {
let fields_len = buf.get_i16();
let mut fields = Vec::with_capacity(fields_len as usize);
for _ in 0..fields_len {
let field = FieldDescription {
name: codec::get_cstring(buf).unwrap_or_else(|| "".to_owned()),
table_id: buf.get_i32(),
column_id: buf.get_i16(),
type_id: buf.get_u32(),
type_size: buf.get_i16(),
type_modifier: buf.get_i32(),
format_code: buf.get_i16(),
};
fields.push(field);
}
Ok(RowDescription { fields })
}
}
#[non_exhaustive]
#[derive(PartialEq, Eq, Debug, Default, new, Clone)]
pub struct ParameterDescription {
pub types: Vec<u32>,
}
pub const MESSAGE_TYPE_BYTE_PARAMETER_DESCRITION: u8 = b't';
impl Message for ParameterDescription {
#[inline]
fn message_type() -> Option<u8> {
Some(MESSAGE_TYPE_BYTE_PARAMETER_DESCRITION)
}
#[inline]
fn max_message_length() -> usize {
super::LONG_BACKEND_PACKET_SIZE_LIMIT
}
fn message_length(&self) -> usize {
4 + 2 + self.types.len() * 4
}
fn encode_body(&self, buf: &mut BytesMut) -> PgWireResult<()> {
buf.put_u16(self.types.len() as u16);
for t in &self.types {
buf.put_i32(*t as i32);
}
Ok(())
}
fn decode_body(buf: &mut BytesMut, _: usize, _ctx: &DecodeContext) -> PgWireResult<Self> {
let types_len = buf.get_u16();
let mut types = Vec::with_capacity(types_len as usize);
for _ in 0..types_len {
types.push(buf.get_i32() as u32);
}
Ok(ParameterDescription { types })
}
}
#[non_exhaustive]
#[derive(PartialEq, Eq, Debug, Default, new, Clone)]
pub struct DataRow {
pub data: BytesMut,
pub field_count: i16,
}
impl DataRow {}
pub const MESSAGE_TYPE_BYTE_DATA_ROW: u8 = b'D';
impl Message for DataRow {
#[inline]
fn message_type() -> Option<u8> {
Some(MESSAGE_TYPE_BYTE_DATA_ROW)
}
#[inline]
fn max_message_length() -> usize {
super::LONG_BACKEND_PACKET_SIZE_LIMIT
}
fn message_length(&self) -> usize {
4 + 2 + self.data.len()
}
fn encode_body(&self, buf: &mut BytesMut) -> PgWireResult<()> {
buf.put_i16(self.field_count);
buf.reserve(self.data.len());
buf.put_slice(&self.data);
Ok(())
}
fn decode_body(buf: &mut BytesMut, msg_len: usize, _ctx: &DecodeContext) -> PgWireResult<Self> {
let field_count = buf.get_i16();
let data = buf.split_to(msg_len - 4 - 2);
Ok(DataRow { data, field_count })
}
}
#[non_exhaustive]
#[derive(PartialEq, Eq, Debug, Default, new)]
pub struct NoData;
pub const MESSAGE_TYPE_BYTE_NO_DATA: u8 = b'n';
impl Message for NoData {
#[inline]
fn message_type() -> Option<u8> {
Some(MESSAGE_TYPE_BYTE_NO_DATA)
}
#[inline]
fn max_message_length() -> usize {
super::SMALL_BACKEND_PACKET_SIZE_LIMIT
}
fn message_length(&self) -> usize {
4
}
fn encode_body(&self, _buf: &mut BytesMut) -> PgWireResult<()> {
Ok(())
}
fn decode_body(_buf: &mut BytesMut, _: usize, _ctx: &DecodeContext) -> PgWireResult<Self> {
Ok(NoData::new())
}
}