Re: Support logical replication of DDLs - Mailing list pgsql-hackers

From Ajin Cherian
Subject Re: Support logical replication of DDLs
Date
Msg-id CAFPTHDYMs9zRUHkBZiCSVRBuC7UOg8yn11vd8QH_FsCfUnUZcw@mail.gmail.com
Whole thread Raw
In response to Re: Support logical replication of DDLs  (vignesh C <vignesh21@gmail.com>)
Responses Re: Support logical replication of DDLs
List pgsql-hackers
On Thu, 27 Oct 2022 at 16:02, vignesh C <vignesh21@gmail.com> wrote:
>
> 2) This function should handle "alter procedure" too:
> +/*
> + * Deparse an AlterFunctionStmt (ALTER FUNCTION/ROUTINE)
> + *
> + * Given a function OID and the parse tree that created it, return the JSON
> + * blob representing the alter command.
> + */
> +static ObjTree *
> +deparse_AlterFunction(Oid objectId, Node *parsetree)
> +{
> +       AlterFunctionStmt *node = (AlterFunctionStmt *) parsetree;
> +       ObjTree    *alterFunc;
> +       ObjTree    *sign;
> +       HeapTuple       procTup;
>
> Currently "alter procedure" statement are replicated as "alter
> function" statements in the subscriber.

Fixed this.

> 3) In few of the extensions we execute "alter operator family" like in
> hstore extension, we should exclude replicating "alter operator
> family" when create extension is in progress:
>   /* Don't deparse SQL commands generated while creating extension */
>   if (cmd->in_extension)
>     return NULL;
>
> The above check should be included in the below code, else the create
> extension statment will fail as internal statements will be executed:
>
> +static ObjTree *
> +deparse_AlterOpFamily(CollectedCommand *cmd)
> +{
> +       ObjTree    *alterOpFam;
> +       AlterOpFamilyStmt *stmt = (AlterOpFamilyStmt *) cmd->parsetree;
> +       HeapTuple       ftp;
> +       Form_pg_opfamily opfForm;
> +       List       *list;
> +       ListCell   *cell;
> +
> +       ftp = SearchSysCache1(OPFAMILYOID,
> +
> ObjectIdGetDatum(cmd->d.opfam.address.objectId));
> +       if (!HeapTupleIsValid(ftp))
> +               elog(ERROR, "cache lookup failed for operator family %u",
> +                        cmd->d.opfam.address.objectId);
> +       opfForm = (Form_pg_opfamily) GETSTRUCT(ftp);
> +

Fixed this.

> 4) This if...else can be removed, the nspid and typname can be handled
> for others in default. *nspid can be set to InvalidOid at the
> beginning.
> +       if (type_oid == INTERVALOID ||
> +               type_oid == TIMESTAMPOID ||
> +               type_oid == TIMESTAMPTZOID ||
> +               type_oid == TIMEOID ||
> +               type_oid == TIMETZOID)
> +       {
> +               switch (type_oid)
> +               {
> +                       case INTERVALOID:
> +                               *typname = pstrdup("INTERVAL");
> +                               break;
> +                       case TIMESTAMPTZOID:
> +                               if (typemod < 0)
> +                                       *typname = pstrdup("TIMESTAMP
> WITH TIME ZONE");
> +                               else
> +                                       /* otherwise, WITH TZ is added
> by typmod. */
> +                                       *typname = pstrdup("TIMESTAMP");
> +                               break;
> +                       case TIMESTAMPOID:
> +                               *typname = pstrdup("TIMESTAMP");
> +                               break;
> +                       case TIMETZOID:
> +                               if (typemod < 0)
> +                                       *typname = pstrdup("TIME WITH
> TIME ZONE");
> +                               else
> +                                       /* otherwise, WITH TZ is added
> by typmod. */
> +                                       *typname = pstrdup("TIME");
> +                               break;
> +                       case TIMEOID:
> +                               *typname = pstrdup("TIME");
> +                               break;
> +               }
> +               *nspid = InvalidOid;
> +       }
> +       else
> +       {
> +               /*
> +                * No additional processing is required for other
> types, so get the
> +                * type name and schema directly from the catalog.
> +                */
> +               *nspid = typeform->typnamespace;
> +               *typname = pstrdup(NameStr(typeform->typname));
> +       }
>

Changed this.

> 5) The following includes are not required in ddl_deparse.c:
> #include "catalog/pg_attribute.h"
> #include "catalog/pg_class.h"
> #include "lib/ilist.h"
> #include "nodes/makefuncs.h"
> #include "nodes/parsenodes.h"
> #include "utils/memutils.h"
>

Fixed this.

> 6) Inconsistent error reporting:
> In few places elog is used and in few places ereport is used:
> +       HeapTuple       polTup = get_catalog_object_by_oid(polRel,
> Anum_pg_policy_oid, policyOid);
> +       Form_pg_policy polForm;
> +
> +       if (!HeapTupleIsValid(polTup))
> +               elog(ERROR, "cache lookup failed for policy %u", policyOid);
>
>
> +               char       *rolename;
> +
> +               roltup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleoid));
> +               if (!HeapTupleIsValid(roltup))
> +                       ereport(ERROR,
> +                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
> +                                        errmsg("role with OID %u does
> not exist", roleoid)));
>
> We can try to use the same style of error reporting.
>

Changed all errors to elog

> 8) Inclusion ordering in ddl_deparse.c:
> 8.a) The following should be slightly reordered
> +#include "access/amapi.h"
> +#include "access/table.h"
> +#include "access/relation.h"
>
> 8.b) The following should be slightly reordered
> +#include "postgres.h"
> +#include "tcop/ddl_deparse.h"
> +#include "access/amapi.h"
>
> 9) In few places multi line comment can be changed to single line comment:
> 9.a)
> +       /*
> +        * Fetch the pg_class tuple of the index relation
> +        */
>
> 9.b)
> +       /*
> +        * Fetch the pg_am tuple of the index' access method
> +        */
>
> 9.c)
> +       /*
> +        * Reject unsupported case right away.
> +        */
>
> 10)  This should also specify ROUTINE in the comment
>   /*
>    * Verbose syntax
>    *
>    * ALTER FUNCTION %{signature}s %{definition: }s
>    */
>   alterFunc = new_objtree_VA(node->objtype == OBJECT_ROUTINE ?
>                  "ALTER ROUTINE" : "ALTER FUNCTION", 0);
>
> 11) This can be changed in alphabetical order(collation first and then column):
> 11.a)
>  +               case OBJECT_COLUMN:
> +                       return "COLUMN";
> +               case OBJECT_COLLATION:
> +                       return "COLLATION";
> +               case OBJECT_CONVERSION:
> +                       return "CONVERSION";
>
> 11.b) similarly here:
>     case OBJECT_FDW:
>       return "FOREIGN DATA WRAPPER";
>     case OBJECT_FOREIGN_SERVER:
>       return "SERVER";
>     case OBJECT_FOREIGN_TABLE:
>       return "FOREIGN TABLE";
>
> 11.c) similarly here:
>     case OBJECT_FUNCTION:
>       return "FUNCTION";
>     case OBJECT_ROUTINE:
>       return "ROUTINE";
>     case OBJECT_INDEX:
>       return "INDEX";
>
> 11.d) similarly here:
>     case OBJECT_OPCLASS:
>       return "OPERATOR CLASS";
>     case OBJECT_OPERATOR:
>       return "OPERATOR";
>     case OBJECT_OPFAMILY:
>       return "OPERATOR FAMILY";
>
> 11.e) similarly here:
>     case OBJECT_TRIGGER:
>       return "TRIGGER";
>     case OBJECT_TSCONFIGURATION:
>       return "TEXT SEARCH CONFIGURATION";
>
>     /*
>      * case OBJECT_TSCONFIG_MAPPING:
>      *    return "TEXT SEARCH CONFIGURATION MAPPING";
>      */
>     case OBJECT_TSDICTIONARY:
>       return "TEXT SEARCH DICTIONARY";
>     case OBJECT_TSPARSER:
>       return "TEXT SEARCH PARSER";
>     case OBJECT_TSTEMPLATE:
>       return "TEXT SEARCH TEMPLATE";
>     case OBJECT_TYPE:
>       return "TYPE";
>

Fixed this.

> 12) new_objtree can be used instead of new_objtree_VA when there is no
> arguments, one additional check can be avoided
>
> 12.a) alterFunc = new_objtree_VA(node->objtype == OBJECT_ROUTINE ?
>                  "ALTER ROUTINE" : "ALTER FUNCTION", 0);
>
> 12.b)     ObjTree    *tmpobj = new_objtree_VA("", 0);
>
> 12.c)       tmpobj = new_objtree_VA(strVal(defel->arg), 0);
>
> 12.d)       tmpobj = new_objtree_VA("ROWS", 0);
>
> 12.e)   grantStmt = new_objtree_VA(fmt, 0);
>
> 12.f)     tmp = new_objtree_VA("ALL PRIVILEGES", 0);
>
> 12.g)         tmpobj2 = new_objtree_VA("FOR ORDER BY", 0);
>
> 12.h)   composite = new_objtree_VA("CREATE TYPE", 0);
>
> 12.i)     tmp = new_objtree_VA("OPTIONS", 0);
>
> 12.j)     tmp = new_objtree_VA("NO HANDLER", 0);
>
> 12.k) .... similarly in few more places .....
>

Fixed these.

On Thu, Nov 3, 2022 at 1:51 AM vignesh C <vignesh21@gmail.com> wrote:
>
> Few comments:
> 1) Empty () should be appended in case if there are no table elements:
> +               tableelts = deparse_TableElements(relation,
> node->tableElts, dpcontext,
> +
>            false,        /* not typed table */
> +
>            false);       /* not composite */
> +               tableelts = obtainConstraints(tableelts, objectId, InvalidOid);
> +
> +               append_array_object(createStmt, "(%{table_elements:,
> }s)", tableelts);
>
> This is required for:
> CREATE TABLE ihighway () INHERITS (road);
>

Fixed this.

> 2.a)
> Here cell2 will be of type RoleSpec, the below should be changed:
> +                       foreach(cell2, (List *) opt->arg)
> +                       {
> +                               String  *val = lfirst_node(String, cell2);
> +                               ObjTree *obj =
> new_objtree_for_role(strVal(val));
> +
> +                               roles = lappend(roles, new_object_object(obj));
> +                       }
>
> to:
> foreach(cell2, (List *) opt->arg)
> {
> RoleSpec   *rolespec = lfirst(cell2);
> ObjTree    *obj = new_objtree_for_rolespec(rolespec);
>
> roles = lappend(roles, new_object_object(obj));
> }
>

Fixed this.

> This change is required for:
> ALTER DEFAULT PRIVILEGES FOR ROLE regress_selinto_user REVOKE INSERT
> ON TABLES FROM regress_selinto_user;
>
> 2.b) After the above change the following function cna be removed:
> +/*
> + * Helper routine for %{}R objects, with role specified by name.
> + */
> +static ObjTree *
> +new_objtree_for_role(char *rolename)
> +{
> +       ObjTree    *role;
> +
> +       role = new_objtree_VA(NULL,2,
> +                                                 "is_public",
> ObjTypeBool, strcmp(rolename, "public") == 0,
> +                                                 "rolename",
> ObjTypeString, rolename);
> +       return role;
> +}
>

Fixed this.

I've addressed a few comments from Vignesh, there are quite a few more
comments remaining. I will update them in my next patch.

regards,
Ajin Cherian
Fujitsu Australia

Attachment

pgsql-hackers by date:

Previous
From: Pavel Stehule
Date:
Subject: Re: psql: Add command to use extended query protocol
Next
From: Michael Paquier
Date:
Subject: Re: Use pg_pwritev_with_retry() instead of write() in dir_open_for_write() to avoid partial writes?