Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor to use NonNull in datum::Array #656

Merged
merged 3 commits into from
Aug 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pgx-tests/src/tests/array_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ fn get_arr_ndim(arr: Array<i32>) -> libc::c_int {
}

#[pg_extern]
#[allow(deprecated)]
fn over_implicit_drop() -> Vec<i64> {
// Create an array of exactly Datum-sized numbers.
let mut vec: Vec<i64> = vec![1, 2, 3, 4, 5];
Expand Down
58 changes: 41 additions & 17 deletions pgx/src/datum/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ Use of this source code is governed by the MIT license that can be found in the
*/

use crate::{pg_sys, FromDatum, IntoDatum, PgMemoryContexts};
use core::ptr::NonNull;
use serde::Serializer;
use std::marker::PhantomData;
use std::{mem, ptr, slice};

pub type VariadicArray<'a, T> = Array<'a, T>;

pub struct Array<'a, T: FromDatum> {
_ptr: *mut pg_sys::varlena,
array_type: *mut pg_sys::ArrayType,
_ptr: Option<NonNull<pg_sys::varlena>>,
array_type: Option<NonNull<pg_sys::ArrayType>>,
nelems: usize,
elem_slice: &'a [pg_sys::Datum],
null_slice: &'a [bool],
Expand Down Expand Up @@ -53,14 +54,29 @@ impl<'a, T: FromDatum> Array<'a, T> {
/// - `elements` is non-null
/// - `nulls` is non-null
/// - both `elements` and `nulls` point to a slice of equal-or-greater length than `nelems`
#[deprecated(
since = "0.5.0",
note = "creating arbitrary Arrays from raw pointers has unsound interactions!
please open an issue in tcdi/pgx if you need this, with your stated use-case"
)]
pub unsafe fn over(
elements: *mut pg_sys::Datum,
nulls: *mut bool,
nelems: usize,
) -> Array<'a, T> {
// FIXME: This function existing prevents simply using NonNull<varlena>
// or NonNull<ArrayType>. It has also caused issues like tcdi/pgx#633
// Ideally it would cease being used soon.
// It can be replaced with ways to make Postgres varlena arrays in Rust,
// if there are any users who desire such a thing.
//
// Remember to remove the Array::over tests in pgx-tests/src/tests/array_tests.rs
// when you finally kill this off.
let _ptr: Option<NonNull<pg_sys::varlena>> = None;
let array_type: Option<NonNull<pg_sys::ArrayType>> = None;
Array::<T> {
_ptr: ptr::null_mut(),
array_type: ptr::null_mut(),
_ptr,
array_type,
nelems,
elem_slice: slice::from_raw_parts(elements, nelems),
null_slice: slice::from_raw_parts(nulls, nelems),
Expand All @@ -75,8 +91,8 @@ impl<'a, T: FromDatum> Array<'a, T> {
/// - `nulls` is non-null
/// - both `elements` and `nulls` point to a slice of equal-or-greater length than `nelems`
unsafe fn from_pg(
_ptr: *mut pg_sys::varlena,
array_type: *mut pg_sys::ArrayType,
_ptr: Option<NonNull<pg_sys::varlena>>,
array_type: Option<NonNull<pg_sys::ArrayType>>,
elements: *mut pg_sys::Datum,
nulls: *mut bool,
Comment on lines 96 to 97
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are being kept as-is for the moment because the actual fix for them is using the new RawArray abstraction plus bitvec to handle things, removing usage of deconstruct_array, and that's a more complex followup.

nelems: usize,
Expand All @@ -92,11 +108,11 @@ impl<'a, T: FromDatum> Array<'a, T> {
}

pub fn into_array_type(self) -> *const pg_sys::ArrayType {
if self.array_type.is_null() {
panic!("attempt to dereference a NULL array");
}

let ptr = self.array_type;
let ptr = if let Some(at) = self.array_type {
at.as_ptr()
} else {
ptr::null()
};
mem::forget(self);
ptr
}
Expand Down Expand Up @@ -124,11 +140,13 @@ impl<'a, T: FromDatum> Array<'a, T> {
///
/// This function will panic when called if the array contains any SQL NULL values.
pub fn iter_deny_null(&self) -> ArrayTypedIterator<'_, T> {
if self.array_type.is_null() {
if let Some(at) = self.array_type {
if unsafe { pg_sys::array_contains_nulls(at.as_ptr()) } {
panic!("array contains NULL");
}
} else {
panic!("array is NULL");
} else if unsafe { pg_sys::array_contains_nulls(self.array_type) } {
panic!("array contains NULL");
}
};

ArrayTypedIterator {
array: self,
Expand Down Expand Up @@ -251,7 +269,7 @@ impl<'a, T: FromDatum> Iterator for ArrayIntoIterator<'a, T> {
impl<'a, T: FromDatum> FromDatum for Array<'a, T> {
#[inline]
unsafe fn from_datum(datum: pg_sys::Datum, is_null: bool) -> Option<Array<'a, T>> {
if is_null {
if is_null || datum.is_null() {
None
} else {
let ptr = datum.ptr_cast();
Expand Down Expand Up @@ -291,7 +309,13 @@ impl<'a, T: FromDatum> FromDatum for Array<'a, T> {
&mut nelems,
);

Some(Array::from_pg(ptr, array, elements, nulls, nelems as usize))
Some(Array::from_pg(
NonNull::new(ptr),
NonNull::new(array),
elements,
nulls,
nelems as usize,
))
}
}
}
Expand Down