Skip to content

Commit 87f055d

Browse files
committed
Add support for ALTER TABLE RENAME CONSTRAINT.
Renaming constraints on hypertables is now supported. Using the ONLY option with RENAME CONSTRAINT is blocked for hypertables. Renaming constraints on chunks is also blocked. This commit also fixes a possible bug in chunk_constraint code. Previously, `chunk_constraint_add_from_tuple` used GETSTRUCT on the tuple to convert the tuple to `FormData_chunk_constraint`. This was incorrect since some fields can be NULL. Using GETSTRUCT for tables with NULLABLE fields is unsafe and indeed was incorrect· in this case.
1 parent 0b79156 commit 87f055d

File tree

6 files changed

+287
-71
lines changed

6 files changed

+287
-71
lines changed

src/catalog.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ enum Anum_chunk_constraint
312312
#define Natts_chunk_constraint \
313313
(_Anum_chunk_constraint_max - 1)
314314

315+
/* Do Not use GET_STRUCT with FormData_chunk_constraint. It contains NULLS */
315316
typedef struct FormData_chunk_constraint
316317
{
317318
int32 chunk_id;

src/chunk_constraint.c

Lines changed: 150 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
#include <catalog/pg_constraint.h>
1212
#include <catalog/pg_constraint_fn.h>
1313
#include <catalog/objectaddress.h>
14+
#include <commands/tablecmds.h>
1415
#include <catalog/dependency.h>
1516
#include <funcapi.h>
17+
#include <nodes/makefuncs.h>
1618

1719
#include "scanner.h"
1820
#include "chunk_constraint.h"
@@ -65,6 +67,36 @@ chunk_constraints_expand(ChunkConstraints *ccs, int16 new_capacity)
6567
ccs->constraints = repalloc(ccs->constraints, CHUNK_CONSTRAINTS_SIZE(new_capacity));
6668
}
6769

70+
71+
static
72+
void
73+
chunk_constraint_choose_name(Name dst, bool is_dimension, int32 dimension_slice_id, const char *hypertable_constraint_name, int32 chunk_id)
74+
{
75+
if (is_dimension)
76+
{
77+
snprintf(NameStr(*dst), NAMEDATALEN, "constraint_%d",
78+
dimension_slice_id);
79+
}
80+
else
81+
{
82+
char constrname[100];
83+
CatalogSecurityContext sec_ctx;
84+
85+
Assert(hypertable_constraint_name != NULL);
86+
87+
catalog_become_owner(catalog_get(), &sec_ctx);
88+
snprintf(constrname,
89+
100,
90+
"%d_" INT64_FORMAT "_%s",
91+
chunk_id,
92+
catalog_table_next_seq_id(catalog_get(), CHUNK_CONSTRAINT),
93+
hypertable_constraint_name);
94+
catalog_restore_user(&sec_ctx);
95+
96+
namestrcpy(dst, constrname);
97+
}
98+
}
99+
68100
static ChunkConstraint *
69101
chunk_constraints_add(ChunkConstraints *ccs,
70102
int32 chunk_id,
@@ -81,30 +113,14 @@ chunk_constraints_add(ChunkConstraints *ccs,
81113

82114
if (NULL == constraint_name)
83115
{
116+
chunk_constraint_choose_name(&cc->fd.constraint_name,
117+
is_dimension_constraint(cc),
118+
cc->fd.dimension_slice_id,
119+
hypertable_constraint_name,
120+
cc->fd.chunk_id);
121+
84122
if (is_dimension_constraint(cc))
85-
{
86-
snprintf(NameStr(cc->fd.constraint_name),
87-
NAMEDATALEN,
88-
"constraint_%d",
89-
cc->fd.dimension_slice_id);
90123
namestrcpy(&cc->fd.hypertable_constraint_name, "");
91-
}
92-
else if (NULL != hypertable_constraint_name)
93-
{
94-
CatalogSecurityContext sec_ctx;
95-
char constrname[100];
96-
97-
catalog_become_owner(catalog_get(), &sec_ctx);
98-
snprintf(constrname,
99-
100,
100-
"%d_" INT64_FORMAT "_%s",
101-
cc->fd.chunk_id,
102-
catalog_table_next_seq_id(catalog_get(), CHUNK_CONSTRAINT),
103-
hypertable_constraint_name);
104-
catalog_restore_user(&sec_ctx);
105-
106-
namestrcpy(&cc->fd.constraint_name, constrname);
107-
}
108124
}
109125
else
110126
namestrcpy(&cc->fd.constraint_name, constraint_name);
@@ -189,22 +205,33 @@ chunk_constraint_insert(ChunkConstraint *constraint)
189205

190206

191207
static ChunkConstraint *
192-
chunk_constraints_add_from_tuple(ChunkConstraints *ccs, HeapTuple tuple)
208+
chunk_constraints_add_from_tuple(ChunkConstraints *ccs, TupleInfo *ti)
193209
{
194-
FormData_chunk_constraint *form = (FormData_chunk_constraint *) GETSTRUCT(tuple);
195-
int32 dimension_slice_id = form->dimension_slice_id;
196-
const char *hypertable_constraint_name = NameStr(form->hypertable_constraint_name);
210+
bool nulls[Natts_chunk_constraint];
211+
Datum values[Natts_chunk_constraint];
212+
int32 dimension_slice_id;
213+
Name constraint_name;
214+
Name hypertable_constraint_name;
197215

198-
if (heap_attisnull(tuple, Anum_chunk_constraint_dimension_slice_id))
216+
heap_deform_tuple(ti->tuple, ti->desc, values, nulls);
217+
218+
constraint_name = DatumGetName(values[Anum_chunk_constraint_constraint_name - 1]);
219+
if (heap_attisnull(ti->tuple, Anum_chunk_constraint_dimension_slice_id))
220+
{
199221
dimension_slice_id = 0;
222+
hypertable_constraint_name = DatumGetName(values[Anum_chunk_constraint_hypertable_constraint_name - 1]);
223+
}
200224
else
201-
hypertable_constraint_name = "";
225+
{
226+
dimension_slice_id = DatumGetInt32(values[Anum_chunk_constraint_dimension_slice_id - 1]);
227+
hypertable_constraint_name = DatumGetName(DirectFunctionCall1(namein, CStringGetDatum("")));
228+
}
202229

203230
return chunk_constraints_add(ccs,
204-
form->chunk_id,
231+
DatumGetInt32(values[Anum_chunk_constraint_chunk_id - 1]),
205232
dimension_slice_id,
206-
NameStr(form->constraint_name),
207-
hypertable_constraint_name);
233+
NameStr(*constraint_name),
234+
NameStr(*hypertable_constraint_name));
208235
}
209236

210237
/*
@@ -316,7 +343,7 @@ chunk_constraint_tuple_found(TupleInfo *ti, void *data)
316343
{
317344
ChunkConstraints *ccs = data;
318345

319-
chunk_constraints_add_from_tuple(ccs, ti->tuple);
346+
chunk_constraints_add_from_tuple(ccs, ti);
320347

321348
return true;
322349
}
@@ -408,7 +435,7 @@ chunk_constraint_dimension_slice_id_tuple_found(TupleInfo *ti, void *data)
408435
else
409436
chunk = entry->chunk;
410437

411-
chunk_constraints_add_from_tuple(chunk->constraints, ti->tuple);
438+
chunk_constraints_add_from_tuple(chunk->constraints, ti);
412439

413440
hypercube_add_slice(chunk->cube, ccsd->slice);
414441

@@ -546,23 +573,31 @@ chunk_constraint_create_on_chunk(Chunk *chunk, Oid constraint_oid)
546573
chunk->fd.hypertable_id);
547574
}
548575

549-
typedef struct DeleteConstraintInfo
576+
typedef struct ConstraintInfo
550577
{
551-
int32 chunk_id;
552-
Oid chunk_oid;
553-
char *hypertable_constraint_name;
554-
} DeleteConstraintInfo;
578+
const char *hypertable_constraint_name;
579+
} ConstraintInfo;
580+
581+
typedef struct RenameHypertableConstraintInfo
582+
{
583+
ConstraintInfo base;
584+
const char *newname;
585+
} RenameHypertableConstraintInfo;
586+
555587

556588
static bool
557589
chunk_constraint_delete_tuple(TupleInfo *ti, void *data)
558590
{
559-
DeleteConstraintInfo *info = data;
560591
bool isnull;
561592
Datum constrname = heap_getattr(ti->tuple, Anum_chunk_constraint_constraint_name,
562593
ti->desc, &isnull);
594+
int32 chunk_id = DatumGetInt32(heap_getattr(ti->tuple, Anum_chunk_constraint_chunk_id,
595+
ti->desc, &isnull));
596+
Chunk *chunk = chunk_get_by_id(chunk_id, 0, true);
597+
563598
ObjectAddress constrobj = {
564599
.classId = ConstraintRelationId,
565-
.objectId = get_relation_constraint_oid(info->chunk_oid,
600+
.objectId = get_relation_constraint_oid(chunk->table_id,
566601
NameStr(*DatumGetName(constrname)), false),
567602
};
568603

@@ -575,22 +610,19 @@ chunk_constraint_delete_tuple(TupleInfo *ti, void *data)
575610
static bool
576611
hypertable_constraint_tuple_filter(TupleInfo *ti, void *data)
577612
{
578-
DeleteConstraintInfo *info = data;
613+
ConstraintInfo *info = data;
579614
bool nulls[Natts_chunk_constraint];
580615
Datum values[Natts_chunk_constraint];
581-
int32 chunk_id;
582616
const char *constrname;
583617

584618
heap_deform_tuple(ti->tuple, ti->desc, values, nulls);
585619

586620
if (nulls[Anum_chunk_constraint_hypertable_constraint_name - 1])
587621
return false;
588622

589-
chunk_id = DatumGetInt32(values[Anum_chunk_constraint_chunk_id - 1]);
590623
constrname = NameStr(*DatumGetName(values[Anum_chunk_constraint_hypertable_constraint_name - 1]));
591624

592-
return info->chunk_id == chunk_id &&
593-
NULL != info->hypertable_constraint_name &&
625+
return NULL != info->hypertable_constraint_name &&
594626
strcmp(info->hypertable_constraint_name, constrname) == 0;
595627
}
596628

@@ -599,9 +631,7 @@ chunk_constraint_delete_by_hypertable_constraint_name(int32 chunk_id,
599631
Oid chunk_oid,
600632
char *hypertable_constraint_name)
601633
{
602-
DeleteConstraintInfo info = {
603-
.chunk_id = chunk_id,
604-
.chunk_oid = chunk_oid,
634+
ConstraintInfo info = {
605635
.hypertable_constraint_name = hypertable_constraint_name,
606636
};
607637

@@ -615,16 +645,10 @@ chunk_constraint_delete_by_hypertable_constraint_name(int32 chunk_id,
615645
int
616646
chunk_constraint_delete_by_chunk_id(int32 chunk_id, Oid chunk_oid)
617647
{
618-
DeleteConstraintInfo info = {
619-
.chunk_id = chunk_id,
620-
.chunk_oid = chunk_oid,
621-
.hypertable_constraint_name = NULL,
622-
};
623-
624648
return chunk_constraint_scan_by_chunk_id_internal(chunk_id,
625649
chunk_constraint_delete_tuple,
626650
NULL,
627-
&info,
651+
NULL,
628652
RowExclusiveLock);
629653
}
630654

@@ -640,3 +664,74 @@ chunk_constraint_recreate(ChunkConstraint *cc, Oid chunk_oid)
640664
performDeletion(&constrobj, DROP_RESTRICT, 0);
641665
chunk_constraint_create_on_table(cc, chunk_oid);
642666
}
667+
668+
static void
669+
chunk_constraint_rename_on_chunk_table(int32 chunk_id, char *old_name, char *new_name)
670+
{
671+
Chunk *chunk = chunk_get_by_id(chunk_id, 0, true);
672+
RenameStmt rename = {
673+
.renameType = OBJECT_TABCONSTRAINT,
674+
.relation = makeRangeVar(NameStr(chunk->fd.schema_name), NameStr(chunk->fd.table_name), 0),
675+
.subname = old_name,
676+
.newname = new_name,
677+
};
678+
679+
RenameConstraint(&rename);
680+
}
681+
682+
static bool
683+
chunk_constraint_rename_hypertable_tuple(TupleInfo *ti, void *data)
684+
{
685+
RenameHypertableConstraintInfo *info = data;
686+
687+
bool nulls[Natts_chunk_constraint];
688+
Datum values[Natts_chunk_constraint];
689+
bool repl[Natts_chunk_constraint] = {false};
690+
691+
HeapTuple tuple;
692+
NameData new_hypertable_constraint_name;
693+
NameData new_chunk_constraint_name;
694+
Name old_chunk_constraint_name;
695+
int32 chunk_id;
696+
697+
heap_deform_tuple(ti->tuple, ti->desc, values, nulls);
698+
699+
chunk_id = DatumGetInt32(values[Anum_chunk_constraint_chunk_id - 1]);
700+
namestrcpy(&new_hypertable_constraint_name, info->newname);
701+
chunk_constraint_choose_name(&new_chunk_constraint_name,
702+
false,
703+
0,
704+
info->newname,
705+
chunk_id);
706+
707+
values[Anum_chunk_constraint_hypertable_constraint_name - 1] = NameGetDatum(&new_hypertable_constraint_name);
708+
repl[Anum_chunk_constraint_hypertable_constraint_name - 1] = true;
709+
old_chunk_constraint_name = DatumGetName(values[Anum_chunk_constraint_constraint_name - 1]);
710+
values[Anum_chunk_constraint_constraint_name - 1] = NameGetDatum(&new_chunk_constraint_name);
711+
repl[Anum_chunk_constraint_constraint_name - 1] = true;
712+
713+
chunk_constraint_rename_on_chunk_table(chunk_id, NameStr(*old_chunk_constraint_name), NameStr(new_chunk_constraint_name));
714+
715+
tuple = heap_modify_tuple(ti->tuple, ti->desc, values, nulls, repl);
716+
catalog_update(ti->scanrel, tuple);
717+
heap_freetuple(tuple);
718+
719+
return true;
720+
}
721+
722+
int
723+
chunk_constraint_rename_hypertable_constraint(int32 chunk_id, const char *oldname, const char *newname)
724+
{
725+
RenameHypertableConstraintInfo info = {
726+
.base = {
727+
.hypertable_constraint_name = oldname,
728+
},
729+
.newname = newname,
730+
};
731+
732+
return chunk_constraint_scan_by_chunk_id_internal(chunk_id,
733+
chunk_constraint_rename_hypertable_tuple,
734+
hypertable_constraint_tuple_filter,
735+
&info,
736+
RowExclusiveLock);
737+
}

src/chunk_constraint.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,7 @@ extern void chunk_constraint_create_on_chunk(Chunk *chunk, Oid constraint_oid);
4545
extern int chunk_constraint_delete_by_hypertable_constraint_name(int32 chunk_id, Oid chunk_oid, char *hypertable_constraint_name);
4646
extern int chunk_constraint_delete_by_chunk_id(int32 chunk_id, Oid chunk_oid);
4747
extern void chunk_constraint_recreate(ChunkConstraint *cc, Oid chunk_oid);
48+
extern int chunk_constraint_rename_hypertable_constraint(int32 chunk_id, const char *oldname, const char *newname);
49+
4850

4951
#endif /* TIMESCALEDB_CHUNK_CONSTRAINT_H */

src/process_utility.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,49 @@ process_rename_index(Cache *hcache, Oid relid, RenameStmt *stmt)
619619
}
620620
}
621621

622+
static void
623+
rename_hypertable_constraint(Hypertable *ht, Oid chunk_relid, void *arg)
624+
{
625+
RenameStmt *stmt = (RenameStmt *) arg;
626+
Chunk *chunk = chunk_get_by_relid(chunk_relid, ht->space->num_dimensions, true);
627+
628+
chunk_constraint_rename_hypertable_constraint(chunk->fd.id, stmt->subname, stmt->newname);
629+
}
630+
631+
632+
static void
633+
process_rename_constraint(Cache *hcache, Oid relid, RenameStmt *stmt)
634+
{
635+
Hypertable *ht;
636+
637+
ht = hypertable_cache_get_entry(hcache, relid);
638+
639+
if (NULL != ht)
640+
{
641+
#if PG10
642+
bool only = !stmt->relation->inh;
643+
#elif PG96
644+
bool only = (stmt->relation->inhOpt == INH_NO);
645+
#endif
646+
if (only)
647+
ereport(ERROR,
648+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
649+
errmsg("ONLY option not supported when renaming hypertable constraints")));
650+
foreach_chunk(ht, rename_hypertable_constraint, stmt);
651+
}
652+
else
653+
{
654+
Chunk *chunk = chunk_get_by_relid(relid, 0, false);
655+
656+
if (NULL != chunk)
657+
ereport(ERROR,
658+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
659+
errmsg("Renaming constraints on chunks is not supported")));
660+
661+
}
662+
}
663+
664+
622665
static void
623666
process_rename(Node *parsetree)
624667
{
@@ -650,6 +693,9 @@ process_rename(Node *parsetree)
650693
case OBJECT_INDEX:
651694
process_rename_index(hcache, relid, stmt);
652695
break;
696+
case OBJECT_TABCONSTRAINT:
697+
process_rename_constraint(hcache, relid, stmt);
698+
break;
653699
default:
654700
break;
655701
}

0 commit comments

Comments
 (0)