zero_postgres/protocol/backend/
copy.rs

1//! COPY protocol backend messages.
2
3use crate::error::Result;
4use crate::protocol::codec::{read_u8, read_u16};
5use crate::protocol::types::FormatCode;
6
7/// CopyInResponse message - server is ready to receive COPY data.
8#[derive(Debug, Clone)]
9pub struct CopyInResponse {
10    /// Overall format (0=text, 1=binary)
11    pub format: FormatCode,
12    /// Per-column format codes
13    pub column_formats: Vec<FormatCode>,
14}
15
16impl CopyInResponse {
17    /// Parse a CopyInResponse message from payload bytes.
18    pub fn parse(payload: &[u8]) -> Result<Self> {
19        let (format_byte, rest) = read_u8(payload)?;
20        let format = FormatCode::from_u16(format_byte as u16);
21
22        let (num_columns, mut rest) = read_u16(rest)?;
23        let mut column_formats = Vec::with_capacity(num_columns as usize);
24
25        for _ in 0..num_columns {
26            let (fmt, remaining) = read_u16(rest)?;
27            column_formats.push(FormatCode::from_u16(fmt));
28            rest = remaining;
29        }
30
31        Ok(Self {
32            format,
33            column_formats,
34        })
35    }
36
37    /// Check if binary format is used.
38    pub fn is_binary(&self) -> bool {
39        matches!(self.format, FormatCode::Binary)
40    }
41}
42
43/// CopyOutResponse message - server is about to send COPY data.
44#[derive(Debug, Clone)]
45pub struct CopyOutResponse {
46    /// Overall format (0=text, 1=binary)
47    pub format: FormatCode,
48    /// Per-column format codes
49    pub column_formats: Vec<FormatCode>,
50}
51
52impl CopyOutResponse {
53    /// Parse a CopyOutResponse message from payload bytes.
54    pub fn parse(payload: &[u8]) -> Result<Self> {
55        let (format_byte, rest) = read_u8(payload)?;
56        let format = FormatCode::from_u16(format_byte as u16);
57
58        let (num_columns, mut rest) = read_u16(rest)?;
59        let mut column_formats = Vec::with_capacity(num_columns as usize);
60
61        for _ in 0..num_columns {
62            let (fmt, remaining) = read_u16(rest)?;
63            column_formats.push(FormatCode::from_u16(fmt));
64            rest = remaining;
65        }
66
67        Ok(Self {
68            format,
69            column_formats,
70        })
71    }
72
73    /// Check if binary format is used.
74    pub fn is_binary(&self) -> bool {
75        matches!(self.format, FormatCode::Binary)
76    }
77}
78
79/// CopyBothResponse message - server is ready for bidirectional COPY (replication).
80#[derive(Debug, Clone)]
81pub struct CopyBothResponse {
82    /// Overall format (0=text, 1=binary)
83    pub format: FormatCode,
84    /// Per-column format codes
85    pub column_formats: Vec<FormatCode>,
86}
87
88impl CopyBothResponse {
89    /// Parse a CopyBothResponse message from payload bytes.
90    pub fn parse(payload: &[u8]) -> Result<Self> {
91        let (format_byte, rest) = read_u8(payload)?;
92        let format = FormatCode::from_u16(format_byte as u16);
93
94        let (num_columns, mut rest) = read_u16(rest)?;
95        let mut column_formats = Vec::with_capacity(num_columns as usize);
96
97        for _ in 0..num_columns {
98            let (fmt, remaining) = read_u16(rest)?;
99            column_formats.push(FormatCode::from_u16(fmt));
100            rest = remaining;
101        }
102
103        Ok(Self {
104            format,
105            column_formats,
106        })
107    }
108}