Fix rename constraint/rename index

When a constraint is backed by an index like a unique constraint
or a primary key constraint the constraint can be renamed by either
ALTER TABLE RENAME CONSTRAINT or by ALTER INDEX RENAME. Depending
on the command used to rename different internal metadata tables
would be adjusted leading to corrupt metadata. This patch makes
ALTER TABLE RENAME CONSTRAINT and ALTER INDEX RENAME adjust the
same metadata tables.
This commit is contained in:
Sven Klemm 2020-09-05 17:34:08 +02:00 committed by Sven Klemm
parent 202692f1ef
commit 6d7edb99ba
6 changed files with 200 additions and 0 deletions

View File

@ -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)

View File

@ -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,

View File

@ -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)
{

View File

@ -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,

View File

@ -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;

View File

@ -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;