Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nvvFg-0002zX-5I for pgsql-hackers@arkaria.postgresql.org; Tue, 31 May 2022 06:21:12 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1nvvFe-0007c7-75 for pgsql-hackers@arkaria.postgresql.org; Tue, 31 May 2022 06:21:10 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nvvFd-0007by-Qp for pgsql-hackers@lists.postgresql.org; Tue, 31 May 2022 06:21:09 +0000 Received: from mail-qk1-x72e.google.com ([2607:f8b0:4864:20::72e]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1nvvFb-0004xt-1w for pgsql-hackers@lists.postgresql.org; Tue, 31 May 2022 06:21:09 +0000 Received: by mail-qk1-x72e.google.com with SMTP id 14so12518877qkl.6 for ; Mon, 30 May 2022 23:21:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=foXWp+I8keOeW0Iu+nWcUVQf3ymhcfNNT9x+YYcGlYg=; b=HaazoMLUyOwQeNQBu+mxyUGOf3jVoe3W0GWK6xlO05phL5NFeJzHuYVmem6j55ku8S 6SIb3vLed6ilV5yH6JjjzgLz1sRKNMHsYnbTckWLJ0TYuZ7slUydXmsLLaXqUWInCymv qDMzpC1zpxt3sGMFySVzeKV2yLNadA7kQul6rnnu1ebi9kcxBuMRNta9PzdbUr0QfM9q w4fmk+JR9ncnssJaPa0Den9Xgp+GzrULqax4muHhht68zxmcgpAf9L8y9qzKQ7lBCQHm n2wJsA+0Lw44XJUxN1R+59d8kExb0LFYN+UnxDIq2ulSYy7iKmFJOEXk87EukpKqiytK rOcg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=foXWp+I8keOeW0Iu+nWcUVQf3ymhcfNNT9x+YYcGlYg=; b=zm0aXJGiD6PWCdZHrBoO7PgUud0JP4boHzBRKCHWqbgGeMEv8zqsNijQ0Xh4P13r2t lb1SDq57UweVcVH4vkzKh0z1D2y1FSBtv4GP+2C/R/MQX3p9nt1jKKRwyx7QtIa+SgYU XP5NkIs1bQMbQDMNJbRQ30kKlLpWFIn5irBUHHDFm660ZLgytEzQYODOFaU73rE6fqSo FWiK3Q6rgAITXP5A9MtMBW6Cv1uYZn2CeHDBAeqkwd0z/Zm90BHijZ3Le+AOVaoxRgHw 4vkWr3o8+myW5DbMU8IF/TewspUiDBEVtQDIR3L56Gf7ZGh0287FjHG920RvdJmtJj/E j8Lg== X-Gm-Message-State: AOAM5325xpTGcGFPnPYJ/D1ZLFlhVeAjk/02OuiJak76N69m3etO8lPV MR9q7PoZmtXSM0ZU9G6Wkbbr/MWdjKNjYXRS2AA= X-Google-Smtp-Source: ABdhPJxorYc6rCZJeF3YVXdFmEvGtxI5efrcDng+JnvisiUJWc/sN+a4ivhj0EmuLpMHfqIPU5899j9wabPIVfY4yJk= X-Received: by 2002:a05:620a:3d0:b0:6a3:6346:d962 with SMTP id r16-20020a05620a03d000b006a36346d962mr33212721qkm.260.1653978065262; Mon, 30 May 2022 23:21:05 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Peter Smith Date: Tue, 31 May 2022 16:20:48 +1000 Message-ID: Subject: Re: Skipping schema changes in publication To: vignesh C Cc: "osumi.takamichi@fujitsu.com" , Amit Kapila , Bharath Rupireddy , PostgreSQL Hackers Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Here are my review comments for patch v7-0002. =3D=3D=3D=3D=3D=3D 1. doc/src/sgml/logical-replication.sgml @@ -1167,8 +1167,9 @@ CONTEXT: processing remote data for replication origin "pg_16395" during "INSER To add tables to a publication, the user must have ownership rights on = the table. To add all tables in schema to a publication, the user must be a - superuser. To create a publication that publishes all tables or all tables in - schema automatically, the user must be a superuser. + superuser. To add all tables to a publication, the user must be a super= user. + To create a publication that publishes all tables or all tables in sche= ma + automatically, the user must be a superuser. I felt that maybe this whole paragraph should be rearranged. Put the "create publication" parts before the "alter publication" parts; Re-word the sentences more similarly. I also felt the ALL TABLES and ALL TABLES IN SCHEMA etc should be written uppercase/literal since that is what was meant. SUGGESTION To create a publication using FOR ALL TABLES or FOR ALL TABLES IN SCHEMA, the user must be a superuser. To add ALL TABLES or ALL TABLES IN SCHEMA to a publication, the user must be a superuser. To add tables to a publication, the user must have ownership rights on the table. ~~~ 2. doc/src/sgml/ref/alter_publication.sgml @@ -82,8 +88,8 @@ ALTER PUBLICATION name RESET You must own the publication to use ALTER PUBLICATION. - Adding a table to a publication additionally requires owning that table= . - The ADD ALL TABLES IN SCHEMA, + Adding a table to or excluding a table from a publication additionally + requires owning that table. The ADD ALL TABLES IN SCHEMA, SET ALL TABLES IN SCHEMA to a publication and Isn't this missing some information that says ADD ALL TABLES requires the invoking user to be a superuser? ~~~ 3. doc/src/sgml/ref/alter_publication.sgml - examples + + Alter publication production_publication to pu= blish + all tables except users and + departments tables: + +ALTER PUBLICATION production_publication ADD ALL TABLES EXCEPT users, departments; + + I didn't think it needs to say "tables" 2x (e.g. remove the last "tables") ~~~ 4. doc/src/sgml/ref/create_publication.sgml - examples + + Create a publication that publishes all changes in all the tables excep= t for + the changes of users and + departments tables: + +CREATE PUBLICATION mypublication FOR ALL TABLES EXCEPT users, departments; + + I didn't think it needs to say "tables" 2x (e.g. remove the last "tables") ~~~ 5. src/backend/catalog/pg_publication.c foreach(lc, ancestors) { Oid ancestor =3D lfirst_oid(lc); - List *apubids =3D GetRelationPublications(ancestor); - List *aschemaPubids =3D NIL; + List *apubids =3D GetRelationPublications(ancestor, false); + List *aschemapubids =3D NIL; + List *aexceptpubids =3D NIL; level++; - if (list_member_oid(apubids, puboid)) + /* check if member of table publications */ + if (!list_member_oid(apubids, puboid)) { - topmost_relid =3D ancestor; - - if (ancestor_level) - *ancestor_level =3D level; - } - else - { - aschemaPubids =3D GetSchemaPublications(get_rel_namespace(ancestor)); - if (list_member_oid(aschemaPubids, puboid)) + /* check if member of schema publications */ + aschemapubids =3D GetSchemaPublications(get_rel_namespace(ancestor)); + if (!list_member_oid(aschemapubids, puboid)) { - topmost_relid =3D ancestor; - - if (ancestor_level) - *ancestor_level =3D level; + /* + * If the publication is all tables publication and the table + * is not part of exception tables. + */ + if (puballtables) + { + aexceptpubids =3D GetRelationPublications(ancestor, true); + if (list_member_oid(aexceptpubids, puboid)) + goto next; + } + else + goto next; } } + topmost_relid =3D ancestor; + + if (ancestor_level) + *ancestor_level =3D level; + +next: list_free(apubids); - list_free(aschemaPubids); + list_free(aschemapubids); + list_free(aexceptpubids); } I felt those negative (!) conditions and those goto are making this logic hard to understand. Can=E2=80=99t it be simplified more than this? Ev= en just having another bool flag might help make it easier. e.g. Perhaps something a bit like this (but add some comments) foreach(lc, ancestors) { Oid ancestor =3D lfirst_oid(lc); List *apubids =3D GetRelationPublications(ancestor); List *aschemaPubids =3D NIL; List *aexceptpubids =3D NIL; bool set_top =3D false; level++; set_top =3D list_member_oid(apubids, puboid); if (!set_top) { aschemaPubids =3D GetSchemaPublications(get_rel_namespace(ancestor)); set_top =3D list_member_oid(aschemaPubids, puboid); if (!set_top && puballtables) { aexceptpubids =3D GetRelationPublications(ancestor, true); set_top =3D !list_member_oid(aexceptpubids, puboid); } } if (set_top) { topmost_relid =3D ancestor; if (ancestor_level) *ancestor_level =3D level; } list_free(apubids); list_free(aschemapubids); list_free(aexceptpubids); } ------ 6. src/backend/commands/publicationcmds.c - CheckPublicationDefValues +/* + * Check if the publication has default values + * + * Check the following: + * a) Publication is not set with "FOR ALL TABLES" + * b) Publication is having default options + * c) Publication is not associated with schemas + * d) Publication is not associated with relations + */ +static bool +CheckPublicationDefValues(HeapTuple tup) I think Osumi-san already gave a review [1] about this same comment. So I only wanted to add that it should not say "options" here: "default options" -> "default publication parameter values" ~~~ 7. src/backend/commands/publicationcmds.c - AlterPublicationSetAllTables +#ifdef USE_ASSERT_CHECKING + Assert(!pubform->puballtables); +#endif Why is this #ifdef needed? Isn't that logic built into the Assert macro alr= eady? ~~~ 8. src/backend/commands/publicationcmds.c - AlterPublicationSetAllTables + /* set ALL TABLES flag */ Use uppercase 'S' to match other comments. ~~~ 9. src/backend/commands/publicationcmds.c - AlterPublication + if (!isdefault) + ereport(ERROR, + errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("adding ALL TABLES requires the publication to have default publication options, no tables/schemas associated and ALL TABLES flag should not be set"), + errhint("Use ALTER PUBLICATION ... RESET to reset the publication")); IMO this errmsg text is not very good but I think Osumi-san [1] has also given a review comment about the same errmsg. So I only wanted to add that should not say "options" here: "default publication options" -> "default publication parameter values" ~~~ 10. src/backend/parser/gram.y /**************************************************************************= *** * * ALTER PUBLICATION name SET ( options ) * * ALTER PUBLICATION name ADD pub_obj [, ...] * * ALTER PUBLICATION name DROP pub_obj [, ...] * * ALTER PUBLICATION name SET pub_obj [, ...] * * ALTER PUBLICATION name RESET * * pub_obj is one of: * * TABLE table_name [, ...] * ALL TABLES IN SCHEMA schema_name [, ...] * **************************************************************************= ***/ - Should the above comment be updated to mention also ADD ALL TABLES ... EXCEPT [TABLE] ... ~~~ 11. src/bin/pg_dump/pg_dump.c - dumpPublication + /* Include exception tables if the publication has except tables */ + for (cell =3D exceptinfo.head; cell; cell =3D cell->next) + { + PublicationRelInfo *pubrinfo =3D (PublicationRelInfo *) cell->ptr; + PublicationInfo *relpubinfo =3D pubrinfo->publication; + TableInfo *tbinfo; + + if (pubinfo =3D=3D relpubinfo) I am unsure if that variable 'relpubinfo' is of much use; it is only used one time. ~~~ 12. src/bin/pg_dump/t/002_pg_dump.pl I think there should be more test cases here: E.g.1. EXCEPT TABLE should also test a list of tables E.g.2. EXCEPT with optional TABLE keyword ommitted ~~~ 13. src/bin/psql/describe.c - question about the SQL Since the new 'except' is a boolean column, wouldn't it be more natural if all the SQL was treating it as one? e.g. should the SQL be saying "IS preexpect", "IS NOT prexcept"; instead of comparing preexpect to 't' and 'f' character. ~~~ 14. .../t/032_rep_changes_except_table.pl +# Test replication with publications created using FOR ALL TABLES EXCEPT T= ABLE +# option. +# Create schemas and tables on publisher "option" -> "clause" ------ [1] https://www.postgresql.org/message-id/TYCPR01MB83730A2F1D6A5303E9C1416A= EDD99%40TYCPR01MB8373.jpnprd01.prod.outlook.com Kind Regards, Peter Smith. Fujitsu Australia