hstore transform, structured pg_raise, TRUNCATE/INSTEAD OF triggers, domain array/composite support#29
Merged
Merged
Conversation
…rs, domain array/composite support Four PL/Ruby-parity features, each verified against PostgreSQL 18 with the full regression suite (25 plphp tests + jsonb_plphp + hstore_plphp, all green): - hstore_plphp: a TRANSFORM FOR TYPE hstore mapping hstore <-> PHP associative arrays (PHP null -> hstore NULL), companion to jsonb_plphp. - pg_raise(level, message [, detail [, hint [, sqlstate]]]): attaches DETAIL, HINT and a custom SQLSTATE like RAISE ... USING. Fields are preserved on a caught PgError, through nested SPI propagation, and now at top-level uncaught errors via a new field-stash bridge through the zend_bailout path -- which also fixes uncaught errors previously collapsing to SQLSTATE XX000 and losing DETAIL/HINT. - TRUNCATE (statement) and INSTEAD OF (view) triggers: previously the trigger handler errored on the unrecognized event/timing; $_TD now reports 'TRUNCATE' / 'INSTEAD OF', and INSTEAD OF returns drive the row. - Domains over array/composite: classified through getBaseType so an array domain arrives as (and returns) a PHP array; CHECK constraints still enforced. Item deferred: applying transforms inside trigger/SETOF/composite/SPI rows (plphp applies transforms only to top-level scalars today, as does jsonb) is a broad tuple-I/O change left as separate future work. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jul 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes four PL/Ruby-parity gaps in PL/php. Every change was built and run against PostgreSQL 18 / PHP 8.3 in a container; the full suite is green (25 plphp tests, plus
jsonb_plphpandhstore_plphp).Features
1.
hstoretransform (hstore_plphp)New sibling to
jsonb_plphp.CREATE EXTENSION hstore_plphpaddsTRANSFORM FOR TYPE hstore, mapping anhstoreto a PHP associative array of string keys → string-or-nullvalues and back (a PHPnullvalue → hstoreNULL). Converts through the hstore extension's ownhstore_to_array/hstore(text[])(OIDs resolved viapg_transform), so it never touches hstore internals. New regression suite.2. Structured
pg_raisepg_raise(level, message [, detail [, hint [, sqlstate]]])— attachesDETAIL,HINT, and (forerror) a validated customSQLSTATE, the equivalent of PL/pgSQL'sRAISE ... USING. Fields are readable on a caughtPgError, survive nested SPI propagation, and now appear on top-level uncaught errors too. That last part required a new field-stash bridge through plphp'szend_bailoutreporting path, which also fixes a latent bug: uncaught database/pg_raiseerrors previously collapsed toSQLSTATE XX000with no DETAIL/HINT.3.
TRUNCATEandINSTEAD OFtriggersThe trigger handler used to
elog(ERROR)on any event that wasn't INSERT/UPDATE/DELETE or any timing that wasn't BEFORE/AFTER — so TRUNCATE and INSTEAD OF triggers were unusable. Now$_TD['event']can be'TRUNCATE'and$_TD['when']can be'INSTEAD OF', and INSTEAD OF return values drive the row.WHEN(...)was already PostgreSQL-evaluated. Newtrigger2regression test.4. Domains over arrays and composites
Type classification now looks through domains via
getBaseType, so a domain over an array arrives as (and can be returned as) a PHP array, and a domain over a composite as an associative array. The declared type's input function still runs, so domainCHECKconstraints are enforced on results. Scalar domains were already transparent. Newdomainsregression test.Deferred
Applying transforms inside trigger/SETOF/composite/SPI rows (as PL/Ruby does) is intentionally not included: plphp currently applies transforms only to top-level scalar args/returns —
jsonb_plphphas the same limitation — and extending it is a broad change to the text-based tuple I/O in both directions. Left as separate future work.Testing
Built stock + patched against PG 18 / PHP 8.3; ran
make installcheckfor plphp,jsonb_plphp, andhstore_plphp. All expected-output files were generated from real runs. No existing expected output changed except the intentionalpgerroradditions.🤖 Generated with Claude Code