Contents
PL/php vs PL/Perl feature comparison
This compares PL/php against PostgreSQL’s built-in PL/Perl and records which PL/Perl features PL/php now provides. Items marked added were implemented so that PL/php reaches parity with PL/Perl’s function set; a few items are intentionally out of scope, with the rationale given.
Language capabilities
| Capability | PL/Perl | PL/php | Notes |
|---|---|---|---|
| Scalar functions | ✅ | ✅ | |
| Array arguments / return (multi-dim) | ✅ | ✅ | |
| Composite / record arguments and return | ✅ | ✅ | |
Set-returning functions (return_next) |
✅ | ✅ | |
RETURNS TABLE / OUT / INOUT arguments |
✅ | ✅ | PL/php also supports named parameters, which PL/Perl does not |
Trigger functions ($_TD) |
✅ | ✅ | |
| Session-shared data | %_SHARED |
$_SHARED |
|
| Private per-function data | ❌ | $_SD added |
like PL/Python’s SD; PL/Perl has no per-function store |
Anonymous code blocks (DO) |
✅ | ✅ added | DO $$ ... $$ LANGUAGE plphp |
| Procedures with transaction control | ✅ | ✅ added | CALL a PROCEDURE; spi_commit/spi_rollback in a non-atomic context |
| Trusted (sandboxed) variant | plperl (Safe.pm) |
❌ by design | PHP’s safe_mode was removed in 5.4; PL/php is untrusted/superuser-only (see Security) |
Built-in functions
| PL/Perl | PL/php | Notes |
|---|---|---|
spi_exec_query |
spi_exec |
Runs a query, returns a result to iterate |
spi_fetchrow / row access |
spi_fetch_row |
Iterates a materialized spi_exec result |
| (row count / status) | spi_processed, spi_status, spi_rewind |
|
spi_query |
spi_query added |
Opens a cursor; streams rows without materializing |
spi_fetchrow |
spi_fetchrow added |
Fetch next row from a cursor; auto-closes at exhaustion |
spi_cursor_close |
spi_cursor_close added |
Abandon a cursor early |
errors trappable with eval |
try/catch (PgError $e) added |
PgError carries SQLSTATE, detail, and hint (richer than $@) |
| SRF returns array reference | return an array from the SRF added | One element per row, as an alternative to return_next |
| (no equivalent) | spi_each(query, callable) added |
Streaming per-row callback; PL/Perl has no equivalent |
elog(level, msg) |
elog added |
DEBUG/LOG/INFO/NOTICE/WARNING/ERROR; pg_raise remains as the older spelling |
spi_prepare |
spi_prepare added |
Type names given as SQL type strings |
spi_exec_prepared |
spi_exec_prepared added |
|
spi_query_prepared |
spi_query_prepared added |
Opens a cursor for a prepared plan (was an alias of spi_exec_prepared in 2.0) |
spi_freeplan |
spi_freeplan added |
|
quote_literal |
quote_literal added |
|
quote_nullable |
quote_nullable added |
|
quote_ident |
quote_ident added |
|
spi_commit / spi_rollback |
spi_commit / spi_rollback added |
Transaction control in a procedure invoked by CALL (non-atomic) |
looks_like_number |
(none) | Use PHP’s built-in is_numeric() |
encode_bytea / decode_bytea |
(none) | Use PHP’s bin2hex / hex2bin, base64_encode, etc. |
encode_array_literal / encode_typed_literal |
(none) | Marginal; build literals with the quoting helpers |
Interpreter configuration
| PL/Perl | PL/php | Notes |
|---|---|---|
plperl.on_init |
plphp.on_init added |
PHP source run at interpreter initialization |
| (start proc, PL/Tcl-style) | plphp.start_proc |
Runs a named PL/php function once per session |
plperl.use_strict |
(none) | No PHP equivalent; PHP is always “strict” about undefined functions |
Transforms
| PL/Perl | PL/php | Notes |
|---|---|---|
jsonb_plperl |
jsonb_plphp added |
TRANSFORM FOR TYPE jsonb: native values in both directions |
bool_plperl |
(none) | PL/php already maps t/f; a transform would add little |
Intentionally not implemented
- Trusted/sandboxed language. PL/Perl’s
plperlusesSafe.pmto restrict operations. Modern PHP has no equivalent (safe_modewas removed in PHP 5.4), so PL/php is untrusted only.
See doc/plphp.md for full usage of the functions listed above.