diff --git a/src/chunk_constraint.c b/src/chunk_constraint.c index f7ffcdd48..fa1daa9d1 100644 --- a/src/chunk_constraint.c +++ b/src/chunk_constraint.c @@ -853,6 +853,12 @@ chunk_constraint_rename_hypertable_from_tuple(TupleInfo *ti, const char *newname NameStr(new_chunk_constraint_name)); new_tuple = heap_modify_tuple(tuple, tupdesc, values, nulls, repl); + + ts_chunk_index_adjust_meta(chunk_id, + newname, + NameStr(*old_chunk_constraint_name), + NameStr(new_chunk_constraint_name)); + ts_catalog_update(ti->scanrel, new_tuple); heap_freetuple(new_tuple); @@ -860,6 +866,52 @@ chunk_constraint_rename_hypertable_from_tuple(TupleInfo *ti, const char *newname heap_freetuple(tuple); } +/* + * Adjust internal metadata after index/constraint rename + */ +int +ts_chunk_constraint_adjust_meta(int32 chunk_id, const char *ht_constraint_name, const char *oldname, + const char *newname) +{ + ScanIterator iterator = + ts_scan_iterator_create(CHUNK_CONSTRAINT, RowExclusiveLock, CurrentMemoryContext); + int count = 0; + + init_scan_by_chunk_id_constraint_name(&iterator, chunk_id, oldname); + + ts_scanner_foreach(&iterator) + { + bool nulls[Natts_chunk_constraint]; + bool repl[Natts_chunk_constraint] = { false }; + Datum values[Natts_chunk_constraint]; + bool should_free; + TupleInfo *ti = ts_scan_iterator_tuple_info(&iterator); + HeapTuple tuple = ts_scanner_fetch_heap_tuple(ti, false, &should_free); + HeapTuple new_tuple; + + heap_deform_tuple(tuple, ts_scanner_get_tupledesc(ti), values, nulls); + + values[AttrNumberGetAttrOffset(Anum_chunk_constraint_hypertable_constraint_name)] = + CStringGetDatum(ht_constraint_name); + repl[AttrNumberGetAttrOffset(Anum_chunk_constraint_hypertable_constraint_name)] = true; + values[AttrNumberGetAttrOffset(Anum_chunk_constraint_constraint_name)] = + CStringGetDatum(newname); + repl[AttrNumberGetAttrOffset(Anum_chunk_constraint_constraint_name)] = true; + + new_tuple = heap_modify_tuple(tuple, ts_scanner_get_tupledesc(ti), values, nulls, repl); + + ts_catalog_update(ti->scanrel, new_tuple); + heap_freetuple(new_tuple); + + if (should_free) + heap_freetuple(tuple); + + count++; + } + + return count; +} + int ts_chunk_constraint_rename_hypertable_constraint(int32 chunk_id, const char *oldname, const char *newname) diff --git a/src/chunk_constraint.h b/src/chunk_constraint.h index 1c85e7a01..03618429e 100644 --- a/src/chunk_constraint.h +++ b/src/chunk_constraint.h @@ -69,6 +69,8 @@ extern int ts_chunk_constraint_delete_by_constraint_name(int32 chunk_id, extern void ts_chunk_constraint_recreate(ChunkConstraint *cc, Oid chunk_oid); extern int ts_chunk_constraint_rename_hypertable_constraint(int32 chunk_id, const char *oldname, const char *newname); +extern int ts_chunk_constraint_adjust_meta(int32 chunk_id, const char *ht_constraint_name, + const char *oldname, const char *newname); extern char * ts_chunk_constraint_get_name_from_hypertable_constraint(Oid chunk_relid, diff --git a/src/chunk_index.c b/src/chunk_index.c index 85269a321..c7d555880 100644 --- a/src/chunk_index.c +++ b/src/chunk_index.c @@ -37,6 +37,7 @@ #include "hypertable_cache.h" #include "catalog.h" #include "scanner.h" +#include "scan_iterator.h" #include "chunk.h" static bool chunk_index_insert(int32 chunk_id, const char *chunk_index, int32 hypertable_id, @@ -888,6 +889,11 @@ chunk_index_tuple_rename(TupleInfo *ti, void *data) chunk_index_choose_name(NameStr(chunk->fd.table_name), info->newname, chunk_schemaoid); Oid chunk_indexrelid = get_relname_relid(NameStr(chunk_index->index_name), chunk_schemaoid); + ts_chunk_constraint_adjust_meta(chunk->fd.id, + info->newname, + NameStr(chunk_index->index_name), + chunk_index_name); + /* Update the metadata */ namestrcpy(&chunk_index->index_name, chunk_index_name); namestrcpy(&chunk_index->hypertable_index_name, info->newname); @@ -907,6 +913,68 @@ chunk_index_tuple_rename(TupleInfo *ti, void *data) return SCAN_DONE; } +static void +init_scan_by_chunk_id_index_name(ScanIterator *iterator, int32 chunk_id, const char *index_name) +{ + iterator->ctx.index = + catalog_get_index(ts_catalog_get(), CHUNK_INDEX, CHUNK_INDEX_CHUNK_ID_INDEX_NAME_IDX); + + ts_scan_iterator_scan_key_init(iterator, + Anum_chunk_index_chunk_id, + BTEqualStrategyNumber, + F_INT4EQ, + Int32GetDatum(chunk_id)); + ts_scan_iterator_scan_key_init(iterator, + Anum_chunk_index_index_name, + BTEqualStrategyNumber, + F_NAMEEQ, + CStringGetDatum(index_name)); +} + +/* + * Adjust internal metadata after index/constraint rename + */ +int +ts_chunk_index_adjust_meta(int32 chunk_id, const char *ht_index_name, const char *oldname, + const char *newname) +{ + ScanIterator iterator = + ts_scan_iterator_create(CHUNK_INDEX, RowExclusiveLock, CurrentMemoryContext); + int count = 0; + + init_scan_by_chunk_id_index_name(&iterator, chunk_id, oldname); + + ts_scanner_foreach(&iterator) + { + bool nulls[Natts_chunk_index]; + bool repl[Natts_chunk_index] = { false }; + Datum values[Natts_chunk_index]; + bool should_free; + TupleInfo *ti = ts_scan_iterator_tuple_info(&iterator); + HeapTuple tuple = ts_scanner_fetch_heap_tuple(ti, false, &should_free); + HeapTuple new_tuple; + + heap_deform_tuple(tuple, ts_scanner_get_tupledesc(ti), values, nulls); + + values[AttrNumberGetAttrOffset(Anum_chunk_index_hypertable_index_name)] = + CStringGetDatum(ht_index_name); + repl[AttrNumberGetAttrOffset(Anum_chunk_index_hypertable_index_name)] = true; + values[AttrNumberGetAttrOffset(Anum_chunk_index_index_name)] = CStringGetDatum(newname); + repl[AttrNumberGetAttrOffset(Anum_chunk_index_index_name)] = true; + + new_tuple = heap_modify_tuple(tuple, ts_scanner_get_tupledesc(ti), values, nulls, repl); + + ts_catalog_update(ti->scanrel, new_tuple); + heap_freetuple(new_tuple); + + if (should_free) + heap_freetuple(tuple); + + count++; + } + return count; +} + int ts_chunk_index_rename(Chunk *chunk, Oid chunk_indexrelid, const char *newname) { diff --git a/src/chunk_index.h b/src/chunk_index.h index c64aac74e..7751c70a3 100644 --- a/src/chunk_index.h +++ b/src/chunk_index.h @@ -45,6 +45,8 @@ extern void ts_chunk_index_delete_by_name(const char *schema, const char *index_ extern int ts_chunk_index_rename(Chunk *chunk, Oid chunk_indexrelid, const char *newname); extern int ts_chunk_index_rename_parent(Hypertable *ht, Oid hypertable_indexrelid, const char *newname); +extern int ts_chunk_index_adjust_meta(int32 chunk_id, const char *ht_index_name, + const char *old_name, const char *new_name); extern int ts_chunk_index_set_tablespace(Hypertable *ht, Oid hypertable_indexrelid, const char *tablespace); extern void ts_chunk_index_create_from_constraint(int32 hypertable_id, Oid hypertable_constraint, diff --git a/test/expected/alter.out b/test/expected/alter.out index 22819cb31..347c2edd1 100644 --- a/test/expected/alter.out +++ b/test/expected/alter.out @@ -686,3 +686,51 @@ SELECT * from _timescaledb_catalog.chunk; (2 rows) DROP TABLE my_table; +-- test renaming unique constraints/indexes +CREATE TABLE t_hypertable ( id INTEGER NOT NULL, time TIMESTAMPTZ NOT NULL, value FLOAT NOT NULL CHECK (value > 0), UNIQUE(id, time)); +SELECT create_hypertable('t_hypertable', 'time'); + create_hypertable +---------------------------- + (13,public,t_hypertable,t) +(1 row) + +INSERT INTO t_hypertable AS h VALUES ( 1, '2020-01-01 00:00:00', 3.2) ON CONFLICT (id, time) DO UPDATE SET value = h.value + EXCLUDED.value; +INSERT INTO t_hypertable AS h VALUES ( 1, '2021-01-01 00:00:00', 3.2) ON CONFLICT (id, time) DO UPDATE SET value = h.value + EXCLUDED.value; +BEGIN; +ALTER INDEX t_hypertable_id_time_key RENAME TO t_new_constraint; +-- chunk_index and chunk_constraint should both have updated constraint names +SELECT hypertable_index_name, index_name from _timescaledb_catalog.chunk_index WHERE hypertable_index_name = 't_new_constraint' ORDER BY 1,2; + hypertable_index_name | index_name +-----------------------+------------------------------------- + t_new_constraint | _hyper_13_26_chunk_t_new_constraint + t_new_constraint | _hyper_13_27_chunk_t_new_constraint +(2 rows) + +SELECT hypertable_constraint_name, constraint_name from _timescaledb_catalog.chunk_constraint WHERE hypertable_constraint_name = 't_new_constraint' ORDER BY 1,2; + hypertable_constraint_name | constraint_name +----------------------------+------------------------------------- + t_new_constraint | _hyper_13_26_chunk_t_new_constraint + t_new_constraint | _hyper_13_27_chunk_t_new_constraint +(2 rows) + +INSERT INTO t_hypertable AS h VALUES ( 1, '2020-01-01 00:01:00', 3.2) ON CONFLICT (id, time) DO UPDATE SET value = h.value + EXCLUDED.value; +ROLLBACK; +BEGIN; +ALTER TABLE t_hypertable RENAME CONSTRAINT t_hypertable_id_time_key TO t_new_constraint; +-- chunk_index and chunk_constraint should both have updated constraint names +SELECT hypertable_index_name, index_name from _timescaledb_catalog.chunk_index WHERE hypertable_index_name = 't_new_constraint' ORDER BY 1,2; + hypertable_index_name | index_name +-----------------------+----------------------- + t_new_constraint | 26_5_t_new_constraint + t_new_constraint | 27_6_t_new_constraint +(2 rows) + +SELECT hypertable_constraint_name, constraint_name from _timescaledb_catalog.chunk_constraint WHERE hypertable_constraint_name = 't_new_constraint' ORDER BY 1,2; + hypertable_constraint_name | constraint_name +----------------------------+----------------------- + t_new_constraint | 26_5_t_new_constraint + t_new_constraint | 27_6_t_new_constraint +(2 rows) + +INSERT INTO t_hypertable AS h VALUES ( 1, '2020-01-01 00:01:00', 3.2) ON CONFLICT (id, time) DO UPDATE SET value = h.value + EXCLUDED.value; +ROLLBACK; diff --git a/test/sql/alter.sql b/test/sql/alter.sql index 70aeaeac9..ea76595b8 100644 --- a/test/sql/alter.sql +++ b/test/sql/alter.sql @@ -378,3 +378,31 @@ SELECT * from _timescaledb_catalog.hypertable; SELECT * from _timescaledb_catalog.chunk; DROP TABLE my_table; + +-- test renaming unique constraints/indexes +CREATE TABLE t_hypertable ( id INTEGER NOT NULL, time TIMESTAMPTZ NOT NULL, value FLOAT NOT NULL CHECK (value > 0), UNIQUE(id, time)); +SELECT create_hypertable('t_hypertable', 'time'); + +INSERT INTO t_hypertable AS h VALUES ( 1, '2020-01-01 00:00:00', 3.2) ON CONFLICT (id, time) DO UPDATE SET value = h.value + EXCLUDED.value; +INSERT INTO t_hypertable AS h VALUES ( 1, '2021-01-01 00:00:00', 3.2) ON CONFLICT (id, time) DO UPDATE SET value = h.value + EXCLUDED.value; + +BEGIN; +ALTER INDEX t_hypertable_id_time_key RENAME TO t_new_constraint; + +-- chunk_index and chunk_constraint should both have updated constraint names +SELECT hypertable_index_name, index_name from _timescaledb_catalog.chunk_index WHERE hypertable_index_name = 't_new_constraint' ORDER BY 1,2; +SELECT hypertable_constraint_name, constraint_name from _timescaledb_catalog.chunk_constraint WHERE hypertable_constraint_name = 't_new_constraint' ORDER BY 1,2; + +INSERT INTO t_hypertable AS h VALUES ( 1, '2020-01-01 00:01:00', 3.2) ON CONFLICT (id, time) DO UPDATE SET value = h.value + EXCLUDED.value; +ROLLBACK; + +BEGIN; +ALTER TABLE t_hypertable RENAME CONSTRAINT t_hypertable_id_time_key TO t_new_constraint; + +-- chunk_index and chunk_constraint should both have updated constraint names +SELECT hypertable_index_name, index_name from _timescaledb_catalog.chunk_index WHERE hypertable_index_name = 't_new_constraint' ORDER BY 1,2; +SELECT hypertable_constraint_name, constraint_name from _timescaledb_catalog.chunk_constraint WHERE hypertable_constraint_name = 't_new_constraint' ORDER BY 1,2; + +INSERT INTO t_hypertable AS h VALUES ( 1, '2020-01-01 00:01:00', 3.2) ON CONFLICT (id, time) DO UPDATE SET value = h.value + EXCLUDED.value; +ROLLBACK; +