1use bytes::BytesMut;
15use super::EncodeError;
16
17pub struct PgEncoder;
20
21impl PgEncoder {
22 pub fn encode_query_string(sql: &str) -> BytesMut {
28 let mut buf = BytesMut::new();
29
30 let content_len = sql.len() + 1; if content_len > (i32::MAX as usize) - 4 {
33 return buf;
36 }
37
38 buf.extend_from_slice(b"Q");
40
41 let total_len = (content_len + 4) as i32; buf.extend_from_slice(&total_len.to_be_bytes());
45
46 buf.extend_from_slice(sql.as_bytes());
48
49 buf.extend_from_slice(&[0]);
51
52 buf
53 }
54
55 pub fn encode_terminate() -> BytesMut {
57 let mut buf = BytesMut::new();
58 buf.extend_from_slice(&[b'X', 0, 0, 0, 4]);
59 buf
60 }
61
62 pub fn encode_sync() -> BytesMut {
64 let mut buf = BytesMut::new();
65 buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
66 buf
67 }
68
69 pub fn encode_parse(name: &str, sql: &str, param_types: &[u32]) -> BytesMut {
80 let mut buf = BytesMut::new();
81
82 buf.extend_from_slice(b"P");
84
85 let mut content = Vec::new();
86
87 content.extend_from_slice(name.as_bytes());
89 content.push(0);
90
91 content.extend_from_slice(sql.as_bytes());
93 content.push(0);
94
95 content.extend_from_slice(&(param_types.len() as i16).to_be_bytes());
97
98 for &oid in param_types {
100 content.extend_from_slice(&oid.to_be_bytes());
101 }
102
103 let len = (content.len() + 4) as i32;
105 buf.extend_from_slice(&len.to_be_bytes());
106 buf.extend_from_slice(&content);
107
108 buf
109 }
110
111 pub fn encode_bind(portal: &str, statement: &str, params: &[Option<Vec<u8>>]) -> Result<BytesMut, EncodeError> {
128 if params.len() > i16::MAX as usize {
129 return Err(EncodeError::TooManyParameters(params.len()));
130 }
131
132 let mut buf = BytesMut::new();
133
134 buf.extend_from_slice(b"B");
136
137 let mut content = Vec::new();
138
139 content.extend_from_slice(portal.as_bytes());
141 content.push(0);
142
143 content.extend_from_slice(statement.as_bytes());
145 content.push(0);
146
147 content.extend_from_slice(&0i16.to_be_bytes());
149
150 content.extend_from_slice(&(params.len() as i16).to_be_bytes());
152
153 for param in params {
155 match param {
156 None => {
157 content.extend_from_slice(&(-1i32).to_be_bytes());
159 }
160 Some(data) => {
161 if data.len() > i32::MAX as usize {
162 return Err(EncodeError::MessageTooLarge(data.len()));
163 }
164 content.extend_from_slice(&(data.len() as i32).to_be_bytes());
165 content.extend_from_slice(data);
166 }
167 }
168 }
169
170 content.extend_from_slice(&0i16.to_be_bytes());
172
173 let len = (content.len() + 4) as i32;
175 buf.extend_from_slice(&len.to_be_bytes());
176 buf.extend_from_slice(&content);
177
178 Ok(buf)
179 }
180
181 pub fn encode_execute(portal: &str, max_rows: i32) -> BytesMut {
188 let mut buf = BytesMut::new();
189
190 buf.extend_from_slice(b"E");
192
193 let mut content = Vec::new();
194
195 content.extend_from_slice(portal.as_bytes());
197 content.push(0);
198
199 content.extend_from_slice(&max_rows.to_be_bytes());
201
202 let len = (content.len() + 4) as i32;
204 buf.extend_from_slice(&len.to_be_bytes());
205 buf.extend_from_slice(&content);
206
207 buf
208 }
209
210 pub fn encode_describe(is_portal: bool, name: &str) -> BytesMut {
217 let mut buf = BytesMut::new();
218
219 buf.extend_from_slice(b"D");
221
222 let mut content = Vec::new();
223
224 content.push(if is_portal { b'P' } else { b'S' });
226
227 content.extend_from_slice(name.as_bytes());
229 content.push(0);
230
231 let len = (content.len() + 4) as i32;
233 buf.extend_from_slice(&len.to_be_bytes());
234 buf.extend_from_slice(&content);
235
236 buf
237 }
238
239 pub fn encode_extended_query(sql: &str, params: &[Option<Vec<u8>>]) -> Result<BytesMut, EncodeError> {
243 if params.len() > i16::MAX as usize {
244 return Err(EncodeError::TooManyParameters(params.len()));
245 }
246
247 let params_size: usize = params
252 .iter()
253 .map(|p| 4 + p.as_ref().map_or(0, |v| v.len()))
254 .sum();
255 let total_size = 9 + sql.len() + 13 + params_size + 10 + 5;
256
257 let mut buf = BytesMut::with_capacity(total_size);
258
259 buf.extend_from_slice(b"P");
261 let parse_len = (1 + sql.len() + 1 + 2 + 4) as i32; buf.extend_from_slice(&parse_len.to_be_bytes());
263 buf.extend_from_slice(&[0]); buf.extend_from_slice(sql.as_bytes());
265 buf.extend_from_slice(&[0]); buf.extend_from_slice(&0i16.to_be_bytes()); buf.extend_from_slice(b"B");
270 let bind_len = (1 + 1 + 2 + 2 + params_size + 2 + 4) as i32;
271 buf.extend_from_slice(&bind_len.to_be_bytes());
272 buf.extend_from_slice(&[0]); buf.extend_from_slice(&[0]); buf.extend_from_slice(&0i16.to_be_bytes()); buf.extend_from_slice(&(params.len() as i16).to_be_bytes());
276 for param in params {
277 match param {
278 None => buf.extend_from_slice(&(-1i32).to_be_bytes()),
279 Some(data) => {
280 if data.len() > i32::MAX as usize {
281 return Err(EncodeError::MessageTooLarge(data.len()));
282 }
283 buf.extend_from_slice(&(data.len() as i32).to_be_bytes());
284 buf.extend_from_slice(data);
285 }
286 }
287 }
288 buf.extend_from_slice(&0i16.to_be_bytes()); buf.extend_from_slice(b"E");
292 buf.extend_from_slice(&9i32.to_be_bytes()); buf.extend_from_slice(&[0]); buf.extend_from_slice(&0i32.to_be_bytes()); buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
298
299 Ok(buf)
300 }
301
302 pub fn encode_copy_fail(reason: &str) -> BytesMut {
308 let mut buf = BytesMut::new();
309 buf.extend_from_slice(b"f");
310 let content_len = reason.len() + 1; let len = (content_len + 4) as i32;
312 buf.extend_from_slice(&len.to_be_bytes());
313 buf.extend_from_slice(reason.as_bytes());
314 buf.extend_from_slice(&[0]);
315 buf
316 }
317
318 pub fn encode_close(is_portal: bool, name: &str) -> BytesMut {
325 let mut buf = BytesMut::new();
326 buf.extend_from_slice(b"C");
327 let content_len = 1 + name.len() + 1; let len = (content_len + 4) as i32;
329 buf.extend_from_slice(&len.to_be_bytes());
330 buf.extend_from_slice(&[if is_portal { b'P' } else { b'S' }]);
331 buf.extend_from_slice(name.as_bytes());
332 buf.extend_from_slice(&[0]);
333 buf
334 }
335}
336
337#[cfg(test)]
338mod tests {
339 use super::*;
340
341 #[test]
343 fn test_encode_query_string() {
344 let sql = "SELECT 1";
345 let bytes = PgEncoder::encode_query_string(sql);
346
347 assert_eq!(bytes[0], b'Q');
349
350 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
352 assert_eq!(len, 13);
353
354 assert_eq!(&bytes[5..13], b"SELECT 1");
356
357 assert_eq!(bytes[13], 0);
359 }
360
361 #[test]
362 fn test_encode_terminate() {
363 let bytes = PgEncoder::encode_terminate();
364 assert_eq!(bytes.as_ref(), &[b'X', 0, 0, 0, 4]);
365 }
366
367 #[test]
368 fn test_encode_sync() {
369 let bytes = PgEncoder::encode_sync();
370 assert_eq!(bytes.as_ref(), &[b'S', 0, 0, 0, 4]);
371 }
372
373 #[test]
374 fn test_encode_parse() {
375 let bytes = PgEncoder::encode_parse("", "SELECT $1", &[]);
376
377 assert_eq!(bytes[0], b'P');
379
380 let content = String::from_utf8_lossy(&bytes[5..]);
382 assert!(content.contains("SELECT $1"));
383 }
384
385 #[test]
386 fn test_encode_bind() {
387 let params = vec![
388 Some(b"42".to_vec()),
389 None, ];
391 let bytes = PgEncoder::encode_bind("", "", ¶ms).unwrap();
392
393 assert_eq!(bytes[0], b'B');
395
396 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
398 assert!(len > 4); }
400
401 #[test]
402 fn test_encode_execute() {
403 let bytes = PgEncoder::encode_execute("", 0);
404
405 assert_eq!(bytes[0], b'E');
407
408 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
410 assert_eq!(len, 9);
411 }
412
413 #[test]
414 fn test_encode_extended_query() {
415 let params = vec![Some(b"hello".to_vec())];
416 let bytes = PgEncoder::encode_extended_query("SELECT $1", ¶ms).unwrap();
417
418 assert!(bytes.windows(1).any(|w| w == [b'P']));
420 assert!(bytes.windows(1).any(|w| w == [b'B']));
421 assert!(bytes.windows(1).any(|w| w == [b'E']));
422 assert!(bytes.windows(1).any(|w| w == [b'S']));
423 }
424
425 #[test]
426 fn test_encode_copy_fail() {
427 let bytes = PgEncoder::encode_copy_fail("bad data");
428 assert_eq!(bytes[0], b'f');
429 let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
430 assert_eq!(len as usize, 4 + "bad data".len() + 1);
431 assert_eq!(&bytes[5..13], b"bad data");
432 assert_eq!(bytes[13], 0);
433 }
434
435 #[test]
436 fn test_encode_close_statement() {
437 let bytes = PgEncoder::encode_close(false, "my_stmt");
438 assert_eq!(bytes[0], b'C');
439 assert_eq!(bytes[5], b'S'); assert_eq!(&bytes[6..13], b"my_stmt");
441 assert_eq!(bytes[13], 0);
442 }
443
444 #[test]
445 fn test_encode_close_portal() {
446 let bytes = PgEncoder::encode_close(true, "");
447 assert_eq!(bytes[0], b'C');
448 assert_eq!(bytes[5], b'P'); assert_eq!(bytes[6], 0); }
451}
452
453use bytes::BufMut;
462
463pub enum Param<'a> {
466 Null,
468 Bytes(&'a [u8]),
470}
471
472impl PgEncoder {
473 #[inline(always)]
476 fn put_i32_be(buf: &mut BytesMut, v: i32) {
477 buf.put_i32(v);
478 }
479
480 #[inline(always)]
481 fn put_i16_be(buf: &mut BytesMut, v: i16) {
482 buf.put_i16(v);
483 }
484
485 #[inline]
490 pub fn encode_bind_ultra<'a>(buf: &mut BytesMut, statement: &str, params: &[Param<'a>]) -> Result<(), EncodeError> {
491 if params.len() > i16::MAX as usize {
492 return Err(EncodeError::TooManyParameters(params.len()));
493 }
494
495 let params_size: usize = params
497 .iter()
498 .map(|p| match p {
499 Param::Null => 4,
500 Param::Bytes(b) => 4 + b.len(),
501 })
502 .sum();
503 let content_len = 1 + statement.len() + 1 + 2 + 2 + params_size + 2;
504
505 buf.reserve(1 + 4 + content_len);
507
508 buf.put_u8(b'B');
510
511 Self::put_i32_be(buf, (content_len + 4) as i32);
513
514 buf.put_u8(0);
516
517 buf.extend_from_slice(statement.as_bytes());
519 buf.put_u8(0);
520
521 Self::put_i16_be(buf, 0);
523
524 Self::put_i16_be(buf, params.len() as i16);
526
527 for param in params {
529 match param {
530 Param::Null => Self::put_i32_be(buf, -1),
531 Param::Bytes(data) => {
532 if data.len() > i32::MAX as usize {
533 return Err(EncodeError::MessageTooLarge(data.len()));
534 }
535 Self::put_i32_be(buf, data.len() as i32);
536 buf.extend_from_slice(data);
537 }
538 }
539 }
540
541 Self::put_i16_be(buf, 0);
543 Ok(())
544 }
545
546 #[inline(always)]
548 pub fn encode_execute_ultra(buf: &mut BytesMut) {
549 buf.extend_from_slice(&[b'E', 0, 0, 0, 9, 0, 0, 0, 0, 0]);
552 }
553
554 #[inline(always)]
556 pub fn encode_sync_ultra(buf: &mut BytesMut) {
557 buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
558 }
559
560 #[inline]
565 pub fn encode_bind_to(buf: &mut BytesMut, statement: &str, params: &[Option<Vec<u8>>]) -> Result<(), EncodeError> {
566 if params.len() > i16::MAX as usize {
567 return Err(EncodeError::TooManyParameters(params.len()));
568 }
569
570 let params_size: usize = params
573 .iter()
574 .map(|p| 4 + p.as_ref().map_or(0, |v| v.len()))
575 .sum();
576 let content_len = 1 + statement.len() + 1 + 2 + 2 + params_size + 2;
577
578 buf.reserve(1 + 4 + content_len);
579
580 buf.put_u8(b'B');
582
583 Self::put_i32_be(buf, (content_len + 4) as i32);
585
586 buf.put_u8(0);
588
589 buf.extend_from_slice(statement.as_bytes());
591 buf.put_u8(0);
592
593 Self::put_i16_be(buf, 0);
595
596 Self::put_i16_be(buf, params.len() as i16);
598
599 for param in params {
601 match param {
602 None => Self::put_i32_be(buf, -1),
603 Some(data) => {
604 if data.len() > i32::MAX as usize {
605 return Err(EncodeError::MessageTooLarge(data.len()));
606 }
607 Self::put_i32_be(buf, data.len() as i32);
608 buf.extend_from_slice(data);
609 }
610 }
611 }
612
613 Self::put_i16_be(buf, 0);
615 Ok(())
616 }
617
618 #[inline]
620 pub fn encode_execute_to(buf: &mut BytesMut) {
621 buf.extend_from_slice(&[b'E', 0, 0, 0, 9, 0, 0, 0, 0, 0]);
623 }
624
625 #[inline]
627 pub fn encode_sync_to(buf: &mut BytesMut) {
628 buf.extend_from_slice(&[b'S', 0, 0, 0, 4]);
629 }
630}