diff --git a/README.md b/README.md index eb6915460..19871ef96 100644 --- a/README.md +++ b/README.md @@ -242,6 +242,26 @@ this feature is now considered deprecated in favor of a lower-overhead interop. You may still request implementations of `TryFrom for pgx::MatchingType` and `From for pgx::MatchingType` by enabling the `"time-crate"` feature. +### "unsafe-postgres": Allow compilation for Postgres forks that have a different ABI + +As of Postgres v15, forks are allowed to specify they use a different ABI than canonical Postgres. +Since pgx makes countless assumptions about Postgres' internal ABI it is not possible for it to +guarantee that a compiled pgx extension will probably execute within such a Postgres fork. You, +dear compiler runner, can make this guarantee for yourself by specifying the `unsafe-postgres` +feature flag. Otherwise, a pgx extension will fail to compile with an error similar to: + +``` +error[E0080]: evaluation of constant value failed + --> pgx/src/lib.rs:151:5 + | +151 | / assert!( +152 | | same_slice(pg_sys::FMGR_ABI_EXTRA, b"xPostgreSQL\0"), +153 | | "Unsupported Postgres ABI. Perhaps you need `--features unsafe-postgres`?", +154 | | ); + | |_____^ the evaluated program panicked at 'Unsupported Postgres ABI. Perhaps you need `--features unsafe-postgres`?', pgx/src/lib.rs:151:5 + | +``` + ### Experimental Features Adding `pgx = { version = "0.5.0", features = ["postgrestd"] }` to your Cargo.toml diff --git a/pgx/Cargo.toml b/pgx/Cargo.toml index 25520640a..b628627a5 100644 --- a/pgx/Cargo.toml +++ b/pgx/Cargo.toml @@ -27,6 +27,7 @@ pg14 = [ "pgx-pg-sys/pg14" ] pg15 = [ "pgx-pg-sys/pg15" ] time-crate = ["dep:time"] no-schema-generation = ["pgx-macros/no-schema-generation", "pgx-sql-entity-graph/no-schema-generation"] +unsafe-postgres = [] # when trying to compile against something that looks like Postgres but claims to be diffent [package.metadata.docs.rs] features = ["pg14", "cshim"] diff --git a/pgx/src/lib.rs b/pgx/src/lib.rs index 632686be6..b2bca3808 100644 --- a/pgx/src/lib.rs +++ b/pgx/src/lib.rs @@ -128,6 +128,33 @@ pub use pg_sys::{ #[doc(hidden)] pub use pgx_sql_entity_graph; +// Postgres v15 has the concept of an ABI "name". The default is `b"PostgreSQL\0"` and this is the +// ABI that pgx extensions expect to be running under. We will refuse to compile if it is detected +// that we're trying to be built against some other kind of "postgres" that has its own ABI name. +// +// Unless the compiling user explicitly told us that they're aware of this via `--features unsafe-postgres`. +#[cfg(all(feature = "pg15", not(feature = "unsafe-postgres")))] +const _: () = { + // to appease `const` + const fn same_slice(a: &[u8], b: &[u8]) -> bool { + if a.len() != b.len() { + return false; + } + let mut i = 0; + while i < a.len() { + if a[i] != b[i] { + return false; + } + i += 1; + } + true + } + assert!( + same_slice(pg_sys::FMGR_ABI_EXTRA, b"PostgreSQL\0"), + "Unsupported Postgres ABI. Perhaps you need `--features unsafe-postgres`?", + ); +}; + /// A macro for marking a library compatible with [`pgx`][crate]. /// ///
@@ -220,8 +247,9 @@ macro_rules! pg_magic_func { namedatalen: pgx::pg_sys::NAMEDATALEN as i32, float8byval: cfg!(target_pointer_width = "64") as i32, abi_extra: { - // array::from_fn isn't const yet, boohoo, so const-copy a bstr - let magic = b"PostgreSQL"; + // we'll use what the bindings tell us, but if it ain't "PostgreSQL" then we'll + // raise a compilation error unless the `unsafe-postgres` feature is set + let magic = pgx::pg_sys::FMGR_ABI_EXTRA; let mut abi = [0 as ::pgx::ffi::c_char; 32]; let mut i = 0; while i < magic.len() {