Repository navigation
Keep install and update scripts' settings changes from leaking to the caller - #11
jnasbyupgrade wants to merge 17 commits into
Conversation
CREATE EXTENSION and ALTER EXTENSION UPDATE left the caller's client_min_messages at warning, and updating from 0.2.0 or 0.2.1 also changed search_path. Remove the settings save/restore and the SETs from sql/trunklet.sql and the 0.2.0--0.2.1, 0.2.1--0.3.0 and 0.3.2--0.3.3 update scripts. The suite now asserts both settings are unchanged after a fresh install and after an update, and the update helper no longer needs to schema-qualify names. test/sql/build.sql loads the raw script with \i, so it sets client_min_messages itself.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the
|
Check client_min_messages around CREATE EXTENSION in search_path.sql rather than load.sql, and reword the HISTORY entry to match the observed settings after each update and install script.
Restores the released update scripts' settings save/restore, with each SET and the set-back made SET LOCAL so the caller's search_path and client_min_messages survive the script.
| * client_min_messages first: TEST_UPDATE_FROM's own install script may have left | ||
| * it raised, which would hide an update script doing the same. | ||
| */ | ||
| SET client_min_messages = notice; |
There was a problem hiding this comment.
This is doing the same thing as what's in test/sql/search_path.sql; refactor them. And I'd say if we're going to do this we should actually validate all of pg_settings (uh, I guess can ignore things that would require server restart etc), not just search_path and client_min.
There was a problem hiding this comment.
Claude here. Done in baccd69.
- Shared helper:
test/helpers/settings_snapshot.sql, used by bothtest/sql/search_path.sqlandtest/helpers/update_with_data.sql. - It compares every
pg_settingsrow with contextuserorsuperuser, the only onesSETcan change in-session, so restart and reload settings are skipped. Settings that first appear after the script are ignored, because loading a library can define new ones. search_path.sqlnow has a singleis_empty()assertion, so its output doesn't vary by PG version.- Mutations that confirmed it catches a setting outside the old two: adding
SET work_mem = '7MB';tosql/trunklet.sqlfailssearch_pathin fresh mode, and adding it tosql/trunklet--0.3.2--0.3.3.sqlfails update-from-0.3.2 mode, on both PG17 and PG12.
test/helpers/settings_snapshot.sql snapshots every pg_settings row with context user or superuser and exposes a view of the ones that changed. search_path.sql and update_with_data.sql both use it, replacing their separate search_path/client_min_messages checks.
jnasbyupgrade
left a comment
There was a problem hiding this comment.
You seem to be using 2 different styles for the settings polution stuff; one with pgTap output and one without. It's confusing. I would prefer that we do all of it (including setup) with pgTap functions (ie, lives_ok()). I'm OK with some of it being raw SQL if that makes more sense, but I think the final check really should be pgTap.
Also, i'm not sure we actually need test/sql/search_path.sql anymore. Presumably we should just test this as part of load.sql (uh, which I guess if we're doing that it can't actually use pgTap). Given that we probably do want the UPDATE testing to verify this as well, and that that probably should use pgTap, maybe the right thing here is to have the helper define setup and then check functions in pg_temp. Or maybe 2 separete chunks of code that just refer to the view are OK. (Note that really nothing in the extension should be screwing with GUCs ever, so I think it's fine if we actually check the view some time after CREATE or ALTER).
|
|
||
| ALTER EXTENSION trunklet UPDATE; | ||
|
|
||
| DO $body$ |
There was a problem hiding this comment.
WTF you're STILL re-inventing wheels! Pick ONE way to validate settings are sane. And have the helper define a text-returning function that runs a pgTap test ensuring nothing changed (ie, maybe use bag_eq or results_eq). And I lean towards we don't really need to drop the temp objects.
There was a problem hiding this comment.
Claude here. As of f562476 there is one check. test/helpers/settings_snapshot.sql defines pg_temp.settings_snapshot() and pg_temp.settings_check(action), and that pair runs around each CREATE EXTENSION in test/install/load.sql and around ALTER EXTENSION UPDATE here. It's plain SQL, not pgTap, because this file runs inside load.sql, before the suite loads pgTap. The temp objects are no longer dropped.
There was a problem hiding this comment.
Claude here. The load-time check in load.sql and update_with_data.sql is plain SQL that raises an error rather than pgTap, because load.sql's output is never compared: a pgTap not ok there would fail nothing, and only an error that breaks the downstream tests fails the run. Where output is compared, in test/build/build.sql, the same helper now runs under pgTap lives_ok (91bb4f5), replacing its old search_path assertion, so there is one settings check.
| CREATE TEMP TABLE after AS | ||
| SELECT current_setting('search_path') | ||
| ; | ||
| CREATE TEMP TABLE changed AS SELECT * FROM pg_temp.settings_changed; |
There was a problem hiding this comment.
Claude here. The copy froze the changed settings before this file reset search_path for pgTap, so that reset wouldn't show up as a change itself. As of f562476, test/sql/search_path.sql is gone, and the copy with it; test/install/load.sql checks the CREATE EXTENSION instead.
`test/install/load.sql` snapshots every user-settable setting and checks it after `CREATE EXTENSION`, and `test/helpers/update_with_data.sql` uses the same `pg_temp.settings_snapshot()`/`pg_temp.settings_check()` pair around `ALTER EXTENSION UPDATE`. `test/sql/search_path.sql` is removed. An error in `load.sql` fails the run only by breaking the downstream tests, so the `CREATE` and its check run in one transaction: a leak rolls back the install and the suite fails. The released 0.2.0, 0.2.1 and 0.3.3 install scripts now use `SET LOCAL`, including in the settings set-back, so installing them by version no longer leaks `search_path` or `client_min_messages`. Each released script changed from plain `SET` has a comment saying so.
|
Claude here, answering the review body above, as of f562476.
|
The 0.2.0 install and the 0.2.1--0.3.0 update have no set-back, so a caller at error sees client_min_messages at warning until the transaction ends. State that in HISTORY.asc and the PR description, move the set-back "released as plain SET" comments above their statements, note the two shipped update scripts in RELEASE.md, and clarify two test comments.
test/build/build.sql now snapshots settings before CREATE EXTENSION and asserts via lives_ok that none changed, replacing the weaker search_path check, so the repo has one settings check.
…standard trunklet.sql and trunklet--0.2.0--0.2.1.sql no longer set client_min_messages. trunklet.sql now runs with search_path = pg_catalog, set back with SET LOCAL. The build test sets client_min_messages itself before \i-ing trunklet.sql.
…t and comment fixes - trunklet.sql and 0.2.0--0.2.1: restore the saved settings with set_config(..., true) so a list setting such as "public, pg_temp" is restored as a list, and run with search_path = pg_catalog, pg_temp. - build test: do the setup under pgTap (lives_ok) and discard the set-back's result row. - update_with_data.sql: run ALTER EXTENSION UPDATE in a transaction so SET LOCAL leaks from update scripts are caught. - 0.2.0 script: one comment above both SET LOCALs; load.sql comment format; HISTORY.asc drops release-process detail.
A bare \i of sql/trunklet.sql now has its restored search_path checked, so the old SET LOCAL %I = %L set-back fails the suite.
Install and update scripts now change settings only with
SET LOCAL, so the caller'ssearch_pathandclient_min_messagesare unchanged once the transaction runningCREATE EXTENSION trunkletorALTER EXTENSION trunklet UPDATEends. The test install fails the suite if a script leaves any user-settable setting changed. Stacked on #10, whose update helper schema-qualifies everything after the update to work around the leak.Within the transaction
search_pathis always unchanged, and so isclient_min_messagesexcept for a caller aterror, who seeswarninguntil the transaction ends when installing0.2.0or when updating from0.2.0or0.2.1(the0.2.1--0.3.0step): those two scripts have no set-back.Why
SET LOCALis enough: before an extension script runs, the server already setssearch_path, and raisesclient_min_messagestowarningwhen the caller is below it, and it restores the caller's values when the script ends. A plainSETin the script overrides that restore andSET LOCALdoes not, so the scripts' existing save-and-set-back (which saves the server's values, not the caller's) is kept, withLOCALadded (the two unreleased scripts useset_config(..., true), below). The server savesclient_min_messagesonly when the caller is belowwarning; for a caller aterror, a script'sSET LOCALof it lasts until the end of the enclosing transaction unless the script sets it back, which is the exception above.Changes
SETbecomesSET LOCAL, and nothing else in the released scripts changes apart from a comment in each that it shipped with plainSET. The two unreleased scripts also dropclient_min_messages:sql/trunklet.sql: no longer setsclient_min_messages. It now runs withSET LOCAL search_path = pg_catalog, pg_temp(withoutpg_temp, it would still be searched first for relations and types), saves onlysearch_path, and sets it back withset_config(name, setting, true), which isSET LOCALbut reads the saved value as a list:SET LOCAL %I = %Lwould turnpublic, pg_tempinto one quoted name. The member objects and schemas of a freshCREATE EXTENSIONare unchanged, and no reference needed qualifying.sql/trunklet--0.2.0.sql:client_min_messagesandsearch_path(this script has no set-back).sql/trunklet--0.2.1.sql:client_min_messages,search_pathand the set-back.sql/trunklet--0.3.3.sql:client_min_messagesand the set-back.sql/trunklet--0.2.0--0.2.1.sql: no longer setsclient_min_messages;search_pathand the set-back are changed the same way as insql/trunklet.sql. It is new since 0.3.3, so it has no comment.sql/trunklet--0.2.1--0.3.0.sql:client_min_messagesandsearch_path(this script has no set-back).sql/trunklet--0.3.2--0.3.3.sql:client_min_messagesand the set-back.sql/trunklet--0.2.0.sql,sql/trunklet--0.2.1.sqlandsql/trunklet--0.3.3.sqltherefore no longer match their release branches exactly.RELEASE.mdrecords that difference for its drift check, and notes thatsql/trunklet--0.2.1--0.3.0.sqlandsql/trunklet--0.3.2--0.3.3.sqlalso differ from what shipped.test/helpers/settings_snapshot.sqlis a new shared helper.pg_temp.settings_snapshot()records everypg_settingsrow with contextuserorsuperuser(the only onesSETcan change in-session), andpg_temp.settings_check(action)raises an error naming each setting that has since changed, with its before and after value. Settings that first appear after the snapshot are ignored, because loading a library can define new ones.test/install/load.sqlsetsclient_min_messagestonotice(belowwarning, so a plainSETwould show; a caller aterroror higher is not exercised), snapshots, and checks afterCREATE EXTENSION. TheCREATEand its check run in one transaction. An error inload.sqldoesn't failmakeby itself (pgxntool's.IGNORE: installcheck), so a failed check rolls back the install, and the downstream suite then fails on every PostgreSQL version.test/helpers/update_with_data.sqldrops the schema qualification and runs the same two functions aroundALTER EXTENSION UPDATE, which runs in aBEGIN/COMMITlikeload.sql'sCREATE, so aSET LOCALleft by an update script is caught too. A failed check there stopsload.sqlbefore the helper drops its_trunklet_testschema, and the suite then fails on that schema already existing.test/build/build.sqlreplaces itssearch_pathassertion with the same helper: it runs the snapshot,CREATE EXTENSION,pg_temp.settings_check('CREATE EXTENSION')andDROP EXTENSIONall under pgTaplives_ok. Unlikeload.sql, the build test's output is compared, so anot okfails it. It setsclient_min_messagestowarningimmediately before\i sql/trunklet.sql, which runs outsideCREATE EXTENSION. AddingSET work_mem = '7MB';tosql/trunklet.sqlturnsok 3intonot ok 3 - CREATE EXTENSION changed no setting. The\i sql/trunklet.sqloutsideCREATE EXTENSIONwrites its output to/dev/null, because the set-back'sset_config()result row depends on the server's defaultsearch_path. Its first block also setssearch_path = public, pg_tempand checks it is restored after the\i: the set-back is observable only under a bare\i, sinceCREATE/ALTER EXTENSIONrestoresearch_pathafterwards, and the oldSET LOCAL %I = %Lset-back leaves"public, pg_temp"there (make testexits 2 with it).test/sql/search_path.sqlandtest/expected/search_path.outare removed;load.sqlcovers the freshCREATE EXTENSION.HISTORY.ascnotes the change, including the unreleased scripts' settings handling.Verification CI doesn't cover
Re-run at the current head, with
SET work_mem = '7MB';(orSET LOCAL work_mem = '7MB';where noted) appended to a script, each makes the command exit non-zero:sql/trunklet.sql:make teston PG17 (SETandSET LOCAL; the build test reportsnot ok 3 - CREATE EXTENSION changed no setting) and on PG12 (SET).sql/trunklet--0.3.2--0.3.3.sql:make test-updateon PG17 (SETandSET LOCAL;ALTER EXTENSION UPDATE changed settings) and on PG12 (SET).sql/trunklet--0.2.0.sql:make test-updateon PG17 (SET).make test,make test-update, andmake test-update TEST_UPDATE_FROM=0.2.1and=0.3.3pass on PG17 (port 5417) and PG12 (port 5412). Installing the old and newsql/trunklet.sqlinto scratch databases gives identicalpg_dump -soutput on PG12 and on PG17 (apart from the random\restricttoken). From a transaction withsearch_path = public, pg_temp,\i sql/trunklet.sqlleavespublic, pg_temp.