Skip to content
plpgsql_wrap

plpgsql_wrap

plpgsql_wrap : Oracle WRAP-equivalent PL/pgSQL language handler storing AES-256-GCM encrypted procedure source.

Overview

ID Extension Package Version Category License Language
9210
plpgsql_wrap
plpgsql_wrap
1.0
SIM
PostgreSQL
C
Attribute Has Binary Has Library Need Load Has DDL Relocatable Trusted
--s-d--
No
Yes
No
Yes
no
no
Relationships
Requires
plpgsql
See Also
orafce
pg_dbms_metadata
pgaudit

PGDG RPM and Pigsty DEB package hexacluster/plpgsql_wrap 1.0; control requires plpgsql and superuser=true; links OpenSSL.

Packages

Type Repo Version PG Major Compatibility Package Pattern Dependencies
EXT
PGDG
1.0
18
17
16
15
14
plpgsql_wrap plpgsql
RPM
PGDG
1.0
18
17
16
15
14
plpgsql_wrap_$v openssl-libs
DEB
PIGSTY
1.0
18
17
16
15
14
postgresql-$v-plpgsql-wrap libssl3
Linux / PG PG18 PG17 PG16 PG15 PG14
el8.x86_64
PGDG 1.0
PGDG 1.0
PGDG 1.0
PGDG 1.0
PGDG 1.0
el8.aarch64
PGDG 1.0
PGDG 1.0
PGDG 1.0
PGDG 1.0
PGDG 1.0
el9.x86_64
PGDG 1.0
PGDG 1.0
PGDG 1.0
PGDG 1.0
PGDG 1.0
el9.aarch64
PGDG 1.0
PGDG 1.0
PGDG 1.0
PGDG 1.0
PGDG 1.0
el10.x86_64
PGDG 1.0
PGDG 1.0
PGDG 1.0
PGDG 1.0
PGDG 1.0
el10.aarch64
PGDG 1.0
PGDG 1.0
PGDG 1.0
PGDG 1.0
PGDG 1.0
d12.x86_64
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
d12.aarch64
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
d13.x86_64
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
d13.aarch64
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
u22.x86_64
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
u22.aarch64
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
u24.x86_64
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
u24.aarch64
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
u26.x86_64
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
u26.aarch64
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
PIGSTY 1.0
Package Version OS ORG SIZE File URL
plpgsql_wrap_18 1.0 el8.x86_64 pgdg 22.6 KiB plpgsql_wrap_18-1.0-2PGDG.rhel8.10.x86_64.rpm
plpgsql_wrap_18 1.0 el8.aarch64 pgdg 22.2 KiB plpgsql_wrap_18-1.0-2PGDG.rhel8.10.aarch64.rpm
plpgsql_wrap_18 1.0 el9.x86_64 pgdg 23.1 KiB plpgsql_wrap_18-1.0-2PGDG.rhel9.8.x86_64.rpm
plpgsql_wrap_18 1.0 el9.x86_64 pgdg 23.1 KiB plpgsql_wrap_18-1.0-2PGDG.rhel9.7.x86_64.rpm
plpgsql_wrap_18 1.0 el9.x86_64 pgdg 23.2 KiB plpgsql_wrap_18-1.0-2PGDG.rhel9.6.x86_64.rpm
plpgsql_wrap_18 1.0 el9.aarch64 pgdg 22.5 KiB plpgsql_wrap_18-1.0-2PGDG.rhel9.8.aarch64.rpm
plpgsql_wrap_18 1.0 el9.aarch64 pgdg 22.5 KiB plpgsql_wrap_18-1.0-2PGDG.rhel9.7.aarch64.rpm
plpgsql_wrap_18 1.0 el9.aarch64 pgdg 22.7 KiB plpgsql_wrap_18-1.0-2PGDG.rhel9.6.aarch64.rpm
plpgsql_wrap_18 1.0 el10.x86_64 pgdg 23.2 KiB plpgsql_wrap_18-1.0-2PGDG.rhel10.2.x86_64.rpm
plpgsql_wrap_18 1.0 el10.x86_64 pgdg 23.2 KiB plpgsql_wrap_18-1.0-2PGDG.rhel10.1.x86_64.rpm
plpgsql_wrap_18 1.0 el10.x86_64 pgdg 23.6 KiB plpgsql_wrap_18-1.0-2PGDG.rhel10.0.x86_64.rpm
plpgsql_wrap_18 1.0 el10.aarch64 pgdg 22.8 KiB plpgsql_wrap_18-1.0-2PGDG.rhel10.2.aarch64.rpm
plpgsql_wrap_18 1.0 el10.aarch64 pgdg 22.8 KiB plpgsql_wrap_18-1.0-2PGDG.rhel10.1.aarch64.rpm
plpgsql_wrap_18 1.0 el10.aarch64 pgdg 22.8 KiB plpgsql_wrap_18-1.0-2PGDG.rhel10.0.aarch64.rpm
postgresql-18-plpgsql-wrap 1.0 d12.x86_64 pigsty 31.0 KiB postgresql-18-plpgsql-wrap_1.0-1PIGSTY~bookworm_amd64.deb
postgresql-18-plpgsql-wrap 1.0 d12.aarch64 pigsty 30.7 KiB postgresql-18-plpgsql-wrap_1.0-1PIGSTY~bookworm_arm64.deb
postgresql-18-plpgsql-wrap 1.0 d13.x86_64 pigsty 30.8 KiB postgresql-18-plpgsql-wrap_1.0-1PIGSTY~trixie_amd64.deb
postgresql-18-plpgsql-wrap 1.0 d13.aarch64 pigsty 30.8 KiB postgresql-18-plpgsql-wrap_1.0-1PIGSTY~trixie_arm64.deb
postgresql-18-plpgsql-wrap 1.0 u22.x86_64 pigsty 32.4 KiB postgresql-18-plpgsql-wrap_1.0-1PIGSTY~jammy_amd64.deb
postgresql-18-plpgsql-wrap 1.0 u22.aarch64 pigsty 32.6 KiB postgresql-18-plpgsql-wrap_1.0-1PIGSTY~jammy_arm64.deb
postgresql-18-plpgsql-wrap 1.0 u24.x86_64 pigsty 32.1 KiB postgresql-18-plpgsql-wrap_1.0-1PIGSTY~noble_amd64.deb
postgresql-18-plpgsql-wrap 1.0 u24.aarch64 pigsty 32.1 KiB postgresql-18-plpgsql-wrap_1.0-1PIGSTY~noble_arm64.deb
postgresql-18-plpgsql-wrap 1.0 u26.x86_64 pigsty 32.0 KiB postgresql-18-plpgsql-wrap_1.0-1PIGSTY~resolute_amd64.deb
postgresql-18-plpgsql-wrap 1.0 u26.aarch64 pigsty 31.9 KiB postgresql-18-plpgsql-wrap_1.0-1PIGSTY~resolute_arm64.deb

Source

pig build pkg plpgsql_wrap;		# build rpm/deb

Install

Make sure PGDG repo available:

pig repo add pgdg -u    # add pgdg repo and update cache

Install this extension with pig:

pig install plpgsql_wrap;		# install via package name, for the active PG version

pig install plpgsql_wrap -v 18;   # install for PG 18
pig install plpgsql_wrap -v 17;   # install for PG 17
pig install plpgsql_wrap -v 16;   # install for PG 16
pig install plpgsql_wrap -v 15;   # install for PG 15
pig install plpgsql_wrap -v 14;   # install for PG 14

Create this extension with:

CREATE EXTENSION plpgsql_wrap CASCADE; -- requires plpgsql

Usage

Sources: README, v1.0 release, control file

plpgsql_wrap provides an Oracle WRAP-style procedural language for PostgreSQL. Functions written with LANGUAGE plpgsql_wrap are validated as PL/pgSQL and then stored encrypted in pg_proc.prosrc as PLPGSQLWRAP:1:<hex>.

Install With A Key

Build the extension with a 32-byte AES-256-GCM key:

export WRAP_KEY_HEX=$(openssl rand -hex 32)
make WRAP_KEY_HEX=$WRAP_KEY_HEX
sudo make install

Back up the key. Wrapped functions can only be unwrapped or restored safely when the correct compiled key is available.

Install the extension in each database that needs the language:

CREATE EXTENSION plpgsql_wrap; -- requires plpgsql

Create Wrapped Functions

Use normal PL/pgSQL syntax with a different language name:

CREATE OR REPLACE FUNCTION public.calculate_bonus(emp_id int, yr int)
RETURNS numeric
LANGUAGE plpgsql_wrap
AS $$
DECLARE
  v_salary numeric;
BEGIN
  SELECT salary INTO v_salary FROM employees WHERE id = emp_id;
  RETURN v_salary * 0.15;
END;
$$;

The stored body is opaque:

SELECT substring(prosrc, 1, 32) AS wrapped_code
FROM pg_proc
WHERE proname = 'calculate_bonus';

Dump, Restore, And Unwrap

pg_dump emits the encrypted PLPGSQLWRAP:1: blob. A restore on a server with the same compiled key works normally. A different key leaves the blob stored, but calls fail when the validator/authentication path cannot authenticate it.

Superusers can permanently unwrap a function when they know the key:

SELECT plpgsql_wrap.unwrap_procedure(
  'myhexkey',
  'public',
  'calculate_bonus',
  'emp_id int, yr int'
);

Caveats

  • Version 1.0 supports PostgreSQL 14-18.
  • The control file requires plpgsql and superuser installation.
  • This protects casual source inspection and dumps, but the compiled key is a critical secret. Treat package artifacts and build logs accordingly.
  • Syntax is validated before encryption, so ordinary PL/pgSQL syntax errors abort CREATE FUNCTION before encrypted storage is written.
Last updated on