diesel/pg/connection/stmt/
mod.rs1#![allow(unsafe_code)] extern crate pq_sys;
3
4use alloc::ffi::CString;
5use core::ffi as libc;
6use core::ptr;
7
8use super::result::PgResult;
9use super::statement_cache::PrepareForCache;
10use crate::connection::statement_cache::PreparedStatement;
11use crate::pg::PgTypeMetadata;
12use crate::result::QueryResult;
13
14use super::raw::RawConnection;
15
16enum StatementKind {
17 Unnamed { sql: CString, param_types: Vec<u32> },
18 Named { name: CString },
19}
20
21pub(crate) struct Statement {
22 kind: StatementKind,
23 param_formats: Vec<libc::c_int>,
24}
25
26impl PreparedStatement for Statement {
27 fn parameter_count(&self) -> u64 {
28 self.param_formats.len() as u64
29 }
30}
31
32impl Statement {
33 pub(super) fn execute(
34 &self,
35 raw_connection: &mut RawConnection,
36 param_data: &[Option<Vec<u8>>],
37 row_by_row: bool,
38 disallow_copy: bool,
39 ) -> QueryResult<PgResult> {
40 if self.param_formats.len() != param_data.len() {
44 return Err(
45 crate::connection::statement_cache::invalid_prepared_statement_parameter_count(
46 self.param_formats.len(),
47 param_data.len(),
48 ),
49 );
50 }
51
52 let params_pointer = param_data
53 .iter()
54 .map(|data| {
55 data.as_ref()
56 .map(|d| d.as_ptr() as *const libc::c_char)
57 .unwrap_or(ptr::null())
58 })
59 .collect::<Vec<_>>();
60 let param_lengths = param_data
61 .iter()
62 .map(|data| data.as_ref().map(|d| d.len().try_into()).unwrap_or(Ok(0)))
63 .collect::<Result<Vec<_>, _>>()
64 .map_err(|_: core::num::TryFromIntError| {
65 crate::result::Error::SerializationError(
66 "A bind parameter's serialized size is bigger than fits on an i32".into(),
67 )
68 })?;
69 let param_count: libc::c_int =
70 params_pointer
71 .len()
72 .try_into()
73 .map_err(|_: core::num::TryFromIntError| {
74 crate::result::Error::SerializationError(
75 "There are more than i32::MAX bind parameters".into(),
76 )
77 })?;
78
79 match &self.kind {
80 StatementKind::Named { name } => {
81 unsafe {
82 raw_connection.send_query_prepared(
85 name.as_ptr(),
86 param_count,
87 params_pointer.as_ptr(),
88 param_lengths.as_ptr(),
89 self.param_formats.as_ptr(),
90 1,
91 )
92 }?
93 }
94 StatementKind::Unnamed { sql, param_types } => unsafe {
95 raw_connection.send_query_params(
101 sql.as_ptr(),
102 param_count,
103 param_types.as_ptr(),
104 params_pointer.as_ptr(),
105 param_lengths.as_ptr(),
106 self.param_formats.as_ptr(),
107 1,
108 )
109 }?,
110 };
111
112 if row_by_row {
113 raw_connection.enable_row_by_row_mode()?;
114 }
115 let result = raw_connection.get_next_result()?.expect("Is never none");
116 handle_copy_in_normal_stmt(raw_connection, disallow_copy, result)
117 }
118
119 pub(super) fn prepare(
120 raw_connection: &mut RawConnection,
121 sql: &str,
122 is_cached: PrepareForCache,
123 param_types: &[PgTypeMetadata],
124 ) -> QueryResult<Self> {
125 let sql_cstr = CString::new(sql)?;
126 let param_types_vec = param_types
127 .iter()
128 .map(|x| x.oid())
129 .collect::<Result<Vec<_>, _>>()
130 .map_err(|e| crate::result::Error::SerializationError(Box::new(e)))?;
131
132 match is_cached {
133 PrepareForCache::Yes { counter } => {
134 let name_cstr = CString::new(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("__diesel_stmt_{0}", counter))
})format!("__diesel_stmt_{counter}"))?;
137 let internal_result =
138 unsafe {
139 let param_count: libc::c_int = param_types.len().try_into().map_err(
140 |_: core::num::TryFromIntError| {
141 crate::result::Error::SerializationError(
142 "There are more than i32::MAX bind parameters".into(),
143 )
144 },
145 )?;
146 raw_connection.prepare(
147 name_cstr.as_ptr(),
148 sql_cstr.as_ptr(),
149 param_count,
150 param_types_vec.as_ptr(),
151 )
152 };
153 PgResult::new(internal_result?, raw_connection)?;
154
155 Ok(Statement {
156 kind: StatementKind::Named { name: name_cstr },
157 param_formats: ::alloc::vec::from_elem_global(1, param_types.len())vec![1; param_types.len()],
158 })
159 }
160 PrepareForCache::No => {
161 Ok(Statement {
168 kind: StatementKind::Unnamed {
169 sql: sql_cstr,
170 param_types: param_types_vec,
171 },
172 param_formats: ::alloc::vec::from_elem_global(1, param_types.len())vec![1; param_types.len()],
173 })
174 }
175 }
176 }
177}
178
179pub(super) fn handle_copy_in_normal_stmt(
180 raw_connection: &mut RawConnection,
181 disallow_copy: bool,
182 result: PgResult,
183) -> QueryResult<PgResult> {
184 if disallow_copy
185 && #[allow(non_exhaustive_omitted_patterns)] match result.result_status() {
pq_sys::ExecStatusType::PGRES_COPY_IN |
pq_sys::ExecStatusType::PGRES_COPY_OUT |
pq_sys::ExecStatusType::PGRES_COPY_BOTH => true,
_ => false,
}matches!(
186 result.result_status(),
187 pq_sys::ExecStatusType::PGRES_COPY_IN
188 | pq_sys::ExecStatusType::PGRES_COPY_OUT
189 | pq_sys::ExecStatusType::PGRES_COPY_BOTH
190 )
191 {
192 raw_connection.consume_results()?;
193 }
194 Ok(result)
195}