pg_event_trigger_dropped_objects: add is_temp column

It now also reports temporary objects dropped that are local to the
backend.  Previously we weren't reporting any temp objects because it
was deemed unnecessary; but as it turns out, it is necessary if we want
to keep close track of DDL command execution inside one session.  Temp
objects are reported as living in schema pg_temp, which works because
such a schema-qualification always refers to the temp objects of the
current session.
This commit is contained in:
Alvaro Herrera 2015-04-06 11:40:55 -03:00
parent 70dc2db7f1
commit e9a077cad3
11 changed files with 87 additions and 41 deletions

View File

@ -17877,6 +17877,13 @@ FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
in the dependency graph leading to this object
</entry>
</row>
<row>
<entry><literal>is_temporary</literal></entry>
<entry><type>bool</type></entry>
<entry>
Flag indicating that the object was a temporary object.
</entry>
</row>
<row>
<entry><literal>object_type</literal></entry>
<entry><type>text</type></entry>

View File

@ -3687,7 +3687,7 @@ getObjectIdentityParts(const ObjectAddress *object,
elog(ERROR, "cache lookup failed for collation %u",
object->objectId);
coll = (Form_pg_collation) GETSTRUCT(collTup);
schema = get_namespace_name(coll->collnamespace);
schema = get_namespace_name_or_temp(coll->collnamespace);
appendStringInfoString(&buffer,
quote_qualified_identifier(schema,
NameStr(coll->collname)));
@ -3751,7 +3751,7 @@ getObjectIdentityParts(const ObjectAddress *object,
elog(ERROR, "cache lookup failed for conversion %u",
object->objectId);
conForm = (Form_pg_conversion) GETSTRUCT(conTup);
schema = get_namespace_name(conForm->connamespace);
schema = get_namespace_name_or_temp(conForm->connamespace);
appendStringInfoString(&buffer,
quote_qualified_identifier(schema,
NameStr(conForm->conname)));
@ -3849,7 +3849,7 @@ getObjectIdentityParts(const ObjectAddress *object,
elog(ERROR, "cache lookup failed for opclass %u",
object->objectId);
opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
schema = get_namespace_name(opcForm->opcnamespace);
schema = get_namespace_name_or_temp(opcForm->opcnamespace);
amTup = SearchSysCache1(AMOID,
ObjectIdGetDatum(opcForm->opcmethod));
@ -4066,7 +4066,7 @@ getObjectIdentityParts(const ObjectAddress *object,
{
char *nspname;
nspname = get_namespace_name(object->objectId);
nspname = get_namespace_name_or_temp(object->objectId);
if (!nspname)
elog(ERROR, "cache lookup failed for namespace %u",
object->objectId);
@ -4089,7 +4089,7 @@ getObjectIdentityParts(const ObjectAddress *object,
elog(ERROR, "cache lookup failed for text search parser %u",
object->objectId);
formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
schema = get_namespace_name(formParser->prsnamespace);
schema = get_namespace_name_or_temp(formParser->prsnamespace);
appendStringInfoString(&buffer,
quote_qualified_identifier(schema,
NameStr(formParser->prsname)));
@ -4112,7 +4112,7 @@ getObjectIdentityParts(const ObjectAddress *object,
elog(ERROR, "cache lookup failed for text search dictionary %u",
object->objectId);
formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
schema = get_namespace_name(formDict->dictnamespace);
schema = get_namespace_name_or_temp(formDict->dictnamespace);
appendStringInfoString(&buffer,
quote_qualified_identifier(schema,
NameStr(formDict->dictname)));
@ -4135,7 +4135,7 @@ getObjectIdentityParts(const ObjectAddress *object,
elog(ERROR, "cache lookup failed for text search template %u",
object->objectId);
formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
schema = get_namespace_name(formTmpl->tmplnamespace);
schema = get_namespace_name_or_temp(formTmpl->tmplnamespace);
appendStringInfoString(&buffer,
quote_qualified_identifier(schema,
NameStr(formTmpl->tmplname)));
@ -4158,7 +4158,7 @@ getObjectIdentityParts(const ObjectAddress *object,
elog(ERROR, "cache lookup failed for text search configuration %u",
object->objectId);
formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
schema = get_namespace_name(formCfg->cfgnamespace);
schema = get_namespace_name_or_temp(formCfg->cfgnamespace);
appendStringInfoString(&buffer,
quote_qualified_identifier(schema,
NameStr(formCfg->cfgname)));
@ -4305,7 +4305,7 @@ getObjectIdentityParts(const ObjectAddress *object,
if (OidIsValid(defacl->defaclnamespace))
{
schema = get_namespace_name(defacl->defaclnamespace);
schema = get_namespace_name_or_temp(defacl->defaclnamespace);
appendStringInfo(&buffer,
" in schema %s",
quote_identifier(schema));
@ -4421,7 +4421,7 @@ getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **objname)
opfForm->opfmethod);
amForm = (Form_pg_am) GETSTRUCT(amTup);
schema = get_namespace_name(opfForm->opfnamespace);
schema = get_namespace_name_or_temp(opfForm->opfnamespace);
appendStringInfo(buffer, "%s USING %s",
quote_qualified_identifier(schema,
NameStr(opfForm->opfname)),
@ -4453,7 +4453,7 @@ getRelationIdentity(StringInfo buffer, Oid relid, List **objname)
elog(ERROR, "cache lookup failed for relation %u", relid);
relForm = (Form_pg_class) GETSTRUCT(relTup);
schema = get_namespace_name(relForm->relnamespace);
schema = get_namespace_name_or_temp(relForm->relnamespace);
appendStringInfoString(buffer,
quote_qualified_identifier(schema,
NameStr(relForm->relname)));

View File

@ -121,6 +121,7 @@ typedef struct SQLDropObject
List *addrargs;
bool original;
bool normal;
bool istemp;
slist_node next;
} SQLDropObject;
@ -1294,9 +1295,10 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
Assert(EventTriggerSupportsObjectClass(getObjectClass(object)));
/* don't report temp schemas */
/* don't report temp schemas except my own */
if (object->classId == NamespaceRelationId &&
isAnyTempNamespace(object->objectId))
(isAnyTempNamespace(object->objectId) &&
!isTempNamespace(object->objectId)))
return;
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
@ -1336,16 +1338,24 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
Oid namespaceId;
namespaceId = DatumGetObjectId(datum);
/* Don't report objects in temp namespaces */
if (isAnyTempNamespace(namespaceId))
/* temp objects are only reported if they are my own */
if (isTempNamespace(namespaceId))
{
obj->schemaname = "pg_temp";
obj->istemp = true;
}
else if (isAnyTempNamespace(namespaceId))
{
pfree(obj);
heap_close(catalog, AccessShareLock);
MemoryContextSwitchTo(oldcxt);
return;
}
obj->schemaname = get_namespace_name(namespaceId);
else
{
obj->schemaname = get_namespace_name(namespaceId);
obj->istemp = false;
}
}
}
@ -1365,6 +1375,12 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
heap_close(catalog, AccessShareLock);
}
else
{
if (object->classId == NamespaceRelationId &&
isTempNamespace(object->objectId))
obj->istemp = true;
}
/* object identity, objname and objargs */
obj->objidentity =
@ -1433,8 +1449,8 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
{
SQLDropObject *obj;
int i = 0;
Datum values[11];
bool nulls[11];
Datum values[12];
bool nulls[12];
obj = slist_container(SQLDropObject, next, iter.cur);
@ -1456,6 +1472,9 @@ pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
/* normal */
values[i++] = BoolGetDatum(obj->normal);
/* is_temporary */
values[i++] = BoolGetDatum(obj->istemp);
/* object_type */
values[i++] = CStringGetTextDatum(obj->objecttype);

View File

@ -305,7 +305,7 @@ format_type_internal(Oid type_oid, int32 typemod,
if (!force_qualify && TypeIsVisible(type_oid))
nspname = NULL;
else
nspname = get_namespace_name(typeform->typnamespace);
nspname = get_namespace_name_or_temp(typeform->typnamespace);
typname = NameStr(typeform->typname);

View File

@ -460,7 +460,7 @@ format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs)
procform = (Form_pg_proc) GETSTRUCT(proctup);
nargs = procform->pronargs;
*objnames = list_make2(get_namespace_name(procform->pronamespace),
*objnames = list_make2(get_namespace_name_or_temp(procform->pronamespace),
pstrdup(NameStr(procform->proname)));
*objargs = NIL;
for (i = 0; i < nargs; i++)
@ -922,7 +922,7 @@ format_operator_parts(Oid operator_oid, List **objnames, List **objargs)
operator_oid);
oprForm = (Form_pg_operator) GETSTRUCT(opertup);
*objnames = list_make2(get_namespace_name(oprForm->oprnamespace),
*objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),
pstrdup(NameStr(oprForm->oprname)));
*objargs = NIL;
if (oprForm->oprleft)

View File

@ -19,6 +19,7 @@
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "bootstrap/bootstrap.h"
#include "catalog/namespace.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_collation.h"
@ -2884,6 +2885,20 @@ get_namespace_name(Oid nspid)
return NULL;
}
/*
* get_namespace_name_or_temp
* As above, but if it is this backend's temporary namespace, return
* "pg_temp" instead.
*/
char *
get_namespace_name_or_temp(Oid nspid)
{
if (isTempNamespace(nspid))
return "pg_temp";
else
return get_namespace_name(nspid);
}
/* ---------- PG_RANGE CACHE ---------- */
/*

View File

@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201504021
#define CATALOG_VERSION_NO 201504061
#endif

View File

@ -5120,8 +5120,7 @@ DATA(insert OID = 3785 ( pg_logical_slot_peek_binary_changes PGNSP PGUID 12 100
DESCR("peek at binary changes from replication slot");
/* event triggers */
DATA(insert OID = 3566 ( pg_event_trigger_dropped_objects PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,16,16,25,25,25,25,1009,1009}" "{o,o,o,o,o,o,o,o,o,o,o}" "{classid, objid, objsubid, original, normal, object_type, schema_name, object_name, object_identity, address_names, address_args}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ ));
DATA(insert OID = 3566 ( pg_event_trigger_dropped_objects PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,16,16,16,25,25,25,25,1009,1009}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{classid, objid, objsubid, original, normal, is_temporary, object_type, schema_name, object_name, object_identity, address_names, address_args}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ ));
DESCR("list objects dropped by the current command");
DATA(insert OID = 4566 ( pg_event_trigger_table_rewrite_oid PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 26 "" "{26}" "{o}" "{oid}" _null_ pg_event_trigger_table_rewrite_oid _null_ _null_ _null_ ));
DESCR("return Oid of the table getting rewritten");

View File

@ -151,6 +151,7 @@ extern void free_attstatsslot(Oid atttype,
Datum *values, int nvalues,
float4 *numbers, int nnumbers);
extern char *get_namespace_name(Oid nspid);
extern char *get_namespace_name_or_temp(Oid nspid);
extern Oid get_range_subtype(Oid rangeOid);
#define type_is_array(typid) (get_element_type(typid) != InvalidOid)

View File

@ -151,6 +151,7 @@ drop event trigger regress_event_trigger_end;
CREATE SCHEMA schema_one authorization regression_bob;
CREATE SCHEMA schema_two authorization regression_bob;
CREATE SCHEMA audit_tbls authorization regression_bob;
CREATE TEMP TABLE a_temp_tbl ();
SET SESSION AUTHORIZATION regression_bob;
CREATE TABLE schema_one.table_one(a int);
CREATE TABLE schema_one."table two"(a int);
@ -352,9 +353,9 @@ BEGIN
IF NOT r.normal AND NOT r.original THEN
CONTINUE;
END IF;
RAISE NOTICE 'NORMAL: orig=% normal=% type=% identity=% name=% args=%',
r.original, r.normal, r.object_type, r.object_identity,
r.address_names, r.address_args;
RAISE NOTICE 'NORMAL: 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 EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop
@ -364,23 +365,25 @@ CREATE SCHEMA evttrig
CREATE INDEX one_idx ON one (col_b)
CREATE TABLE two (col_c INTEGER CHECK (col_c > 0) REFERENCES one DEFAULT 42);
ALTER TABLE evttrig.two DROP COLUMN col_c;
NOTICE: NORMAL: orig=t normal=f type=table column identity=evttrig.two.col_c name={evttrig,two,col_c} args={}
NOTICE: NORMAL: orig=f normal=t type=table constraint identity=two_col_c_check on evttrig.two name={evttrig,two,two_col_c_check} args={}
NOTICE: NORMAL: orig=t normal=f istemp=f type=table column identity=evttrig.two.col_c name={evttrig,two,col_c} args={}
NOTICE: NORMAL: orig=f normal=t istemp=f type=table constraint identity=two_col_c_check on evttrig.two name={evttrig,two,two_col_c_check} args={}
ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT;
NOTICE: NORMAL: orig=t normal=f type=default value identity=for evttrig.one.col_b name={evttrig,one,col_b} args={}
NOTICE: NORMAL: orig=t normal=f istemp=f type=default value identity=for evttrig.one.col_b name={evttrig,one,col_b} args={}
ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey;
NOTICE: NORMAL: orig=t normal=f type=table constraint identity=one_pkey on evttrig.one name={evttrig,one,one_pkey} args={}
NOTICE: NORMAL: orig=t normal=f istemp=f type=table constraint identity=one_pkey on evttrig.one name={evttrig,one,one_pkey} args={}
DROP INDEX evttrig.one_idx;
NOTICE: NORMAL: orig=t normal=f type=index identity=evttrig.one_idx name={evttrig,one_idx} args={}
NOTICE: NORMAL: orig=t normal=f istemp=f type=index identity=evttrig.one_idx name={evttrig,one_idx} args={}
DROP SCHEMA evttrig CASCADE;
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table evttrig.one
drop cascades to table evttrig.two
NOTICE: NORMAL: orig=t normal=f type=schema identity=evttrig name={evttrig} args={}
NOTICE: NORMAL: orig=f normal=t type=table identity=evttrig.one name={evttrig,one} args={}
NOTICE: NORMAL: orig=f normal=t type=sequence identity=evttrig.one_col_a_seq name={evttrig,one_col_a_seq} args={}
NOTICE: NORMAL: orig=f normal=t type=default value identity=for evttrig.one.col_a name={evttrig,one,col_a} args={}
NOTICE: NORMAL: orig=f normal=t type=table identity=evttrig.two name={evttrig,two} args={}
NOTICE: NORMAL: orig=t normal=f istemp=f type=schema identity=evttrig name={evttrig} args={}
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.one name={evttrig,one} args={}
NOTICE: NORMAL: orig=f normal=t istemp=f type=sequence identity=evttrig.one_col_a_seq name={evttrig,one_col_a_seq} args={}
NOTICE: NORMAL: orig=f normal=t istemp=f type=default value identity=for evttrig.one.col_a name={evttrig,one,col_a} args={}
NOTICE: NORMAL: orig=f normal=t istemp=f type=table identity=evttrig.two name={evttrig,two} 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={}
DROP EVENT TRIGGER regress_event_trigger_report_dropped;
-- only allowed from within an event trigger function, should fail
select pg_event_trigger_table_rewrite_oid();

View File

@ -143,6 +143,7 @@ drop event trigger regress_event_trigger_end;
CREATE SCHEMA schema_one authorization regression_bob;
CREATE SCHEMA schema_two authorization regression_bob;
CREATE SCHEMA audit_tbls authorization regression_bob;
CREATE TEMP TABLE a_temp_tbl ();
SET SESSION AUTHORIZATION regression_bob;
CREATE TABLE schema_one.table_one(a int);
@ -253,9 +254,9 @@ BEGIN
IF NOT r.normal AND NOT r.original THEN
CONTINUE;
END IF;
RAISE NOTICE 'NORMAL: orig=% normal=% type=% identity=% name=% args=%',
r.original, r.normal, r.object_type, r.object_identity,
r.address_names, r.address_args;
RAISE NOTICE 'NORMAL: 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 EVENT TRIGGER regress_event_trigger_report_dropped ON sql_drop
@ -270,6 +271,7 @@ ALTER TABLE evttrig.one ALTER COLUMN col_b DROP DEFAULT;
ALTER TABLE evttrig.one DROP CONSTRAINT one_pkey;
DROP INDEX evttrig.one_idx;
DROP SCHEMA evttrig CASCADE;
DROP TABLE a_temp_tbl;
DROP EVENT TRIGGER regress_event_trigger_report_dropped;