Repository navigation
[2.1.0] Schema-qualify plx's own objects in generated code; make plx non-relocatable - #17
OffgridwithJD wants to merge 2 commits into
Conversation
…catable A string append lowered to a plx_strbuild variable and a plx_sb_append() call, both unqualified, so they resolved through search_path at run time. A function hardened with SET search_path = pg_catalog then failed, as did one whose search_path omitted plx's schema, and a same-named function earlier on the path ran instead (with the definer's privileges for a SECURITY DEFINER function). The validator and inline handler now record plx's schema (the namespace of the running validator/inline handler, which are extension members; this works on PG 13+, where get_extension_schema is not exported before 16), and the transpiler emits <schema>.plx_strbuild and <schema>.plx_sb_append. Stored functions now carry the schema name, so the extension is made non-relocatable. PostgreSQL records relocatability when an extension is created or updated, so this adds extension version 2.1.0 with a no-catalog-change update script; running ALTER EXTENSION plx UPDATE is what records it for an existing installation. Regression tests cover a hardened search_path, an impostor plx_sb_append earlier on the path, and SET SCHEMA being refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jdatcmd
left a comment
There was a problem hiding this comment.
Adversarial review. Tested on PostgreSQL 18.4: builds without warnings, make installcheck passes 13/13, and make metacheck passes.
These hold up:
- No unqualified reference is left:
plx_strbuildandplx_sb_appendare the only extension objects generated code names, and both go throughplx_ext_object. - The in-place append still works with the qualified name: 200,000
s += "x"appends in plxjs take 10 ms. - A schema that needs quoting is emitted correctly:
CREATE EXTENSION plx SCHEMA "My Ext"givess "My Ext".plx_strbuild := '';, and the function runs. ALTER EXTENSION plx UPDATEfrom 2.0.0 reaches 2.1.0 withextrelocatable = f.
Must fix (documentation)
Restoring into a database with plx in a different schema now breaks functions
A dump stores the generated plpgsql, which now contains the schema name. Restoring into a database where plx lives in another schema used to work, because the names were unqualified. Now the restored function fails when it runs:
-- source database: CREATE EXTENSION plx SCHEMA "My Ext"; a plxjs function using s += ...
-- pg_dump -n public, restore into a database with plx in public, then call it:
ERROR: schema "My Ext" does not exist
LINE 3: s "My Ext".plx_strbuild := '';
This follows from the design and I don't think the code should change. But it is a new restriction, so please add it to the CHANGELOG Changed entry and the upgrading or migration docs: install plx in the same schema on the target, or re-run the function DDL after restoring.
Minor
- The PR body says a pre-update installation "reports
2.0.0|t". That is only true for a database created with the old control file. With this build installed,CREATE EXTENSION plx VERSION '2.0.0'already reports2.0.0|f, because PostgreSQL readsrelocatablefrom the current control file. The update script is still needed for existing installations, so this is a wording fix only. - Between installing the new build and running
ALTER EXTENSION plx UPDATE, a database generates schema-qualified names while still being relocatable. ASET SCHEMAin that window breaks the new functions. Worth one line in the upgrade instructions: run the update straight after installing.
CI has not run on this PR yet (fork run waiting for approval).
A function that uses a string append stores plx's schema name, so restoring it into a database where plx is in a different schema leaves it pointing at a schema that is not there. Say so in the README install section and the CHANGELOG, with the two ways out. The CHANGELOG upgrade note now says to run ALTER EXTENSION plx UPDATE straight after installing the build: until then the extension is still relocatable, and moving it breaks functions created with the new build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks. All three points are confirmed and addressed in f77f4df (docs only) and in the PR body. Restore into a database with plx in another schema. Reproduced: a One correction to the scope: only functions that use a string append are affected.
Window before the update. Confirmed in that simulated database:
The CHANGELOG upgrade note now says to run the update straight after installing the build. 🤖 Generated with Claude Code |
Summary
A string append (
s << x,$s .= x,s += x, COBOLSTRING-APPEND) lowers to aplx_strbuildvariable and aplx_sb_append(...)call. Both were emitted unqualified, so PostgreSQL looked them up throughsearch_pathon every call. That caused three problems:SECURITY DEFINERhardening broke. A function withSET search_path = pg_catalogfailed withtype "plx_strbuild" does not exist.plx_sb_appendplanted earlier on the path ran in place of plx's, with the definer's privileges for aSECURITY DEFINERfunction. Unlike in hand-written plpgsql, the author never wrote that call, so they had no reason to defend against it.Generated code now writes
<plx schema>.plx_strbuildand<plx schema>.plx_sb_append:The schema is taken from the namespace of the running validator or inline handler, which are extension members. That works on PG 13+;
get_extension_schema()isn't exported before 16.Non-relocatable, and why this needs 2.1.0
Stored functions now contain the schema name, so
ALTER EXTENSION plx SET SCHEMAwould leave them pointing at the old one.plx.controltherefore setsrelocatable = false, andSET SCHEMAnow fails withextension "plx" does not support SET SCHEMA.PostgreSQL records relocatability in
pg_extensionatCREATE EXTENSIONandALTER EXTENSION UPDATE, not when the control file changes. Existing installations would stay relocatable without an update to run, so this adds:plx--2.1.0.sql, andplx--2.0.0--2.1.0.sql, which changes no objects)default_version = '2.1.0'META.jsonprovidesupdated to 2.1.0. The distributionversion(2.0.1) is left for the release to set.Verified: a database whose plx was created under the 2.0.0 control file reports
2.0.0|t(simulated by settingextrelocatableinpg_extension, sinceCREATE EXTENSION plx VERSION '2.0.0'with this build installed already readsrelocatable = falsefrom the new control file and reports2.0.0|f), and afterALTER EXTENSION plx UPDATEreports2.1.0|f. Run the update straight after installing the build: until then the new build already writes the schema into functions whileSET SCHEMAis still allowed, and moving the extension in that window breaks those functions (verified:type "public.plx_strbuild" does not exist).Restoring a function that uses a string append into a database where plx is in a different schema fails when it runs (
schema "..." does not exist). The README install section and the CHANGELOG say so: install plx in the same schema on the target, or run the function's DDL again. Functions without a string append restore anywhere.Existing functions keep their unqualified names until their DDL is re-run, as with every transpiler change.
Relation to the other PRs: independent of #12 to #16. #13 documents that the extension's schema must be on
search_path; that note should be replaced when this merges. The version number is a proposal. If #16's behaviour change ships in the same release, 2.1.0 fits both.Testing
plx_strbuildcases:SECURITY DEFINER SET search_path = pg_catalogfunction appendingsb_evil.plx_sb_appendahead of plx on the path, which is not usedALTER EXTENSION plx SET SCHEMArefusedSCHEMA ext, a hardened function, a COBOLSTRING-APPENDDO block, and the 2.0.0 → 2.1.0 upgrade.make installcheck(13/13),make differentialcheckandmake metacheckall pass on PG 18.4.🤖 Generated with Claude Code