1#![deny(unsafe_op_in_unsafe_fn)]
11use core::{iter, ptr};
12
13use crate::callconv::{BoxRet, CallCx, RetAbi};
14use crate::fcinfo::{pg_return_null, srf_is_first_call, srf_return_done, srf_return_next};
15use crate::ptr::PointerExt;
16use crate::{pg_sys, IntoDatum, IntoHeapTuple, PgMemoryContexts};
17use pgrx_sql_entity_graph::metadata::{
18 ArgumentError, Returns, ReturnsError, SqlMapping, SqlTranslatable,
19};
20
21#[repr(transparent)]
52pub struct SetOfIterator<'a, T>(
53 TableIterator<'a, (T,)>,
55);
56
57impl<'a, T: 'a> SetOfIterator<'a, T> {
58 pub fn new(iter: impl IntoIterator<Item = T> + 'a) -> Self {
59 Self(TableIterator::new(iter.into_iter().map(|c| (c,))))
61 }
62
63 pub fn empty() -> Self {
64 Self::new(iter::empty())
65 }
66
67 pub fn once(value: T) -> Self {
68 Self::new(iter::once(value))
69 }
70}
71
72impl<'a, T> Iterator for SetOfIterator<'a, T> {
73 type Item = T;
74
75 #[inline]
76 fn next(&mut self) -> Option<Self::Item> {
77 self.0.next().map(|(val,)| val)
78 }
79}
80
81unsafe impl<'a, T> SqlTranslatable for SetOfIterator<'a, T>
83where
84 T: SqlTranslatable,
85{
86 fn argument_sql() -> Result<SqlMapping, ArgumentError> {
87 T::argument_sql()
88 }
89 fn return_sql() -> Result<Returns, ReturnsError> {
90 match T::return_sql() {
91 Ok(Returns::One(sql)) => Ok(Returns::SetOf(sql)),
92 Ok(Returns::SetOf(_)) => Err(ReturnsError::NestedSetOf),
93 Ok(Returns::Table(_)) => Err(ReturnsError::SetOfContainingTable),
94 err @ Err(_) => err,
95 }
96 }
97}
98
99pub struct TableIterator<'a, Row> {
142 iter: Box<dyn Iterator<Item = Row> + 'a>,
143}
144
145impl<'a, Row: 'a> TableIterator<'a, Row> {
146 pub fn new(iter: impl IntoIterator<Item = Row> + 'a) -> Self {
147 Self { iter: Box::new(iter.into_iter()) }
148 }
149
150 pub fn empty() -> Self {
151 Self::new(iter::empty())
152 }
153
154 pub fn once(value: Row) -> Self {
155 Self::new(iter::once(value))
156 }
157}
158
159impl<'a, Row> Iterator for TableIterator<'a, Row> {
160 type Item = Row;
161
162 #[inline]
163 fn next(&mut self) -> Option<Self::Item> {
164 self.iter.next()
165 }
166}
167
168unsafe impl<'iter, C> SqlTranslatable for TableIterator<'iter, (C,)>
169where
170 C: SqlTranslatable + 'iter,
171{
172 fn argument_sql() -> Result<SqlMapping, ArgumentError> {
173 Err(ArgumentError::Table)
174 }
175 fn return_sql() -> Result<Returns, ReturnsError> {
176 let vec = vec![C::return_sql().and_then(|sql| match sql {
177 Returns::One(sql) => Ok(sql),
178 Returns::SetOf(_) => Err(ReturnsError::TableContainingSetOf),
179 Returns::Table(_) => Err(ReturnsError::NestedTable),
180 })?];
181 Ok(Returns::Table(vec))
182 }
183}
184
185unsafe impl<'a, T> RetAbi for SetOfIterator<'a, T>
186where
187 T: BoxRet,
188{
189 type Item = <Self as Iterator>::Item;
190 type Ret = IterRet<Self>;
191
192 unsafe fn check_fcinfo_and_prepare(fcinfo: pg_sys::FunctionCallInfo) -> CallCx {
193 unsafe { TableIterator::<(T,)>::check_fcinfo_and_prepare(fcinfo) }
194 }
195
196 fn to_ret(self) -> Self::Ret {
197 let mut iter = self;
198 IterRet(match iter.next() {
199 None => Step::Done,
200 Some(value) => Step::Init(iter, value),
201 })
202 }
203
204 unsafe fn box_ret_in_fcinfo(fcinfo: pg_sys::FunctionCallInfo, ret: Self::Ret) -> pg_sys::Datum {
205 let ret = match ret.0 {
206 Step::Done => Step::Done,
207 Step::Once(value) => Step::Once((value,)),
208 Step::Init(iter, value) => Step::Init(iter.0, (value,)),
209 };
210 unsafe { TableIterator::<(T,)>::box_ret_in_fcinfo(fcinfo, IterRet(ret)) }
211 }
212
213 unsafe fn fill_fcinfo_fcx(&self, _fcinfo: pg_sys::FunctionCallInfo) {}
214
215 unsafe fn move_into_fcinfo_fcx(self, fcinfo: pg_sys::FunctionCallInfo) {
216 unsafe { self.0.move_into_fcinfo_fcx(fcinfo) }
217 }
218
219 unsafe fn ret_from_fcinfo_fcx(fcinfo: pg_sys::FunctionCallInfo) -> Self::Ret {
220 let step = match unsafe { TableIterator::<(T,)>::ret_from_fcinfo_fcx(fcinfo).0 } {
221 Step::Done => Step::Done,
222 Step::Once((item,)) => Step::Once(item),
223 Step::Init(iter, (value,)) => Step::Init(Self(iter), value),
224 };
225 IterRet(step)
226 }
227
228 unsafe fn finish_call_fcinfo(fcinfo: pg_sys::FunctionCallInfo) {
229 unsafe { TableIterator::<(T,)>::finish_call_fcinfo(fcinfo) }
230 }
231}
232
233unsafe impl<'a, Row> RetAbi for TableIterator<'a, Row>
234where
235 Row: RetAbi,
236{
237 type Item = <Self as Iterator>::Item;
238 type Ret = IterRet<Self>;
239
240 unsafe fn check_fcinfo_and_prepare(fcinfo: pg_sys::FunctionCallInfo) -> CallCx {
241 unsafe {
242 if srf_is_first_call(fcinfo) {
243 let fn_call_cx = pg_sys::init_MultiFuncCall(fcinfo);
244 CallCx::WrappedFn((*fn_call_cx).multi_call_memory_ctx)
245 } else {
246 CallCx::RestoreCx
247 }
248 }
249 }
250
251 fn to_ret(self) -> Self::Ret {
252 let mut iter = self;
253 IterRet(match iter.next() {
254 None => Step::Done,
255 Some(value) => Step::Init(iter, value),
256 })
257 }
258
259 unsafe fn box_ret_in_fcinfo(fcinfo: pg_sys::FunctionCallInfo, ret: Self::Ret) -> pg_sys::Datum {
260 let value = unsafe {
261 match ret.0 {
262 Step::Done => return empty_srf(fcinfo),
263 Step::Once(value) => value,
264 Step::Init(iter, value) => {
265 iter.move_into_fcinfo_fcx(fcinfo);
267 value.fill_fcinfo_fcx(fcinfo);
268 value
269 }
270 }
271 };
272
273 unsafe {
274 let fcx = deref_fcx(fcinfo);
275 srf_return_next(fcinfo, fcx);
276 <Row as RetAbi>::box_ret_in_fcinfo(fcinfo, value.to_ret())
277 }
278 }
279
280 unsafe fn fill_fcinfo_fcx(&self, _fcinfo: pg_sys::FunctionCallInfo) {}
281
282 unsafe fn move_into_fcinfo_fcx(self, fcinfo: pg_sys::FunctionCallInfo) {
283 unsafe {
284 let fcx = deref_fcx(fcinfo);
285 let ptr = srf_memcx(fcx).leak_and_drop_on_delete(self);
286 (*fcx).user_fctx = ptr.cast();
288 }
289 }
290
291 unsafe fn ret_from_fcinfo_fcx(fcinfo: pg_sys::FunctionCallInfo) -> Self::Ret {
292 let iter = unsafe {
294 let fcx = deref_fcx(fcinfo);
295 &mut *(*fcx).user_fctx.cast::<TableIterator<Row>>()
296 };
297 IterRet(match iter.next() {
298 None => Step::Done,
299 Some(value) => Step::Once(value),
300 })
301 }
302
303 unsafe fn finish_call_fcinfo(fcinfo: pg_sys::FunctionCallInfo) {
304 unsafe {
305 let fcx = deref_fcx(fcinfo);
306 srf_return_done(fcinfo, fcx)
307 }
308 }
309}
310
311pub struct IterRet<T: RetAbi>(Step<T>);
313
314enum Step<T: RetAbi> {
316 Done,
317 Once(T::Item),
318 Init(T, T::Item),
319}
320
321pub(crate) unsafe fn empty_srf(fcinfo: pg_sys::FunctionCallInfo) -> pg_sys::Datum {
322 unsafe {
323 let fcx = deref_fcx(fcinfo);
324 srf_return_done(fcinfo, fcx);
325 pg_return_null(fcinfo)
326 }
327}
328
329pub(crate) unsafe fn deref_fcx(fcinfo: pg_sys::FunctionCallInfo) -> *mut pg_sys::FuncCallContext {
331 unsafe { (*(*fcinfo).flinfo).fn_extra.cast() }
332}
333
334pub(crate) unsafe fn srf_memcx(fcx: *mut pg_sys::FuncCallContext) -> PgMemoryContexts {
335 unsafe { PgMemoryContexts::For((*fcx).multi_call_memory_ctx) }
336}
337
338unsafe impl<C> RetAbi for (C,)
346where
347 C: BoxRet, {
349 type Item = C;
350 type Ret = C;
351
352 fn to_ret(self) -> Self::Ret {
353 self.0
354 }
355
356 unsafe fn box_ret_in_fcinfo(fcinfo: pg_sys::FunctionCallInfo, ret: Self::Ret) -> pg_sys::Datum {
358 unsafe { C::box_ret_in_fcinfo(fcinfo, ret.to_ret()) }
359 }
360
361 unsafe fn fill_fcinfo_fcx(&self, _fcinfo: pg_sys::FunctionCallInfo) {}
362
363 unsafe fn move_into_fcinfo_fcx(self, _fcinfo: pg_sys::FunctionCallInfo) {}
364}
365
366macro_rules! impl_table_iter {
367 ($($C:ident),* $(,)?) => {
368 unsafe impl<'iter, $($C,)*> SqlTranslatable for TableIterator<'iter, ($($C,)*)>
369 where
370 $($C: SqlTranslatable + 'iter,)*
371 {
372 fn argument_sql() -> Result<SqlMapping, ArgumentError> {
373 Err(ArgumentError::Table)
374 }
375 fn return_sql() -> Result<Returns, ReturnsError> {
376 let vec = vec![
377 $(
378 $C::return_sql().and_then(|sql| match sql {
379 Returns::One(sql) => Ok(sql),
380 Returns::SetOf(_) => Err(ReturnsError::TableContainingSetOf),
381 Returns::Table(_) => Err(ReturnsError::NestedTable),
382 })?,
383 )*
384 ];
385 Ok(Returns::Table(vec))
386 }
387 }
388
389 impl<$($C: IntoDatum),*> IntoHeapTuple for ($($C,)*) {
390 unsafe fn into_heap_tuple(self, tupdesc: pg_sys::TupleDesc) -> *mut pg_sys::HeapTupleData {
391 #[allow(nonstandard_style)]
393 let ($($C,)*) = self;
394 let datums = [$($C.into_datum(),)*];
395 let mut nulls = datums.map(|option| option.is_none());
396 let mut datums = datums.map(|option| option.unwrap_or(pg_sys::Datum::from(0)));
397
398 unsafe {
399 pg_sys::heap_form_tuple(tupdesc, datums.as_mut_ptr(), nulls.as_mut_ptr())
403 }
404 }
405 }
406
407 unsafe impl<$($C),*> RetAbi for ($($C,)*)
408 where
409 $($C: BoxRet,)*
410 Self: IntoHeapTuple,
411 {
412 type Item = Self;
413 type Ret = Self;
414
415 fn to_ret(self) -> Self::Ret {
416 self
417 }
418
419 unsafe fn box_ret_in_fcinfo(fcinfo: pg_sys::FunctionCallInfo, ret: Self::Ret) -> pg_sys::Datum {
420 unsafe {
421 let fcx = deref_fcx(fcinfo);
422 let heap_tuple = ret.into_heap_tuple((*fcx).tuple_desc);
423 pg_sys::HeapTupleHeaderGetDatum((*heap_tuple).t_data)
424 }
425 }
426
427 unsafe fn move_into_fcinfo_fcx(self, _fcinfo: pg_sys::FunctionCallInfo) {}
428
429 unsafe fn fill_fcinfo_fcx(&self, fcinfo: pg_sys::FunctionCallInfo) {
430 unsafe {
432 let fcx = deref_fcx(fcinfo);
433 srf_memcx(fcx).switch_to(|_| {
434 let mut tupdesc = ptr::null_mut();
435 let mut oid = pg_sys::Oid::default();
436 let ty_class = pg_sys::get_call_result_type(fcinfo, &mut oid, &mut tupdesc);
437 if tupdesc.is_non_null() && ty_class == pg_sys::TypeFuncClass::TYPEFUNC_COMPOSITE {
438 pg_sys::BlessTupleDesc(tupdesc);
439 (*fcx).tuple_desc = tupdesc;
440 }
441 });
442 }
443 }
444 }
445
446 }
447}
448
449impl_table_iter!(T0, T1);
450impl_table_iter!(T0, T1, T2);
451impl_table_iter!(T0, T1, T2, T3);
452impl_table_iter!(T0, T1, T2, T3, T4);
453impl_table_iter!(T0, T1, T2, T3, T4, T5);
454impl_table_iter!(T0, T1, T2, T3, T4, T5, T6);
455impl_table_iter!(T0, T1, T2, T3, T4, T5, T6, T7);
456impl_table_iter!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
457impl_table_iter!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
458impl_table_iter!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
459impl_table_iter!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
460impl_table_iter!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
461impl_table_iter!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
462impl_table_iter!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
463impl_table_iter!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
464impl_table_iter!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
465impl_table_iter!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17);
466impl_table_iter!(
467 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18
468);
469impl_table_iter!(
470 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19
471);
472impl_table_iter!(
473 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20
474);
475impl_table_iter!(
476 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
477 T21
478);
479impl_table_iter!(
480 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
481 T21, T22
482);
483impl_table_iter!(
484 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
485 T21, T22, T23
486);
487impl_table_iter!(
488 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
489 T21, T22, T23, T24
490);
491impl_table_iter!(
492 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
493 T21, T22, T23, T24, T25
494);
495impl_table_iter!(
496 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
497 T21, T22, T23, T24, T25, T26
498);
499impl_table_iter!(
500 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
501 T21, T22, T23, T24, T25, T26, T27
502);
503impl_table_iter!(
504 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
505 T21, T22, T23, T24, T25, T26, T27, T28
506);
507impl_table_iter!(
508 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
509 T21, T22, T23, T24, T25, T26, T27, T28, T29
510);
511impl_table_iter!(
512 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
513 T21, T22, T23, T24, T25, T26, T27, T28, T29, T30
514);
515impl_table_iter!(
516 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20,
517 T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31
518);