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

From Peter Smith
Subject Re: Support logical replication of DDLs
Date
Msg-id CAHut+Psm+9q++y8b70QTeBeZiYcfDNtc_obxSwhxukp0MFhnRA@mail.gmail.com
Whole thread Raw
In response to Re: Support logical replication of DDLs  (Zheng Li <zhengli10@gmail.com>)
Responses Re: Support logical replication of DDLs  (Peter Smith <smithpb2250@gmail.com>)
Re: Support logical replication of DDLs  (Zheng Li <zhengli10@gmail.com>)
List pgsql-hackers
Here are some review comments for patch v32-0001.

This is a WIP - I have not yet looked at the largest file of this
patch (src/backend/commands/ddl_deparse.c)

======

Commit Message

1.

The list of the supported statements should be in alphabetical order
to make it easier to read

~~~

2.

The "Notes" are obviously notes, so the text does not need to say
"Note that..." etc again

"(Note #1) Note that some..." -> "(Note #1) Some..."

"(Note #2) Note that, for..." -> "(Note #2) For..."

"(Note #4) Note that, for..." -> "(Note #4) For..."

~~~

3.

For "Note #3", use uppercase for the SQL keywords in the example.

~~~

4.

For "Note #4":

"We created" -> "we created"

======

src/backend/catalog/aclchk.c

5. ExecuteGrantStmt

@@ -385,7 +385,11 @@ ExecuteGrantStmt(GrantStmt *stmt)
  ereport(ERROR,
  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  errmsg("grantor must be current user")));
+
+ istmt.grantor_uid = grantor;
  }
+ else
+ istmt.grantor_uid = InvalidOid;

This code can be simpler by just declaring the 'grantor' variable at
function scope, then assigning the istmt.grantor_uid along with the
other grantor assignments.

SUGGESTION
Oid grantor = InvalidOid;
...
istmt.grantor_uid = grantor;
istmt.is_grant = stmt->is_grant;
istmt.objtype = stmt->objtype;

======

src/backend/commands/collationcmds.c

6. DefineCollation

+ /* make from existing collationid available to callers */
+ if (from_collid && OidIsValid(collid))
+ ObjectAddressSet(*from_collid,
+ CollationRelationId,
+ collid);

6a.
Maybe the param can be made 'from_existing_colid', then the above code
comment can be made more readable?

~

6b.
Seems some unnecessary wrapping here


======

src/backend/commands/ddl_deparse.c

WIP - I will try to post some review comments on this file next week

======

src/backend/commands/ddl_json.c

7. convSpecifier

typedef enum
{
    SpecTypename,
    SpecOperatorname,
    SpecDottedName,
    SpecString,
    SpecNumber,
    SpecStringLiteral,
    SpecIdentifier,
    SpecRole
} convSpecifier;

Inconsistent case. Some of these say "name" and some say "Name"

~~~

8. Forward declarations

char *ddl_deparse_json_to_string(char *jsonb);

Is this needed here? I thought this was already declared extern in
ddl_deparse.h.

~~~

9. find_string_in_jsonbcontainer

The function comment says "If it's of a type other than jbvString, an
error is raised.", but I do not see this check in the function code.

~~~

10. expand_fmt_recursive

/*
 * Recursive helper for pg_event_trigger_expand_command
 *
 * Find the "fmt" element in the given container, and expand it into the
 * provided StringInfo.
 */


10a.
I am not sure if the mention of "pg_event_trigger_expand_command" is
stale or is not relevant anymore, because that caller is not in this
module.

~

10b.
The first sentence is missing a period.

~~~

11.

        value = findJsonbValueFromContainer(container, JB_FOBJECT, &key);

Should this be checking is value is NULL?

~~~

12. expand_jsonval_dottedname

 * Expand a json value as a dot-separated-name.  The value must be of type
 * object and may contain elements "schemaname" (optional), "objname"
 * (mandatory), "attrname" (optional).  Double quotes are added to each element
 * as necessary, and dot separators where needed.

The comment says "The value must be of type object" but I don't see
any check/assert for that in the code.

~~~

13. expand_jsonval_typename

In other code (e.g. expand_jsonval_dottedname) there are lots of
pfree(str) so why not similar here?

e.g. Shouldn’t the end of the function have like shown below:
pfree(schema);
pfree(typename);
pfree(typmodstr);

~~~

14. expand_jsonval_operator

The function comment is missing a period.

~~~

15. expand_jsonval_string

/*
 * Expand a JSON value as a string.  The value must be of type string or of
 * type object.  In the latter case, it must contain a "fmt" element which will
 * be recursively expanded; also, if the object contains an element "present"
 * and it is set to false, the expansion is the empty string.

15a.
Although the comment says "The value must be of type string or of type
object" the code is checking for jbvString and jbvBinary (??)

~

15b.
    else
        return false;

Is that OK to just return false, or should this in fact be throwing an
error if the wrong type?

~~~

16. expand_jsonval_strlit

    /* Easy case: if there are no ' and no \, just use a single quote */
    if (strchr(str, '\'') == NULL &&
        strchr(str, '\\') == NULL)

That could be simplified as:

if ((strpbk(str, "\'\\") == NULL)

~~~

17. expand_jsonval_number

    strdatum = DatumGetCString(DirectFunctionCall1(numeric_out,

NumericGetDatum(jsonval->val.numeric)));
    appendStringInfoString(buf, strdatum);

Shouldn't this function do pfree(strdatum) at the end?

~~~

18. expand_jsonval_role

/*
 * Expand a JSON value as a role name.  If the is_public element is set to
 * true, PUBLIC is expanded (no quotes); otherwise, expand the given role name,
 * quoting as an identifier.
 */


Maybe better to quote that element name -> 'If the "is_public" element
is set to true...'

~~~

19. expand_one_jsonb_element

The enum jbvType definition says that jbvBinary is a combination of
array/object, so I am not sure if that should be reflected in the
errmsg text (multiple places in this function body) instead of only
saying "JSON object".

~~~

20. ddl_deparse_expand_command

 * %        expand to a literal %.


Remove the period from that line (because not of the other specifier
descriptions have one).

======

src/backend/utils/adt/regproc.c

21. format_procedure_args_internal

+static void
+format_procedure_args_internal(Form_pg_proc procform, StringInfo buf,
+    bool force_qualify)
+{
+ int i;
+ int nargs = procform->pronargs;

The 'nargs' var is used one time only, so hardly seems worth having it.

~~~

22.

+ appendStringInfoString(buf,
+    force_qualify ?
+    format_type_be_qualified(thisargtype) :
+    format_type_be(thisargtype));

22a.
Should these function results be assigned to a char* ptr so that they
can be pfree(ptr) AFTER being appended to the 'buf'?

~

22b.
It's not really nececessary to check the force_qualify at every
iteration. More effient to asign a function pointer outside this loop
and just call that here. IIRC something like this:

char * (*func[2])(Oid) = { format_type_be, format_type_be_qualified };

...

then
appendStringInfoString(buf, func[force_qualify](thisargtype))


======

src/backend/utils/adt/ruleutils.c

23. pg_get_ruledef_detailed

Instead of the multiple if/else it might be easier to just assignup-front:
*whereClause = NULL;
*actions = NIL;

Then the if blocks can just overwrite them.

Also, if you do that, then I expect probably the 'output' temp list
var is not needed at all.

~~~

24. pg_get_viewdef_internal

/*
 * In the case that the CREATE VIEW command execution is still in progress,
 * we would need to search the system cache RULERELNAME to get the rewrite
 * rule of the view as oppose to querying pg_rewrite as in
pg_get_viewdef_worker(),
 * the latter will return empty result.
 */

24a.
I'm not quite sure of the context of this function call. Maybe the
comment was supposed to be worded more like below?

"Because this function is called when CREATE VIEW command execution is
still in progress, we need to search..."

~

24b.
"as oppose" -> "as opposed"

~~~

25. pg_get_triggerdef_worker

if (!isnull)
{
Node    *qual;
char    *qualstr;

qual = stringToNode(TextDatumGetCString(value));
qualstr = pg_get_trigger_whenclause(trigrec, qual, pretty);

appendStringInfo(&buf, "WHEN (%s) ", qualstr);
}

After appending the qualstr to buf, should there be a pfree(qualstr)?

~~~

26. pg_get_trigger_whenclause

Missing function comment.

~~~

27. print_function_sqlbody

-static void
+void
 print_function_sqlbody(StringInfo buf, HeapTuple proctup)
 {

Missing function comment. Probably having a function comment is more
important now that this is not static?

======

src/include/tcop/ddl_deparse.h

28.

+extern char *deparse_utility_command(CollectedCommand *cmd, bool verbose_mode);
+extern char *ddl_deparse_json_to_string(char *jsonb);
+extern char *deparse_drop_command(const char *objidentity, const char
*objecttype,
+   DropBehavior behavior);

Function naming seems inconsistent. ('ddl_deparse_XXX' versus 'deparse_XXX').

------
Kind Regards,
Peter Smith.
Fujitsu Australia



pgsql-hackers by date:

Previous
From: Bharath Rupireddy
Date:
Subject: Re: Use pg_pwritev_with_retry() instead of write() in dir_open_for_write() to avoid partial writes?
Next
From: Peter Eisentraut
Date:
Subject: psql: Add command to use extended query protocol