sqlx_core_oldapi/postgres/
arguments.rs1use std::fmt::{self, Write};
2use std::ops::{Deref, DerefMut};
3
4use crate::arguments::Arguments;
5use crate::encode::{Encode, IsNull};
6use crate::error::Error;
7use crate::ext::ustr::UStr;
8use crate::postgres::{PgConnection, PgTypeInfo, Postgres};
9use crate::types::Type;
10
11#[derive(Default)]
22pub struct PgArgumentBuffer {
23 buffer: Vec<u8>,
24
25 count: usize,
27
28 patches: Vec<(
35 usize, usize, Box<dyn Fn(&mut [u8], &PgTypeInfo) + 'static + Send + Sync>,
38 )>,
39
40 type_holes: Vec<(usize, UStr)>, }
49
50#[derive(Default)]
52pub struct PgArguments {
53 pub(crate) types: Vec<PgTypeInfo>,
55
56 pub(crate) buffer: PgArgumentBuffer,
58}
59
60impl PgArguments {
61 pub(crate) fn add<'q, T>(&mut self, value: T)
62 where
63 T: Encode<'q, Postgres> + Type<Postgres>,
64 {
65 self.types
67 .push(value.produces().unwrap_or_else(T::type_info));
68
69 self.buffer.encode(value);
71
72 self.buffer.count += 1;
74 }
75
76 pub(crate) async fn apply_patches(
79 &mut self,
80 conn: &mut PgConnection,
81 parameters: &[PgTypeInfo],
82 ) -> Result<(), Error> {
83 let PgArgumentBuffer {
84 ref patches,
85 ref type_holes,
86 ref mut buffer,
87 ..
88 } = self.buffer;
89
90 for (offset, ty, callback) in patches {
91 let buf = &mut buffer[*offset..];
92 let ty = ¶meters[*ty];
93
94 callback(buf, ty);
95 }
96
97 for (offset, name) in type_holes {
98 let oid = conn.fetch_type_id_by_name(name).await?;
99 buffer[*offset..(*offset + 4)].copy_from_slice(&oid.0.to_be_bytes());
100 }
101
102 Ok(())
103 }
104}
105
106impl<'q> Arguments<'q> for PgArguments {
107 type Database = Postgres;
108
109 fn reserve(&mut self, additional: usize, size: usize) {
110 self.types.reserve(additional);
111 self.buffer.reserve(size);
112 }
113
114 fn add<T>(&mut self, value: T)
115 where
116 T: Encode<'q, Self::Database> + Type<Self::Database>,
117 {
118 self.add(value)
119 }
120
121 fn format_placeholder<W: Write>(&self, writer: &mut W) -> fmt::Result {
122 write!(writer, "${}", self.buffer.count)
123 }
124}
125
126impl PgArgumentBuffer {
127 pub(crate) fn encode<'q, T>(&mut self, value: T)
128 where
129 T: Encode<'q, Postgres>,
130 {
131 let offset = self.len();
133 self.extend(&[0; 4]);
134
135 let len = if let IsNull::No = value.encode(self) {
137 i32::try_from(self.len() - offset - 4).expect("bind parameter too large")
138 } else {
139 debug_assert_eq!(self.len(), offset + 4);
142 -1_i32
143 };
144
145 self[offset..(offset + 4)].copy_from_slice(&len.to_be_bytes());
147 }
148
149 #[allow(dead_code)]
151 pub(crate) fn patch<F>(&mut self, callback: F)
152 where
153 F: Fn(&mut [u8], &PgTypeInfo) + 'static + Send + Sync,
154 {
155 let offset = self.len();
156 let index = self.count;
157
158 self.patches.push((offset, index, Box::new(callback)));
159 }
160
161 pub(crate) fn patch_type_by_name(&mut self, type_name: &UStr) {
164 let offset = self.len();
165
166 self.extend_from_slice(&0_u32.to_be_bytes());
167 self.type_holes.push((offset, type_name.clone()));
168 }
169}
170
171impl Deref for PgArgumentBuffer {
172 type Target = Vec<u8>;
173
174 #[inline]
175 fn deref(&self) -> &Self::Target {
176 &self.buffer
177 }
178}
179
180impl DerefMut for PgArgumentBuffer {
181 #[inline]
182 fn deref_mut(&mut self) -> &mut Self::Target {
183 &mut self.buffer
184 }
185}