Skip to content

Commit c420c11

Browse files
committed
Create a catalog entry for constraint-backed indexes
This change makes our catalog more in-line with the pg catalog. It also will simplify a lot of other code.
1 parent ec746d1 commit c420c11

18 files changed

+288
-164
lines changed

sql/chunk.sql

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,5 @@ BEGIN
7272

7373
SELECT * INTO STRICT hypertable_row FROM _timescaledb_catalog.hypertable WHERE id = chunk_row.hypertable_id;
7474
main_table_oid := format('%I.%I', hypertable_row.schema_name, hypertable_row.table_name)::regclass;
75-
76-
--create the hypertable-constraints copy
77-
PERFORM _timescaledb_internal.create_chunk_constraint(chunk_row.id, oid)
78-
FROM pg_constraint
79-
WHERE conrelid = main_table_oid
80-
AND _timescaledb_internal.need_chunk_constraint(oid);
81-
8275
END
8376
$BODY$;

sql/chunk_constraint.sql

Lines changed: 21 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,17 @@ CREATE OR REPLACE FUNCTION _timescaledb_internal.create_chunk_constraint(
5757
chunk_id INTEGER,
5858
constraint_oid OID
5959
)
60-
RETURNS VOID LANGUAGE PLPGSQL AS
60+
RETURNS OID LANGUAGE PLPGSQL AS
6161
$BODY$
6262
DECLARE
6363
chunk_constraint_row _timescaledb_catalog.chunk_constraint;
64+
chunk_row _timescaledb_catalog.chunk;
6465
constraint_row pg_constraint;
66+
hypertable_index_class_row pg_class;
67+
chunk_index_class_row pg_class;
6568
constraint_name TEXT;
6669
hypertable_constraint_name TEXT = NULL;
70+
chunk_constraint_oid OID;
6771
BEGIN
6872
SELECT * INTO STRICT constraint_row FROM pg_constraint WHERE OID = constraint_oid;
6973
hypertable_constraint_name := constraint_row.conname;
@@ -72,7 +76,17 @@ BEGIN
7276
INSERT INTO _timescaledb_catalog.chunk_constraint (chunk_id, constraint_name, dimension_slice_id, hypertable_constraint_name)
7377
VALUES (chunk_id, constraint_name, NULL, hypertable_constraint_name) RETURNING * INTO STRICT chunk_constraint_row;
7478

79+
--create actual constraint
7580
PERFORM _timescaledb_internal.chunk_constraint_add_table_constraint(chunk_constraint_row);
81+
82+
SELECT * INTO STRICT chunk_row FROM _timescaledb_catalog.chunk chunk WHERE chunk.id = chunk_id;
83+
84+
SELECT oid INTO STRICT chunk_constraint_oid
85+
FROM pg_constraint con
86+
WHERE con.conrelid = format('%I.%I', chunk_row.schema_name, chunk_row.table_name)::regclass
87+
AND con.conname = constraint_name;
88+
89+
RETURN chunk_constraint_oid;
7690
END
7791
$BODY$;
7892

@@ -88,6 +102,7 @@ $BODY$
88102
DECLARE
89103
chunk_row _timescaledb_catalog.chunk;
90104
chunk_constraint_row _timescaledb_catalog.chunk_constraint;
105+
constraint_row pg_constraint;
91106
BEGIN
92107
SELECT * INTO STRICT chunk_row FROM _timescaledb_catalog.chunk c WHERE c.id = chunk_id;
93108

@@ -96,6 +111,11 @@ BEGIN
96111
AND cc.chunk_id = drop_chunk_constraint.chunk_id
97112
RETURNING * INTO STRICT chunk_constraint_row;
98113

114+
SELECT * INTO STRICT constraint_row
115+
FROM pg_constraint con
116+
WHERE con.conrelid = format('%I.%I', chunk_row.schema_name, chunk_row.table_name)::regclass
117+
AND con.conname = constraint_name;
118+
99119
IF alter_table THEN
100120
EXECUTE format(
101121
$$ ALTER TABLE %I.%I DROP CONSTRAINT %I $$,
@@ -106,71 +126,6 @@ BEGIN
106126
END
107127
$BODY$;
108128

109-
-- do I need to add a hypertable constraint to the chunks?;
110-
CREATE OR REPLACE FUNCTION _timescaledb_internal.need_chunk_constraint(
111-
constraint_oid OID
112-
)
113-
RETURNS BOOLEAN LANGUAGE PLPGSQL VOLATILE AS
114-
$BODY$
115-
DECLARE
116-
constraint_row record;
117-
BEGIN
118-
SELECT * INTO STRICT constraint_row FROM pg_constraint WHERE OID = constraint_oid;
119-
120-
IF constraint_row.contype IN ('c') THEN
121-
-- check and not null constraints handled by regular inheritance (from docs):
122-
-- All check constraints and not-null constraints on a parent table are automatically inherited by its children,
123-
-- unless explicitly specified otherwise with NO INHERIT clauses. Other types of constraints
124-
-- (unique, primary key, and foreign key constraints) are not inherited."
125-
126-
IF constraint_row.connoinherit THEN
127-
RAISE 'NO INHERIT option not supported on hypertables: %', constraint_row.conname
128-
USING ERRCODE = 'IO101';
129-
END IF;
130-
131-
RETURN FALSE;
132-
END IF;
133-
RETURN TRUE;
134-
END
135-
$BODY$;
136-
137-
-- Creates a constraint on all chunks for a hypertable.
138-
CREATE OR REPLACE FUNCTION _timescaledb_internal.add_constraint(
139-
hypertable_id INTEGER,
140-
constraint_oid OID
141-
)
142-
RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS
143-
$BODY$
144-
DECLARE
145-
constraint_row pg_constraint;
146-
hypertable_row _timescaledb_catalog.hypertable;
147-
BEGIN
148-
IF _timescaledb_internal.need_chunk_constraint(constraint_oid) THEN
149-
SELECT * INTO STRICT constraint_row FROM pg_constraint WHERE OID = constraint_oid;
150-
151-
PERFORM _timescaledb_internal.create_chunk_constraint(c.id, constraint_oid)
152-
FROM _timescaledb_catalog.chunk c
153-
WHERE c.hypertable_id = add_constraint.hypertable_id;
154-
END IF;
155-
END
156-
$BODY$;
157-
158-
CREATE OR REPLACE FUNCTION _timescaledb_internal.add_constraint_by_name(
159-
hypertable_id INTEGER,
160-
constraint_name name
161-
)
162-
RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS
163-
$BODY$
164-
DECLARE
165-
constraint_oid OID;
166-
BEGIN
167-
SELECT oid INTO STRICT constraint_oid FROM pg_constraint WHERE conname = constraint_name
168-
AND conrelid = _timescaledb_internal.main_table_from_hypertable(hypertable_id);
169-
170-
PERFORM _timescaledb_internal.add_constraint(hypertable_id, constraint_oid);
171-
END
172-
$BODY$;
173-
174129
-- Drops constraint on all chunks for a hypertable.
175130
CREATE OR REPLACE FUNCTION _timescaledb_internal.drop_constraint(
176131
hypertable_id INTEGER,

sql/ddl_api.sql

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,6 @@ BEGIN
118118
USING ERRCODE = 'IO101';
119119
END;
120120

121-
PERFORM _timescaledb_internal.add_constraint(hypertable_row.id, oid)
122-
FROM pg_constraint
123-
WHERE conrelid = main_table;
124-
125121
IF create_default_indexes THEN
126122
PERFORM _timescaledb_internal.create_default_indexes(hypertable_row, main_table, partitioning_column);
127123
END IF;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,26 @@
11
DROP FUNCTION IF EXISTS drop_chunks(INTEGER, NAME, NAME, BOOLEAN);
2+
3+
DROP FUNCTION _timescaledb_internal.create_chunk_constraint(integer,oid);
4+
DROP FUNCTION _timescaledb_internal.add_constraint(integer,oid);
5+
DROP FUNCTION _timescaledb_internal.add_constraint_by_name(integer,name);
6+
DROP FUNCTION _timescaledb_internal.need_chunk_constraint(oid);
7+
8+
INSERT INTO _timescaledb_catalog.chunk_index (chunk_id, index_name, hypertable_id, hypertable_index_name)
9+
SELECT chunk_con.chunk_id, pg_chunk_index_class.relname, chunk.hypertable_id, pg_hypertable_index_class.relname
10+
FROM _timescaledb_catalog.chunk_constraint chunk_con
11+
INNER JOIN _timescaledb_catalog.chunk chunk ON (chunk_con.chunk_id = chunk.id)
12+
INNER JOIN _timescaledb_catalog.hypertable hypertable ON (chunk.hypertable_id = hypertable.id)
13+
INNER JOIN pg_constraint pg_chunk_con ON (
14+
pg_chunk_con.conrelid = format('%I.%I', chunk.schema_name, chunk.table_name)::regclass
15+
AND pg_chunk_con.conname = chunk_con.constraint_name
16+
)
17+
INNER JOIN pg_class pg_chunk_index_class ON (
18+
pg_chunk_con.conindid = pg_chunk_index_class.oid
19+
)
20+
INNER JOIN pg_constraint pg_hypertable_con ON (
21+
pg_hypertable_con.conrelid = format('%I.%I', hypertable.schema_name, hypertable.table_name)::regclass
22+
AND pg_hypertable_con.conname = chunk_con.hypertable_constraint_name
23+
)
24+
INNER JOIN pg_class pg_hypertable_index_class ON (
25+
pg_hypertable_con.conindid = pg_hypertable_index_class.oid
26+
);

src/catalog.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ const static InternalFunctionDef internal_function_definitions[_MAX_INTERNAL_FUN
9494
.name = "ddl_change_owner",
9595
.args = 2,
9696
},
97-
[DDL_ADD_CONSTRAINT] = {
98-
.name = "add_constraint_by_name",
97+
[DDL_CREATE_CHUNK_CONSTRAINT] = {
98+
.name = "create_chunk_constraint",
9999
.args = 2,
100100
},
101101
[DDL_DROP_CONSTRAINT] = {

src/catalog.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,18 @@ enum CatalogTable
3232
};
3333

3434
#define CatalogInternalCall1(func, datum1) \
35-
OidFunctionCall1(catalog_get_internal_function_id(catalog_get(), func), datum1);
35+
OidFunctionCall1(catalog_get_internal_function_id(catalog_get(), func), datum1)
3636
#define CatalogInternalCall2(func, datum1, datum2) \
37-
OidFunctionCall2(catalog_get_internal_function_id(catalog_get(), func), datum1, datum2);
37+
OidFunctionCall2(catalog_get_internal_function_id(catalog_get(), func), datum1, datum2)
3838
#define CatalogInternalCall3(func, datum1, datum2, datum3) \
39-
OidFunctionCall3(catalog_get_internal_function_id(catalog_get(), func), datum1, datum2, datum3);
39+
OidFunctionCall3(catalog_get_internal_function_id(catalog_get(), func), datum1, datum2, datum3)
4040
#define CatalogInternalCall4(func, datum1, datum2, datum3, datum4) \
41-
OidFunctionCall4(catalog_get_internal_function_id(catalog_get(), func), datum1, datum2, datum3, datum4);
41+
OidFunctionCall4(catalog_get_internal_function_id(catalog_get(), func), datum1, datum2, datum3, datum4)
4242

4343
typedef enum InternalFunction
4444
{
4545
DDL_CHANGE_OWNER = 0,
46-
DDL_ADD_CONSTRAINT,
46+
DDL_CREATE_CHUNK_CONSTRAINT,
4747
DDL_DROP_CONSTRAINT,
4848
DDL_DROP_HYPERTABLE,
4949
DDL_RENAME_HYPERTABLE,

src/chunk.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ chunk_create_after_lock(Hypertable *ht, Point *p, const char *schema, const char
320320
/* Create all indexes on the chunk */
321321
chunk_index_create_all(ht->fd.id, ht->main_table_relid, chunk->fd.id, chunk->table_id);
322322

323+
chunk_constraint_create_all_on_chunk(ht, chunk);
324+
323325
catalog_restore_user(&sec_ctx);
324326

325327
return chunk;

src/chunk_constraint.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,23 @@
44
#include <access/heapam.h>
55
#include <access/xact.h>
66
#include <catalog/indexing.h>
7+
#include <catalog/pg_constraint.h>
8+
#include <catalog/objectaddress.h>
79

810
#include "scanner.h"
911
#include "chunk_constraint.h"
12+
#include "chunk_index.h"
1013
#include "dimension_slice.h"
1114
#include "hypercube.h"
1215
#include "chunk.h"
16+
#include "hypertable.h"
17+
#include "errors.h"
18+
#include "process_utility.h"
19+
20+
#define create_chunk_constraint(chunk, constraint_oid) \
21+
DatumGetObjectId(CatalogInternalCall2(DDL_CREATE_CHUNK_CONSTRAINT, \
22+
Int32GetDatum(chunk->fd.id), \
23+
ObjectIdGetDatum(constraint_oid)))
1324

1425
static inline ChunkConstraint *
1526
chunk_constraint_fill(ChunkConstraint *cc, HeapTuple tuple)
@@ -190,3 +201,90 @@ chunk_constraint_insert_multi(ChunkConstraint *constraints, Size num_constraints
190201

191202
heap_close(rel, RowExclusiveLock);
192203
}
204+
205+
static bool
206+
chunk_constraint_need_on_chunk(Form_pg_constraint conform)
207+
{
208+
if (conform->contype == CONSTRAINT_CHECK)
209+
{
210+
/*
211+
* check and not null constraints handled by regular inheritance (from
212+
* docs): All check constraints and not-null constraints on a parent
213+
* table are automatically inherited by its children, unless
214+
* explicitly specified otherwise with NO INHERIT clauses. Other types
215+
* of constraints (unique, primary key, and foreign key constraints)
216+
* are not inherited."
217+
*/
218+
if (conform->connoinherit)
219+
{
220+
ereport(ERROR,
221+
(errcode(ERRCODE_IO_OPERATION_NOT_SUPPORTED),
222+
errmsg("NO INHERIT option not supported on hypertables: %s", conform->conname.data)
223+
));
224+
}
225+
return false;
226+
}
227+
return true;
228+
}
229+
230+
static void
231+
chunk_constraint_create_on_chunk_impl(Hypertable *ht, Chunk *chunk, HeapTuple constraint_htup)
232+
{
233+
Form_pg_constraint pg_constraint = (Form_pg_constraint) GETSTRUCT(constraint_htup);
234+
235+
if (chunk_constraint_need_on_chunk(pg_constraint))
236+
{
237+
Oid hypertable_constraint_oid = HeapTupleGetOid(constraint_htup);
238+
Oid chunk_constraint_oid;
239+
CatalogSecurityContext sec_ctx;
240+
241+
catalog_become_owner(catalog_get(), &sec_ctx);
242+
process_utility_set_expect_chunk_modification(true);
243+
chunk_constraint_oid = create_chunk_constraint(chunk, hypertable_constraint_oid);
244+
process_utility_set_expect_chunk_modification(false);
245+
catalog_restore_user(&sec_ctx);
246+
247+
Assert(OidIsValid(chunk_constraint_oid));
248+
249+
if (OidIsValid(pg_constraint->conindid) && pg_constraint->contype != CONSTRAINT_FOREIGN)
250+
{
251+
chunk_index_create_from_constraint(ht->fd.id, hypertable_constraint_oid, chunk->fd.id, chunk_constraint_oid);
252+
}
253+
}
254+
}
255+
256+
void
257+
chunk_constraint_create_all_on_chunk(Hypertable *ht, Chunk *chunk)
258+
{
259+
ScanKeyData skey;
260+
Relation rel;
261+
SysScanDesc scan;
262+
HeapTuple htup;
263+
264+
ScanKeyInit(&skey,
265+
Anum_pg_constraint_conrelid,
266+
BTEqualStrategyNumber, F_OIDEQ, ht->main_table_relid);
267+
268+
rel = heap_open(ConstraintRelationId, AccessShareLock);
269+
scan = systable_beginscan(rel, ConstraintRelidIndexId, true,
270+
NULL, 1, &skey);
271+
272+
while (HeapTupleIsValid(htup = systable_getnext(scan)))
273+
{
274+
chunk_constraint_create_on_chunk_impl(ht, chunk, htup);
275+
}
276+
systable_endscan(scan);
277+
heap_close(rel, AccessShareLock);
278+
}
279+
280+
void
281+
chunk_constraint_create_on_chunk(Hypertable *ht, Chunk *chunk, Oid constraintOid)
282+
{
283+
Relation rel;
284+
HeapTuple htup;
285+
286+
rel = heap_open(ConstraintRelationId, AccessShareLock);
287+
htup = get_catalog_object_by_oid(rel, constraintOid);
288+
chunk_constraint_create_on_chunk_impl(ht, chunk, htup);
289+
heap_close(rel, AccessShareLock);
290+
}

src/chunk_constraint.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <nodes/pg_list.h>
77

88
#include "catalog.h"
9+
#include "hypertable.h"
910

1011
typedef struct ChunkConstraint
1112
{
@@ -26,5 +27,6 @@ typedef struct ChunkScanCtx ChunkScanCtx;
2627
extern Chunk *chunk_constraint_scan_by_chunk_id(Chunk *chunk);
2728
extern int chunk_constraint_scan_by_dimension_slice_id(DimensionSlice *slice, ChunkScanCtx *ctx);
2829
extern void chunk_constraint_insert_multi(ChunkConstraint *constraints, Size num_constraints);
29-
30+
extern void chunk_constraint_create_all_on_chunk(Hypertable *ht, Chunk *chunk);
31+
extern void chunk_constraint_create_on_chunk(Hypertable *ht, Chunk *chunk, Oid constraintOid);
3032
#endif /* TIMESCALEDB_CHUNK_CONSTRAINT_H */

0 commit comments

Comments
 (0)