1use std::collections::BTreeMap;
8
9use crate::codec::{message_total_len, DecodeLen, Reader, MESSAGE_HEADER_LEN};
10use crate::protocol::{
11 resolve_format_code, resolve_format_codes, CancelKey, DecodeOutcome, FormatCode, PgWireError,
12 ProtocolVersion, CANCEL_REQUEST_CODE, GSSENC_REQUEST_CODE, SSL_REQUEST_CODE,
13};
14
15pub const DEFAULT_MAX_MESSAGE_LEN: usize = 16 * 1024 * 1024;
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum StartupFrame {
19 Startup(StartupMessage),
20 CancelRequest {
21 process_id: i32,
22 secret_key: CancelKey,
23 },
24 SSLRequest,
25 GSSEncRequest,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct StartupMessage {
30 pub version: ProtocolVersion,
31 pub parameters: BTreeMap<String, String>,
32 pub parameter_pairs: Vec<(String, String)>,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct StartupNegotiation {
38 pub requested_version: ProtocolVersion,
39 pub negotiated_version: ProtocolVersion,
40 pub unrecognized_options: Vec<String>,
41}
42
43impl StartupNegotiation {
44 #[must_use]
45 pub fn requires_response(&self) -> bool {
46 self.requested_version != self.negotiated_version || !self.unrecognized_options.is_empty()
47 }
48
49 #[must_use]
50 pub fn response(&self) -> Option<crate::backend::BackendMessage> {
51 self.requires_response().then(
52 || crate::backend::BackendMessage::NegotiateProtocolVersion {
53 newest_protocol_version: self.negotiated_version,
54 unrecognized_options: self.unrecognized_options.clone(),
55 },
56 )
57 }
58}
59
60impl StartupMessage {
61 pub fn get(&self, key: &str) -> Option<&str> {
62 self.parameters.get(key).map(String::as_str)
63 }
64
65 pub fn user(&self) -> Option<&str> {
66 self.get("user")
67 }
68
69 pub fn database(&self) -> Option<&str> {
70 self.get("database")
71 }
72
73 pub fn application_name(&self) -> Option<&str> {
74 self.get("application_name")
75 }
76
77 pub fn negotiate(
80 &self,
81 supported_protocol_options: &[&str],
82 ) -> Result<StartupNegotiation, PgWireError> {
83 self.negotiate_with_max(ProtocolVersion::LATEST, supported_protocol_options)
84 }
85
86 pub fn negotiate_with_max(
89 &self,
90 newest_supported: ProtocolVersion,
91 supported_protocol_options: &[&str],
92 ) -> Result<StartupNegotiation, PgWireError> {
93 let negotiated_version = self.version.negotiate_with_max(newest_supported)?;
94 let unrecognized_options = self
95 .parameter_pairs
96 .iter()
97 .map(|(name, _)| name)
98 .filter(|name| {
99 name.starts_with("_pq_.") && !supported_protocol_options.contains(&name.as_str())
100 })
101 .cloned()
102 .collect();
103 Ok(StartupNegotiation {
104 requested_version: self.version,
105 negotiated_version,
106 unrecognized_options,
107 })
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq)]
112pub enum FrontendMessage {
113 Query(String),
114 Parse(Parse),
115 Bind(Bind),
116 Describe(DescribeTarget),
117 Execute(Execute),
118 Close(CloseTarget),
119 Flush,
120 Sync,
121 Terminate,
122 Password(PasswordMessage),
123 CopyData(Vec<u8>),
124 CopyDone,
125 CopyFail(String),
126 FunctionCall(FunctionCall),
127}
128
129#[derive(Debug, Clone, PartialEq, Eq)]
130pub struct Parse {
131 pub statement: String,
132 pub query: String,
133 pub parameter_type_oids: Vec<u32>,
134}
135
136#[derive(Debug, Clone, PartialEq, Eq)]
137pub struct Bind {
138 pub portal: String,
139 pub statement: String,
140 pub parameter_formats: Vec<FormatCode>,
141 pub parameters: Vec<Option<Vec<u8>>>,
142 pub result_formats: Vec<FormatCode>,
143}
144
145impl Bind {
146 pub fn resolved_parameter_formats(&self) -> Result<Vec<FormatCode>, PgWireError> {
148 resolve_format_codes(
149 &self.parameter_formats,
150 self.parameters.len(),
151 |format_count, parameter_count| PgWireError::ParameterFormatCountMismatch {
152 format_count,
153 parameter_count,
154 },
155 )
156 }
157
158 pub fn parameter_format(&self, index: usize) -> Result<FormatCode, PgWireError> {
160 resolve_format_code(
161 &self.parameter_formats,
162 self.parameters.len(),
163 index,
164 "Bind parameter",
165 |format_count, parameter_count| PgWireError::ParameterFormatCountMismatch {
166 format_count,
167 parameter_count,
168 },
169 )
170 }
171
172 pub fn resolved_result_formats(
174 &self,
175 column_count: usize,
176 ) -> Result<Vec<FormatCode>, PgWireError> {
177 resolve_format_codes(
178 &self.result_formats,
179 column_count,
180 |format_count, column_count| PgWireError::ResultFormatCountMismatch {
181 format_count,
182 column_count,
183 },
184 )
185 }
186
187 pub fn result_format(
189 &self,
190 index: usize,
191 column_count: usize,
192 ) -> Result<FormatCode, PgWireError> {
193 resolve_format_code(
194 &self.result_formats,
195 column_count,
196 index,
197 "Bind result column",
198 |format_count, column_count| PgWireError::ResultFormatCountMismatch {
199 format_count,
200 column_count,
201 },
202 )
203 }
204}
205
206#[derive(Debug, Clone, PartialEq, Eq)]
208pub struct PasswordMessage(Vec<u8>);
209
210impl PasswordMessage {
211 #[must_use]
212 pub fn new(bytes: impl Into<Vec<u8>>) -> Self {
213 Self(bytes.into())
214 }
215
216 #[must_use]
217 pub fn as_bytes(&self) -> &[u8] {
218 &self.0
219 }
220
221 #[must_use]
222 pub fn into_bytes(self) -> Vec<u8> {
223 self.0
224 }
225}
226
227impl AsRef<[u8]> for PasswordMessage {
228 fn as_ref(&self) -> &[u8] {
229 self.as_bytes()
230 }
231}
232
233#[derive(Debug, Clone, PartialEq, Eq)]
234pub enum DescribeTarget {
235 Statement(String),
236 Portal(String),
237}
238
239#[derive(Debug, Clone, PartialEq, Eq)]
240pub struct Execute {
241 pub portal: String,
242 pub max_rows: i32,
243}
244
245#[derive(Debug, Clone, PartialEq, Eq)]
246pub enum CloseTarget {
247 Statement(String),
248 Portal(String),
249}
250
251#[derive(Debug, Clone, PartialEq, Eq)]
252pub struct FunctionCall {
253 pub function_oid: u32,
254 pub argument_formats: Vec<FormatCode>,
255 pub arguments: Vec<Option<Vec<u8>>>,
256 pub result_format: FormatCode,
257}
258
259impl FunctionCall {
260 pub fn resolved_argument_formats(&self) -> Result<Vec<FormatCode>, PgWireError> {
262 resolve_format_codes(
263 &self.argument_formats,
264 self.arguments.len(),
265 |format_count, argument_count| PgWireError::FunctionArgumentFormatCountMismatch {
266 format_count,
267 argument_count,
268 },
269 )
270 }
271
272 pub fn argument_format(&self, index: usize) -> Result<FormatCode, PgWireError> {
274 resolve_format_code(
275 &self.argument_formats,
276 self.arguments.len(),
277 index,
278 "FunctionCall argument",
279 |format_count, argument_count| PgWireError::FunctionArgumentFormatCountMismatch {
280 format_count,
281 argument_count,
282 },
283 )
284 }
285}
286
287pub fn decode_startup(input: &[u8]) -> DecodeOutcome<StartupFrame> {
288 decode_startup_with_max(input, DEFAULT_MAX_MESSAGE_LEN)
289}
290
291pub fn decode_startup_with_max(input: &[u8], max_len: usize) -> DecodeOutcome<StartupFrame> {
292 let total = match message_total_len(input, false, max_len) {
293 DecodeLen::Complete(total) => total,
294 DecodeLen::Incomplete => return Ok(None),
295 DecodeLen::Error(error) => return Err(error),
296 };
297
298 let body = &input[4..total];
299 let mut reader = Reader::new(body);
300 let version_or_code = reader.read_i32("startup version")?;
301 let frame = match version_or_code {
302 SSL_REQUEST_CODE => {
303 reader.ensure_empty("SSL request")?;
304 StartupFrame::SSLRequest
305 }
306 GSSENC_REQUEST_CODE => {
307 reader.ensure_empty("GSSENC request")?;
308 StartupFrame::GSSEncRequest
309 }
310 CANCEL_REQUEST_CODE => {
311 let process_id = reader.read_i32("cancel request process id")?;
312 let key_length = reader.remaining();
313 let secret_key = CancelKey::new(
314 reader
315 .read_exact(key_length, "cancel request secret key")?
316 .to_vec(),
317 )?;
318 reader.ensure_empty("cancel request")?;
319 StartupFrame::CancelRequest {
320 process_id,
321 secret_key,
322 }
323 }
324 other => {
325 let version = ProtocolVersion::from_raw(other);
326 version.negotiate()?;
327 StartupFrame::Startup(parse_startup_message(version, reader)?)
328 }
329 };
330 Ok(Some((frame, total)))
331}
332
333pub fn decode_frontend(input: &[u8]) -> DecodeOutcome<FrontendMessage> {
334 decode_frontend_with_max(input, DEFAULT_MAX_MESSAGE_LEN)
335}
336
337pub fn decode_frontend_with_max(input: &[u8], max_len: usize) -> DecodeOutcome<FrontendMessage> {
338 let total = match message_total_len(input, true, max_len) {
339 DecodeLen::Complete(total) => total,
340 DecodeLen::Incomplete => return Ok(None),
341 DecodeLen::Error(error) => return Err(error),
342 };
343
344 let tag = input[0];
345 let body = &input[MESSAGE_HEADER_LEN..total];
346 let message = parse_frontend_message(tag, body)?;
347 Ok(Some((message, total)))
348}
349
350fn parse_startup_message(
351 version: ProtocolVersion,
352 mut reader: Reader<'_>,
353) -> Result<StartupMessage, PgWireError> {
354 let mut parameters = BTreeMap::new();
355 let mut parameter_pairs = Vec::new();
356 loop {
357 if reader.remaining() == 0 {
358 return Err(PgWireError::MissingNul {
359 context: "startup parameters",
360 });
361 }
362 if reader.remaining() == 1 {
363 let terminator = reader.read_byte("startup terminator")?;
364 if terminator == 0 {
365 break;
366 }
367 return Err(PgWireError::MissingNul {
368 context: "startup parameters",
369 });
370 }
371
372 let key = reader.read_cstring("startup parameter key")?;
373 if key.is_empty() {
374 reader.ensure_empty("startup parameters")?;
375 break;
376 }
377 let value = reader.read_cstring("startup parameter value")?;
378 parameter_pairs.push((key.clone(), value.clone()));
379 parameters.insert(key, value);
380 }
381 Ok(StartupMessage {
382 version,
383 parameters,
384 parameter_pairs,
385 })
386}
387
388fn parse_frontend_message(tag: u8, body: &[u8]) -> Result<FrontendMessage, PgWireError> {
389 let mut reader = Reader::new(body);
390 let message = match tag {
391 b'Q' => FrontendMessage::Query(parse_single_cstring(&mut reader, "Query")?),
392 b'P' => FrontendMessage::Parse(parse_parse(&mut reader)?),
393 b'B' => FrontendMessage::Bind(parse_bind(&mut reader)?),
394 b'D' => FrontendMessage::Describe(parse_describe(&mut reader)?),
395 b'E' => FrontendMessage::Execute(parse_execute(&mut reader)?),
396 b'C' => FrontendMessage::Close(parse_close(&mut reader)?),
397 b'H' => {
398 reader.ensure_empty("Flush")?;
399 FrontendMessage::Flush
400 }
401 b'S' => {
402 reader.ensure_empty("Sync")?;
403 FrontendMessage::Sync
404 }
405 b'X' => {
406 reader.ensure_empty("Terminate")?;
407 FrontendMessage::Terminate
408 }
409 b'p' => FrontendMessage::Password(PasswordMessage::new(body)),
410 b'd' => FrontendMessage::CopyData(body.to_vec()),
411 b'c' => {
412 reader.ensure_empty("CopyDone")?;
413 FrontendMessage::CopyDone
414 }
415 b'f' => FrontendMessage::CopyFail(parse_single_cstring(&mut reader, "CopyFail")?),
416 b'F' => FrontendMessage::FunctionCall(parse_function_call(&mut reader)?),
417 other => return Err(PgWireError::UnknownFrontendTag(other)),
418 };
419 Ok(message)
420}
421
422fn parse_parse(reader: &mut Reader<'_>) -> Result<Parse, PgWireError> {
423 let statement = reader.read_cstring("Parse statement name")?;
424 let query = reader.read_cstring("Parse query")?;
425 let count = read_count(reader, "Parse parameter type count")?;
426 let mut parameter_type_oids = Vec::with_capacity(count);
427 for _ in 0..count {
428 parameter_type_oids.push(reader.read_u32("Parse parameter type oid")?);
429 }
430 reader.ensure_empty("Parse")?;
431 Ok(Parse {
432 statement,
433 query,
434 parameter_type_oids,
435 })
436}
437
438fn parse_bind(reader: &mut Reader<'_>) -> Result<Bind, PgWireError> {
439 let portal = reader.read_cstring("Bind portal name")?;
440 let statement = reader.read_cstring("Bind statement name")?;
441 let parameter_format_count = read_count(reader, "Bind parameter format count")?;
442 let mut parameter_formats = Vec::with_capacity(parameter_format_count);
443 for _ in 0..parameter_format_count {
444 parameter_formats.push(FormatCode::from_i16(
445 reader.read_i16("Bind parameter format code")?,
446 )?);
447 }
448
449 let parameter_count = read_count(reader, "Bind parameter count")?;
450 if parameter_format_count > 1 && parameter_format_count != parameter_count {
451 return Err(PgWireError::ParameterFormatCountMismatch {
452 format_count: parameter_format_count,
453 parameter_count,
454 });
455 }
456 let mut parameters = Vec::with_capacity(parameter_count);
457 for _ in 0..parameter_count {
458 let value = match reader.read_len_i32("Bind parameter value length")? {
459 Some(length) => Some(reader.read_exact(length, "Bind parameter value")?.to_vec()),
460 None => None,
461 };
462 parameters.push(value);
463 }
464
465 let result_format_count = read_count(reader, "Bind result format count")?;
466 let mut result_formats = Vec::with_capacity(result_format_count);
467 for _ in 0..result_format_count {
468 result_formats.push(FormatCode::from_i16(
469 reader.read_i16("Bind result format code")?,
470 )?);
471 }
472 reader.ensure_empty("Bind")?;
473 Ok(Bind {
474 portal,
475 statement,
476 parameter_formats,
477 parameters,
478 result_formats,
479 })
480}
481
482fn parse_describe(reader: &mut Reader<'_>) -> Result<DescribeTarget, PgWireError> {
483 let target = reader.read_byte("Describe target type")?;
484 let name = reader.read_cstring("Describe target name")?;
485 reader.ensure_empty("Describe")?;
486 match target {
487 b'S' => Ok(DescribeTarget::Statement(name)),
488 b'P' => Ok(DescribeTarget::Portal(name)),
489 other => Err(PgWireError::UnknownFrontendTag(other)),
490 }
491}
492
493fn parse_execute(reader: &mut Reader<'_>) -> Result<Execute, PgWireError> {
494 let portal = reader.read_cstring("Execute portal name")?;
495 let max_rows = reader.read_i32("Execute max rows")?;
496 if max_rows < 0 {
497 return Err(PgWireError::NegativeValue {
498 context: "Execute max rows",
499 });
500 }
501 reader.ensure_empty("Execute")?;
502 Ok(Execute { portal, max_rows })
503}
504
505fn parse_close(reader: &mut Reader<'_>) -> Result<CloseTarget, PgWireError> {
506 let target = reader.read_byte("Close target type")?;
507 let name = reader.read_cstring("Close target name")?;
508 reader.ensure_empty("Close")?;
509 match target {
510 b'S' => Ok(CloseTarget::Statement(name)),
511 b'P' => Ok(CloseTarget::Portal(name)),
512 other => Err(PgWireError::UnknownFrontendTag(other)),
513 }
514}
515
516fn parse_function_call(reader: &mut Reader<'_>) -> Result<FunctionCall, PgWireError> {
517 let function_oid = reader.read_u32("FunctionCall function oid")?;
518 let argument_format_count = read_count(reader, "FunctionCall argument format count")?;
519 let mut argument_formats = Vec::with_capacity(argument_format_count);
520 for _ in 0..argument_format_count {
521 argument_formats.push(FormatCode::from_i16(
522 reader.read_i16("FunctionCall argument format code")?,
523 )?);
524 }
525
526 let argument_count = read_count(reader, "FunctionCall argument count")?;
527 if argument_format_count > 1 && argument_format_count != argument_count {
528 return Err(PgWireError::FunctionArgumentFormatCountMismatch {
529 format_count: argument_format_count,
530 argument_count,
531 });
532 }
533 let mut arguments = Vec::with_capacity(argument_count);
534 for _ in 0..argument_count {
535 let value = match reader.read_len_i32("FunctionCall argument value length")? {
536 Some(length) => Some(
537 reader
538 .read_exact(length, "FunctionCall argument value")?
539 .to_vec(),
540 ),
541 None => None,
542 };
543 arguments.push(value);
544 }
545
546 let result_format = FormatCode::from_i16(reader.read_i16("FunctionCall result format code")?)?;
547 reader.ensure_empty("FunctionCall")?;
548 Ok(FunctionCall {
549 function_oid,
550 argument_formats,
551 arguments,
552 result_format,
553 })
554}
555
556fn parse_single_cstring(
557 reader: &mut Reader<'_>,
558 context: &'static str,
559) -> Result<String, PgWireError> {
560 let value = reader.read_cstring(context)?;
561 reader.ensure_empty(context)?;
562 Ok(value)
563}
564
565fn read_count(reader: &mut Reader<'_>, context: &'static str) -> Result<usize, PgWireError> {
566 let count = reader.read_i16(context)?;
567 if count < 0 {
568 return Err(PgWireError::NegativeValue { context });
569 }
570 Ok(count as usize)
571}