Skip to content

Commit e65dbc9

Browse files
author
Amit Kapila
committed
Change publication's publish_generated_columns option type to enum.
The current boolean publish_generated_columns option only supports a binary choice, which is insufficient for future enhancements where generated columns can be of different types (e.g., stored or virtual). The supported values for the publish_generated_columns option are 'none' and 'stored'. Author: Vignesh C <vignesh21@gmail.com> Reviewed-by: Peter Smith <smithpb2250@gmail.com> Reviewed-by: Peter Eisentraut <peter@eisentraut.org> Reviewed-by: Amit Kapila <amit.kapila16@gmail.com> Discussion: https://postgr.es/m/d718d219-dd47-4a33-bb97-56e8fc4da994@eisentraut.org Discussion: https://postgr.es/m/B80D17B2-2C8E-4C7D-87F2-E5B4BE3C069E@gmail.com
1 parent eef4a33 commit e65dbc9

File tree

19 files changed

+394
-230
lines changed

19 files changed

+394
-230
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6394,6 +6394,20 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
63946394
</para></entry>
63956395
</row>
63966396

6397+
<row>
6398+
<entry role="catalog_table_entry"><para role="column_definition">
6399+
<structfield>pubgencols</structfield> <type>char</type>
6400+
</para>
6401+
<para>
6402+
Controls how to handle generated column replication when there is no
6403+
publication column list:
6404+
<literal>n</literal> = generated columns in the tables associated with
6405+
the publication should not be replicated,
6406+
<literal>s</literal> = stored generated columns in the tables associated
6407+
with the publication should be replicated.
6408+
</para></entry>
6409+
</row>
6410+
63976411
<row>
63986412
<entry role="catalog_table_entry"><para role="column_definition">
63996413
<structfield>pubviaroot</structfield> <type>bool</type>

doc/src/sgml/ref/create_publication.sgml

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
8989

9090
<para>
9191
When a column list is specified, only the named columns are replicated.
92-
The column list can contain generated columns as well. If no column list
93-
is specified, all table columns (except generated columns) are replicated
94-
through this publication, including any columns added later. It has no
95-
effect on <literal>TRUNCATE</literal> commands. See
92+
The column list can contain stored generated columns as well. If no
93+
column list is specified, all table columns (except generated columns)
94+
are replicated through this publication, including any columns added
95+
later. It has no effect on <literal>TRUNCATE</literal> commands. See
9696
<xref linkend="logical-replication-col-lists"/> for details about column
9797
lists.
9898
</para>
@@ -190,20 +190,31 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable>
190190
</varlistentry>
191191

192192
<varlistentry id="sql-createpublication-params-with-publish-generated-columns">
193-
<term><literal>publish_generated_columns</literal> (<type>boolean</type>)</term>
193+
<term><literal>publish_generated_columns</literal> (<type>enum</type>)</term>
194194
<listitem>
195195
<para>
196196
Specifies whether the generated columns present in the tables
197-
associated with the publication should be replicated.
198-
The default is <literal>false</literal>.
197+
associated with the publication should be replicated. Possible values
198+
are <literal>none</literal> and <literal>stored</literal>.
199+
</para>
200+
201+
<para>
202+
The default is <literal>none</literal> meaning the generated
203+
columns present in the tables associated with publication will not be
204+
replicated.
205+
</para>
206+
207+
<para>
208+
If set to <literal>stored</literal>, the stored generated columns
209+
present in the tables associated with publication will be replicated.
199210
</para>
200211

201212
<note>
202213
<para>
203214
If the subscriber is from a release prior to 18, then initial table
204215
synchronization won't copy generated columns even if parameter
205-
<literal>publish_generated_columns</literal> is true in the
206-
publisher.
216+
<literal>publish_generated_columns</literal> is <literal>stored</literal>
217+
in the publisher.
207218
</para>
208219
</note>
209220
</listitem>

src/backend/catalog/pg_publication.c

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -622,10 +622,11 @@ pub_collist_to_bitmapset(Bitmapset *columns, Datum pubcols, MemoryContext mcxt)
622622
/*
623623
* Returns a bitmap representing the columns of the specified table.
624624
*
625-
* Generated columns are included if include_gencols is true.
625+
* Generated columns are included if include_gencols_type is
626+
* PUBLISH_GENCOLS_STORED.
626627
*/
627628
Bitmapset *
628-
pub_form_cols_map(Relation relation, bool include_gencols)
629+
pub_form_cols_map(Relation relation, PublishGencolsType include_gencols_type)
629630
{
630631
Bitmapset *result = NULL;
631632
TupleDesc desc = RelationGetDescr(relation);
@@ -634,9 +635,20 @@ pub_form_cols_map(Relation relation, bool include_gencols)
634635
{
635636
Form_pg_attribute att = TupleDescAttr(desc, i);
636637

637-
if (att->attisdropped || (att->attgenerated && !include_gencols))
638+
if (att->attisdropped)
638639
continue;
639640

641+
if (att->attgenerated)
642+
{
643+
/* We only support replication of STORED generated cols. */
644+
if (att->attgenerated != ATTRIBUTE_GENERATED_STORED)
645+
continue;
646+
647+
/* User hasn't requested to replicate STORED generated cols. */
648+
if (include_gencols_type != PUBLISH_GENCOLS_STORED)
649+
continue;
650+
}
651+
640652
result = bms_add_member(result, att->attnum);
641653
}
642654

@@ -1068,7 +1080,7 @@ GetPublication(Oid pubid)
10681080
pub->pubactions.pubdelete = pubform->pubdelete;
10691081
pub->pubactions.pubtruncate = pubform->pubtruncate;
10701082
pub->pubviaroot = pubform->pubviaroot;
1071-
pub->pubgencols = pubform->pubgencols;
1083+
pub->pubgencols_type = pubform->pubgencols_type;
10721084

10731085
ReleaseSysCache(tup);
10741086

@@ -1276,9 +1288,23 @@ pg_get_publication_tables(PG_FUNCTION_ARGS)
12761288
{
12771289
Form_pg_attribute att = TupleDescAttr(desc, i);
12781290

1279-
if (att->attisdropped || (att->attgenerated && !pub->pubgencols))
1291+
if (att->attisdropped)
12801292
continue;
12811293

1294+
if (att->attgenerated)
1295+
{
1296+
/* We only support replication of STORED generated cols. */
1297+
if (att->attgenerated != ATTRIBUTE_GENERATED_STORED)
1298+
continue;
1299+
1300+
/*
1301+
* User hasn't requested to replicate STORED generated
1302+
* cols.
1303+
*/
1304+
if (pub->pubgencols_type != PUBLISH_GENCOLS_STORED)
1305+
continue;
1306+
}
1307+
12821308
attnums[nattnums++] = att->attnum;
12831309
}
12841310

src/backend/commands/publicationcmds.c

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ static void PublicationDropTables(Oid pubid, List *rels, bool missing_ok);
7070
static void PublicationAddSchemas(Oid pubid, List *schemas, bool if_not_exists,
7171
AlterPublicationStmt *stmt);
7272
static void PublicationDropSchemas(Oid pubid, List *schemas, bool missing_ok);
73+
static char defGetGeneratedColsOption(DefElem *def);
7374

7475

7576
static void
@@ -80,7 +81,7 @@ parse_publication_options(ParseState *pstate,
8081
bool *publish_via_partition_root_given,
8182
bool *publish_via_partition_root,
8283
bool *publish_generated_columns_given,
83-
bool *publish_generated_columns)
84+
char *publish_generated_columns)
8485
{
8586
ListCell *lc;
8687

@@ -94,7 +95,7 @@ parse_publication_options(ParseState *pstate,
9495
pubactions->pubdelete = true;
9596
pubactions->pubtruncate = true;
9697
*publish_via_partition_root = false;
97-
*publish_generated_columns = false;
98+
*publish_generated_columns = PUBLISH_GENCOLS_NONE;
9899

99100
/* Parse options */
100101
foreach(lc, options)
@@ -160,7 +161,7 @@ parse_publication_options(ParseState *pstate,
160161
if (*publish_generated_columns_given)
161162
errorConflictingDefElem(defel, pstate);
162163
*publish_generated_columns_given = true;
163-
*publish_generated_columns = defGetBoolean(defel);
164+
*publish_generated_columns = defGetGeneratedColsOption(defel);
164165
}
165166
else
166167
ereport(ERROR,
@@ -344,15 +345,16 @@ pub_rf_contains_invalid_column(Oid pubid, Relation relation, List *ancestors,
344345
* by the column list. If any column is missing, *invalid_column_list is set
345346
* to true.
346347
* 2. Ensures that all the generated columns referenced in the REPLICA IDENTITY
347-
* are published either by listing them in the column list or by enabling
348-
* publish_generated_columns option. If any unpublished generated column is
349-
* found, *invalid_gen_col is set to true.
348+
* are published, either by being explicitly named in the column list or, if
349+
* no column list is specified, by setting the option
350+
* publish_generated_columns to stored. If any unpublished
351+
* generated column is found, *invalid_gen_col is set to true.
350352
*
351353
* Returns true if any of the above conditions are not met.
352354
*/
353355
bool
354356
pub_contains_invalid_column(Oid pubid, Relation relation, List *ancestors,
355-
bool pubviaroot, bool pubgencols,
357+
bool pubviaroot, char pubgencols_type,
356358
bool *invalid_column_list,
357359
bool *invalid_gen_col)
358360
{
@@ -394,10 +396,10 @@ pub_contains_invalid_column(Oid pubid, Relation relation, List *ancestors,
394396

395397
/*
396398
* As we don't allow a column list with REPLICA IDENTITY FULL, the
397-
* publish_generated_columns option must be set to true if the table
399+
* publish_generated_columns option must be set to stored if the table
398400
* has any stored generated columns.
399401
*/
400-
if (!pubgencols &&
402+
if (pubgencols_type != PUBLISH_GENCOLS_STORED &&
401403
relation->rd_att->constr &&
402404
relation->rd_att->constr->has_generated_stored)
403405
*invalid_gen_col = true;
@@ -425,10 +427,10 @@ pub_contains_invalid_column(Oid pubid, Relation relation, List *ancestors,
425427
if (columns == NULL)
426428
{
427429
/*
428-
* The publish_generated_columns option must be set to true if the
429-
* REPLICA IDENTITY contains any stored generated column.
430+
* The publish_generated_columns option must be set to stored if
431+
* the REPLICA IDENTITY contains any stored generated column.
430432
*/
431-
if (!pubgencols && att->attgenerated)
433+
if (pubgencols_type != PUBLISH_GENCOLS_STORED && att->attgenerated)
432434
{
433435
*invalid_gen_col = true;
434436
break;
@@ -775,7 +777,7 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
775777
bool publish_via_partition_root_given;
776778
bool publish_via_partition_root;
777779
bool publish_generated_columns_given;
778-
bool publish_generated_columns;
780+
char publish_generated_columns;
779781
AclResult aclresult;
780782
List *relations = NIL;
781783
List *schemaidlist = NIL;
@@ -834,8 +836,8 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt)
834836
BoolGetDatum(pubactions.pubtruncate);
835837
values[Anum_pg_publication_pubviaroot - 1] =
836838
BoolGetDatum(publish_via_partition_root);
837-
values[Anum_pg_publication_pubgencols - 1] =
838-
BoolGetDatum(publish_generated_columns);
839+
values[Anum_pg_publication_pubgencols_type - 1] =
840+
CharGetDatum(publish_generated_columns);
839841

840842
tup = heap_form_tuple(RelationGetDescr(rel), values, nulls);
841843

@@ -922,7 +924,7 @@ AlterPublicationOptions(ParseState *pstate, AlterPublicationStmt *stmt,
922924
bool publish_via_partition_root_given;
923925
bool publish_via_partition_root;
924926
bool publish_generated_columns_given;
925-
bool publish_generated_columns;
927+
char publish_generated_columns;
926928
ObjectAddress obj;
927929
Form_pg_publication pubform;
928930
List *root_relids = NIL;
@@ -1046,8 +1048,8 @@ AlterPublicationOptions(ParseState *pstate, AlterPublicationStmt *stmt,
10461048

10471049
if (publish_generated_columns_given)
10481050
{
1049-
values[Anum_pg_publication_pubgencols - 1] = BoolGetDatum(publish_generated_columns);
1050-
replaces[Anum_pg_publication_pubgencols - 1] = true;
1051+
values[Anum_pg_publication_pubgencols_type - 1] = CharGetDatum(publish_generated_columns);
1052+
replaces[Anum_pg_publication_pubgencols_type - 1] = true;
10511053
}
10521054

10531055
tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls,
@@ -2043,3 +2045,33 @@ AlterPublicationOwner_oid(Oid subid, Oid newOwnerId)
20432045

20442046
table_close(rel, RowExclusiveLock);
20452047
}
2048+
2049+
/*
2050+
* Extract the publish_generated_columns option value from a DefElem. "stored"
2051+
* and "none" values are accepted.
2052+
*/
2053+
static char
2054+
defGetGeneratedColsOption(DefElem *def)
2055+
{
2056+
char *sval;
2057+
2058+
/*
2059+
* If no parameter value given, assume "stored" is meant.
2060+
*/
2061+
if (!def->arg)
2062+
return PUBLISH_GENCOLS_STORED;
2063+
2064+
sval = defGetString(def);
2065+
2066+
if (pg_strcasecmp(sval, "none") == 0)
2067+
return PUBLISH_GENCOLS_NONE;
2068+
if (pg_strcasecmp(sval, "stored") == 0)
2069+
return PUBLISH_GENCOLS_STORED;
2070+
2071+
ereport(ERROR,
2072+
errcode(ERRCODE_SYNTAX_ERROR),
2073+
errmsg("%s requires a \"none\" or \"stored\" value",
2074+
def->defname));
2075+
2076+
return PUBLISH_GENCOLS_NONE; /* keep compiler quiet */
2077+
}

0 commit comments

Comments
 (0)