From e2e7e5f286b2282d17440961a1efa043ba054824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Nordstr=C3=B6m?= Date: Fri, 31 Mar 2023 14:22:35 +0200 Subject: [PATCH] Make hypertables support replica identity Add support for setting replica identity on hypertables via ALTER TABLE. The replica identity is used in logical replication to identify rows that have changed. Currently, replica identity can only be altered on hypertables via the root; changing it directly on chunks will raise an error. --- .unreleased/feature_5515 | 1 + src/chunk.c | 40 +++++++++ src/chunk_index.c | 5 +- src/chunk_index.h | 4 +- src/hypertable.c | 12 --- src/process_utility.c | 64 +++++++++++++- test/expected/alter.out | 111 ++++++++++++++++++++++++ test/expected/ddl_errors.out | 12 --- test/sql/alter.sql | 58 +++++++++++++ test/sql/ddl_errors.sql | 12 --- tsl/src/remote/dist_ddl.c | 1 + tsl/test/expected/dist_ddl.out | 154 +++++++++++++++++++++++++++++++++ tsl/test/sql/dist_ddl.sql | 15 ++++ 13 files changed, 445 insertions(+), 44 deletions(-) create mode 100644 .unreleased/feature_5515 diff --git a/.unreleased/feature_5515 b/.unreleased/feature_5515 new file mode 100644 index 000000000..edd1611b2 --- /dev/null +++ b/.unreleased/feature_5515 @@ -0,0 +1 @@ +Implements: #5515 Make hypertables support replica identity diff --git a/src/chunk.c b/src/chunk.c index 0c589be8e..2e2697665 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -1006,6 +1006,44 @@ chunk_insert_into_metadata_after_lock(const Chunk *chunk) ts_chunk_constraints_insert_metadata(chunk->constraints); } +/* + * Ensure the replica identity setting of a chunk matches that of the root + * table. + */ +static void +chunk_set_replica_identity(const Chunk *chunk) +{ + Relation ht_rel = relation_open(chunk->hypertable_relid, AccessShareLock); + ReplicaIdentityStmt stmt = { + .type = T_ReplicaIdentityStmt, + .identity_type = ht_rel->rd_rel->relreplident, + }; + AlterTableCmd cmd = { + .type = T_AlterTableCmd, + .def = (Node *) &stmt, + .subtype = AT_ReplicaIdentity, + }; + CatalogSecurityContext sec_ctx; + + if (stmt.identity_type == REPLICA_IDENTITY_INDEX) + { + ChunkIndexMapping idxm; + + /* Lookup the corresponding chunk index. If this index is + * dropped, the behavior is the same as NOTHING (as per PG + * documentation). */ + if (!ts_chunk_index_get_by_hypertable_indexrelid(chunk, ht_rel->rd_replidindex, &idxm)) + stmt.identity_type = REPLICA_IDENTITY_NOTHING; + else + stmt.name = get_rel_name(idxm.indexoid); + } + + ts_catalog_database_info_become_owner(ts_catalog_database_info_get(), &sec_ctx); + AlterTableInternal(chunk->table_id, list_make1(&cmd), false); + ts_catalog_restore_user(&sec_ctx); + table_close(ht_rel, NoLock); +} + static void chunk_create_table_constraints(const Hypertable *ht, const Chunk *chunk) { @@ -1020,6 +1058,8 @@ chunk_create_table_constraints(const Hypertable *ht, const Chunk *chunk) chunk->fd.id, chunk->table_id, InvalidOid); + + chunk_set_replica_identity(chunk); } } diff --git a/src/chunk_index.c b/src/chunk_index.c index 6769c14e6..de365f71f 100644 --- a/src/chunk_index.c +++ b/src/chunk_index.c @@ -787,7 +787,8 @@ chunk_index_tuple_found(TupleInfo *ti, void *const data) } bool -ts_chunk_index_get_by_indexrelid(Chunk *chunk, Oid chunk_indexrelid, ChunkIndexMapping *cim_out) +ts_chunk_index_get_by_indexrelid(const Chunk *chunk, Oid chunk_indexrelid, + ChunkIndexMapping *cim_out) { int tuples_found; ScanKeyData scankey[2]; @@ -835,7 +836,7 @@ chunk_hypertable_index_name_filter(const TupleInfo *ti, void *data) } TSDLLEXPORT bool -ts_chunk_index_get_by_hypertable_indexrelid(Chunk *chunk, Oid hypertable_indexrelid, +ts_chunk_index_get_by_hypertable_indexrelid(const Chunk *chunk, Oid hypertable_indexrelid, ChunkIndexMapping *cim_out) { int tuples_found; diff --git a/src/chunk_index.h b/src/chunk_index.h index a7c81d88d..709915661 100644 --- a/src/chunk_index.h +++ b/src/chunk_index.h @@ -51,10 +51,10 @@ extern int ts_chunk_index_set_tablespace(Hypertable *ht, Oid hypertable_indexrel extern void ts_chunk_index_create_from_constraint(int32 hypertable_id, Oid hypertable_constraint, int32 chunk_id, Oid chunk_constraint); extern List *ts_chunk_index_get_mappings(Hypertable *ht, Oid hypertable_indexrelid); -extern TSDLLEXPORT bool ts_chunk_index_get_by_hypertable_indexrelid(Chunk *chunk, +extern TSDLLEXPORT bool ts_chunk_index_get_by_hypertable_indexrelid(const Chunk *chunk, Oid hypertable_indexrelid, ChunkIndexMapping *cim_out); -extern TSDLLEXPORT bool ts_chunk_index_get_by_indexrelid(Chunk *chunk, Oid chunk_indexrelid, +extern TSDLLEXPORT bool ts_chunk_index_get_by_indexrelid(const Chunk *chunk, Oid chunk_indexrelid, ChunkIndexMapping *cim_out); extern TSDLLEXPORT void ts_chunk_index_mark_clustered(Oid chunkrelid, Oid indexrelid); diff --git a/src/hypertable.c b/src/hypertable.c index 99c966d49..bd2299bec 100644 --- a/src/hypertable.c +++ b/src/hypertable.c @@ -1342,12 +1342,6 @@ table_is_logged(Oid table_relid) return get_rel_persistence(table_relid) == RELPERSISTENCE_PERMANENT; } -static bool -table_has_replica_identity(const Relation rel) -{ - return rel->rd_rel->relreplident != REPLICA_IDENTITY_DEFAULT; -} - inline static bool table_has_rules(Relation rel) { @@ -2184,12 +2178,6 @@ ts_hypertable_create_from_info(Oid table_relid, int32 hypertable_id, uint32 flag errdetail( "It is not possible to turn temporary or unlogged tables into hypertables."))); - if (table_has_replica_identity(rel)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("table \"%s\" has replica identity set", get_rel_name(table_relid)), - errdetail("Logical replication is not supported on hypertables."))); - if (table_has_rules(rel)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), diff --git a/src/process_utility.c b/src/process_utility.c index fc8efb14f..7c7ac232c 100644 --- a/src/process_utility.c +++ b/src/process_utility.c @@ -3,6 +3,7 @@ * Please see the included NOTICE for copyright information and * LICENSE-APACHE for a copy of the license. */ +#include #include #include #include @@ -3218,6 +3219,64 @@ process_altertable_chunk(Hypertable *ht, Oid chunk_relid, void *arg) AlterTableInternal(chunk_relid, list_make1(cmd), false); } +static void +process_altertable_chunk_replica_identity(Hypertable *ht, Oid chunk_relid, void *arg) +{ + AlterTableCmd *cmd = castNode(AlterTableCmd, copyObject(arg)); + ReplicaIdentityStmt *stmt = castNode(ReplicaIdentityStmt, cmd->def); + char relkind = get_rel_relkind(chunk_relid); + + /* If this is not a local chunk (e.g., it is foreign table representing a + * data node or OSM chunk), then we don't set replica identity locally */ + if (relkind != RELKIND_RELATION) + return; + + if (stmt->identity_type == REPLICA_IDENTITY_INDEX) + { + Chunk *chunk = ts_chunk_get_by_relid(chunk_relid, true); + Oid hyper_schema_oid = get_rel_namespace(ht->main_table_relid); + Oid hyper_index_oid = get_relname_relid(stmt->name, hyper_schema_oid); + ChunkIndexMapping cim; + + Assert(OidIsValid(hyper_index_oid)); + + if (!ts_chunk_index_get_by_hypertable_indexrelid(chunk, hyper_index_oid, &cim)) + elog(ERROR, + "chunk \"%s.%s\" has no index corresponding to hypertable index \"%s\"", + NameStr(chunk->fd.schema_name), + NameStr(chunk->fd.table_name), + stmt->name); + + stmt->name = get_rel_name(cim.indexoid); + } + + AlterTableInternal(chunk_relid, list_make1(cmd), false); +} + +static void +process_altertable_replica_identity(Hypertable *ht, AlterTableCmd *cmd) +{ + ReplicaIdentityStmt *stmt = castNode(ReplicaIdentityStmt, cmd->def); + + if (stmt->identity_type == REPLICA_IDENTITY_INDEX) + { + Oid hyper_schema_oid = get_rel_namespace(ht->main_table_relid); + Oid hyper_index_oid; + + hyper_index_oid = get_relname_relid(stmt->name, hyper_schema_oid); + + if (!OidIsValid(hyper_index_oid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("index \"%s\" for table \"%s.%s\" does not exist", + stmt->name, + NameStr(ht->fd.schema_name), + NameStr(ht->fd.table_name)))); + } + + foreach_chunk(ht, process_altertable_chunk_replica_identity, cmd); +} + static void process_altertable_set_tablespace_end(Hypertable *ht, AlterTableCmd *cmd) { @@ -3712,10 +3771,7 @@ process_altertable_end_subcmd(Hypertable *ht, Node *parsetree, ObjectAddress *ob /* Break here to silence compiler */ break; case AT_ReplicaIdentity: - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("hypertables do not support logical replication"))); - /* Break here to silence compiler */ + process_altertable_replica_identity(ht, cmd); break; case AT_EnableRule: case AT_EnableAlwaysRule: diff --git a/test/expected/alter.out b/test/expected/alter.out index 39b8501fb..f0cc457e4 100644 --- a/test/expected/alter.out +++ b/test/expected/alter.out @@ -791,3 +791,114 @@ ALTER TABLE i4474 ALTER COLUMN time SET statistics 10; SET ROLE role_4474; INSERT INTO i4474 SELECT '2021-01-01'; RESET ROLE; +DROP TABLE i4474 CASCADE; +DROP ROLE role_4474; +-- verify that setting replica identity works and chunks inherit the +-- root table's setting +CREATE TABLE replid(time timestamptz, value int); +SELECT create_hypertable('replid', 'time', chunk_time_interval => interval '1 day', create_default_indexes => false); +NOTICE: adding not-null constraint to column "time" + create_hypertable +---------------------- + (16,public,replid,t) +(1 row) + +-- replica identity set to default +SELECT relreplident FROM pg_class WHERE relname = 'replid'; + relreplident +-------------- + d +(1 row) + +INSERT INTO replid VALUES ('2023-01-01', 1); +-- the new chunk should have the same replica identity setting +SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; + relname | relreplident +--------------------+-------------- + _hyper_16_31_chunk | d +(1 row) + +-- test change to replica identity full +ALTER TABLE replid REPLICA IDENTITY FULL; +SELECT relname, relreplident FROM pg_class WHERE relname = 'replid' ORDER BY relname; + relname | relreplident +---------+-------------- + replid | f +(1 row) + +-- the chunk's setting should also change to FULL +SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; + relname | relreplident +--------------------+-------------- + _hyper_16_31_chunk | f +(1 row) + +-- change to replica identity index +CREATE UNIQUE INDEX time_key ON replid (time); +ALTER TABLE replid REPLICA IDENTITY USING INDEX time_key; +SELECT relname, relreplident FROM pg_class WHERE relname = 'replid' ORDER BY relname; + relname | relreplident +---------+-------------- + replid | i +(1 row) + +SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; + relname | relreplident +--------------------+-------------- + _hyper_16_31_chunk | i +(1 row) + +SELECT indexrelid::regclass::text AS index_name +FROM show_chunks('replid') chid +INNER JOIN pg_index i ON (i.indrelid = chid) AND indisreplident=true +ORDER BY index_name; + index_name +--------------------------------------------------- + _timescaledb_internal._hyper_16_31_chunk_time_key +(1 row) + +INSERT INTO replid VALUES ('2023-01-02', 2); +-- the new chunk will also have replica identity "index" +SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; + relname | relreplident +--------------------+-------------- + _hyper_16_31_chunk | i + _hyper_16_32_chunk | i +(2 rows) + +SELECT indexrelid::regclass::text AS index_name +FROM show_chunks('replid') chid +INNER JOIN pg_index i ON (i.indrelid = chid) AND indisreplident=true +ORDER BY index_name; + index_name +--------------------------------------------------- + _timescaledb_internal._hyper_16_31_chunk_time_key + _timescaledb_internal._hyper_16_32_chunk_time_key +(2 rows) + +-- drop the replica identity index and create a new chunk. The new +-- chunk should have replica identity "NOTHING" since this is the +-- behavior of replica identity index when the index is dropped. +DROP INDEX time_key; +INSERT INTO replid VALUES ('2023-01-03', 3); +-- no indexes left +SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; + relname | relreplident +--------------------+-------------- + _hyper_16_31_chunk | i + _hyper_16_32_chunk | i + _hyper_16_33_chunk | n +(3 rows) + +SELECT indexrelid::regclass::text AS index_name +FROM show_chunks('replid') chid +INNER JOIN pg_index i ON (i.indrelid = chid) AND indisreplident=true +ORDER BY index_name; + index_name +------------ +(0 rows) + +-- Alter replica identity directly on a chunk is not supported +SELECT ch AS chunk_name FROM show_chunks('replid') ch ORDER BY chunk_name LIMIT 1 \gset +ALTER TABLE :chunk_name REPLICA IDENTITY FULL; +ERROR: operation not supported on chunk tables diff --git a/test/expected/ddl_errors.out b/test/expected/ddl_errors.out index 343f23c8a..e2509a381 100644 --- a/test/expected/ddl_errors.out +++ b/test/expected/ddl_errors.out @@ -94,18 +94,6 @@ ALTER TABLE "Hypertable_1" SET UNLOGGED; ERROR: logging cannot be turned off for hypertables \set ON_ERROR_STOP 1 ALTER TABLE "Hypertable_1" SET LOGGED; -CREATE TABLE PUBLIC."Hypertable_1_replica_ident" ( - time BIGINT NOT NULL, - "Device_id" TEXT NOT NULL, - temp_c int NOT NULL DEFAULT -1 -); -ALTER TABLE "Hypertable_1_replica_ident" REPLICA IDENTITY FULL; -\set ON_ERROR_STOP 0 -SELECT * FROM create_hypertable('"public"."Hypertable_1_replica_ident"', 'time', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month')); -ERROR: table "Hypertable_1_replica_ident" has replica identity set -ALTER TABLE "Hypertable_1" REPLICA IDENTITY FULL; -ERROR: hypertables do not support logical replication -\set ON_ERROR_STOP 1 CREATE TABLE PUBLIC."Hypertable_1_rule" ( time BIGINT NOT NULL, "Device_id" TEXT NOT NULL, diff --git a/test/sql/alter.sql b/test/sql/alter.sql index 3ab49ea43..87abc0981 100644 --- a/test/sql/alter.sql +++ b/test/sql/alter.sql @@ -446,4 +446,62 @@ ALTER TABLE i4474 ALTER COLUMN time SET statistics 10; SET ROLE role_4474; INSERT INTO i4474 SELECT '2021-01-01'; RESET ROLE; +DROP TABLE i4474 CASCADE; +DROP ROLE role_4474; + +-- verify that setting replica identity works and chunks inherit the +-- root table's setting +CREATE TABLE replid(time timestamptz, value int); +SELECT create_hypertable('replid', 'time', chunk_time_interval => interval '1 day', create_default_indexes => false); + +-- replica identity set to default +SELECT relreplident FROM pg_class WHERE relname = 'replid'; + +INSERT INTO replid VALUES ('2023-01-01', 1); +-- the new chunk should have the same replica identity setting +SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; + +-- test change to replica identity full +ALTER TABLE replid REPLICA IDENTITY FULL; +SELECT relname, relreplident FROM pg_class WHERE relname = 'replid' ORDER BY relname; +-- the chunk's setting should also change to FULL +SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; + +-- change to replica identity index +CREATE UNIQUE INDEX time_key ON replid (time); +ALTER TABLE replid REPLICA IDENTITY USING INDEX time_key; + +SELECT relname, relreplident FROM pg_class WHERE relname = 'replid' ORDER BY relname; +SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; +SELECT indexrelid::regclass::text AS index_name +FROM show_chunks('replid') chid +INNER JOIN pg_index i ON (i.indrelid = chid) AND indisreplident=true +ORDER BY index_name; + +INSERT INTO replid VALUES ('2023-01-02', 2); + +-- the new chunk will also have replica identity "index" +SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; +SELECT indexrelid::regclass::text AS index_name +FROM show_chunks('replid') chid +INNER JOIN pg_index i ON (i.indrelid = chid) AND indisreplident=true +ORDER BY index_name; + +-- drop the replica identity index and create a new chunk. The new +-- chunk should have replica identity "NOTHING" since this is the +-- behavior of replica identity index when the index is dropped. +DROP INDEX time_key; +INSERT INTO replid VALUES ('2023-01-03', 3); + +-- no indexes left +SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; +SELECT indexrelid::regclass::text AS index_name +FROM show_chunks('replid') chid +INNER JOIN pg_index i ON (i.indrelid = chid) AND indisreplident=true +ORDER BY index_name; + +-- Alter replica identity directly on a chunk is not supported +SELECT ch AS chunk_name FROM show_chunks('replid') ch ORDER BY chunk_name LIMIT 1 \gset +ALTER TABLE :chunk_name REPLICA IDENTITY FULL; +SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; diff --git a/test/sql/ddl_errors.sql b/test/sql/ddl_errors.sql index affa07348..b9d13452a 100644 --- a/test/sql/ddl_errors.sql +++ b/test/sql/ddl_errors.sql @@ -85,18 +85,6 @@ ALTER TABLE "Hypertable_1" SET UNLOGGED; \set ON_ERROR_STOP 1 ALTER TABLE "Hypertable_1" SET LOGGED; -CREATE TABLE PUBLIC."Hypertable_1_replica_ident" ( - time BIGINT NOT NULL, - "Device_id" TEXT NOT NULL, - temp_c int NOT NULL DEFAULT -1 -); -ALTER TABLE "Hypertable_1_replica_ident" REPLICA IDENTITY FULL; - -\set ON_ERROR_STOP 0 -SELECT * FROM create_hypertable('"public"."Hypertable_1_replica_ident"', 'time', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month')); -ALTER TABLE "Hypertable_1" REPLICA IDENTITY FULL; -\set ON_ERROR_STOP 1 - CREATE TABLE PUBLIC."Hypertable_1_rule" ( time BIGINT NOT NULL, diff --git a/tsl/src/remote/dist_ddl.c b/tsl/src/remote/dist_ddl.c index 50ee22234..7cb59dced 100644 --- a/tsl/src/remote/dist_ddl.c +++ b/tsl/src/remote/dist_ddl.c @@ -793,6 +793,7 @@ dist_ddl_process_alter_table(const ProcessUtilityArgs *args) case AT_DropNotNull: case AT_AddIndex: case AT_AlterColumnType: + case AT_ReplicaIdentity: exec_type = set_alter_table_exec_type(exec_type, DIST_DDL_EXEC_ON_END); break; case AT_ChangeOwner: diff --git a/tsl/test/expected/dist_ddl.out b/tsl/test/expected/dist_ddl.out index 403e5801b..ce7e273fe 100644 --- a/tsl/test/expected/dist_ddl.out +++ b/tsl/test/expected/dist_ddl.out @@ -596,6 +596,160 @@ SELECT * FROM show_chunks('disttable'); _timescaledb_internal._dist_hyper_1_5_chunk (5 rows) +-- Replica identity +SELECT * FROM test.remote_exec(NULL, +$$ + SELECT relname, relreplident FROM pg_class WHERE relname = 'disttable' ORDER BY relname; + SELECT relname, relreplident FROM show_chunks('disttable') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; +$$); +NOTICE: [db_dist_ddl_1]: + SELECT relname, relreplident FROM pg_class WHERE relname = 'disttable' ORDER BY relname +NOTICE: [db_dist_ddl_1]: +relname |relreplident +---------+------------ +disttable|d +(1 row) + + +NOTICE: [db_dist_ddl_1]: + SELECT relname, relreplident FROM show_chunks('disttable') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname +NOTICE: [db_dist_ddl_1]: +relname |relreplident +---------------------+------------ +_dist_hyper_1_1_chunk|d +_dist_hyper_1_2_chunk|d +_dist_hyper_1_3_chunk|d +_dist_hyper_1_4_chunk|d +_dist_hyper_1_5_chunk|d +(5 rows) + + +NOTICE: [db_dist_ddl_2]: + SELECT relname, relreplident FROM pg_class WHERE relname = 'disttable' ORDER BY relname +NOTICE: [db_dist_ddl_2]: +relname |relreplident +---------+------------ +disttable|d +(1 row) + + +NOTICE: [db_dist_ddl_2]: + SELECT relname, relreplident FROM show_chunks('disttable') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname +NOTICE: [db_dist_ddl_2]: +relname |relreplident +---------------------+------------ +_dist_hyper_1_1_chunk|d +_dist_hyper_1_2_chunk|d +_dist_hyper_1_3_chunk|d +_dist_hyper_1_4_chunk|d +_dist_hyper_1_5_chunk|d +(5 rows) + + +NOTICE: [db_dist_ddl_3]: + SELECT relname, relreplident FROM pg_class WHERE relname = 'disttable' ORDER BY relname +NOTICE: [db_dist_ddl_3]: +relname |relreplident +---------+------------ +disttable|d +(1 row) + + +NOTICE: [db_dist_ddl_3]: + SELECT relname, relreplident FROM show_chunks('disttable') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname +NOTICE: [db_dist_ddl_3]: +relname |relreplident +---------------------+------------ +_dist_hyper_1_1_chunk|d +_dist_hyper_1_2_chunk|d +_dist_hyper_1_3_chunk|d +_dist_hyper_1_4_chunk|d +_dist_hyper_1_5_chunk|d +(5 rows) + + + remote_exec +------------- + +(1 row) + +ALTER TABLE disttable REPLICA IDENTITY FULL; +SELECT * FROM test.remote_exec(NULL, +$$ + SELECT relname, relreplident FROM pg_class WHERE relname = 'disttable' ORDER BY relname; + SELECT relname, relreplident FROM show_chunks('disttable') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; +$$); +NOTICE: [db_dist_ddl_1]: + SELECT relname, relreplident FROM pg_class WHERE relname = 'disttable' ORDER BY relname +NOTICE: [db_dist_ddl_1]: +relname |relreplident +---------+------------ +disttable|f +(1 row) + + +NOTICE: [db_dist_ddl_1]: + SELECT relname, relreplident FROM show_chunks('disttable') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname +NOTICE: [db_dist_ddl_1]: +relname |relreplident +---------------------+------------ +_dist_hyper_1_1_chunk|f +_dist_hyper_1_2_chunk|f +_dist_hyper_1_3_chunk|f +_dist_hyper_1_4_chunk|f +_dist_hyper_1_5_chunk|f +(5 rows) + + +NOTICE: [db_dist_ddl_2]: + SELECT relname, relreplident FROM pg_class WHERE relname = 'disttable' ORDER BY relname +NOTICE: [db_dist_ddl_2]: +relname |relreplident +---------+------------ +disttable|f +(1 row) + + +NOTICE: [db_dist_ddl_2]: + SELECT relname, relreplident FROM show_chunks('disttable') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname +NOTICE: [db_dist_ddl_2]: +relname |relreplident +---------------------+------------ +_dist_hyper_1_1_chunk|f +_dist_hyper_1_2_chunk|f +_dist_hyper_1_3_chunk|f +_dist_hyper_1_4_chunk|f +_dist_hyper_1_5_chunk|f +(5 rows) + + +NOTICE: [db_dist_ddl_3]: + SELECT relname, relreplident FROM pg_class WHERE relname = 'disttable' ORDER BY relname +NOTICE: [db_dist_ddl_3]: +relname |relreplident +---------+------------ +disttable|f +(1 row) + + +NOTICE: [db_dist_ddl_3]: + SELECT relname, relreplident FROM show_chunks('disttable') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname +NOTICE: [db_dist_ddl_3]: +relname |relreplident +---------------------+------------ +_dist_hyper_1_1_chunk|f +_dist_hyper_1_2_chunk|f +_dist_hyper_1_3_chunk|f +_dist_hyper_1_4_chunk|f +_dist_hyper_1_5_chunk|f +(5 rows) + + + remote_exec +------------- + +(1 row) + -- Rename column ALTER TABLE disttable RENAME COLUMN description TO descr; SELECT * FROM test.show_columns('disttable') diff --git a/tsl/test/sql/dist_ddl.sql b/tsl/test/sql/dist_ddl.sql index 7e0a31576..353da08c3 100644 --- a/tsl/test/sql/dist_ddl.sql +++ b/tsl/test/sql/dist_ddl.sql @@ -194,6 +194,21 @@ INSERT INTO disttable VALUES SELECT * FROM show_chunks('disttable'); +-- Replica identity +SELECT * FROM test.remote_exec(NULL, +$$ + SELECT relname, relreplident FROM pg_class WHERE relname = 'disttable' ORDER BY relname; + SELECT relname, relreplident FROM show_chunks('disttable') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; +$$); + +ALTER TABLE disttable REPLICA IDENTITY FULL; + +SELECT * FROM test.remote_exec(NULL, +$$ + SELECT relname, relreplident FROM pg_class WHERE relname = 'disttable' ORDER BY relname; + SELECT relname, relreplident FROM show_chunks('disttable') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname; +$$); + -- Rename column ALTER TABLE disttable RENAME COLUMN description TO descr; SELECT * FROM test.show_columns('disttable')