summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2025-09-11 17:11:54 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2025-09-11 17:11:54 -0400
commit451373dc5c4177ad97f6378316911741cdc3011b (patch)
tree108ca72a8c3ff0be5ba6c8390661b0ae032a2f62 /src
parentcbe37dbf6cde9df0d8e8b3fda3190ebfde979b83 (diff)
Report the correct is_temporary flag for column defaults.
pg_event_trigger_dropped_objects() would report a column default object with is_temporary = false, even if it belongs to a temporary table. This seems clearly wrong, so adjust it to report the table's temp-ness. While here, refactor EventTriggerSQLDropAddObject to make its handling of namespace objects less messy and avoid duplication of the schema-lookup code. And add some explicit test coverage of dropped-object reports for dependencies of temp tables. Back-patch to v15. The bug exists further back, but the GetAttrDefaultColumnAddress function this patch depends on does not, and it doesn't seem worth adjusting it to cope with the older code. Author: Antoine Violin <violin.antuan@gmail.com> Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/CAFjUV9x3-hv0gihf+CtUc-1it0hh7Skp9iYFhMS7FJjtAeAptA@mail.gmail.com Backpatch-through: 15
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/event_trigger.c111
-rw-r--r--src/test/regress/expected/event_trigger.out35
-rw-r--r--src/test/regress/sql/event_trigger.sql20
3 files changed, 134 insertions, 32 deletions
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 356aac4afc0..6bbdd40c17e 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -20,6 +20,7 @@
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
+#include "catalog/pg_attrdef.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
@@ -98,6 +99,8 @@ static Oid insert_event_trigger_tuple(const char *trigname, const char *eventnam
static void validate_ddl_tags(const char *filtervar, List *taglist);
static void validate_table_rewrite_tags(const char *filtervar, List *taglist);
static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata);
+static bool obtain_object_name_namespace(const ObjectAddress *object,
+ SQLDropObject *obj);
static const char *stringify_grant_objtype(ObjectType objtype);
static const char *stringify_adefprivs_objtype(ObjectType objtype);
@@ -1180,12 +1183,6 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
Assert(EventTriggerSupportsObjectClass(getObjectClass(object)));
- /* don't report temp schemas except my own */
- if (object->classId == NamespaceRelationId &&
- (isAnyTempNamespace(object->objectId) &&
- !isTempNamespace(object->objectId)))
- return;
-
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
obj = palloc0(sizeof(SQLDropObject));
@@ -1193,21 +1190,88 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
obj->original = original;
obj->normal = normal;
+ if (object->classId == NamespaceRelationId)
+ {
+ /* Special handling is needed for temp namespaces */
+ if (isTempNamespace(object->objectId))
+ obj->istemp = true;
+ else if (isAnyTempNamespace(object->objectId))
+ {
+ /* don't report temp schemas except my own */
+ pfree(obj);
+ MemoryContextSwitchTo(oldcxt);
+ return;
+ }
+ }
+ else if (object->classId == AttrDefaultRelationId)
+ {
+ /* We treat a column default as temp if its table is temp */
+ ObjectAddress colobject;
+
+ colobject = GetAttrDefaultColumnAddress(object->objectId);
+ if (OidIsValid(colobject.objectId))
+ {
+ colobject.objectSubId = 0; /* convert to table reference */
+ if (!obtain_object_name_namespace(&colobject, obj))
+ {
+ pfree(obj);
+ MemoryContextSwitchTo(oldcxt);
+ return;
+ }
+ }
+ }
+ else
+ {
+ /* Generic handling for all other object classes */
+ if (!obtain_object_name_namespace(object, obj))
+ {
+ /* don't report temp objects except my own */
+ pfree(obj);
+ MemoryContextSwitchTo(oldcxt);
+ return;
+ }
+ }
+
+ /* object identity, objname and objargs */
+ obj->objidentity =
+ getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs,
+ false);
+
+ /* object type */
+ obj->objecttype = getObjectTypeDescription(&obj->address, false);
+
+ slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
+
+ MemoryContextSwitchTo(oldcxt);
+}
+
+/*
+ * Fill obj->objname, obj->schemaname, and obj->istemp based on object.
+ *
+ * Returns true if this object should be reported, false if it should
+ * be ignored because it is a temporary object of another session.
+ */
+static bool
+obtain_object_name_namespace(const ObjectAddress *object, SQLDropObject *obj)
+{
/*
* Obtain schema names from the object's catalog tuple, if one exists;
* this lets us skip objects in temp schemas. We trust that
* ObjectProperty contains all object classes that can be
* schema-qualified.
+ *
+ * Currently, this function does nothing for object classes that are not
+ * in ObjectProperty, but we might sometime add special cases for that.
*/
if (is_objectclass_supported(object->classId))
{
Relation catalog;
HeapTuple tuple;
- catalog = table_open(obj->address.classId, AccessShareLock);
+ catalog = table_open(object->classId, AccessShareLock);
tuple = get_catalog_object_by_oid(catalog,
get_object_attnum_oid(object->classId),
- obj->address.objectId);
+ object->objectId);
if (tuple)
{
@@ -1215,7 +1279,7 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
Datum datum;
bool isnull;
- attnum = get_object_attnum_namespace(obj->address.classId);
+ attnum = get_object_attnum_namespace(object->classId);
if (attnum != InvalidAttrNumber)
{
datum = heap_getattr(tuple, attnum,
@@ -1233,10 +1297,9 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
}
else if (isAnyTempNamespace(namespaceId))
{
- pfree(obj);
+ /* no need to fill any fields of *obj */
table_close(catalog, AccessShareLock);
- MemoryContextSwitchTo(oldcxt);
- return;
+ return false;
}
else
{
@@ -1246,10 +1309,10 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
}
}
- if (get_object_namensp_unique(obj->address.classId) &&
- obj->address.objectSubId == 0)
+ if (get_object_namensp_unique(object->classId) &&
+ object->objectSubId == 0)
{
- attnum = get_object_attnum_name(obj->address.classId);
+ attnum = get_object_attnum_name(object->classId);
if (attnum != InvalidAttrNumber)
{
datum = heap_getattr(tuple, attnum,
@@ -1262,24 +1325,8 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
table_close(catalog, AccessShareLock);
}
- else
- {
- if (object->classId == NamespaceRelationId &&
- isTempNamespace(object->objectId))
- obj->istemp = true;
- }
- /* object identity, objname and objargs */
- obj->objidentity =
- getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs,
- false);
-
- /* object type */
- obj->objecttype = getObjectTypeDescription(&obj->address, false);
-
- slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
-
- MemoryContextSwitchTo(oldcxt);
+ return true;
}
/*
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 5a10958df52..1c42d269981 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -476,6 +476,41 @@ NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_10_15
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.part_15_20 name={evttrig,part_15_20} args={}
DROP TABLE a_temp_tbl;
NOTICE: NORMAL: orig=t normal=f istemp=t type=table identity=pg_temp.a_temp_tbl name={pg_temp,a_temp_tbl} args={}
+-- check unfiltered results, too
+CREATE OR REPLACE FUNCTION event_trigger_report_dropped()
+ RETURNS event_trigger
+ LANGUAGE plpgsql
+AS $$
+DECLARE r record;
+BEGIN
+ FOR r IN SELECT * from pg_event_trigger_dropped_objects()
+ LOOP
+ RAISE NOTICE 'DROP: orig=% normal=% istemp=% type=% identity=% name=% args=%',
+ r.original, r.normal, r.is_temporary, r.object_type,
+ r.object_identity, r.address_names, r.address_args;
+ END LOOP;
+END; $$;
+NOTICE: END: command_tag=CREATE FUNCTION type=function identity=public.event_trigger_report_dropped()
+CREATE TABLE evtrg_nontemp_table (f1 int primary key, f2 int default 42);
+NOTICE: END: command_tag=CREATE TABLE type=table identity=public.evtrg_nontemp_table
+NOTICE: END: command_tag=CREATE INDEX type=index identity=public.evtrg_nontemp_table_pkey
+DROP TABLE evtrg_nontemp_table;
+NOTICE: DROP: orig=t normal=f istemp=f type=table identity=public.evtrg_nontemp_table name={public,evtrg_nontemp_table} args={}
+NOTICE: DROP: orig=f normal=f istemp=f type=type identity=public.evtrg_nontemp_table name={public.evtrg_nontemp_table} args={}
+NOTICE: DROP: orig=f normal=f istemp=f type=type identity=public.evtrg_nontemp_table[] name={public.evtrg_nontemp_table[]} args={}
+NOTICE: DROP: orig=f normal=f istemp=f type=default value identity=for public.evtrg_nontemp_table.f2 name={public,evtrg_nontemp_table,f2} args={}
+NOTICE: DROP: orig=f normal=f istemp=f type=table constraint identity=evtrg_nontemp_table_pkey on public.evtrg_nontemp_table name={public,evtrg_nontemp_table,evtrg_nontemp_table_pkey} args={}
+NOTICE: DROP: orig=f normal=f istemp=f type=index identity=public.evtrg_nontemp_table_pkey name={public,evtrg_nontemp_table_pkey} args={}
+CREATE TEMP TABLE a_temp_tbl (f1 int primary key, f2 int default 42);
+NOTICE: END: command_tag=CREATE TABLE type=table identity=pg_temp.a_temp_tbl
+NOTICE: END: command_tag=CREATE INDEX type=index identity=pg_temp.a_temp_tbl_pkey
+DROP TABLE a_temp_tbl;
+NOTICE: DROP: orig=t normal=f istemp=t type=table identity=pg_temp.a_temp_tbl name={pg_temp,a_temp_tbl} args={}
+NOTICE: DROP: orig=f normal=f istemp=t type=type identity=pg_temp.a_temp_tbl name={pg_temp.a_temp_tbl} args={}
+NOTICE: DROP: orig=f normal=f istemp=t type=type identity=pg_temp.a_temp_tbl[] name={pg_temp.a_temp_tbl[]} args={}
+NOTICE: DROP: orig=f normal=f istemp=t type=default value identity=for pg_temp.a_temp_tbl.f2 name={pg_temp,a_temp_tbl,f2} args={}
+NOTICE: DROP: orig=f normal=f istemp=t type=table constraint identity=a_temp_tbl_pkey on pg_temp.a_temp_tbl name={pg_temp,a_temp_tbl,a_temp_tbl_pkey} args={}
+NOTICE: DROP: orig=f normal=f istemp=t type=index identity=pg_temp.a_temp_tbl_pkey name={pg_temp,a_temp_tbl_pkey} args={}
-- CREATE OPERATOR CLASS without FAMILY clause should report
-- both CREATE OPERATOR FAMILY and CREATE OPERATOR CLASS
CREATE OPERATOR CLASS evttrigopclass FOR TYPE int USING btree AS STORAGE int;
diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql
index 1aeaddbe715..865f324dde6 100644
--- a/src/test/regress/sql/event_trigger.sql
+++ b/src/test/regress/sql/event_trigger.sql
@@ -337,6 +337,26 @@ DROP INDEX evttrig.one_idx;
DROP SCHEMA evttrig CASCADE;
DROP TABLE a_temp_tbl;
+-- check unfiltered results, too
+CREATE OR REPLACE FUNCTION event_trigger_report_dropped()
+ RETURNS event_trigger
+ LANGUAGE plpgsql
+AS $$
+DECLARE r record;
+BEGIN
+ FOR r IN SELECT * from pg_event_trigger_dropped_objects()
+ LOOP
+ RAISE NOTICE 'DROP: orig=% normal=% istemp=% type=% identity=% name=% args=%',
+ r.original, r.normal, r.is_temporary, r.object_type,
+ r.object_identity, r.address_names, r.address_args;
+ END LOOP;
+END; $$;
+
+CREATE TABLE evtrg_nontemp_table (f1 int primary key, f2 int default 42);
+DROP TABLE evtrg_nontemp_table;
+CREATE TEMP TABLE a_temp_tbl (f1 int primary key, f2 int default 42);
+DROP TABLE a_temp_tbl;
+
-- CREATE OPERATOR CLASS without FAMILY clause should report
-- both CREATE OPERATOR FAMILY and CREATE OPERATOR CLASS
CREATE OPERATOR CLASS evttrigopclass FOR TYPE int USING btree AS STORAGE int;