fraiseql_wire/protocol/message.rs
1//! Protocol message types
2
3use bytes::Bytes;
4
5/// Frontend message (client → server)
6#[derive(Debug, Clone)]
7pub enum FrontendMessage {
8 /// Startup message
9 Startup {
10 /// Protocol version
11 version: i32,
12 /// Connection parameters
13 params: Vec<(String, String)>,
14 },
15
16 /// Password message
17 Password(String),
18
19 /// Query message
20 Query(String),
21
22 /// Terminate message
23 Terminate,
24
25 /// SASL initial response message
26 SaslInitialResponse {
27 /// SASL mechanism name (e.g., "SCRAM-SHA-256")
28 mechanism: String,
29 /// SASL client first message data
30 data: Vec<u8>,
31 },
32
33 /// SASL response message
34 SaslResponse {
35 /// SASL client final message data
36 data: Vec<u8>,
37 },
38}
39
40/// Backend message (server → client)
41#[derive(Debug, Clone)]
42pub enum BackendMessage {
43 /// Authentication request
44 Authentication(AuthenticationMessage),
45
46 /// Backend key data (for cancellation)
47 BackendKeyData {
48 /// Process ID
49 process_id: i32,
50 /// Secret key
51 secret_key: i32,
52 },
53
54 /// Command complete
55 CommandComplete(String),
56
57 /// Data row
58 DataRow(Vec<Option<Bytes>>),
59
60 /// Error response
61 ErrorResponse(ErrorFields),
62
63 /// Notice response
64 NoticeResponse(ErrorFields),
65
66 /// Parameter status
67 ParameterStatus {
68 /// Parameter name
69 name: String,
70 /// Parameter value
71 value: String,
72 },
73
74 /// Ready for query
75 ReadyForQuery {
76 /// Transaction status
77 status: u8,
78 },
79
80 /// Row description
81 RowDescription(Vec<FieldDescription>),
82}
83
84/// Authentication message types
85#[derive(Debug, Clone)]
86pub enum AuthenticationMessage {
87 /// Authentication OK
88 Ok,
89
90 /// Cleartext password required
91 CleartextPassword,
92
93 /// MD5 password required
94 Md5Password {
95 /// Salt for MD5 hash
96 salt: [u8; 4],
97 },
98
99 /// SASL authentication mechanisms available (Postgres 10+)
100 Sasl {
101 /// List of SASL mechanism names (e.g., ["SCRAM-SHA-256"])
102 mechanisms: Vec<String>,
103 },
104
105 /// SASL continuation message (server challenge)
106 SaslContinue {
107 /// SASL server first/continue message data
108 data: Vec<u8>,
109 },
110
111 /// SASL final message (server verification)
112 SaslFinal {
113 /// SASL server final message data
114 data: Vec<u8>,
115 },
116}
117
118/// Field description (column metadata)
119#[derive(Debug, Clone)]
120pub struct FieldDescription {
121 /// Column name
122 pub name: String,
123 /// Table OID (0 if not a table column)
124 pub table_oid: i32,
125 /// Column attribute number (0 if not a table column)
126 pub column_attr: i16,
127 /// Data type OID
128 pub type_oid: u32,
129 /// Data type size
130 pub type_size: i16,
131 /// Type modifier
132 pub type_modifier: i32,
133 /// Format code (0 = text, 1 = binary)
134 pub format_code: i16,
135}
136
137/// Error/notice fields
138#[derive(Debug, Clone, Default)]
139pub struct ErrorFields {
140 /// Severity (ERROR, WARNING, etc.)
141 pub severity: Option<String>,
142 /// SQLSTATE code
143 pub code: Option<String>,
144 /// Human-readable message
145 pub message: Option<String>,
146 /// Additional detail
147 pub detail: Option<String>,
148 /// Hint
149 pub hint: Option<String>,
150 /// Position in query string
151 pub position: Option<String>,
152}
153
154impl std::fmt::Display for ErrorFields {
155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156 if let Some(ref msg) = self.message {
157 write!(f, "{}", msg)?;
158 }
159 if let Some(ref code) = self.code {
160 write!(f, " ({})", code)?;
161 }
162 Ok(())
163 }
164}