Repository navigation
Keep install and update scripts' settings changes from leaking to the caller - #11
jnasbyupgrade wants to merge 15 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.
The install and update scripts change settings only with
SET LOCAL, so once the transaction runningCREATE EXTENSION trunkletorALTER EXTENSION trunklet UPDATEends, the caller'ssearch_pathandclient_min_messagesare unchanged. Within that transactionsearch_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. The test install now fails the suite if either one leaves any user-settable setting changed. This is stacked on #10, whose update helper schema-qualifies everything after the update to work around the leak.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 unchanged apart fromLOCAL. 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 these files changes apart from a comment, in each already-released script, that it shipped with plainSET:sql/trunklet.sql:client_min_messagesand theSET %I = %Lset-back.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:client_min_messages,search_pathand the set-back. 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 the server saves it and 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. 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 snapshots beforeCREATE EXTENSIONand assertspg_temp.settings_check('CREATE EXTENSION')under pgTaplives_ok. Unlikeload.sql, the build test's output is compared, so anot okfails it. AddingSET work_mem = '7MB';tosql/trunklet.sqlturnsok 2intonot ok 2 - CREATE EXTENSION changed no setting.test/sql/search_path.sqlandtest/expected/search_path.outare removed;load.sqlcovers the freshCREATE EXTENSION.HISTORY.ascnotes the change.Verification CI doesn't cover
Each of these mutations, adding
SET work_mem = '7MB';, makesmakeexit non-zero with the check's error inload.out:sql/trunklet.sql:make testandmake verify-resultson PG17, andmake teston PG12 (CREATE EXTENSION changed settings).sql/trunklet--0.3.2--0.3.3.sql:make test-updateon PG17 (ALTER EXTENSION UPDATE changed settings).sql/trunklet--0.2.0.sql:make test-updateon PG17 (CREATE EXTENSION changed settings).With the
BEGIN/COMMITremoved, thesql/trunklet.sqlmutation still reports the error inload.out, butmake testexits 0.