diff options
author | Amit Kapila <akapila@postgresql.org> | 2025-01-23 15:28:37 +0530 |
---|---|---|
committer | Amit Kapila <akapila@postgresql.org> | 2025-01-23 15:28:37 +0530 |
commit | e65dbc9927fb86aa3c8a914ede6a6ae934384f5a (patch) | |
tree | baf5c64867d7376c40135fc115860c1339087204 | |
parent | eef4a33f62f7300765b5ffa8c966fa2fba50d176 (diff) | |
download | postgresql-e65dbc9927fb86aa3c8a914ede6a6ae934384f5a.tar.gz postgresql-e65dbc9927fb86aa3c8a914ede6a6ae934384f5a.zip |
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
-rw-r--r-- | doc/src/sgml/catalogs.sgml | 14 | ||||
-rw-r--r-- | doc/src/sgml/ref/create_publication.sgml | 29 | ||||
-rw-r--r-- | src/backend/catalog/pg_publication.c | 36 | ||||
-rw-r--r-- | src/backend/commands/publicationcmds.c | 68 | ||||
-rw-r--r-- | src/backend/replication/logical/proto.c | 66 | ||||
-rw-r--r-- | src/backend/replication/pgoutput/pgoutput.c | 36 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 2 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_dump.c | 17 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_dump.h | 3 | ||||
-rw-r--r-- | src/bin/pg_dump/t/002_pg_dump.pl | 4 | ||||
-rw-r--r-- | src/bin/psql/describe.c | 20 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/catalog/pg_publication.h | 26 | ||||
-rw-r--r-- | src/include/commands/publicationcmds.h | 2 | ||||
-rw-r--r-- | src/include/replication/logicalproto.h | 11 | ||||
-rw-r--r-- | src/test/regress/expected/publication.out | 179 | ||||
-rw-r--r-- | src/test/regress/sql/publication.sql | 41 | ||||
-rw-r--r-- | src/test/subscription/t/011_generated.pl | 67 | ||||
-rw-r--r-- | src/tools/pgindent/typedefs.list | 1 |
19 files changed, 394 insertions, 230 deletions
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index d3036c5ba9d..c88bcaa7df9 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -6396,6 +6396,20 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l <row> <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>pubgencols</structfield> <type>char</type> + </para> + <para> + Controls how to handle generated column replication when there is no + publication column list: + <literal>n</literal> = generated columns in the tables associated with + the publication should not be replicated, + <literal>s</literal> = stored generated columns in the tables associated + with the publication should be replicated. + </para></entry> + </row> + + <row> + <entry role="catalog_table_entry"><para role="column_definition"> <structfield>pubviaroot</structfield> <type>bool</type> </para> <para> diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml index 5e25536554a..e822ea2aaa9 100644 --- a/doc/src/sgml/ref/create_publication.sgml +++ b/doc/src/sgml/ref/create_publication.sgml @@ -89,10 +89,10 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable> <para> When a column list is specified, only the named columns are replicated. - The column list can contain generated columns as well. If no column list - is specified, all table columns (except generated columns) are replicated - through this publication, including any columns added later. It has no - effect on <literal>TRUNCATE</literal> commands. See + The column list can contain stored generated columns as well. If no + column list is specified, all table columns (except generated columns) + are replicated through this publication, including any columns added + later. It has no effect on <literal>TRUNCATE</literal> commands. See <xref linkend="logical-replication-col-lists"/> for details about column lists. </para> @@ -190,20 +190,31 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable> </varlistentry> <varlistentry id="sql-createpublication-params-with-publish-generated-columns"> - <term><literal>publish_generated_columns</literal> (<type>boolean</type>)</term> + <term><literal>publish_generated_columns</literal> (<type>enum</type>)</term> <listitem> <para> Specifies whether the generated columns present in the tables - associated with the publication should be replicated. - The default is <literal>false</literal>. + associated with the publication should be replicated. Possible values + are <literal>none</literal> and <literal>stored</literal>. + </para> + + <para> + The default is <literal>none</literal> meaning the generated + columns present in the tables associated with publication will not be + replicated. + </para> + + <para> + If set to <literal>stored</literal>, the stored generated columns + present in the tables associated with publication will be replicated. </para> <note> <para> If the subscriber is from a release prior to 18, then initial table synchronization won't copy generated columns even if parameter - <literal>publish_generated_columns</literal> is true in the - publisher. + <literal>publish_generated_columns</literal> is <literal>stored</literal> + in the publisher. </para> </note> </listitem> diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c index b89098f5e99..7900a8f6a13 100644 --- a/src/backend/catalog/pg_publication.c +++ b/src/backend/catalog/pg_publication.c @@ -622,10 +622,11 @@ pub_collist_to_bitmapset(Bitmapset *columns, Datum pubcols, MemoryContext mcxt) /* * Returns a bitmap representing the columns of the specified table. * - * Generated columns are included if include_gencols is true. + * Generated columns are included if include_gencols_type is + * PUBLISH_GENCOLS_STORED. */ Bitmapset * -pub_form_cols_map(Relation relation, bool include_gencols) +pub_form_cols_map(Relation relation, PublishGencolsType include_gencols_type) { Bitmapset *result = NULL; TupleDesc desc = RelationGetDescr(relation); @@ -634,9 +635,20 @@ pub_form_cols_map(Relation relation, bool include_gencols) { Form_pg_attribute att = TupleDescAttr(desc, i); - if (att->attisdropped || (att->attgenerated && !include_gencols)) + if (att->attisdropped) continue; + if (att->attgenerated) + { + /* We only support replication of STORED generated cols. */ + if (att->attgenerated != ATTRIBUTE_GENERATED_STORED) + continue; + + /* User hasn't requested to replicate STORED generated cols. */ + if (include_gencols_type != PUBLISH_GENCOLS_STORED) + continue; + } + result = bms_add_member(result, att->attnum); } @@ -1068,7 +1080,7 @@ GetPublication(Oid pubid) pub->pubactions.pubdelete = pubform->pubdelete; pub->pubactions.pubtruncate = pubform->pubtruncate; pub->pubviaroot = pubform->pubviaroot; - pub->pubgencols = pubform->pubgencols; + pub->pubgencols_type = pubform->pubgencols_type; ReleaseSysCache(tup); @@ -1276,9 +1288,23 @@ pg_get_publication_tables(PG_FUNCTION_ARGS) { Form_pg_attribute att = TupleDescAttr(desc, i); - if (att->attisdropped || (att->attgenerated && !pub->pubgencols)) + if (att->attisdropped) continue; + if (att->attgenerated) + { + /* We only support replication of STORED generated cols. */ + if (att->attgenerated != ATTRIBUTE_GENERATED_STORED) + continue; + + /* + * User hasn't requested to replicate STORED generated + * cols. + */ + if (pub->pubgencols_type != PUBLISH_GENCOLS_STORED) + continue; + } + attnums[nattnums++] = att->attnum; } diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c index 35747b3df5f..b49d9ab78bf 100644 --- a/src/backend/commands/publicationcmds.c +++ b/src/backend/commands/publicationcmds.c @@ -70,6 +70,7 @@ static void PublicationDropTables(Oid pubid, List *rels, bool missing_ok); static void PublicationAddSchemas(Oid pubid, List *schemas, bool if_not_exists, AlterPublicationStmt *stmt); static void PublicationDropSchemas(Oid pubid, List *schemas, bool missing_ok); +static char defGetGeneratedColsOption(DefElem *def); static void @@ -80,7 +81,7 @@ parse_publication_options(ParseState *pstate, bool *publish_via_partition_root_given, bool *publish_via_partition_root, bool *publish_generated_columns_given, - bool *publish_generated_columns) + char *publish_generated_columns) { ListCell *lc; @@ -94,7 +95,7 @@ parse_publication_options(ParseState *pstate, pubactions->pubdelete = true; pubactions->pubtruncate = true; *publish_via_partition_root = false; - *publish_generated_columns = false; + *publish_generated_columns = PUBLISH_GENCOLS_NONE; /* Parse options */ foreach(lc, options) @@ -160,7 +161,7 @@ parse_publication_options(ParseState *pstate, if (*publish_generated_columns_given) errorConflictingDefElem(defel, pstate); *publish_generated_columns_given = true; - *publish_generated_columns = defGetBoolean(defel); + *publish_generated_columns = defGetGeneratedColsOption(defel); } else ereport(ERROR, @@ -344,15 +345,16 @@ pub_rf_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, * by the column list. If any column is missing, *invalid_column_list is set * to true. * 2. Ensures that all the generated columns referenced in the REPLICA IDENTITY - * are published either by listing them in the column list or by enabling - * publish_generated_columns option. If any unpublished generated column is - * found, *invalid_gen_col is set to true. + * are published, either by being explicitly named in the column list or, if + * no column list is specified, by setting the option + * publish_generated_columns to stored. If any unpublished + * generated column is found, *invalid_gen_col is set to true. * * Returns true if any of the above conditions are not met. */ bool pub_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, - bool pubviaroot, bool pubgencols, + bool pubviaroot, char pubgencols_type, bool *invalid_column_list, bool *invalid_gen_col) { @@ -394,10 +396,10 @@ pub_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, /* * As we don't allow a column list with REPLICA IDENTITY FULL, the - * publish_generated_columns option must be set to true if the table + * publish_generated_columns option must be set to stored if the table * has any stored generated columns. */ - if (!pubgencols && + if (pubgencols_type != PUBLISH_GENCOLS_STORED && relation->rd_att->constr && relation->rd_att->constr->has_generated_stored) *invalid_gen_col = true; @@ -425,10 +427,10 @@ pub_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, if (columns == NULL) { /* - * The publish_generated_columns option must be set to true if the - * REPLICA IDENTITY contains any stored generated column. + * The publish_generated_columns option must be set to stored if + * the REPLICA IDENTITY contains any stored generated column. */ - if (!pubgencols && att->attgenerated) + if (pubgencols_type != PUBLISH_GENCOLS_STORED && att->attgenerated) { *invalid_gen_col = true; break; @@ -775,7 +777,7 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt) bool publish_via_partition_root_given; bool publish_via_partition_root; bool publish_generated_columns_given; - bool publish_generated_columns; + char publish_generated_columns; AclResult aclresult; List *relations = NIL; List *schemaidlist = NIL; @@ -834,8 +836,8 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt) BoolGetDatum(pubactions.pubtruncate); values[Anum_pg_publication_pubviaroot - 1] = BoolGetDatum(publish_via_partition_root); - values[Anum_pg_publication_pubgencols - 1] = - BoolGetDatum(publish_generated_columns); + values[Anum_pg_publication_pubgencols_type - 1] = + CharGetDatum(publish_generated_columns); tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); @@ -922,7 +924,7 @@ AlterPublicationOptions(ParseState *pstate, AlterPublicationStmt *stmt, bool publish_via_partition_root_given; bool publish_via_partition_root; bool publish_generated_columns_given; - bool publish_generated_columns; + char publish_generated_columns; ObjectAddress obj; Form_pg_publication pubform; List *root_relids = NIL; @@ -1046,8 +1048,8 @@ AlterPublicationOptions(ParseState *pstate, AlterPublicationStmt *stmt, if (publish_generated_columns_given) { - values[Anum_pg_publication_pubgencols - 1] = BoolGetDatum(publish_generated_columns); - replaces[Anum_pg_publication_pubgencols - 1] = true; + values[Anum_pg_publication_pubgencols_type - 1] = CharGetDatum(publish_generated_columns); + replaces[Anum_pg_publication_pubgencols_type - 1] = true; } tup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, @@ -2043,3 +2045,33 @@ AlterPublicationOwner_oid(Oid subid, Oid newOwnerId) table_close(rel, RowExclusiveLock); } + +/* + * Extract the publish_generated_columns option value from a DefElem. "stored" + * and "none" values are accepted. + */ +static char +defGetGeneratedColsOption(DefElem *def) +{ + char *sval; + + /* + * If no parameter value given, assume "stored" is meant. + */ + if (!def->arg) + return PUBLISH_GENCOLS_STORED; + + sval = defGetString(def); + + if (pg_strcasecmp(sval, "none") == 0) + return PUBLISH_GENCOLS_NONE; + if (pg_strcasecmp(sval, "stored") == 0) + return PUBLISH_GENCOLS_STORED; + + ereport(ERROR, + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("%s requires a \"none\" or \"stored\" value", + def->defname)); + + return PUBLISH_GENCOLS_NONE; /* keep compiler quiet */ +} diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c index bef350714db..dc72b7c8f77 100644 --- a/src/backend/replication/logical/proto.c +++ b/src/backend/replication/logical/proto.c @@ -30,11 +30,12 @@ #define TRUNCATE_RESTART_SEQS (1<<1) static void logicalrep_write_attrs(StringInfo out, Relation rel, - Bitmapset *columns, bool include_gencols); + Bitmapset *columns, + PublishGencolsType include_gencols_type); static void logicalrep_write_tuple(StringInfo out, Relation rel, TupleTableSlot *slot, bool binary, Bitmapset *columns, - bool include_gencols); + PublishGencolsType include_gencols_type); static void logicalrep_read_attrs(StringInfo in, LogicalRepRelation *rel); static void logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple); @@ -401,7 +402,8 @@ logicalrep_read_origin(StringInfo in, XLogRecPtr *origin_lsn) void logicalrep_write_insert(StringInfo out, TransactionId xid, Relation rel, TupleTableSlot *newslot, bool binary, - Bitmapset *columns, bool include_gencols) + Bitmapset *columns, + PublishGencolsType include_gencols_type) { pq_sendbyte(out, LOGICAL_REP_MSG_INSERT); @@ -413,7 +415,8 @@ logicalrep_write_insert(StringInfo out, TransactionId xid, Relation rel, pq_sendint32(out, RelationGetRelid(rel)); pq_sendbyte(out, 'N'); /* new tuple follows */ - logicalrep_write_tuple(out, rel, newslot, binary, columns, include_gencols); + logicalrep_write_tuple(out, rel, newslot, binary, columns, + include_gencols_type); } /* @@ -446,7 +449,8 @@ logicalrep_read_insert(StringInfo in, LogicalRepTupleData *newtup) void logicalrep_write_update(StringInfo out, TransactionId xid, Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot, - bool binary, Bitmapset *columns, bool include_gencols) + bool binary, Bitmapset *columns, + PublishGencolsType include_gencols_type) { pq_sendbyte(out, LOGICAL_REP_MSG_UPDATE); @@ -468,11 +472,12 @@ logicalrep_write_update(StringInfo out, TransactionId xid, Relation rel, else pq_sendbyte(out, 'K'); /* old key follows */ logicalrep_write_tuple(out, rel, oldslot, binary, columns, - include_gencols); + include_gencols_type); } pq_sendbyte(out, 'N'); /* new tuple follows */ - logicalrep_write_tuple(out, rel, newslot, binary, columns, include_gencols); + logicalrep_write_tuple(out, rel, newslot, binary, columns, + include_gencols_type); } /* @@ -522,7 +527,8 @@ logicalrep_read_update(StringInfo in, bool *has_oldtuple, void logicalrep_write_delete(StringInfo out, TransactionId xid, Relation rel, TupleTableSlot *oldslot, bool binary, - Bitmapset *columns, bool include_gencols) + Bitmapset *columns, + PublishGencolsType include_gencols_type) { Assert(rel->rd_rel->relreplident == REPLICA_IDENTITY_DEFAULT || rel->rd_rel->relreplident == REPLICA_IDENTITY_FULL || @@ -542,7 +548,8 @@ logicalrep_write_delete(StringInfo out, TransactionId xid, Relation rel, else pq_sendbyte(out, 'K'); /* old key follows */ - logicalrep_write_tuple(out, rel, oldslot, binary, columns, include_gencols); + logicalrep_write_tuple(out, rel, oldslot, binary, columns, + include_gencols_type); } /* @@ -658,7 +665,8 @@ logicalrep_write_message(StringInfo out, TransactionId xid, XLogRecPtr lsn, */ void logicalrep_write_rel(StringInfo out, TransactionId xid, Relation rel, - Bitmapset *columns, bool include_gencols) + Bitmapset *columns, + PublishGencolsType include_gencols_type) { char *relname; @@ -680,7 +688,7 @@ logicalrep_write_rel(StringInfo out, TransactionId xid, Relation rel, pq_sendbyte(out, rel->rd_rel->relreplident); /* send the attribute info */ - logicalrep_write_attrs(out, rel, columns, include_gencols); + logicalrep_write_attrs(out, rel, columns, include_gencols_type); } /* @@ -757,7 +765,8 @@ logicalrep_read_typ(StringInfo in, LogicalRepTyp *ltyp) */ static void logicalrep_write_tuple(StringInfo out, Relation rel, TupleTableSlot *slot, - bool binary, Bitmapset *columns, bool include_gencols) + bool binary, Bitmapset *columns, + PublishGencolsType include_gencols_type) { TupleDesc desc; Datum *values; @@ -771,7 +780,8 @@ logicalrep_write_tuple(StringInfo out, Relation rel, TupleTableSlot *slot, { Form_pg_attribute att = TupleDescAttr(desc, i); - if (!logicalrep_should_publish_column(att, columns, include_gencols)) + if (!logicalrep_should_publish_column(att, columns, + include_gencols_type)) continue; nliveatts++; @@ -789,7 +799,8 @@ logicalrep_write_tuple(StringInfo out, Relation rel, TupleTableSlot *slot, Form_pg_type typclass; Form_pg_attribute att = TupleDescAttr(desc, i); - if (!logicalrep_should_publish_column(att, columns, include_gencols)) + if (!logicalrep_should_publish_column(att, columns, + include_gencols_type)) continue; if (isnull[i]) @@ -908,7 +919,7 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple) */ static void logicalrep_write_attrs(StringInfo out, Relation rel, Bitmapset *columns, - bool include_gencols) + PublishGencolsType include_gencols_type) { TupleDesc desc; int i; @@ -923,7 +934,8 @@ logicalrep_write_attrs(StringInfo out, Relation rel, Bitmapset *columns, { Form_pg_attribute att = TupleDescAttr(desc, i); - if (!logicalrep_should_publish_column(att, columns, include_gencols)) + if (!logicalrep_should_publish_column(att, columns, + include_gencols_type)) continue; nliveatts++; @@ -941,7 +953,8 @@ logicalrep_write_attrs(StringInfo out, Relation rel, Bitmapset *columns, Form_pg_attribute att = TupleDescAttr(desc, i); uint8 flags = 0; - if (!logicalrep_should_publish_column(att, columns, include_gencols)) + if (!logicalrep_should_publish_column(att, columns, + include_gencols_type)) continue; /* REPLICA IDENTITY FULL means all columns are sent as part of key. */ @@ -1254,16 +1267,17 @@ logicalrep_message_type(LogicalRepMsgType action) * * 'columns' represents the publication column list (if any) for that table. * - * 'include_gencols' flag indicates whether generated columns should be + * 'include_gencols_type' value indicates whether generated columns should be * published when there is no column list. Typically, this will have the same * value as the 'publish_generated_columns' publication parameter. * * Note that generated columns can be published only when present in a - * publication column list, or when include_gencols is true. + * publication column list, or when include_gencols_type is + * PUBLISH_GENCOLS_STORED. */ bool logicalrep_should_publish_column(Form_pg_attribute att, Bitmapset *columns, - bool include_gencols) + PublishGencolsType include_gencols_type) { if (att->attisdropped) return false; @@ -1273,5 +1287,15 @@ logicalrep_should_publish_column(Form_pg_attribute att, Bitmapset *columns, return bms_is_member(att->attnum, columns); /* All non-generated columns are always published. */ - return att->attgenerated ? include_gencols : true; + if (!att->attgenerated) + return true; + + /* + * Stored generated columns are only published when the user sets + * publish_generated_columns as stored. + */ + if (att->attgenerated == ATTRIBUTE_GENERATED_STORED) + return include_gencols_type == PUBLISH_GENCOLS_STORED; + + return false; } diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c index 2b7499b34b9..a363c88ffc0 100644 --- a/src/backend/replication/pgoutput/pgoutput.c +++ b/src/backend/replication/pgoutput/pgoutput.c @@ -128,10 +128,13 @@ typedef struct RelationSyncEntry bool schema_sent; /* - * This is set if the 'publish_generated_columns' parameter is true, and - * the relation contains generated columns. + * This will be PUBLISH_GENCOLS_STORED if the relation contains generated + * columns and the 'publish_generated_columns' parameter is set to + * PUBLISH_GENCOLS_STORED. Otherwise, it will be PUBLISH_GENCOLS_NONE, + * indicating that no generated columns should be published, unless + * explicitly specified in the column list. */ - bool include_gencols; + PublishGencolsType include_gencols_type; List *streamed_txns; /* streamed toplevel transactions with this * schema */ @@ -763,7 +766,7 @@ send_relation_and_attrs(Relation relation, TransactionId xid, { TupleDesc desc = RelationGetDescr(relation); Bitmapset *columns = relentry->columns; - bool include_gencols = relentry->include_gencols; + PublishGencolsType include_gencols_type = relentry->include_gencols_type; int i; /* @@ -778,7 +781,8 @@ send_relation_and_attrs(Relation relation, TransactionId xid, { Form_pg_attribute att = TupleDescAttr(desc, i); - if (!logicalrep_should_publish_column(att, columns, include_gencols)) + if (!logicalrep_should_publish_column(att, columns, + include_gencols_type)) continue; if (att->atttypid < FirstGenbkiObjectId) @@ -790,7 +794,8 @@ send_relation_and_attrs(Relation relation, TransactionId xid, } OutputPluginPrepareWrite(ctx, false); - logicalrep_write_rel(ctx->out, xid, relation, columns, include_gencols); + logicalrep_write_rel(ctx->out, xid, relation, columns, + include_gencols_type); OutputPluginWrite(ctx, false); } @@ -1044,7 +1049,7 @@ check_and_init_gencol(PGOutputData *data, List *publications, /* There are no generated columns to be published. */ if (!gencolpresent) { - entry->include_gencols = false; + entry->include_gencols_type = PUBLISH_GENCOLS_NONE; return; } @@ -1064,10 +1069,10 @@ check_and_init_gencol(PGOutputData *data, List *publications, if (first) { - entry->include_gencols = pub->pubgencols; + entry->include_gencols_type = pub->pubgencols_type; first = false; } - else if (entry->include_gencols != pub->pubgencols) + else if (entry->include_gencols_type != pub->pubgencols_type) ereport(ERROR, errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot use different values of publish_generated_columns for table \"%s.%s\" in different publications", @@ -1131,7 +1136,8 @@ pgoutput_column_list_init(PGOutputData *data, List *publications, { MemoryContext oldcxt = MemoryContextSwitchTo(entry->entry_cxt); - relcols = pub_form_cols_map(relation, entry->include_gencols); + relcols = pub_form_cols_map(relation, + entry->include_gencols_type); MemoryContextSwitchTo(oldcxt); } @@ -1571,17 +1577,17 @@ pgoutput_change(LogicalDecodingContext *ctx, ReorderBufferTXN *txn, case REORDER_BUFFER_CHANGE_INSERT: logicalrep_write_insert(ctx->out, xid, targetrel, new_slot, data->binary, relentry->columns, - relentry->include_gencols); + relentry->include_gencols_type); break; case REORDER_BUFFER_CHANGE_UPDATE: logicalrep_write_update(ctx->out, xid, targetrel, old_slot, new_slot, data->binary, relentry->columns, - relentry->include_gencols); + relentry->include_gencols_type); break; case REORDER_BUFFER_CHANGE_DELETE: logicalrep_write_delete(ctx->out, xid, targetrel, old_slot, data->binary, relentry->columns, - relentry->include_gencols); + relentry->include_gencols_type); break; default: Assert(false); @@ -2032,7 +2038,7 @@ get_rel_sync_entry(PGOutputData *data, Relation relation) { entry->replicate_valid = false; entry->schema_sent = false; - entry->include_gencols = false; + entry->include_gencols_type = PUBLISH_GENCOLS_NONE; entry->streamed_txns = NIL; entry->pubactions.pubinsert = entry->pubactions.pubupdate = entry->pubactions.pubdelete = entry->pubactions.pubtruncate = false; @@ -2082,7 +2088,7 @@ get_rel_sync_entry(PGOutputData *data, Relation relation) * earlier definition. */ entry->schema_sent = false; - entry->include_gencols = false; + entry->include_gencols_type = PUBLISH_GENCOLS_NONE; list_free(entry->streamed_txns); entry->streamed_txns = NIL; bms_free(entry->columns); diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 43219a9629c..ee39d085ebe 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -5820,7 +5820,7 @@ RelationBuildPublicationDesc(Relation relation, PublicationDesc *pubdesc) if ((pubform->pubupdate || pubform->pubdelete) && pub_contains_invalid_column(pubid, relation, ancestors, pubform->pubviaroot, - pubform->pubgencols, + pubform->pubgencols_type, &invalid_column_list, &invalid_gen_col)) { diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 8f73a5df956..9b840fc400a 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -50,6 +50,7 @@ #include "catalog/pg_default_acl_d.h" #include "catalog/pg_largeobject_d.h" #include "catalog/pg_proc_d.h" +#include "catalog/pg_publication_d.h" #include "catalog/pg_subscription_d.h" #include "catalog/pg_type_d.h" #include "common/connect.h" @@ -4290,7 +4291,7 @@ getPublications(Archive *fout) int i_pubdelete; int i_pubtruncate; int i_pubviaroot; - int i_pubgencols; + int i_pubgencols_type; int i, ntups; @@ -4315,9 +4316,9 @@ getPublications(Archive *fout) appendPQExpBufferStr(query, "false AS pubviaroot, "); if (fout->remoteVersion >= 180000) - appendPQExpBufferStr(query, "p.pubgencols "); + appendPQExpBufferStr(query, "p.pubgencols_type "); else - appendPQExpBufferStr(query, "false AS pubgencols "); + appendPQExpBufferStr(query, CppAsString2(PUBLISH_GENCOLS_NONE) " AS pubgencols_type "); appendPQExpBufferStr(query, "FROM pg_publication p"); @@ -4338,7 +4339,7 @@ getPublications(Archive *fout) i_pubdelete = PQfnumber(res, "pubdelete"); i_pubtruncate = PQfnumber(res, "pubtruncate"); i_pubviaroot = PQfnumber(res, "pubviaroot"); - i_pubgencols = PQfnumber(res, "pubgencols"); + i_pubgencols_type = PQfnumber(res, "pubgencols_type"); pubinfo = pg_malloc(ntups * sizeof(PublicationInfo)); @@ -4363,8 +4364,8 @@ getPublications(Archive *fout) (strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0); pubinfo[i].pubviaroot = (strcmp(PQgetvalue(res, i, i_pubviaroot), "t") == 0); - pubinfo[i].pubgencols = - (strcmp(PQgetvalue(res, i, i_pubgencols), "t") == 0); + pubinfo[i].pubgencols_type = + *(PQgetvalue(res, i, i_pubgencols_type)); /* Decide whether we want to dump it */ selectDumpableObject(&(pubinfo[i].dobj), fout); @@ -4446,8 +4447,8 @@ dumpPublication(Archive *fout, const PublicationInfo *pubinfo) if (pubinfo->pubviaroot) appendPQExpBufferStr(query, ", publish_via_partition_root = true"); - if (pubinfo->pubgencols) - appendPQExpBufferStr(query, ", publish_generated_columns = true"); + if (pubinfo->pubgencols_type == PUBLISH_GENCOLS_STORED) + appendPQExpBufferStr(query, ", publish_generated_columns = stored"); appendPQExpBufferStr(query, ");\n"); diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index f62b564ed1b..7139c88a69a 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -15,6 +15,7 @@ #define PG_DUMP_H #include "pg_backup.h" +#include "catalog/pg_publication_d.h" #define oidcmp(x,y) ( ((x) < (y) ? -1 : ((x) > (y)) ? 1 : 0) ) @@ -638,7 +639,7 @@ typedef struct _PublicationInfo bool pubdelete; bool pubtruncate; bool pubviaroot; - bool pubgencols; + PublishGencolsType pubgencols_type; } PublicationInfo; /* diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index a643a73270e..805ba9f49fd 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -3054,9 +3054,9 @@ my %tests = ( 'CREATE PUBLICATION pub5' => { create_order => 50, create_sql => - 'CREATE PUBLICATION pub5 WITH (publish_generated_columns = true);', + 'CREATE PUBLICATION pub5 WITH (publish_generated_columns = stored);', regexp => qr/^ - \QCREATE PUBLICATION pub5 WITH (publish = 'insert, update, delete, truncate', publish_generated_columns = true);\E + \QCREATE PUBLICATION pub5 WITH (publish = 'insert, update, delete, truncate', publish_generated_columns = stored);\E /xm, like => { %full_runs, section_post_data => 1, }, }, diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 8c0ad8439eb..2e84b61f184 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -24,6 +24,7 @@ #include "catalog/pg_constraint_d.h" #include "catalog/pg_default_acl_d.h" #include "catalog/pg_proc_d.h" +#include "catalog/pg_publication_d.h" #include "catalog/pg_statistic_ext_d.h" #include "catalog/pg_subscription_d.h" #include "catalog/pg_type_d.h" @@ -6372,7 +6373,12 @@ listPublications(const char *pattern) gettext_noop("Truncates")); if (pset.sversion >= 180000) appendPQExpBuffer(&buf, - ",\n pubgencols AS \"%s\"", + ",\n (CASE pubgencols_type\n" + " WHEN '%c' THEN 'none'\n" + " WHEN '%c' THEN 'stored'\n" + " END) AS \"%s\"", + PUBLISH_GENCOLS_NONE, + PUBLISH_GENCOLS_STORED, gettext_noop("Generated columns")); if (pset.sversion >= 130000) appendPQExpBuffer(&buf, @@ -6500,11 +6506,17 @@ describePublications(const char *pattern) ", false AS pubtruncate"); if (has_pubgencols) - appendPQExpBufferStr(&buf, - ", pubgencols"); + appendPQExpBuffer(&buf, + ", (CASE pubgencols_type\n" + " WHEN '%c' THEN 'none'\n" + " WHEN '%c' THEN 'stored'\n" + " END) AS \"%s\"\n", + PUBLISH_GENCOLS_NONE, + PUBLISH_GENCOLS_STORED, + gettext_noop("Generated columns")); else appendPQExpBufferStr(&buf, - ", false AS pubgencols"); + ", 'none' AS pubgencols"); if (has_pubviaroot) appendPQExpBufferStr(&buf, diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 28de0c83342..586b83f2f4d 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202501171 +#define CATALOG_VERSION_NO 202501231 #endif diff --git a/src/include/catalog/pg_publication.h b/src/include/catalog/pg_publication.h index 3c2ae2a960c..9e6cddcac4c 100644 --- a/src/include/catalog/pg_publication.h +++ b/src/include/catalog/pg_publication.h @@ -55,8 +55,11 @@ CATALOG(pg_publication,6104,PublicationRelationId) /* true if partition changes are published using root schema */ bool pubviaroot; - /* true if generated columns data should be published */ - bool pubgencols; + /* + * 'n'(none) if generated column data should not be published. 's'(stored) + * if stored generated column data should be published. + */ + char pubgencols_type; } FormData_pg_publication; /* ---------------- @@ -107,13 +110,27 @@ typedef struct PublicationDesc bool gencols_valid_for_delete; } PublicationDesc; +#ifdef EXPOSE_TO_CLIENT_CODE + +typedef enum PublishGencolsType +{ + /* Generated columns present should not be replicated. */ + PUBLISH_GENCOLS_NONE = 'n', + + /* Generated columns present should be replicated. */ + PUBLISH_GENCOLS_STORED = 's', + +} PublishGencolsType; + +#endif /* EXPOSE_TO_CLIENT_CODE */ + typedef struct Publication { Oid oid; char *name; bool alltables; bool pubviaroot; - bool pubgencols; + PublishGencolsType pubgencols_type; PublicationActions pubactions; } Publication; @@ -171,6 +188,7 @@ extern ObjectAddress publication_add_schema(Oid pubid, Oid schemaid, extern Bitmapset *pub_collist_to_bitmapset(Bitmapset *columns, Datum pubcols, MemoryContext mcxt); -extern Bitmapset *pub_form_cols_map(Relation relation, bool include_gencols); +extern Bitmapset *pub_form_cols_map(Relation relation, + PublishGencolsType include_gencols_type); #endif /* PG_PUBLICATION_H */ diff --git a/src/include/commands/publicationcmds.h b/src/include/commands/publicationcmds.h index 170c5ce00f0..e11a942ea0f 100644 --- a/src/include/commands/publicationcmds.h +++ b/src/include/commands/publicationcmds.h @@ -35,7 +35,7 @@ extern bool pub_rf_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot); extern bool pub_contains_invalid_column(Oid pubid, Relation relation, List *ancestors, bool pubviaroot, - bool pubgencols, + char pubgencols_type, bool *invalid_column_list, bool *invalid_gen_col); diff --git a/src/include/replication/logicalproto.h b/src/include/replication/logicalproto.h index 7012247825d..b261c60d3fa 100644 --- a/src/include/replication/logicalproto.h +++ b/src/include/replication/logicalproto.h @@ -225,19 +225,20 @@ extern char *logicalrep_read_origin(StringInfo in, XLogRecPtr *origin_lsn); extern void logicalrep_write_insert(StringInfo out, TransactionId xid, Relation rel, TupleTableSlot *newslot, bool binary, Bitmapset *columns, - bool include_gencols); + PublishGencolsType include_gencols_type); extern LogicalRepRelId logicalrep_read_insert(StringInfo in, LogicalRepTupleData *newtup); extern void logicalrep_write_update(StringInfo out, TransactionId xid, Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot, bool binary, - Bitmapset *columns, bool include_gencols); + Bitmapset *columns, + PublishGencolsType include_gencols_type); extern LogicalRepRelId logicalrep_read_update(StringInfo in, bool *has_oldtuple, LogicalRepTupleData *oldtup, LogicalRepTupleData *newtup); extern void logicalrep_write_delete(StringInfo out, TransactionId xid, Relation rel, TupleTableSlot *oldslot, bool binary, Bitmapset *columns, - bool include_gencols); + PublishGencolsType include_gencols_type); extern LogicalRepRelId logicalrep_read_delete(StringInfo in, LogicalRepTupleData *oldtup); extern void logicalrep_write_truncate(StringInfo out, TransactionId xid, @@ -249,7 +250,7 @@ extern void logicalrep_write_message(StringInfo out, TransactionId xid, XLogRecP bool transactional, const char *prefix, Size sz, const char *message); extern void logicalrep_write_rel(StringInfo out, TransactionId xid, Relation rel, Bitmapset *columns, - bool include_gencols); + PublishGencolsType include_gencols_type); extern LogicalRepRelation *logicalrep_read_rel(StringInfo in); extern void logicalrep_write_typ(StringInfo out, TransactionId xid, Oid typoid); @@ -274,6 +275,6 @@ extern void logicalrep_read_stream_abort(StringInfo in, extern const char *logicalrep_message_type(LogicalRepMsgType action); extern bool logicalrep_should_publish_column(Form_pg_attribute att, Bitmapset *columns, - bool include_gencols); + PublishGencolsType include_gencols_type); #endif /* LOGICAL_PROTO_H */ diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out index c48f11f2935..bc3898fbe58 100644 --- a/src/test/regress/expected/publication.out +++ b/src/test/regress/expected/publication.out @@ -17,7 +17,7 @@ SELECT obj_description(p.oid, 'pg_publication') FROM pg_publication p; (1 row) SET client_min_messages = 'ERROR'; -CREATE PUBLICATION testpib_ins_trunct WITH (publish = insert); +CREATE PUBLICATION testpub_ins_trunct WITH (publish = insert); RESET client_min_messages; ALTER PUBLICATION testpub_default SET (publish = update); -- error cases @@ -29,18 +29,18 @@ CREATE PUBLICATION testpub_xxx WITH (publish_via_partition_root = 'true', publis ERROR: conflicting or redundant options LINE 1: ...ub_xxx WITH (publish_via_partition_root = 'true', publish_vi... ^ -CREATE PUBLICATION testpub_xxx WITH (publish_generated_columns = 'true', publish_generated_columns = '0'); +CREATE PUBLICATION testpub_xxx WITH (publish_generated_columns = stored, publish_generated_columns = none); ERROR: conflicting or redundant options -LINE 1: ...pub_xxx WITH (publish_generated_columns = 'true', publish_ge... +LINE 1: ...pub_xxx WITH (publish_generated_columns = stored, publish_ge... ^ -CREATE PUBLICATION testpub_xxx WITH (publish_generated_columns = 'foo'); -ERROR: publish_generated_columns requires a Boolean value +CREATE PUBLICATION testpub_xxx WITH (publish_generated_columns = foo); +ERROR: publish_generated_columns requires a "none" or "stored" value \dRp List of publications Name | Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------+--------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - testpib_ins_trunct | regress_publication_user | f | t | f | f | f | f | f - testpub_default | regress_publication_user | f | f | t | f | f | f | f + testpub_default | regress_publication_user | f | f | t | f | f | none | f + testpub_ins_trunct | regress_publication_user | f | t | f | f | f | none | f (2 rows) ALTER PUBLICATION testpub_default SET (publish = 'insert, update, delete'); @@ -48,8 +48,8 @@ ALTER PUBLICATION testpub_default SET (publish = 'insert, update, delete'); List of publications Name | Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------+--------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - testpib_ins_trunct | regress_publication_user | f | t | f | f | f | f | f - testpub_default | regress_publication_user | f | t | t | t | f | f | f + testpub_default | regress_publication_user | f | t | t | t | f | none | f + testpub_ins_trunct | regress_publication_user | f | t | f | f | f | none | f (2 rows) --- adding tables @@ -96,7 +96,7 @@ ALTER PUBLICATION testpub_fortable ADD TABLES IN SCHEMA pub_test; Publication testpub_fortable Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "public.testpub_tbl1" Tables from schemas: @@ -108,7 +108,7 @@ ALTER PUBLICATION testpub_fortable DROP TABLES IN SCHEMA pub_test; Publication testpub_fortable Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "public.testpub_tbl1" @@ -118,7 +118,7 @@ ALTER PUBLICATION testpub_fortable SET TABLES IN SCHEMA pub_test; Publication testpub_fortable Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test" @@ -132,7 +132,7 @@ RESET client_min_messages; Publication testpub_for_tbl_schema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "pub_test.testpub_nopk" Tables from schemas: @@ -153,7 +153,7 @@ ALTER PUBLICATION testpub_forschema ADD TABLE pub_test.testpub_nopk; Publication testpub_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "pub_test.testpub_nopk" Tables from schemas: @@ -165,7 +165,7 @@ ALTER PUBLICATION testpub_forschema DROP TABLE pub_test.testpub_nopk; Publication testpub_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test" @@ -179,7 +179,7 @@ ALTER PUBLICATION testpub_forschema SET TABLE pub_test.testpub_nopk; Publication testpub_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "pub_test.testpub_nopk" @@ -206,7 +206,7 @@ Not-null constraints: Publication testpub_foralltables Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | t | t | t | f | f | f | f + regress_publication_user | t | t | t | f | f | none | f (1 row) DROP TABLE testpub_tbl2; @@ -221,7 +221,7 @@ RESET client_min_messages; Publication testpub3 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "public.testpub_tbl3" "public.testpub_tbl3a" @@ -230,7 +230,7 @@ Tables: Publication testpub4 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "public.testpub_tbl3" @@ -254,7 +254,7 @@ ALTER PUBLICATION testpub_forparted ADD TABLE testpub_parted; Publication testpub_forparted Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "public.testpub_parted" @@ -272,7 +272,7 @@ ALTER PUBLICATION testpub_forparted SET (publish_via_partition_root = true); Publication testpub_forparted Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | t + regress_publication_user | f | t | t | t | t | none | t Tables: "public.testpub_parted" @@ -304,7 +304,7 @@ RESET client_min_messages; Publication testpub5 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | f | f | f | f | f + regress_publication_user | f | t | f | f | f | none | f Tables: "public.testpub_rf_tbl1" "public.testpub_rf_tbl2" WHERE ((c <> 'test'::text) AND (d < 5)) @@ -320,7 +320,7 @@ ALTER PUBLICATION testpub5 ADD TABLE testpub_rf_tbl3 WHERE (e > 1000 AND e < 200 Publication testpub5 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | f | f | f | f | f + regress_publication_user | f | t | f | f | f | none | f Tables: "public.testpub_rf_tbl1" "public.testpub_rf_tbl2" WHERE ((c <> 'test'::text) AND (d < 5)) @@ -339,7 +339,7 @@ ALTER PUBLICATION testpub5 DROP TABLE testpub_rf_tbl2; Publication testpub5 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | f | f | f | f | f + regress_publication_user | f | t | f | f | f | none | f Tables: "public.testpub_rf_tbl1" "public.testpub_rf_tbl3" WHERE ((e > 1000) AND (e < 2000)) @@ -350,7 +350,7 @@ ALTER PUBLICATION testpub5 SET TABLE testpub_rf_tbl3 WHERE (e > 300 AND e < 500) Publication testpub5 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | f | f | f | f | f + regress_publication_user | f | t | f | f | f | none | f Tables: "public.testpub_rf_tbl3" WHERE ((e > 300) AND (e < 500)) @@ -386,7 +386,7 @@ RESET client_min_messages; Publication testpub_syntax1 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | f | f | f | f | f + regress_publication_user | f | t | f | f | f | none | f Tables: "public.testpub_rf_tbl1" "public.testpub_rf_tbl3" WHERE (e < 999) @@ -399,7 +399,7 @@ RESET client_min_messages; Publication testpub_syntax2 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | f | f | f | f | f + regress_publication_user | f | t | f | f | f | none | f Tables: "public.testpub_rf_tbl1" "testpub_rf_schema1.testpub_rf_tbl5" WHERE (h < 999) @@ -517,7 +517,7 @@ RESET client_min_messages; Publication testpub6 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "testpub_rf_schema2.testpub_rf_tbl6" WHERE (i < 99) Tables from schemas: @@ -692,7 +692,7 @@ ERROR: cannot update table "testpub_gencol" DETAIL: Replica identity must not contain unpublished generated columns. DROP PUBLICATION pub_gencol; -- ok - generated column "b" is published explicitly -CREATE PUBLICATION pub_gencol FOR TABLE testpub_gencol with (publish_generated_columns = true); +CREATE PUBLICATION pub_gencol FOR TABLE testpub_gencol with (publish_generated_columns = stored); UPDATE testpub_gencol SET a = 100 WHERE a = 1; DROP PUBLICATION pub_gencol; DROP TABLE testpub_gencol; @@ -767,7 +767,7 @@ ALTER PUBLICATION testpub_table_ins ADD TABLE testpub_tbl5 (a); -- ok Publication testpub_table_ins Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | f | f | t | f | f + regress_publication_user | f | t | f | f | t | none | f Tables: "public.testpub_tbl5" (a) @@ -960,7 +960,7 @@ ALTER PUBLICATION testpub_both_filters ADD TABLE testpub_tbl_both_filters (a,c) Publication testpub_both_filters Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "public.testpub_tbl_both_filters" (a, c) WHERE (c <> 1) @@ -1171,7 +1171,7 @@ ERROR: publication "testpub_fortbl" already exists Publication testpub_fortbl Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "pub_test.testpub_nopk" "public.testpub_tbl1" @@ -1183,7 +1183,7 @@ DETAIL: This operation is not supported for views. ALTER PUBLICATION testpub_default ADD TABLE testpub_tbl1; ALTER PUBLICATION testpub_default SET TABLE testpub_tbl1; ALTER PUBLICATION testpub_default ADD TABLE pub_test.testpub_nopk; -ALTER PUBLICATION testpib_ins_trunct ADD TABLE pub_test.testpub_nopk, testpub_tbl1; +ALTER PUBLICATION testpub_ins_trunct ADD TABLE pub_test.testpub_nopk, testpub_tbl1; \d+ pub_test.testpub_nopk Table "pub_test.testpub_nopk" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description @@ -1191,9 +1191,9 @@ ALTER PUBLICATION testpib_ins_trunct ADD TABLE pub_test.testpub_nopk, testpub_tb foo | integer | | | | plain | | bar | integer | | | | plain | | Publications: - "testpib_ins_trunct" "testpub_default" "testpub_fortbl" + "testpub_ins_trunct" \d+ testpub_tbl1 Table "public.testpub_tbl1" @@ -1204,9 +1204,9 @@ Publications: Indexes: "testpub_tbl1_pkey" PRIMARY KEY, btree (id) Publications: - "testpib_ins_trunct" "testpub_default" "testpub_fortbl" + "testpub_ins_trunct" Not-null constraints: "testpub_tbl1_id_not_null" NOT NULL "id" @@ -1214,7 +1214,7 @@ Not-null constraints: Publication testpub_default Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | f | f | f + regress_publication_user | f | t | t | t | f | none | f Tables: "pub_test.testpub_nopk" "public.testpub_tbl1" @@ -1232,8 +1232,8 @@ ERROR: relation "testpub_nopk" is not part of the publication Indexes: "testpub_tbl1_pkey" PRIMARY KEY, btree (id) Publications: - "testpib_ins_trunct" "testpub_fortbl" + "testpub_ins_trunct" Not-null constraints: "testpub_tbl1_id_not_null" NOT NULL "id" @@ -1297,7 +1297,7 @@ DROP TABLE testpub_tbl1; Publication testpub_default Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | f | f | f + regress_publication_user | f | t | t | t | f | none | f (1 row) -- fail - must be owner of publication @@ -1310,7 +1310,7 @@ ALTER PUBLICATION testpub_default RENAME TO testpub_foo; List of publications Name | Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root -------------+--------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - testpub_foo | regress_publication_user | f | t | t | t | f | f | f + testpub_foo | regress_publication_user | f | t | t | t | f | none | f (1 row) -- rename back to keep the rest simple @@ -1320,7 +1320,7 @@ ALTER PUBLICATION testpub_default OWNER TO regress_publication_user2; List of publications Name | Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root -----------------+---------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - testpub_default | regress_publication_user2 | f | t | t | t | f | f | f + testpub_default | regress_publication_user2 | f | t | t | t | f | none | f (1 row) -- adding schemas and tables @@ -1339,7 +1339,7 @@ CREATE PUBLICATION testpub1_forschema FOR TABLES IN SCHEMA pub_test1; Publication testpub1_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" @@ -1348,7 +1348,7 @@ CREATE PUBLICATION testpub2_forschema FOR TABLES IN SCHEMA pub_test1, pub_test2, Publication testpub2_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" "pub_test2" @@ -1365,7 +1365,7 @@ RESET client_min_messages; Publication testpub3_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "public" @@ -1373,7 +1373,7 @@ Tables from schemas: Publication testpub4_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "CURRENT_SCHEMA" @@ -1381,7 +1381,7 @@ Tables from schemas: Publication testpub5_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "CURRENT_SCHEMA" "public" @@ -1390,7 +1390,7 @@ Tables from schemas: Publication testpub6_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "CURRENT_SCHEMA" "public" @@ -1399,7 +1399,7 @@ Tables from schemas: Publication testpub_fortable Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "CURRENT_SCHEMA.CURRENT_SCHEMA" @@ -1436,7 +1436,7 @@ DROP SCHEMA pub_test3; Publication testpub2_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" "pub_test2" @@ -1447,7 +1447,7 @@ ALTER SCHEMA pub_test1 RENAME to pub_test1_renamed; Publication testpub2_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1_renamed" "pub_test2" @@ -1457,7 +1457,7 @@ ALTER SCHEMA pub_test1_renamed RENAME to pub_test1; Publication testpub2_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" "pub_test2" @@ -1468,7 +1468,7 @@ ALTER PUBLICATION testpub1_forschema ADD TABLES IN SCHEMA pub_test2; Publication testpub1_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" "pub_test2" @@ -1480,7 +1480,7 @@ ERROR: schema "non_existent_schema" does not exist Publication testpub1_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" "pub_test2" @@ -1492,7 +1492,7 @@ ERROR: schema "pub_test1" is already member of publication "testpub1_forschema" Publication testpub1_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" "pub_test2" @@ -1503,7 +1503,7 @@ ALTER PUBLICATION testpub1_forschema DROP TABLES IN SCHEMA pub_test2; Publication testpub1_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" @@ -1514,7 +1514,7 @@ ERROR: tables from schema "pub_test2" are not part of the publication Publication testpub1_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" @@ -1525,7 +1525,7 @@ ERROR: schema "non_existent_schema" does not exist Publication testpub1_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" @@ -1535,7 +1535,7 @@ ALTER PUBLICATION testpub1_forschema DROP TABLES IN SCHEMA pub_test1; Publication testpub1_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f (1 row) -- alter publication set multiple schema @@ -1544,7 +1544,7 @@ ALTER PUBLICATION testpub1_forschema SET TABLES IN SCHEMA pub_test1, pub_test2; Publication testpub1_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" "pub_test2" @@ -1556,7 +1556,7 @@ ERROR: schema "non_existent_schema" does not exist Publication testpub1_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" "pub_test2" @@ -1568,7 +1568,7 @@ ALTER PUBLICATION testpub1_forschema SET TABLES IN SCHEMA pub_test1, pub_test1; Publication testpub1_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" @@ -1650,7 +1650,7 @@ RESET client_min_messages; Publication testpub3_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f (1 row) ALTER PUBLICATION testpub3_forschema SET TABLES IN SCHEMA pub_test1; @@ -1658,7 +1658,7 @@ ALTER PUBLICATION testpub3_forschema SET TABLES IN SCHEMA pub_test1; Publication testpub3_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables from schemas: "pub_test1" @@ -1671,7 +1671,7 @@ RESET client_min_messages; Publication testpub_forschema_fortable Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "pub_test2.tbl1" Tables from schemas: @@ -1681,7 +1681,7 @@ Tables from schemas: Publication testpub_fortable_forschema Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "pub_test2.tbl1" Tables from schemas: @@ -1696,7 +1696,7 @@ LINE 1: CREATE PUBLICATION testpub_error FOR pub_test2.tbl1; DETAIL: One of TABLE or TABLES IN SCHEMA must be specified before a standalone table or schema name. DROP VIEW testpub_view; DROP PUBLICATION testpub_default; -DROP PUBLICATION testpib_ins_trunct; +DROP PUBLICATION testpub_ins_trunct; DROP PUBLICATION testpub_fortbl; DROP PUBLICATION testpub1_forschema; DROP PUBLICATION testpub2_forschema; @@ -1797,76 +1797,87 @@ DROP TABLE sch1.tbl1; DROP SCHEMA sch1 cascade; DROP SCHEMA sch2 cascade; -- ====================================================== --- Test the publication 'publish_generated_columns' parameter enabled or disabled +-- Test the 'publish_generated_columns' parameter with the following values: +-- 'stored', 'none', and the default (no value specified), which defaults to +-- 'stored'. SET client_min_messages = 'ERROR'; -CREATE PUBLICATION pub1 FOR ALL TABLES WITH (publish_generated_columns=1); +CREATE PUBLICATION pub1 FOR ALL TABLES WITH (publish_generated_columns = stored); \dRp+ pub1 Publication pub1 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | t | t | t | t | t | t | f + regress_publication_user | t | t | t | t | t | stored | f (1 row) -CREATE PUBLICATION pub2 FOR ALL TABLES WITH (publish_generated_columns=0); +CREATE PUBLICATION pub2 FOR ALL TABLES WITH (publish_generated_columns = none); \dRp+ pub2 Publication pub2 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | t | t | t | t | t | f | f + regress_publication_user | t | t | t | t | t | none | f +(1 row) + +CREATE PUBLICATION pub3 FOR ALL TABLES WITH (publish_generated_columns); +\dRp+ pub3 + Publication pub3 + Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root +--------------------------+------------+---------+---------+---------+-----------+-------------------+---------- + regress_publication_user | t | t | t | t | t | stored | f (1 row) DROP PUBLICATION pub1; DROP PUBLICATION pub2; --- Test the 'publish_generated_columns' parameter enabled or disabled for +DROP PUBLICATION pub3; +-- Test the 'publish_generated_columns' parameter as 'none' and 'stored' for -- different scenarios with/without generated columns in column lists. CREATE TABLE gencols (a int, gen1 int GENERATED ALWAYS AS (a * 2) STORED); --- Generated columns in column list, when 'publish_generated_columns'=false -CREATE PUBLICATION pub1 FOR table gencols(a, gen1) WITH (publish_generated_columns=false); +-- Generated columns in column list, when 'publish_generated_columns'='none' +CREATE PUBLICATION pub1 FOR table gencols(a, gen1) WITH (publish_generated_columns = none); \dRp+ pub1 Publication pub1 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "public.gencols" (a, gen1) --- Generated columns in column list, when 'publish_generated_columns'=true -CREATE PUBLICATION pub2 FOR table gencols(a, gen1) WITH (publish_generated_columns=true); +-- Generated columns in column list, when 'publish_generated_columns'='stored' +CREATE PUBLICATION pub2 FOR table gencols(a, gen1) WITH (publish_generated_columns = stored); \dRp+ pub2 Publication pub2 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | t | f + regress_publication_user | f | t | t | t | t | stored | f Tables: "public.gencols" (a, gen1) --- Generated columns in column list, then set 'publication_generate_columns'=false -ALTER PUBLICATION pub2 SET (publish_generated_columns = false); +-- Generated columns in column list, then set 'publish_generated_columns'='none' +ALTER PUBLICATION pub2 SET (publish_generated_columns = none); \dRp+ pub2 Publication pub2 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "public.gencols" (a, gen1) --- Remove generated columns from column list, when 'publish_generated_columns'=false +-- Remove generated columns from column list, when 'publish_generated_columns'='none' ALTER PUBLICATION pub2 SET TABLE gencols(a); \dRp+ pub2 Publication pub2 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "public.gencols" (a) --- Add generated columns in column list, when 'publish_generated_columns'=false +-- Add generated columns in column list, when 'publish_generated_columns'='none' ALTER PUBLICATION pub2 SET TABLE gencols(a, gen1); \dRp+ pub2 Publication pub2 Owner | All tables | Inserts | Updates | Deletes | Truncates | Generated columns | Via root --------------------------+------------+---------+---------+---------+-----------+-------------------+---------- - regress_publication_user | f | t | t | t | t | f | f + regress_publication_user | f | t | t | t | t | none | f Tables: "public.gencols" (a, gen1) diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql index c4c21a95d0e..47f0329c244 100644 --- a/src/test/regress/sql/publication.sql +++ b/src/test/regress/sql/publication.sql @@ -15,7 +15,7 @@ COMMENT ON PUBLICATION testpub_default IS 'test publication'; SELECT obj_description(p.oid, 'pg_publication') FROM pg_publication p; SET client_min_messages = 'ERROR'; -CREATE PUBLICATION testpib_ins_trunct WITH (publish = insert); +CREATE PUBLICATION testpub_ins_trunct WITH (publish = insert); RESET client_min_messages; ALTER PUBLICATION testpub_default SET (publish = update); @@ -24,8 +24,8 @@ ALTER PUBLICATION testpub_default SET (publish = update); CREATE PUBLICATION testpub_xxx WITH (foo); CREATE PUBLICATION testpub_xxx WITH (publish = 'cluster, vacuum'); CREATE PUBLICATION testpub_xxx WITH (publish_via_partition_root = 'true', publish_via_partition_root = '0'); -CREATE PUBLICATION testpub_xxx WITH (publish_generated_columns = 'true', publish_generated_columns = '0'); -CREATE PUBLICATION testpub_xxx WITH (publish_generated_columns = 'foo'); +CREATE PUBLICATION testpub_xxx WITH (publish_generated_columns = stored, publish_generated_columns = none); +CREATE PUBLICATION testpub_xxx WITH (publish_generated_columns = foo); \dRp @@ -415,7 +415,7 @@ UPDATE testpub_gencol SET a = 100 WHERE a = 1; DROP PUBLICATION pub_gencol; -- ok - generated column "b" is published explicitly -CREATE PUBLICATION pub_gencol FOR TABLE testpub_gencol with (publish_generated_columns = true); +CREATE PUBLICATION pub_gencol FOR TABLE testpub_gencol with (publish_generated_columns = stored); UPDATE testpub_gencol SET a = 100 WHERE a = 1; DROP PUBLICATION pub_gencol; @@ -795,7 +795,7 @@ ALTER PUBLICATION testpub_default ADD TABLE testpub_tbl1; ALTER PUBLICATION testpub_default SET TABLE testpub_tbl1; ALTER PUBLICATION testpub_default ADD TABLE pub_test.testpub_nopk; -ALTER PUBLICATION testpib_ins_trunct ADD TABLE pub_test.testpub_nopk, testpub_tbl1; +ALTER PUBLICATION testpub_ins_trunct ADD TABLE pub_test.testpub_nopk, testpub_tbl1; \d+ pub_test.testpub_nopk \d+ testpub_tbl1 @@ -1074,7 +1074,7 @@ CREATE PUBLICATION testpub_error FOR pub_test2.tbl1; DROP VIEW testpub_view; DROP PUBLICATION testpub_default; -DROP PUBLICATION testpib_ins_trunct; +DROP PUBLICATION testpub_ins_trunct; DROP PUBLICATION testpub_fortbl; DROP PUBLICATION testpub1_forschema; DROP PUBLICATION testpub2_forschema; @@ -1142,37 +1142,42 @@ DROP SCHEMA sch1 cascade; DROP SCHEMA sch2 cascade; -- ====================================================== --- Test the publication 'publish_generated_columns' parameter enabled or disabled +-- Test the 'publish_generated_columns' parameter with the following values: +-- 'stored', 'none', and the default (no value specified), which defaults to +-- 'stored'. SET client_min_messages = 'ERROR'; -CREATE PUBLICATION pub1 FOR ALL TABLES WITH (publish_generated_columns=1); +CREATE PUBLICATION pub1 FOR ALL TABLES WITH (publish_generated_columns = stored); \dRp+ pub1 -CREATE PUBLICATION pub2 FOR ALL TABLES WITH (publish_generated_columns=0); +CREATE PUBLICATION pub2 FOR ALL TABLES WITH (publish_generated_columns = none); \dRp+ pub2 +CREATE PUBLICATION pub3 FOR ALL TABLES WITH (publish_generated_columns); +\dRp+ pub3 DROP PUBLICATION pub1; DROP PUBLICATION pub2; +DROP PUBLICATION pub3; --- Test the 'publish_generated_columns' parameter enabled or disabled for +-- Test the 'publish_generated_columns' parameter as 'none' and 'stored' for -- different scenarios with/without generated columns in column lists. CREATE TABLE gencols (a int, gen1 int GENERATED ALWAYS AS (a * 2) STORED); --- Generated columns in column list, when 'publish_generated_columns'=false -CREATE PUBLICATION pub1 FOR table gencols(a, gen1) WITH (publish_generated_columns=false); +-- Generated columns in column list, when 'publish_generated_columns'='none' +CREATE PUBLICATION pub1 FOR table gencols(a, gen1) WITH (publish_generated_columns = none); \dRp+ pub1 --- Generated columns in column list, when 'publish_generated_columns'=true -CREATE PUBLICATION pub2 FOR table gencols(a, gen1) WITH (publish_generated_columns=true); +-- Generated columns in column list, when 'publish_generated_columns'='stored' +CREATE PUBLICATION pub2 FOR table gencols(a, gen1) WITH (publish_generated_columns = stored); \dRp+ pub2 --- Generated columns in column list, then set 'publication_generate_columns'=false -ALTER PUBLICATION pub2 SET (publish_generated_columns = false); +-- Generated columns in column list, then set 'publish_generated_columns'='none' +ALTER PUBLICATION pub2 SET (publish_generated_columns = none); \dRp+ pub2 --- Remove generated columns from column list, when 'publish_generated_columns'=false +-- Remove generated columns from column list, when 'publish_generated_columns'='none' ALTER PUBLICATION pub2 SET TABLE gencols(a); \dRp+ pub2 --- Add generated columns in column list, when 'publish_generated_columns'=false +-- Add generated columns in column list, when 'publish_generated_columns'='none' ALTER PUBLICATION pub2 SET TABLE gencols(a, gen1); \dRp+ pub2 diff --git a/src/test/subscription/t/011_generated.pl b/src/test/subscription/t/011_generated.pl index 45587371400..5970bb47360 100644 --- a/src/test/subscription/t/011_generated.pl +++ b/src/test/subscription/t/011_generated.pl @@ -103,16 +103,16 @@ $node_publisher->safe_psql('postgres', "DROP PUBLICATION pub1"); # ============================================================================= # Exercise logical replication of a generated column to a subscriber side # regular column. This is done both when the publication parameter -# 'publish_generated_columns' is set to false (to confirm existing default -# behavior), and is set to true (to confirm replication occurs). +# 'publish_generated_columns' is set to 'none' (to confirm existing default +# behavior), and is set to 'stored' (to confirm replication occurs). # # The test environment is set up as follows: # # - Publication pub1 on the 'postgres' database. -# pub1 has publish_generated_columns=false. +# pub1 has publish_generated_columns as 'none'. # # - Publication pub2 on the 'postgres' database. -# pub2 has publish_generated_columns=true. +# pub2 has publish_generated_columns as 'stored'. # # - Subscription sub1 on the 'postgres' database for publication pub1. # @@ -132,8 +132,8 @@ $node_publisher->safe_psql( 'postgres', qq( CREATE TABLE tab_gen_to_nogen (a int, b int GENERATED ALWAYS AS (a * 2) STORED); INSERT INTO tab_gen_to_nogen (a) VALUES (1), (2), (3); - CREATE PUBLICATION regress_pub1_gen_to_nogen FOR TABLE tab_gen_to_nogen WITH (publish_generated_columns = false); - CREATE PUBLICATION regress_pub2_gen_to_nogen FOR TABLE tab_gen_to_nogen WITH (publish_generated_columns = true); + CREATE PUBLICATION regress_pub1_gen_to_nogen FOR TABLE tab_gen_to_nogen WITH (publish_generated_columns = none); + CREATE PUBLICATION regress_pub2_gen_to_nogen FOR TABLE tab_gen_to_nogen WITH (publish_generated_columns = stored); )); # Create the table and subscription in the 'postgres' database. @@ -157,28 +157,28 @@ $node_subscriber->wait_for_subscription_sync($node_publisher, 'regress_sub2_gen_to_nogen', 'test_pgc_true'); # Verify that generated column data is not copied during the initial -# synchronization when publish_generated_columns is set to false. +# synchronization when publish_generated_columns is set to 'none'. $result = $node_subscriber->safe_psql('postgres', "SELECT a, b FROM tab_gen_to_nogen ORDER BY a"); is( $result, qq(1| 2| -3|), 'tab_gen_to_nogen initial sync, when publish_generated_columns=false'); +3|), 'tab_gen_to_nogen initial sync, when publish_generated_columns=none'); # Verify that generated column data is copied during the initial synchronization -# when publish_generated_columns is set to true. +# when publish_generated_columns is set to 'stored'. $result = $node_subscriber->safe_psql('test_pgc_true', "SELECT a, b FROM tab_gen_to_nogen ORDER BY a"); is( $result, qq(1|2 2|4 3|6), - 'tab_gen_to_nogen initial sync, when publish_generated_columns=true'); + 'tab_gen_to_nogen initial sync, when publish_generated_columns=stored'); # Insert data to verify incremental replication. $node_publisher->safe_psql('postgres', "INSERT INTO tab_gen_to_nogen VALUES (4), (5)"); # Verify that the generated column data is not replicated during incremental -# replication when publish_generated_columns is set to false. +# replication when publish_generated_columns is set to 'none'. $node_publisher->wait_for_catchup('regress_sub1_gen_to_nogen'); $result = $node_subscriber->safe_psql('postgres', "SELECT a, b FROM tab_gen_to_nogen ORDER BY a"); @@ -187,11 +187,11 @@ is( $result, qq(1| 3| 4| 5|), - 'tab_gen_to_nogen incremental replication, when publish_generated_columns=false' + 'tab_gen_to_nogen incremental replication, when publish_generated_columns=none' ); # Verify that generated column data is replicated during incremental -# synchronization when publish_generated_columns is set to true. +# synchronization when publish_generated_columns is set to 'stored'. $node_publisher->wait_for_catchup('regress_sub2_gen_to_nogen'); $result = $node_subscriber->safe_psql('test_pgc_true', "SELECT a, b FROM tab_gen_to_nogen ORDER BY a"); @@ -200,7 +200,7 @@ is( $result, qq(1|2 3|6 4|8 5|10), - 'tab_gen_to_nogen incremental replication, when publish_generated_columns=true' + 'tab_gen_to_nogen incremental replication, when publish_generated_columns=stored' ); # cleanup @@ -221,15 +221,16 @@ $node_subscriber->safe_psql('postgres', "DROP DATABASE test_pgc_true"); # with the publication parameter 'publish_generated_columns'. # # Test: Column lists take precedence, so generated columns in a column list -# will be replicated even when publish_generated_columns=false. +# will be replicated even when publish_generated_columns is 'none'. # # Test: When there is a column list, only those generated columns named in the -# column list will be replicated even when publish_generated_columns=true. +# column list will be replicated even when publish_generated_columns is +# 'stored'. # ============================================================================= # -------------------------------------------------- # Test Case: Publisher replicates the column list, including generated columns, -# even when the publish_generated_columns option is set to false. +# even when the publish_generated_columns option is set to 'none'. # -------------------------------------------------- # Create table and publication. Insert data to verify initial sync. @@ -237,7 +238,7 @@ $node_publisher->safe_psql( 'postgres', qq( CREATE TABLE tab2 (a int, gen1 int GENERATED ALWAYS AS (a * 2) STORED); INSERT INTO tab2 (a) VALUES (1), (2); - CREATE PUBLICATION pub1 FOR table tab2(gen1) WITH (publish_generated_columns=false); + CREATE PUBLICATION pub1 FOR table tab2(gen1) WITH (publish_generated_columns=none); )); # Create table and subscription. @@ -250,19 +251,19 @@ $node_subscriber->safe_psql( # Wait for initial sync. $node_subscriber->wait_for_subscription_sync($node_publisher, 'sub1'); -# Initial sync test when publish_generated_columns=false. -# Verify 'gen1' is replicated regardless of the false parameter value. +# Initial sync test when publish_generated_columns is 'none'. +# Verify 'gen1' is replicated regardless of the 'none' parameter value. $result = $node_subscriber->safe_psql('postgres', "SELECT * FROM tab2 ORDER BY gen1"); is( $result, qq(|2 |4), - 'tab2 initial sync, when publish_generated_columns=false'); + 'tab2 initial sync, when publish_generated_columns=none'); # Insert data to verify incremental replication. $node_publisher->safe_psql('postgres', "INSERT INTO tab2 VALUES (3), (4)"); -# Incremental replication test when publish_generated_columns=false. -# Verify 'gen1' is replicated regardless of the false parameter value. +# Incremental replication test when publish_generated_columns is 'none'. +# Verify 'gen1' is replicated regardless of the 'none' parameter value. $node_publisher->wait_for_catchup('sub1'); $result = $node_subscriber->safe_psql('postgres', "SELECT * FROM tab2 ORDER BY gen1"); @@ -270,15 +271,15 @@ is( $result, qq(|2 |4 |6 |8), - 'tab2 incremental replication, when publish_generated_columns=false'); + 'tab2 incremental replication, when publish_generated_columns=none'); # cleanup $node_subscriber->safe_psql('postgres', "DROP SUBSCRIPTION sub1"); $node_publisher->safe_psql('postgres', "DROP PUBLICATION pub1"); # -------------------------------------------------- -# Test Case: Even when publish_generated_columns is set to true, the publisher -# only publishes the data of columns specified in the column list, +# Test Case: Even when publish_generated_columns is set to 'stored', the +# publisher only publishes the data of columns specified in the column list, # skipping other generated and non-generated columns. # -------------------------------------------------- @@ -287,7 +288,7 @@ $node_publisher->safe_psql( 'postgres', qq( CREATE TABLE tab3 (a int, gen1 int GENERATED ALWAYS AS (a * 2) STORED, gen2 int GENERATED ALWAYS AS (a * 2) STORED); INSERT INTO tab3 (a) VALUES (1), (2); - CREATE PUBLICATION pub1 FOR table tab3(gen1) WITH (publish_generated_columns=true); + CREATE PUBLICATION pub1 FOR table tab3(gen1) WITH (publish_generated_columns=stored); )); # Create table and subscription. @@ -300,19 +301,19 @@ $node_subscriber->safe_psql( # Wait for initial sync. $node_subscriber->wait_for_subscription_sync($node_publisher, 'sub1'); -# Initial sync test when publish_generated_columns=true. -# Verify only 'gen1' is replicated regardless of the true parameter value. +# Initial sync test when publish_generated_columns is 'stored'. +# Verify only 'gen1' is replicated regardless of the 'stored' parameter value. $result = $node_subscriber->safe_psql('postgres', "SELECT * FROM tab3 ORDER BY gen1"); is( $result, qq(|2| |4|), - 'tab3 initial sync, when publish_generated_columns=true'); + 'tab3 initial sync, when publish_generated_columns=stored'); # Insert data to verify incremental replication. $node_publisher->safe_psql('postgres', "INSERT INTO tab3 VALUES (3), (4)"); -# Incremental replication test when publish_generated_columns=true. -# Verify only 'gen1' is replicated regardless of the true parameter value. +# Incremental replication test when publish_generated_columns is 'stored'. +# Verify only 'gen1' is replicated regardless of the 'stored' parameter value. $node_publisher->wait_for_catchup('sub1'); $result = $node_subscriber->safe_psql('postgres', "SELECT * FROM tab3 ORDER BY gen1"); @@ -320,7 +321,7 @@ is( $result, qq(|2| |4| |6| |8|), - 'tab3 incremental replication, when publish_generated_columns=true'); + 'tab3 incremental replication, when publish_generated_columns=stored'); # cleanup $node_subscriber->safe_psql('postgres', "DROP SUBSCRIPTION sub1"); diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index d5aa5c295ae..a2644a2e653 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2276,6 +2276,7 @@ PublicationPartOpt PublicationRelInfo PublicationSchemaInfo PublicationTable +PublishGencolsType PullFilter PullFilterOps PushFilter |