0

I've created a function in PostgreSQL 11.10 to handle DDL change in pglogical to apply it into subscriber. Here is the function:

CREATE OR REPLACE FUNCTION public.intercept_ddl()
 RETURNS event_trigger
 LANGUAGE plpgsql
AS $function$
  declare _qry text;
BEGIN
  if (tg_tag='CREATE TABLE' or tg_tag='ALTER TABLE' or tg_tag='DROP TABLE') then
            SELECT current_query() into _qry;
            PERFORM pglogical.replicate_ddl_command('_qry', '{default}'), _qry;
                                                                               
 end if;
END;
$function$
;

When I tried it, it threw an error:

ERROR:  syntax error at or near "_qry"
LINE 1: SELECT pglogical.replicate_ddl_command('_qry', '{default}')
        ^
QUERY:  SELECT pglogical.replicate_ddl_command('_qry', '{default}')
CONTEXT:  during execution of queued SQL statement: _qry
PL/pgSQL function intercept_ddl() line 6 at PERFORM

How to pass _qry variable so we can use it replicate_ddl_command()?


After fixing single quotes as instructed by Laurenz, I tried again with the command:

alter table test alter COLUMN description type text; 

And got another error message:

ERROR: cannot drop active portal "pglogical"
CONTEXT: during execution of queued SQL statement: alter table test alter COLUMN description type text; SQL statement "SELECT pglogical.replicate_ddl_command( _qry, '{default}')" PL/pgSQL function intercept_ddl() line 7 at PERFORM
1

In addition to fixing single quotes as instructed by Laurenz, you might have to use the (default!) replication set '{ddl_sql}' for the command replicate_ddl_command(). The error message

cannot drop active portal "pglogical"

indicates an open portal with a prepared statement that would conflict with the DDL command.

CREATE OR REPLACE FUNCTION public.intercept_ddl()
  RETURNS event_trigger
  LANGUAGE plpgsql AS
$func$
BEGIN
   PERFORM pglogical.replicate_ddl_command(current_query(), '{ddl_sql}');  -- !!
END
$func$;

You did not disclose the actual event trigger, but could look like this

CREATE EVENT TRIGGER foo
ON ddl_command_start
WHEN TAG IN ('CREATE TABLE', 'ALTER TABLE', 'DROP TABLE')
EXECUTE FUNCTION public.intercept_ddl();

Filter command tags in the trigger itself, obviates the need to do so in the function. That's more efficient as the function is only called for applicable tags to begin with.

Quoting the manual of pglogical:

There are three preexisting replication sets named “default”, “default_insert_only” and “ddl_sql”. [...] The “ddl_sql” replication set is defined to replicate schema changes specified by pglogical.replicate_ddl_command

And:

  • pglogical.replicate_ddl_command(command text, replication_sets text[]) Execute locally and then send the specified command to the replication queue for execution on subscribers which are subscribed to one of the specified replication_sets.Parameters:
    • command – DDL query to execute
    • replication_sets – array of replication sets which this command should be associated with, default “{ddl_sql}”
1
  • HI @Erwin thanks for the the explanation, I will look at pglogical documentation. Mar 15 '21 at 4:00
0

You use _qry in single quotes, as a string constant, which constitutes an illegal SQL statement. Moreover, the strange appendix , _qry is syntactical nonsense.

Try

PERFORM pglogical.replicate_ddl_command(_qry, '{default}');

Then _qry will be recognized as a variable reference.

4
  • I've try that one too, but still failed, replicate_ddl_command require single quote to identified the query. Mar 10 '21 at 12:31
  • I don't believe that. But without an error message, it is hard to tell. Mar 10 '21 at 13:14
  • Here is the error provider=> alter table test alter COLUMN description type text; ERROR: cannot drop active portal "pglogical" CONTEXT: during execution of queued SQL statement: alter table test alter COLUMN description type text; SQL statement "SELECT pglogical.replicate_ddl_command( _qry, '{default}')" PL/pgSQL function intercept_ddl() line 7 at PERFORM during execution of queued SQL statement: alter table test alter COLUMN description type text; SQL statement "SELECT pglogical.replicate_ddl_command( _qry, '{default}')" PL/pgSQL function intercept_ddl() line 7 at PERFORM Mar 10 '21 at 13:17
  • That is not related to syntax. Ask 2dnQuadrant, whose software you are using. Mar 10 '21 at 13:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.