DROP and ddl_command_end.

Поиск
Список
Период
Сортировка
От Kyotaro Horiguchi
Тема DROP and ddl_command_end.
Дата
Msg-id 20200309.165230.469366042677523818.horikyota.ntt@gmail.com
обсуждение исходный текст
Ответы Re: DROP and ddl_command_end.  (Robert Haas <robertmhaas@gmail.com>)
Список pgsql-hackers
Hello.

When I created an event trigger for ddl_command_end, I think the only
means to identify for what the trigger function is called is
pg_event_trigger_ddl_commands() so I wrote as the following function
and defined an event trigger for ddl_command_end.

CREATE OR REPLACE FUNCTION hoge() RETURNS event_trigger AS $$
DECLARE
  cmd record =  pg_event_trigger_ddl_commands();
BEGIN
  RAISE NOTICE '"%" "%" "%"',
        cmd.command_tag, cmd.object_type, cmd.object_identity;
END
$$ LANGUAGE plpgsql;

CREATE EVENT TRIGGER hoge_trigger ON ddl_command_end EXECUTE FUNCTION hoge();

Finally I got an ERROR while DROP.

=# CREATE TABLE t (a int);
NOTICE:  "CREATE TABLE" "table" "public.t"
CREATE TABLE
postgres=# DROP TABLE t;
ERROR:  record "cmd" is not assigned yet
DETAIL:  The tuple structure of a not-yet-assigned record is indeterminate.
CONTEXT:  PL/pgSQL function hoge() line 5 at RAISE

The function doesn't return a record for DROP statements.

The documentation is written as the follows:

https://postgresql.org/docs/current/event-trigger-definition.html
> The ddl_command_end event occurs just after the execution of this same
> set of commands. To obtain more details on the DDL operations that
> took place, use the set-returning function
> pg_event_trigger_ddl_commands() from the ddl_command_end event trigger
> code (see Section 9.28). Note that the trigger fires after the actions
> have taken place (but before the transaction commits), and thus the
> system catalogs can be read as already changed.

So I think at least pg_event_trigger_ddl_command must return a record
for all commands that trigger ddl_command_end and the record should
have the correct command_tag.  DROP TABLE is currently classified as
supporting event trigger.  If we don't do that, any workaround and
documentation is needed.

I may be missing something, andt any opinions, thoughts or suggestions
are welcome.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 91800d1fac..8376ce429b 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -1939,7 +1939,8 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
          * state anyway.
          */
         if (cmd->type == SCT_Simple &&
-            !OidIsValid(cmd->d.simple.address.objectId))
+            !OidIsValid(cmd->d.simple.address.objectId) &&
+            !IsA(cmd->parsetree, DropStmt))
             continue;
 
         MemSet(nulls, 0, sizeof(nulls));
@@ -1952,8 +1953,8 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
             case SCT_CreateOpClass:
             case SCT_AlterTSConfig:
                 {
-                    char       *identity;
-                    char       *type;
+                    char       *identity = NULL;
+                    char       *type = NULL;
                     char       *schema = NULL;
 
                     if (cmd->type == SCT_Simple)
@@ -1969,8 +1970,12 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
                     else if (cmd->type == SCT_AlterTSConfig)
                         addr = cmd->d.atscfg.address;
 
-                    type = getObjectTypeDescription(&addr);
-                    identity = getObjectIdentity(&addr);
+                    if (memcmp(&addr, &InvalidObjectAddress,
+                               sizeof(ObjectAddress)) != 0)
+                    {
+                        type = getObjectTypeDescription(&addr);
+                        identity = getObjectIdentity(&addr);
+                    }
 
                     /*
                      * Obtain schema name, if any ("pg_temp" if a temp
@@ -2023,14 +2028,20 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
                     /* command tag */
                     values[i++] = CStringGetTextDatum(CreateCommandName(cmd->parsetree));
                     /* object_type */
-                    values[i++] = CStringGetTextDatum(type);
+                    if (type != NULL)
+                        values[i++] = CStringGetTextDatum(type);
+                    else
+                        nulls[i++] = true;
                     /* schema */
                     if (schema == NULL)
                         nulls[i++] = true;
                     else
                         values[i++] = CStringGetTextDatum(schema);
                     /* identity */
-                    values[i++] = CStringGetTextDatum(identity);
+                    if (identity != NULL)
+                        values[i++] = CStringGetTextDatum(identity);
+                    else
+                        nulls[i++] = true;
                     /* in_extension */
                     values[i++] = BoolGetDatum(cmd->in_extension);
                     /* command */
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index b1f7f6e2d0..3b801d279a 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1686,8 +1686,8 @@ ProcessUtilitySlow(ParseState *pstate,
 
             case T_DropStmt:
                 ExecDropStmt((DropStmt *) parsetree, isTopLevel);
-                /* no commands stashed for DROP */
-                commandCollected = true;
+                /* Dropped object is not available */
+                address =  InvalidObjectAddress;
                 break;
 
             case T_RenameStmt:

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Michael Paquier
Дата:
Сообщение: Re: Add an optional timeout clause to isolationtester step.
Следующее
От: Masahiko Sawada
Дата:
Сообщение: Re: Improve handling of parameter differences in physical replication