timescaledb/sql/chunk_constraint.sql
Erik Nordström 097db3d589 Refactor chunk index handling
This change refactors the chunk index handling to make better use
of standard PostgreSQL catalog information, while removing the
hypertable_index metadata table and associated triggers, including
those on the chunk_index table. The chunk_index table itself is
also simplified.

A benefit of this refactoring is that indexes are no longer
created using string mangling to construct the CREATE INDEX command
for a chunk, based on the string definition of the hypertable
index. Instead, indexes are created in C using proper index-related
internal data structures.

Chunk indexes can now also be renamed and are added in the parent
index tablespace. Changing tablespace on a hypertable index also
recurses to chunks, as expected. Default indexes that are added when
creating a hypertable use the hypertable's tablespace.

Creating Hypertable indexes with the CONCURRENTLY modifier is
currently blocked, due to unclear semantics regarding concurrent
creation over many tables, including how to deal with snapshots.
2017-10-03 10:51:32 +02:00

189 lines
6.7 KiB
PL/PgSQL

-- Creates a constraint on a chunk.
CREATE OR REPLACE FUNCTION _timescaledb_internal.chunk_constraint_add_table_constraint(
chunk_constraint_row _timescaledb_catalog.chunk_constraint
)
RETURNS VOID LANGUAGE PLPGSQL AS
$BODY$
DECLARE
sql_code TEXT;
chunk_row _timescaledb_catalog.chunk;
hypertable_row _timescaledb_catalog.hypertable;
constraint_oid OID;
def TEXT;
BEGIN
SELECT * INTO STRICT chunk_row FROM _timescaledb_catalog.chunk c WHERE c.id = chunk_constraint_row.chunk_id;
SELECT * INTO STRICT hypertable_row FROM _timescaledb_catalog.hypertable h WHERE h.id = chunk_row.hypertable_id;
IF chunk_constraint_row.dimension_slice_id IS NOT NULL THEN
def := format('CHECK (%s)', _timescaledb_internal.dimension_slice_get_constraint_sql(chunk_constraint_row.dimension_slice_id));
ELSIF chunk_constraint_row.hypertable_constraint_name IS NOT NULL THEN
SELECT oid INTO STRICT constraint_oid FROM pg_constraint
WHERE conname=chunk_constraint_row.hypertable_constraint_name AND
conrelid = format('%I.%I', hypertable_row.schema_name, hypertable_row.table_name)::regclass::oid;
def := pg_get_constraintdef(constraint_oid);
ELSE
RAISE 'Unknown constraint type';
END IF;
sql_code := format(
$$ ALTER TABLE %I.%I ADD CONSTRAINT %I %s $$,
chunk_row.schema_name, chunk_row.table_name, chunk_constraint_row.constraint_name, def
);
EXECUTE sql_code;
END
$BODY$;
CREATE OR REPLACE FUNCTION _timescaledb_internal.chunk_constraint_drop_table_constraint(
chunk_constraint_row _timescaledb_catalog.chunk_constraint
)
RETURNS VOID LANGUAGE PLPGSQL AS
$BODY$
DECLARE
sql_code TEXT;
chunk_row _timescaledb_catalog.chunk;
BEGIN
SELECT * INTO STRICT chunk_row FROM _timescaledb_catalog.chunk c WHERE c.id = chunk_constraint_row.chunk_id;
sql_code := format(
$$ ALTER TABLE %I.%I DROP CONSTRAINT %I $$,
chunk_row.schema_name, chunk_row.table_name, chunk_constraint_row.constraint_name
);
EXECUTE sql_code;
END
$BODY$;
CREATE OR REPLACE FUNCTION _timescaledb_internal.create_chunk_constraint(
chunk_id INTEGER,
constraint_oid OID
)
RETURNS VOID LANGUAGE PLPGSQL AS
$BODY$
DECLARE
chunk_constraint_row _timescaledb_catalog.chunk_constraint;
constraint_row pg_constraint;
constraint_name TEXT;
hypertable_constraint_name TEXT = NULL;
BEGIN
SELECT * INTO STRICT constraint_row FROM pg_constraint WHERE OID = constraint_oid;
hypertable_constraint_name := constraint_row.conname;
constraint_name := format('%s_%s_%s', chunk_id, nextval('_timescaledb_catalog.chunk_constraint_name'), hypertable_constraint_name);
INSERT INTO _timescaledb_catalog.chunk_constraint (chunk_id, constraint_name, dimension_slice_id, hypertable_constraint_name)
VALUES (chunk_id, constraint_name, NULL, hypertable_constraint_name) RETURNING * INTO STRICT chunk_constraint_row;
PERFORM _timescaledb_internal.chunk_constraint_add_table_constraint(chunk_constraint_row);
END
$BODY$;
-- Drop a constraint on a chunk
-- static
CREATE OR REPLACE FUNCTION _timescaledb_internal.drop_chunk_constraint(
chunk_id INTEGER,
constraint_name NAME,
alter_table BOOLEAN = true
)
RETURNS VOID LANGUAGE PLPGSQL AS
$BODY$
DECLARE
chunk_row _timescaledb_catalog.chunk;
chunk_constraint_row _timescaledb_catalog.chunk_constraint;
BEGIN
SELECT * INTO STRICT chunk_row FROM _timescaledb_catalog.chunk c WHERE c.id = chunk_id;
DELETE FROM _timescaledb_catalog.chunk_constraint cc
WHERE cc.constraint_name = drop_chunk_constraint.constraint_name
AND cc.chunk_id = drop_chunk_constraint.chunk_id
RETURNING * INTO STRICT chunk_constraint_row;
IF alter_table THEN
EXECUTE format(
$$ ALTER TABLE %I.%I DROP CONSTRAINT %I $$,
chunk_row.schema_name, chunk_row.table_name, chunk_constraint_row.constraint_name
);
END IF;
END
$BODY$;
-- do I need to add a hypertable constraint to the chunks?;
CREATE OR REPLACE FUNCTION _timescaledb_internal.need_chunk_constraint(
constraint_oid OID
)
RETURNS BOOLEAN LANGUAGE PLPGSQL VOLATILE AS
$BODY$
DECLARE
constraint_row record;
BEGIN
SELECT * INTO STRICT constraint_row FROM pg_constraint WHERE OID = constraint_oid;
IF constraint_row.contype IN ('c') THEN
-- check and not null constraints handled by regular inheritance (from docs):
-- All check constraints and not-null constraints on a parent table are automatically inherited by its children,
-- unless explicitly specified otherwise with NO INHERIT clauses. Other types of constraints
-- (unique, primary key, and foreign key constraints) are not inherited."
IF constraint_row.connoinherit THEN
RAISE 'NO INHERIT option not supported on hypertables: %', constraint_row.conname
USING ERRCODE = 'IO101';
END IF;
RETURN FALSE;
END IF;
RETURN TRUE;
END
$BODY$;
-- Creates a constraint on all chunks for a hypertable.
CREATE OR REPLACE FUNCTION _timescaledb_internal.add_constraint(
hypertable_id INTEGER,
constraint_oid OID
)
RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS
$BODY$
DECLARE
constraint_row pg_constraint;
hypertable_row _timescaledb_catalog.hypertable;
BEGIN
IF _timescaledb_internal.need_chunk_constraint(constraint_oid) THEN
SELECT * INTO STRICT constraint_row FROM pg_constraint WHERE OID = constraint_oid;
PERFORM _timescaledb_internal.create_chunk_constraint(c.id, constraint_oid)
FROM _timescaledb_catalog.chunk c
WHERE c.hypertable_id = add_constraint.hypertable_id;
END IF;
END
$BODY$;
CREATE OR REPLACE FUNCTION _timescaledb_internal.add_constraint_by_name(
hypertable_id INTEGER,
constraint_name name
)
RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS
$BODY$
DECLARE
constraint_oid OID;
BEGIN
SELECT oid INTO STRICT constraint_oid FROM pg_constraint WHERE conname = constraint_name
AND conrelid = _timescaledb_internal.main_table_from_hypertable(hypertable_id);
PERFORM _timescaledb_internal.add_constraint(hypertable_id, constraint_oid);
END
$BODY$;
-- Drops constraint on all chunks for a hypertable.
CREATE OR REPLACE FUNCTION _timescaledb_internal.drop_constraint(
hypertable_id INTEGER,
hypertable_constraint_name NAME
)
RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS
$BODY$
DECLARE
BEGIN
PERFORM _timescaledb_internal.drop_chunk_constraint(cc.chunk_id, cc.constraint_name)
FROM _timescaledb_catalog.chunk c
INNER JOIN _timescaledb_catalog.chunk_constraint cc ON (cc.chunk_id = c.id)
WHERE c.hypertable_id = drop_constraint.hypertable_id AND cc.hypertable_constraint_name = drop_constraint.hypertable_constraint_name;
END
$BODY$;