Re: Support logical replication of DDLs - Mailing list pgsql-hackers
From | Peter Smith |
---|---|
Subject | Re: Support logical replication of DDLs |
Date | |
Msg-id | CAHut+Pt=n55fROZJHEp9Aa1CKvDSHTgxGk+jt4-5NjkbAYaRgA@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 |
The patches here are quite large, so for this review post, I have only done a quick check for cosmetic stuff in the comments of patch v24-0001. ~ I did this mostly just by cutting/pasting the whole patch text into a grammar/spell-checker to see what it reported. Please use the same strategy prior to posting future patch versions, because it will be way more efficient/easier for the author to spend a few minutes to fix everything like this up-front before posting, rather than getting a flood of review comments to deal with (like this post) about such stuff. (BTW, most of these suggestions are just verbatim what my grammar/spell-checker told me) ====== 1. Commit comment (Note #2) Note that, for ATTACH/DETACH PARTITION, we haven't added extra logic on subscriber to handle the case where the table on publisher is a PARTITIONED TABLE while the target table on subcriber side is NORMAL table. We will research this more and improve this later. SUGGESTION (minor changes + fix typo) (Note #2) Note that for ATTACH/DETACH PARTITION we haven't added extra logic on the subscriber to handle the case where the table on the publisher is a PARTITIONED TABLE while the target table on the subscriber is a NORMAL table. We will research this more and improve it later. ====== 2. GENERAL - uppercase the comments Please make all your single-line comments start with uppercase for consistency. Here are some examples to fix: Line 303: + /* add the "ON table" clause */ Line 331: + /* add the USING clause, if any */ Line 349: + /* add the WITH CHECK clause, if any */ Line 653: + /* otherwise, WITH TZ is added by typmod. */ Line 663: + /* otherwise, WITH TZ is added by typmode. */ Line 1946: + /* build list of privileges to grant/revoke */ Line 2017: + /* target objects. We use object identities here */ Line 2041: + /* list of grantees */ Line 2053: + /* the wording of the grant option is variable ... */ Line 2632: + /* skip this one; we add one unconditionally below */ Line 2660: + /* done */ Line 2768: + /* add HANDLER clause */ Line 2780: + /* add VALIDATOR clause */ Line 2792: + /* add an OPTIONS clause, if any */ Line 2845: + /* add HANDLER clause */ Line 2859: + /* add VALIDATOR clause */ Line 2877: + /* add an OPTIONS clause, if any */ Line 5024: + /* add the rest of the stuff */ Line 5040: + /* add the rest of the stuff */ Line 5185: + /* a new constraint has a name and definition */ Line 5211: + /* done */ Line 6124: + /* add a CONCURRENTLY clause */ Line 6127: + /* add the matview name */ Line 6131: + /* add a WITH NO DATA clause */ Line 6302: + /* reloptions */ Line 6310: + /* tablespace */ Line 6592: + /* deconstruct the name list */ Line 6636: + /* deconstruct the name list */ Line 6725: + /* obtain object tuple */ Line 6729: + /* obtain namespace */ ------ 3. Grammar/Spelling 3a. - format_type_detailed + * - nspid is the schema OID. For certain SQL-standard types which have weird + * typmod rules, we return InvalidOid; caller is expected to not schema- + * qualify the name nor add quotes to the type name in this case. "caller" -> "the caller" ~ 3b. - format_type_detailed + * - typemodstr is set to the typemod, if any, as a string with parens "parens" -> "parentheses" ~ 3c. - format_type_detailed + else + /* otherwise, WITH TZ is added by typmode. */ + *typname = pstrdup("TIME"); "typmode" -> "typmod" ? ~ 3d. - new_objtree_for_qualname + * A helper routine to setup %{}D and %{}O elements. "setup" -> "set up" ~ 3e. - new_objtree_for_type +/* + * A helper routine to setup %{}T elements. + */ +static ObjTree * +new_objtree_for_type(Oid typeId, int32 typmod) "setup" -> "set up" ~ 3f. - pg_get_indexdef_detailed +/* + * Return an index definition, split in several pieces. + * + * A large amount of code is duplicated from pg_get_indexdef_worker, but + * control flow is different enough that it doesn't seem worth keeping them + * together. + */ +static void +pg_get_indexdef_detailed(Oid indexrelid, "split in" -> "split into" ~ 3g. - ddl_deparse_to_json + * The command is expanded fully, so that there are no ambiguities even in the + * face of search_path changes. + */ +Datum +ddl_deparse_to_json(PG_FUNCTION_ARGS) "fully, so" -> "fully so" ~ 3h. -deparse_AlterFunction + * Given a function OID and the parsetree that created it, return the JSON + * blob representing the alter command. + */ "the parsetree" -> "the parse tree" ~ 3i. - deparse_AlterObjectSchemaStmt +/* + * deparse an ALTER ... SET SCHEMA command. + */ +static ObjTree * +deparse_AlterObjectSchemaStmt(ObjectAddress address, Node *parsetree, "deparse" -> "Deparse" ~ 3j. deparse_AlterObjectSchemaStmt + /* + * Since the command has already taken place from the point of view of + * catalogs, getObjectIdentity returns the object name with the already + * changed schema. The output of our deparsing must return the original + * schema name however, so we chop the schema name off the identity string + * and then prepend the quoted schema name. "name however," -> "name, however," ~ 3k. - deparse_GrantStmt + /* build list of privileges to grant/revoke */ + if (istmt->all_privs) "build list" -> "build a list" ~ 3l. - deparse_AlterTypeSetStmt + * Deparse an AlterTypeStmt. + * + * Given a type OID and a parsetree that modified it, return an ObjTree + * representing the alter type. + */ +static ObjTree * +deparse_AlterTypeSetStmt(Oid objectId, Node *cmd) "parsetree" -> "parse tree" ~ 3m. - deparse_CompositeTypeStmt + * Deparse a CompositeTypeStmt (CREATE TYPE AS) + * + * Given a type OID and the parsetree that created it, return an ObjTree + * representing the creation command. + */ "parsetree" -> "parse tree" ~ 3n. - deparse_CreateEnumStmt +/* + * Deparse a CreateEnumStmt (CREATE TYPE AS ENUM) + * + * Given a type OID and the parsetree that created it, return an ObjTree + * representing the creation command. + */ "parsetree" -> "parse tree" ~ 3o. - deparse_CreateExtensionStmt +/* + * deparse_CreateExtensionStmt + * deparse a CreateExtensionStmt + * + * Given an extension OID and the parsetree that created it, return the JSON + * blob representing the creation command. + * + */ "parsetree" -> "parse tree" ~ 3p. - deparse_CreateFdwStmt +/* + * deparse_CreateFdwStmt + * Deparse a CreateFdwStmt (CREATE FOREIGN DATA WRAPPER) + * + * Given a trigger OID and the parsetree that created it, + * return an ObjTree representing the creation command. + */ "parsetree" -> "parse tree" ~ 3q. - deparse_AlterFdwStmt +/* + * deparse_AlterFdwStmt + * Deparse an AlterFdwStmt (ALTER FOREIGN DATA WRAPPER) + * + * Given a function OID and the parsetree that create it, return the + * JSON blob representing the alter command. + */ "parsetree" -> "parse tree" "create it" -> "created it" 3r. + /* + * Iterate through options, to see what changed, but use catalog as basis + * for new values. + */ "as basis" -> "as a basis" ~ 3s. +/* + * Deparse a CREATE TYPE AS RANGE statement + * + * Given a type OID and the parsetree that created it, return an ObjTree + * representing the creation command. + */ "parsetree" -> "parse tree" ~ 3t. - deparse_AlterEnumStmt +/* + * Deparse an AlterEnumStmt. + * + * Given a type OID and a parsetree that modified it, return an ObjTree + * representing the alter type. + */ "parsetree" -> "parse tree" ~ 3u. - deparse_AlterTableStmt + /* + * We don't support replicating ALTER TABLE which contains volatile + * functions because It's possible the functions contain DDL/DML in + * which case these opertions will be executed twice and cause + * duplicate data. In addition, we don't know whether the tables being + * accessed by these DDL/DML are published or not. So blindly allowing + * such functions can allow unintended clauses like the tables accessed + * in those functions may not even exist on the subscriber-side. + */ "opertions" -> "operations" "subscriber-side." -> "subscriber." ~ 3v. - deparse_ColumnDef + * Deparse a ColumnDef node within a regular (non typed) table creation. "non typed" -> "non-typed" ~ 3w. - deparse_ColumnDef + /* + * Emit a NOT NULL declaration if necessary. Note that we cannot trust + * pg_attribute.attnotnull here, because that bit is also set when + * primary keys are specified; and we must not emit a NOT NULL + * constraint in that case, unless explicitely specified. Therefore, + * we scan the list of constraints attached to this column to determine + * whether we need to emit anything. + * (Fortunately, NOT NULL constraints cannot be table constraints.) + * + * In the ALTER TABLE cases, we also add a NOT NULL if the colDef is + * marked is_not_null. + */ "specified; and we" -> "specified; we" "explicitely" -> "explicitly" ~ 3x. - deparse_CreateDomain +/* + * Deparse the CREATE DOMAIN + * + * Given a function OID and the parsetree that created it, return the JSON + * blob representing the creation command. + */ "parsetree" -> "parse tree" ~ 3y. - deparse_CreateFunction +/* + * Deparse a CreateFunctionStmt (CREATE FUNCTION) + * + * Given a function OID and the parsetree that created it, return the JSON + * blob representing the creation command. + */ "parsetree" -> "parse tree" ~ 3z. - deparse_CreateFunction + /* + * Now iterate over each parameter in the parsetree to create the + * parameters array. + */ "parsetree" -> "parse tree" ~ 4a. - deparse_CreateFunction + /* + * A PARAM_TABLE parameter indicates end of input arguments; the + * following parameters are part of the return type. We ignore them + * here, but keep track of the current position in the list so that + * we can easily produce the return type below. + */ "end" -> "the end" ~ 4b. - deparse_CreateOpClassStmt + /* Don't deparse sql commands generated while creating extension */ + if (cmd->in_extension) + return NULL; "sql" -> "SQL" ~ 4c. - deparse_CreateOpClassStmt /* + * Add the FAMILY clause; but if it has the same name and namespace as the + * opclass, then have it expand to empty, because it would cause a failure + * if the opfamily was created internally. + */ "clause; " -> "clause, " "empty," -> "empty" ~ 4d. - deparse_CreateOpFamily +/* + * Deparse a CreateTrigStmt (CREATE OPERATOR FAMILY) + * + * Given a trigger OID and the parsetree that created it, return an ObjTree + * representing the creation command. + */ "parsetree" -> "parse tree" ~ 4e. - deparse_CreateSchemaStmt +/* + * Deparse a CreateSchemaStmt. + * + * Given a schema OID and the parsetree that created it, return an ObjTree + * representing the creation command. + * + */ "parsetree" -> "parse tree" ~ 4f. - deparse_CreateSeqStmt +/* + * Deparse a CreateSeqStmt. + * + * Given a sequence OID and the parsetree that create it, return an ObjTree + * representing the creation command. + */ "parsetree" -> "parse tree" "create it" -> "created it" ~ 4g. - deparse_CreateStmt +/* + * Deparse a CreateStmt (CREATE TABLE). + * + * Given a table OID and the parsetree that created it, return an ObjTree + * representing the creation command. + */ "parsetree" -> "parse tree" ~ 4h. + /* + * Typed tables and partitions use a slightly different format string: we + * must not put table_elements with parents directly in the fmt string, + * because if there are no options the parens must not be emitted; and + * also, typed tables do not allow for inheritance. + */ "parens" -> "parentheses" ~ 4i. - deparse_CreateStmt + /* + * We can't put table elements directly in the fmt string as an array + * surrounded by parens here, because an empty clause would cause a + * syntax error. Therefore, we use an indirection element and set + * present=false when there are no elements. + */ "parens" -> "parentheses" ~ 4j. - deparse_CreateStmt + /* + * Get pg_class.relpartbound. We cannot use partbound in the + * parsetree directly as it's the original partbound expression + * which haven't been transformed. + */ "parsetree" -> "parse tree" ? maybe this one if ok if it referring to the parameter with this name. ~ 4k. - deparse_DefineStmt_Operator +/* + * Deparse a DefineStmt (CREATE OPERATOR) + * + * Given a trigger OID and the parsetree that created it, return an ObjTree + * representing the creation command. + */ "parsetree" -> "parse tree" ~ 4l. - deparse_CreateTrigStmt +/* + * Deparse a CreateTrigStmt (CREATE TRIGGER) + * + * Given a trigger OID and the parsetree that created it, return an ObjTree + * representing the creation command. + */ "parsetree" -> "parsetree" ~ 4m. - deparse_RefreshMatViewStmt +/* + * Deparse a RefreshMatViewStmt (REFRESH MATERIALIZED VIEW) + * + * Given a materialized view OID and the parsetree that created it, return an + * ObjTree representing the refresh command. + */ "parseree" -> "parse tree" ~ 4n. - deparse_IndexStmt +/* + * Deparse an IndexStmt. + * + * Given an index OID and the parsetree that created it, return an ObjTree + * representing the creation command. + * + * If the index corresponds to a constraint, NULL is returned. + */ "parsetree" -> "parse tree" ~ 4o. - deparse_InhRelations +/* + * Deparse the INHERITS relations. + * + * Given a table OID, return a schema qualified table list representing + * the parent tables. + */ +static List * +deparse_InhRelations(Oid objectId) "schema qualified" -> "schema-qualified" ~ 4p. - deparse_OnCommitClause +/* + * Deparse the ON COMMMIT ... clause for CREATE ... TEMPORARY ... + */ +static ObjTree * +deparse_OnCommitClause(OnCommitAction option) "COMMMIT" -> "COMMIT" ~ 4q. - deparse_RuleStmt +/* + * Deparse a RuleStmt (CREATE RULE). + * + * Given a rule OID and the parsetree that created it, return an ObjTree + * representing the rule command. + */ "parsetree" -> "parse tree" ~ 4r. - deparse_utility_command + /* + * Allocate everything done by the deparsing routines into a temp context, + * to avoid having to sprinkle them with memory handling code; but allocate + * the output StringInfo before switching. + */ "code; " -> "code, " ~ 4s. - deparse_utility_command + /* + * Many routines underlying this one will invoke ruleutils.c functionality + * in order to obtain deparsed versions of expressions. In such results, + * we want all object names to be qualified, so that results are "portable" + * to environments with different search_path settings. Rather than inject + * what would be repetitive calls to override search path all over the + * place, we do it centrally here. + */ "in order to" => "to" ~ 4t. - convSpecifier +/* + * Conversion specifier, it determines how we expand the json element into + * string. + */ SUGGESTION Conversion specifier which determines how we expand the json element into a string. ~ 4u. - json_trivalue +/* + * A ternary value which represents a boolean type JsonbValue. + */ "which represents" -> "that represents" ~ 4v. - expand_fmt_recursive + /* + * Scan the mandatory element name. Allow for an array separator + * (which may be the empty string) to be specified after colon. + */ "after colon" -> "after a colon" ~ 4w. - 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. + * + * Returns false if no actual expansion was made due to the "present" flag + * being set to "false". + */ "latter case" -> "latter case," ~ 4x. - format_procedure_args_internal +/* + * Append the parenthised arguments of the given pg_proc row into the output + * buffer. force_qualify indicates whether to schema-qualify type names + * regardless of visibility. + */ "parenthised" -> "parenthesized " ~ 4y. +/* + * Internal version that returns definition of a CONSTRAINT command + */ "definition" -> "the definition" ====== 5. Function comment inconsistencies 5a. Sometimes the function name is repeated in the comment and sometimes it is not. e.g. compare deparse_CreateEnumStmt() versus deparse_CreateExtensionStmt(), etc. (IMO there is no need to repeat the function name) ~ 5b. Sometimes the deparse function comments are verbose and say like: + * Given a type OID and a parsetree that modified it, return an ObjTree + * representing the alter type. but sometimes - like deparse_AlterExtensionStmt() etc. - they don't bother to say anything at all. e.g. +/* + * Deparse ALTER EXTENSION .. UPDATE TO VERSION + */ +static ObjTree * +deparse_AlterExtensionStmt(Oid objectId, Node *parsetree) Either it is useful, so say it always, or it is not useful, so say it never. Pick one. ------ 6. GENERAL - json IMO change "json" -> "JSON" everywhere. Here are some examples: Line 7605: + * Conversion specifier, it determines how we expand the json element into Line 7699: + errmsg("missing element \"%s\" in json object", keyname))); Line 7857: + * Expand a json value as a quoted identifier. The value must be of type string. Line 7872: + * Expand a json value as a dot-separated-name. The value must be of type Line 7908: + * Expand a json value as a type name. Line 7966: + * Expand a json value as an operator name Line 7993: + * Expand a json value as a string. The value must be of type string or of Line 8031: + * Expand a json value as a string literal. Line 8070: + * Expand a json value as an integer quantity. Line 8083: + * Expand a json value as a role name. If the is_public element is set to Line 8111: + * Expand one json element into the output StringInfo according to the Line 8807: +{ oid => '4642', descr => 'deparse the DDL command into json format string', Line 8810: +{ oid => '4643', descr => 'expand json format DDL to a plain DDL command', ------ Kind Regards, Peter Smith. Fujitsu Australia
pgsql-hackers by date: