Skip to content

Commit

Permalink
Add support for PostgreSQL 12
Browse files Browse the repository at this point in the history
PostgreSQL 12 brings changes to FunctionCallInfoData (the way arguments
are passed to functions).

Upstream commit:
postgres/postgres@a9c35cf
  • Loading branch information
intgr committed Oct 23, 2019
1 parent be7e47f commit 3c625d8
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 25 deletions.
1 change: 1 addition & 0 deletions pg-extend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fdw = []
postgres-9 = ["fdw"]
postgres-10 = ["fdw"]
postgres-11 = []
postgres-12 = []

[dependencies]

Expand Down
3 changes: 2 additions & 1 deletion pg-extend/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ fn main() {
.expect("Couldn't write bindings!");

let feature_version = get_postgres_feature_version(pg_include);
println!("cargo:rustc-cfg=feature=\"{}\"", feature_version)
println!("cargo:rustc-cfg=feature=\"{}\"", feature_version);
}

fn include_dir() -> Result<String, env::VarError> {
Expand Down Expand Up @@ -122,6 +122,7 @@ fn get_postgres_feature_version(pg_include: String) -> &'static str {
["9", _] => "postgres-9",
["10"] => "postgres-10",
["11"] => "postgres-11",
["12"] => "postgres-12",
val => panic!("unknown Postgres version {:?}", val),
}
}
47 changes: 35 additions & 12 deletions pg-extend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,43 @@ macro_rules! pg_magic {
};
}

/// Returns the slice of Datums, and a parallel slice which specifies if the Datum passed in is (SQL) NULL
#[cfg(feature = "postgres-12")]
type FunctionCallInfoData = pg_sys::FunctionCallInfoBaseData;
#[cfg(not(feature = "postgres-12"))]
type FunctionCallInfoData = pg_sys::FunctionCallInfoData;

/// Returns an iterator of argument Datums
pub fn get_args<'a>(
func_call_info: &'a pg_sys::FunctionCallInfoData,
) -> (
impl 'a + Iterator<Item = &pg_sys::Datum>,
impl 'a + Iterator<Item = pg_bool::Bool>,
) {
func_call_info: &'a FunctionCallInfoData,
) -> impl 'a + Iterator<Item = Option<pg_sys::Datum>> {
let num_args = func_call_info.nargs as usize;

let args = func_call_info.arg[..num_args].iter();
let args_null = func_call_info.argnull[..num_args]
// PostgreSQL 12+: Convert from pg_sys::NullableDatum
#[cfg(feature = "postgres-12")]
return unsafe { func_call_info.args.as_slice(num_args) }
.iter()
.map(|b| pg_bool::Bool::from(*b));

(args, args_null)
.map(|nullable| {
if nullable.isnull {
None
} else {
Some(nullable.value)
}
});

// Older versions store two separate arrays for 'isnull' and datums
#[cfg(not(feature = "postgres-12"))]
return {
let args = &func_call_info.arg[..num_args];
let args_null = &func_call_info.argnull[..num_args];

args.iter().zip(args_null.iter()).map(|(value, isnull)| {
if pg_bool::Bool::from(*isnull).into() {
None
} else {
Some(*value)
}
})
};
}

/// Information for a longjmp
Expand Down Expand Up @@ -126,7 +148,8 @@ pub fn register_panic_handler() {
pub(crate) unsafe fn guard_pg<R, F: FnOnce() -> R>(f: F) -> R {
// setup the check protection
let original_exception_stack: *mut pg_sys::sigjmp_buf = pg_sys::PG_exception_stack;
let mut local_exception_stack: mem::MaybeUninit<pg_sys::sigjmp_buf> = mem::MaybeUninit::uninit();
let mut local_exception_stack: mem::MaybeUninit<pg_sys::sigjmp_buf> =
mem::MaybeUninit::uninit();
let jumped = pg_sys::sigsetjmp(
// grab a mutable reference, cast to a mutabl pointr, then case to the expected erased pointer type
local_exception_stack.as_mut_ptr() as *mut pg_sys::sigjmp_buf as *mut _,
Expand Down
8 changes: 8 additions & 0 deletions pg-extend/src/pg_datum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ impl<'mc> PgDatum<'mc> {
PgDatum(datum, PhantomData)
}

/// Returns a new PgDatum wrapper if you already have Option<Datum>
pub unsafe fn from_option(
_memory_context: &'mc PgAllocator,
datum: Option<Datum>,
) -> PgDatum<'mc> {
PgDatum(datum, PhantomData)
}

/// Return true if this Datum is None
///
/// # Notes
Expand Down
2 changes: 1 addition & 1 deletion pg-extend/src/pg_fdw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

// FDW on PostgreSQL 11+ is not supported. :(
// If anyone tries to enable "fdw" feature with newer Postgres, throw error.
#[cfg(feature = "postgres-11")]
#[cfg(any(feature = "postgres-11", feature = "postgres-12"))]
compile_error!("pg-extend-rs does not support FDW on PostgreSQL 11 or newer. See https://github.com/bluejekyll/pg-extend-rs/issues/49");

use std::boxed::Box;
Expand Down
19 changes: 8 additions & 11 deletions pg-extern-attr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@
extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate syn;
#[macro_use]
extern crate quote;

mod lifetime;
#[macro_use]
extern crate syn;

use proc_macro2::{Ident, Span, TokenStream};
use quote::ToTokens;
Expand All @@ -23,6 +21,8 @@ use syn::spanned::Spanned;
use syn::token::Comma;
use syn::Type;

mod lifetime;

/// A type that represents that PgAllocator is an argument to the Rust function.
type HasPgAllocatorArg = bool;

Expand Down Expand Up @@ -104,14 +104,11 @@ fn extract_arg_data(arg_types: &[Type]) -> (TokenStream, HasPgAllocatorArg) {
let arg_error = format!("unsupported function argument type for {}", arg_name);

let get_arg = quote_spanned!( arg_type.span()=>
let datum = args.next().expect("wrong number of args passed into get_args for args?");
let #arg_name: #arg_type = unsafe {
pg_extend::pg_datum::TryFromPgDatum::try_from(
&memory_context,
pg_extend::pg_datum::PgDatum::from_raw(
&memory_context,
*args.next().expect("wrong number of args passed into get_args for args?"),
args_null.next().expect("wrong number of args passed into get_args for args_null?")
),
pg_extend::pg_datum::PgDatum::from_option(&memory_context, datum),
)
.expect(#arg_error)
};
Expand Down Expand Up @@ -337,7 +334,7 @@ fn impl_info_for_fn(item: &syn::Item) -> TokenStream {
// All params will be in the "current" memory context at the call-site
let memory_context = PgAllocator::current_context();

let func_info: &mut pg_extend::pg_sys::FunctionCallInfoData = unsafe {
let func_info = unsafe {
func_call_info
.as_mut()
.expect("func_call_info was unexpectedly NULL")
Expand All @@ -346,7 +343,7 @@ fn impl_info_for_fn(item: &syn::Item) -> TokenStream {
// guard the Postgres process against the panic, and give us an oportunity to cleanup
let panic_result = panic::catch_unwind(|| {
// extract the argument list
let (mut args, mut args_null) = pg_extend::get_args(func_info);
let mut args = pg_extend::get_args(func_info);

// arbitrary Datum conversions occur here, and could panic
// so this is inside the catch unwind
Expand Down

0 comments on commit 3c625d8

Please sign in to comment.