pub type Oid = u32;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i16)]
#[non_exhaustive]
pub enum FormatCode {
Text = 0,
Binary = 1,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum FrontendMsg<'a> {
Parse {
name: &'a [u8],
sql: &'a [u8],
param_oids: &'a [Oid],
},
Bind {
portal: &'a [u8],
statement: &'a [u8],
param_formats: &'a [FormatCode],
params: &'a [Option<&'a [u8]>],
result_formats: &'a [FormatCode],
},
Execute { portal: &'a [u8], max_rows: i32 },
Sync,
Query(&'a [u8]),
Describe {
kind: u8, name: &'a [u8],
},
Close {
kind: u8, name: &'a [u8],
},
Flush,
SASLInitialResponse { mechanism: &'a [u8], data: &'a [u8] },
SASLResponse(&'a [u8]),
CopyData(&'a [u8]),
CopyDone,
CopyFail(&'a [u8]),
Terminate,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum BackendMsg {
AuthenticationOk,
AuthenticationCleartextPassword,
AuthenticationMd5Password {
salt: [u8; 4],
},
AuthenticationSASL {
mechanisms: Vec<String>,
},
AuthenticationSASLContinue {
data: Vec<u8>,
},
AuthenticationSASLFinal {
data: Vec<u8>,
},
ParameterStatus {
name: String,
value: String,
},
BackendKeyData {
pid: i32,
secret: i32,
},
ReadyForQuery {
status: u8,
},
ParseComplete,
BindComplete,
CloseComplete,
NoData,
CommandComplete {
tag: String,
},
DataRow(RawRow),
RowDescription {
fields: Vec<FieldDescription>,
},
ErrorResponse {
fields: PgError,
},
NoticeResponse {
fields: PgError,
},
EmptyQueryResponse,
ParameterDescription {
type_oids: Vec<Oid>,
},
NotificationResponse {
pid: i32,
channel: String,
payload: String,
},
PortalSuspended,
CopyInResponse {
format: u8, column_formats: Vec<i16>,
},
CopyOutResponse {
format: u8,
column_formats: Vec<i16>,
},
CopyData {
data: Vec<u8>,
},
CopyDone,
}
pub const CELL_INLINE_CAP: usize = 12;
#[derive(Debug, Clone)]
pub struct RawRow {
pub(crate) body: bytes::Bytes,
cells: Cells,
}
impl RawRow {
#[doc(hidden)]
pub fn body(&self) -> &bytes::Bytes {
&self.body
}
}
#[derive(Debug, Clone)]
enum Cells {
Inline {
data: [(u32, i32); CELL_INLINE_CAP],
len: u8,
},
Heap(Box<[(u32, i32)]>),
}
impl RawRow {
pub fn empty() -> Self {
Self {
body: bytes::Bytes::new(),
cells: Cells::Inline {
data: [(0, 0); CELL_INLINE_CAP],
len: 0,
},
}
}
#[inline]
pub fn from_inline_unchecked(
body: bytes::Bytes,
data: [(u32, i32); CELL_INLINE_CAP],
len: u8,
) -> Self {
debug_assert!(len as usize <= CELL_INLINE_CAP);
Self {
body,
cells: Cells::Inline { data, len },
}
}
pub fn from_entries(body: bytes::Bytes, entries: &[(u32, i32)]) -> Self {
let cells = if entries.len() <= CELL_INLINE_CAP {
let mut data = [(0u32, 0i32); CELL_INLINE_CAP];
data[..entries.len()].copy_from_slice(entries);
Cells::Inline {
data,
len: entries.len() as u8,
}
} else {
Cells::Heap(entries.into())
};
Self { body, cells }
}
pub fn from_full_body(body: bytes::Bytes) -> Self {
let len = body.len() as i32;
let mut data = [(0u32, 0i32); CELL_INLINE_CAP];
data[0] = (0, len);
Self {
body,
cells: Cells::Inline { data, len: 1 },
}
}
fn entries(&self) -> &[(u32, i32)] {
match &self.cells {
Cells::Inline { data, len } => &data[..*len as usize],
Cells::Heap(b) => b,
}
}
pub fn len(&self) -> usize {
self.entries().len()
}
pub fn is_empty(&self) -> bool {
self.entries().is_empty()
}
pub fn cell(&self, idx: usize) -> Option<&[u8]> {
let (off, len) = *self.entries().get(idx)?;
if len < 0 {
return None;
}
let start = off as usize;
let end = start + len as usize;
Some(&self.body[start..end])
}
pub fn try_cell(&self, idx: usize) -> Option<Option<&[u8]>> {
let (off, len) = *self.entries().get(idx)?;
if len < 0 {
return Some(None);
}
let start = off as usize;
let end = start + len as usize;
Some(Some(&self.body[start..end]))
}
pub fn iter(&self) -> impl Iterator<Item = Option<&[u8]>> + '_ {
let body = self.body.as_ref();
self.entries().iter().map(move |&(off, len)| {
if len < 0 {
None
} else {
let start = off as usize;
let end = start + len as usize;
Some(&body[start..end])
}
})
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct FieldDescription {
pub name: String,
pub table_oid: Oid,
pub column_id: i16,
pub type_oid: Oid,
pub type_size: i16,
pub type_modifier: i32,
pub format: FormatCode,
}
impl Default for FieldDescription {
fn default() -> Self {
Self {
name: String::new(),
table_oid: 0,
column_id: 0,
type_oid: 0,
type_size: -1,
type_modifier: -1,
format: FormatCode::Binary,
}
}
}
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct PgError {
pub severity: String,
pub code: String,
pub message: String,
pub detail: Option<String>,
pub hint: Option<String>,
pub position: Option<String>,
}