Change publication's publish_generated_columns option type to enum.
authorAmit Kapila <akapila@postgresql.org>
Thu, 23 Jan 2025 09:58:37 +0000 (15:28 +0530)
committerAmit Kapila <akapila@postgresql.org>
Thu, 23 Jan 2025 09:58:37 +0000 (15:28 +0530)
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

19 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/ref/create_publication.sgml
src/backend/catalog/pg_publication.c
src/backend/commands/publicationcmds.c
src/backend/replication/logical/proto.c
src/backend/replication/pgoutput/pgoutput.c
src/backend/utils/cache/relcache.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/bin/pg_dump/t/002_pg_dump.pl
src/bin/psql/describe.c
src/include/catalog/catversion.h
src/include/catalog/pg_publication.h
src/include/commands/publicationcmds.h
src/include/replication/logicalproto.h
src/test/regress/expected/publication.out
src/test/regress/sql/publication.sql
src/test/subscription/t/011_generated.pl
src/tools/pgindent/typedefs.list

index d3036c5ba9d609dac80737fd3c009d16be933e4c..c88bcaa7df9566de40c784326c0d8610ae63d071 100644 (file)
@@ -6394,6 +6394,20 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       </para></entry>
      </row>
 
+     <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>
index 5e25536554a897db4d13333455520c31b3898227..e822ea2aaa9a3dfe4ae5b0d2e1dcb466965b1df7 100644 (file)
@@ -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>
index b89098f5e99aac92320da4491ee64fd4a19612e2..7900a8f6a1338107bc8f3a4f38fcfce09d0a0ae7 100644 (file)
@@ -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;
            }
 
index 35747b3df5f2d9942d734a7bb7dae5b8b918068f..b49d9ab78bf588b5f17e5afaa19062be2e6efde5 100644 (file)
@@ -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 */
+}
index bef350714dbae9910ce8b140f68f13eb7826f627..dc72b7c8f77a9c85eed0051ff215cf3b7177c4cb 100644 (file)
 #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;
 }
index 2b7499b34b91525c9d764a90f67ffedcf0978e8a..a363c88ffc033623c7f47f93a8988d4f8ccc5041 100644 (file)
@@ -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);
index 43219a9629c3b83b9e627fc36693bf09e00cd491..ee39d085ebefb657b19ddf8ee8a1432b2c8a3dd6 100644 (file)
@@ -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))
        {
index 8f73a5df9568b8706cd20b72925e49190c5d72e6..9b840fc400a18b63bd54f52958718c4e23e7e89b 100644 (file)
@@ -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");
 
index f62b564ed1bed4f1c218a893b120d6a4923f2479..7139c88a69a10d65c2efe895503575ec1264e31b 100644 (file)
@@ -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;
 
 /*
index a643a73270e5e99cf5170dbecd2d6f8ba1b7a824..805ba9f49fd51dd2fe185d8bb637b015f0fe9955 100644 (file)
@@ -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, },
    },
index 8c0ad8439eb236ff4471911a5caf1c9d63977de4..2e84b61f184a42f82442e7c56fea9d85e1a5eb9c 100644 (file)
@@ -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,
index 28de0c8334230edeec64f535d51123f56da121d5..586b83f2f4d62c1bc72895f8dd2e2a200811b986 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202501171
+#define CATALOG_VERSION_NO 202501231
 
 #endif
index 3c2ae2a960c692cbff2dc5001f6bd38802adde9f..9e6cddcac4c67d76a16517b058f57f6f4e8a506e 100644 (file)
@@ -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 */
index 170c5ce00f0fbafbeb5ce221f9f0d44f18b33b7c..e11a942ea0fd4d53b26e765574ebca69854de5e3 100644 (file)
@@ -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);
 
index 7012247825d049b0471e0e1e317d8804bc333719..b261c60d3fa1490de38a35d28199ddffda2d2362 100644 (file)
@@ -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 */
index c48f11f2935180fc78ea44861eab3f2a128f9676..bc3898fbe586e24654b586d6f4746526fe74585e 100644 (file)
@@ -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)
 
index c4c21a95d0ec0aac2ca8915e09970a462e818e09..47f0329c2440e7a92c3dbb0a768eff0973db7711 100644 (file)
@@ -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
 
index 45587371400c4627de80747872e35ed78d6e20c5..5970bb473608a3ff6de928e93dad2f9b2c7f6b24 100644 (file)
@@ -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");
index d5aa5c295ae7893b6f6f5db67153d8f12c1b5af4..a2644a2e6535ac2ae3ae8775feb56fe3fc05abd8 100644 (file)
@@ -2276,6 +2276,7 @@ PublicationPartOpt
 PublicationRelInfo
 PublicationSchemaInfo
 PublicationTable
+PublishGencolsType
 PullFilter
 PullFilterOps
 PushFilter