</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>
<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>
</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>
/*
* 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);
{
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);
}
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);
{
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;
}
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
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;
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)
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,
* 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)
{
/*
* 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;
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;
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;
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);
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;
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,
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 */
+}
#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);
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);
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);
}
/*
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);
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);
}
/*
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 ||
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);
}
/*
*/
void
logicalrep_write_rel(StringInfo out, TransactionId xid, Relation rel,
- Bitmapset *columns, bool include_gencols)
+ Bitmapset *columns,
+ PublishGencolsType include_gencols_type)
{
char *relname;
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);
}
/*
*/
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;
{
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++;
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])
*/
static void
logicalrep_write_attrs(StringInfo out, Relation rel, Bitmapset *columns,
- bool include_gencols)
+ PublishGencolsType include_gencols_type)
{
TupleDesc desc;
int i;
{
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++;
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. */
*
* '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;
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;
}
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 */
{
TupleDesc desc = RelationGetDescr(relation);
Bitmapset *columns = relentry->columns;
- bool include_gencols = relentry->include_gencols;
+ PublishGencolsType include_gencols_type = relentry->include_gencols_type;
int i;
/*
{
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)
}
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);
}
/* There are no generated columns to be published. */
if (!gencolpresent)
{
- entry->include_gencols = false;
+ entry->include_gencols_type = PUBLISH_GENCOLS_NONE;
return;
}
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",
{
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);
}
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);
{
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;
* 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);
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))
{
#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"
int i_pubdelete;
int i_pubtruncate;
int i_pubviaroot;
- int i_pubgencols;
+ int i_pubgencols_type;
int i,
ntups;
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");
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));
(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);
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");
#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) )
bool pubdelete;
bool pubtruncate;
bool pubviaroot;
- bool pubgencols;
+ PublishGencolsType pubgencols_type;
} PublicationInfo;
/*
'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, },
},
#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"
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,
", 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,
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202501171
+#define CATALOG_VERSION_NO 202501231
#endif
/* 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;
/* ----------------
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;
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 */
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);
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,
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);
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 */
(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
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');
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
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:
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"
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"
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:
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:
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"
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"
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;
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"
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"
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"
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"
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))
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))
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))
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))
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)
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)
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:
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;
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)
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)
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"
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
foo | integer | | | | plain | |
bar | integer | | | | plain | |
Publications:
- "testpib_ins_trunct"
"testpub_default"
"testpub_fortbl"
+ "testpub_ins_trunct"
\d+ testpub_tbl1
Table "public.testpub_tbl1"
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"
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"
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"
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
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
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
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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
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"
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"
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"
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;
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"
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:
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:
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;
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)
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);
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
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;
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
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;
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
# =============================================================================
# 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.
#
'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.
'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");
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");
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
# 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.
'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.
# 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");
|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.
# --------------------------------------------------
'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.
# 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");
|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");
PublicationRelInfo
PublicationSchemaInfo
PublicationTable
+PublishGencolsType
PullFilter
PullFilterOps
PushFilter