Prevent inserting into logically-replicated columnar table. (#4429)

pull/4432/head
jeff-davis 2020-12-18 12:29:30 -08:00 committed by GitHub
parent f2056e553f
commit 3e0f1aaaab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 0 deletions

View File

@ -23,6 +23,7 @@
#include "catalog/index.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_am.h"
#include "catalog/pg_publication.h"
#include "catalog/pg_trigger.h"
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
@ -44,6 +45,7 @@
#include "utils/memutils.h"
#include "utils/pg_rusage.h"
#include "utils/rel.h"
#include "utils/relcache.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@ -121,6 +123,7 @@ static bool ConditionalLockRelationWithTimeout(Relation rel, LOCKMODE lockMode,
static void LogRelationStats(Relation rel, int elevel);
static void TruncateCStore(Relation rel, int elevel);
static HeapTuple ColumnarSlotCopyHeapTuple(TupleTableSlot *slot);
static void ColumnarCheckLogicalReplication(Relation rel);
/* Custom tuple slot ops used for columnar. Initialized in cstore_tableam_init(). */
TupleTableSlotOps TTSOpsColumnar;
@ -454,6 +457,8 @@ cstore_tuple_insert(Relation relation, TupleTableSlot *slot, CommandId cid,
MemoryContext oldContext = MemoryContextSwitchTo(writeState->perTupleContext);
HeapTuple heapTuple = ExecCopySlotHeapTuple(slot);
ColumnarCheckLogicalReplication(relation);
if (HeapTupleHasExternal(heapTuple))
{
/* detoast any toasted attributes */
@ -497,6 +502,7 @@ cstore_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
RelationGetDescr(relation),
GetCurrentSubTransactionId());
ColumnarCheckLogicalReplication(relation);
for (int i = 0; i < ntuples; i++)
{
TupleTableSlot *tupleSlot = slots[i];
@ -1378,6 +1384,36 @@ columnar_handler(PG_FUNCTION_ARGS)
}
/*
* ColumnarCheckLogicalReplication throws an error if the relation is
* part of any publication. This should be called before any write to
* a columnar table, because columnar changes are not replicated with
* logical replication (similar to a row table without a replica
* identity).
*/
static void
ColumnarCheckLogicalReplication(Relation rel)
{
if (!is_publishable_relation(rel))
{
return;
}
if (rel->rd_pubactions == NULL)
{
GetRelationPublicationActions(rel);
Assert(rel->rd_pubactions != NULL);
}
if (rel->rd_pubactions->pubinsert)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg(
"cannot insert into columnar table that is a part of a publication")));
}
}
/*
* CitusCreateAlterColumnarTableSet generates a portable
*/

View File

@ -84,3 +84,15 @@ WHERE a.int_val = c.int_val AND a.hash = md5(c.text_val);
DROP TABLE test_long_text_hash;
DROP TABLE test_cstore_long_text;
CREATE TABLE test_logical_replication(i int) USING columnar;
-- should succeed
INSERT INTO test_logical_replication VALUES (1);
CREATE PUBLICATION test_columnar_publication
FOR TABLE test_logical_replication;
-- should fail; columnar does not support logical replication
INSERT INTO test_logical_replication VALUES (2);
ERROR: cannot insert into columnar table that is a part of a publication
DROP PUBLICATION test_columnar_publication;
-- should succeed
INSERT INTO test_logical_replication VALUES (3);
DROP TABLE test_logical_replication;

View File

@ -54,3 +54,15 @@ WHERE a.int_val = c.int_val AND a.hash = md5(c.text_val);
DROP TABLE test_long_text_hash;
DROP TABLE test_cstore_long_text;
CREATE TABLE test_logical_replication(i int) USING columnar;
-- should succeed
INSERT INTO test_logical_replication VALUES (1);
CREATE PUBLICATION test_columnar_publication
FOR TABLE test_logical_replication;
-- should fail; columnar does not support logical replication
INSERT INTO test_logical_replication VALUES (2);
DROP PUBLICATION test_columnar_publication;
-- should succeed
INSERT INTO test_logical_replication VALUES (3);
DROP TABLE test_logical_replication;