Summary
Two related, foundational needs surfaced while working out #38 (automated OID-repair), but independent of that design and needed regardless of how it's finalized:
- A standard, internal mechanism for safely disabling whatever needs disabling during the extension's own update scripts — not a one-off, inline solution per update script.
object_reference must refuse to track any object that is itself a member of the object_reference extension.
1. Internal disable/enable mechanism for update scripts
Today, sql/object_reference--0.1.0--stable.sql uses SET LOCAL session_replication_role = replica to suppress the extension's own event triggers during its structural section (dropping/recreating views, columns, etc., where the triggers would otherwise fire on the extension's own internal changes and do the wrong thing). #38 found this needs to change to ALTER EVENT TRIGGER ... DISABLE/ENABLE, uniformly, for all the extension's event triggers (the three existing ones, soon a fourth) — not a differentiated approach. _etg_drop has no way to recognize "this DROP is part of our own extension's update script" the way the other two can via pg_event_trigger_ddl_commands()'s in_extension column (pg_event_trigger_dropped_objects() has no equivalent), so it needs the literal disable/enable bracket regardless — and once that mechanism/privilege is needed for one trigger, extending it to all of them uniformly costs nothing further and removes a second, in_extension-based mechanism to reason about, test, and get subtly wrong. Resolved: no trigger uses in_extension self-recognition; all of them go through the same disable/enable bracket.
Rather than hand-writing ALTER EVENT TRIGGER ... DISABLE/ENABLE (or any other future disabling need) inline in each update script, build a standard, internal-only function (or pair of functions) that update scripts call instead — e.g. __object_reference.begin_internal_update() / __object_reference.end_internal_update(), or whatever shape makes sense once designed. This is needed regardless of what #38's final design looks like: any extension that modifies its own schema in an update script needs a clean way to say "the following statements are our own internal restructuring, not something our own event triggers/checks should react to" — today's session_replication_role trick already does part of this job informally; this issue is about making it a real, deliberate, reusable mechanism rather than an ad hoc pattern repeated (and potentially gotten subtly wrong) in every future update script.
This mechanism has a second consumer, not just update scripts: #38's pg_upgrade__pre()/pg_upgrade__post() functions are, conceptually, doing exactly what an update script's structural section does — mucking with object_reference's own member objects (dropping/recreating _sentry_mv). They should call the same begin/end functions this issue produces around their own DROP/CREATE MATERIALIZED VIEW statements, rather than inventing their own bracket or relying on any _sentry_mv-specific recognition trick.
Things to work out:
- Whether that list of triggers needing disabling is stable, or something future updates might need to extend — design the mechanism so it doesn't need to be re-derived per update script.
- Safety if an update script (or
pg_upgrade__pre()/pg_upgrade__post()) errors out partway through the "disabled" window — should the disable/re-enable be structured so a failure always cleanly reverts (e.g. relying on transactional DDL rollback) rather than needing explicit cleanup logic.
- Whether this belongs as its own tracked capability with its own tests (a fresh update-script author should not be able to forget to re-enable something, or should get a clear failure if they do).
- Deferred follow-up, not blocking: it's not yet confirmed whether
ALTER EVENT TRIGGER ... DISABLE/ENABLE has any wider locking effect (event triggers are evaluated database-wide for every DDL statement — worth checking whether toggling one serializes unrelated DDL elsewhere in the database until the enclosing transaction commits). Track as its own investigation once this mechanism is in use; don't block on it now.
2. Refuse to track any object that belongs to object_reference itself
object_reference should never allow one of its own extension-member objects (its tables, functions, event triggers, schemas, the private helper schema, etc.) to become a tracked object in _object_reference.object/_object_oid. There's no legitimate use case for this, and allowing it is a direct path to subtle, hard-to-diagnose bugs — especially during an extension update, where the extension's own objects are exactly the things being dropped/recreated/renamed as part of normal version migration. If one of those objects were also a tracked object, the update script's own structural changes would trip the same rename-detection/repair machinery meant for user objects, creating a confusing bootstrapping problem: the tracking system reacting to changes in itself while it's mid-update, exactly the kind of self-referential interaction the disable mechanism in part 1 exists to avoid, from a different angle.
Concretely: object_reference.object__getsert() (and whatever else can register a new tracked object, including the future check-and-repair mechanism from #38, which resolves an object's identity by name/OID and could otherwise re-add a self-referential row if one somehow existed) should check whether the target object is a member of the object_reference extension (pg_depend with deptype = 'e' and refobjid = object_reference's own extension OID, or equivalent) and refuse — loudly, with a clear error — rather than silently tracking it.
This should land as validation at registration time, not just documentation — a test should confirm that attempting to track e.g. _object_reference.object itself, or one of the event trigger functions, is rejected.
Note: tracking an object that belongs to some other extension is a different, legitimate case, not covered by this refusal — see the separate follow-up issue about requiring an explicit opt-in for that case.
Summary
Two related, foundational needs surfaced while working out #38 (automated OID-repair), but independent of that design and needed regardless of how it's finalized:
object_referencemust refuse to track any object that is itself a member of theobject_referenceextension.1. Internal disable/enable mechanism for update scripts
Today,
sql/object_reference--0.1.0--stable.sqlusesSET LOCAL session_replication_role = replicato suppress the extension's own event triggers during its structural section (dropping/recreating views, columns, etc., where the triggers would otherwise fire on the extension's own internal changes and do the wrong thing). #38 found this needs to change toALTER EVENT TRIGGER ... DISABLE/ENABLE, uniformly, for all the extension's event triggers (the three existing ones, soon a fourth) — not a differentiated approach._etg_drophas no way to recognize "this DROP is part of our own extension's update script" the way the other two can viapg_event_trigger_ddl_commands()'sin_extensioncolumn (pg_event_trigger_dropped_objects()has no equivalent), so it needs the literal disable/enable bracket regardless — and once that mechanism/privilege is needed for one trigger, extending it to all of them uniformly costs nothing further and removes a second,in_extension-based mechanism to reason about, test, and get subtly wrong. Resolved: no trigger usesin_extensionself-recognition; all of them go through the same disable/enable bracket.Rather than hand-writing
ALTER EVENT TRIGGER ... DISABLE/ENABLE(or any other future disabling need) inline in each update script, build a standard, internal-only function (or pair of functions) that update scripts call instead — e.g.__object_reference.begin_internal_update()/__object_reference.end_internal_update(), or whatever shape makes sense once designed. This is needed regardless of what #38's final design looks like: any extension that modifies its own schema in an update script needs a clean way to say "the following statements are our own internal restructuring, not something our own event triggers/checks should react to" — today'ssession_replication_roletrick already does part of this job informally; this issue is about making it a real, deliberate, reusable mechanism rather than an ad hoc pattern repeated (and potentially gotten subtly wrong) in every future update script.This mechanism has a second consumer, not just update scripts: #38's
pg_upgrade__pre()/pg_upgrade__post()functions are, conceptually, doing exactly what an update script's structural section does — mucking withobject_reference's own member objects (dropping/recreating_sentry_mv). They should call the same begin/end functions this issue produces around their ownDROP/CREATE MATERIALIZED VIEWstatements, rather than inventing their own bracket or relying on any_sentry_mv-specific recognition trick.Things to work out:
pg_upgrade__pre()/pg_upgrade__post()) errors out partway through the "disabled" window — should the disable/re-enable be structured so a failure always cleanly reverts (e.g. relying on transactional DDL rollback) rather than needing explicit cleanup logic.ALTER EVENT TRIGGER ... DISABLE/ENABLEhas any wider locking effect (event triggers are evaluated database-wide for every DDL statement — worth checking whether toggling one serializes unrelated DDL elsewhere in the database until the enclosing transaction commits). Track as its own investigation once this mechanism is in use; don't block on it now.2. Refuse to track any object that belongs to
object_referenceitselfobject_referenceshould never allow one of its own extension-member objects (its tables, functions, event triggers, schemas, the private helper schema, etc.) to become a tracked object in_object_reference.object/_object_oid. There's no legitimate use case for this, and allowing it is a direct path to subtle, hard-to-diagnose bugs — especially during an extension update, where the extension's own objects are exactly the things being dropped/recreated/renamed as part of normal version migration. If one of those objects were also a tracked object, the update script's own structural changes would trip the same rename-detection/repair machinery meant for user objects, creating a confusing bootstrapping problem: the tracking system reacting to changes in itself while it's mid-update, exactly the kind of self-referential interaction the disable mechanism in part 1 exists to avoid, from a different angle.Concretely:
object_reference.object__getsert()(and whatever else can register a new tracked object, including the future check-and-repair mechanism from #38, which resolves an object's identity by name/OID and could otherwise re-add a self-referential row if one somehow existed) should check whether the target object is a member of theobject_referenceextension (pg_dependwithdeptype = 'e'andrefobjid=object_reference's own extension OID, or equivalent) and refuse — loudly, with a clear error — rather than silently tracking it.This should land as validation at registration time, not just documentation — a test should confirm that attempting to track e.g.
_object_reference.objectitself, or one of the event trigger functions, is rejected.Note: tracking an object that belongs to some other extension is a different, legitimate case, not covered by this refusal — see the separate follow-up issue about requiring an explicit opt-in for that case.