Block NO INHERIT constraints on hypertables

Constraints with the NO INHERIT option does not make sense on a
hypertable's root table since these will not be enforced.

Previously, NO INHERIT constraints were blocked on chunks, and were
thus not enforced until chunk creation time, allowing creation of NO
INHERIT constraints on empty hypertables, but then causing failure at
chunk-creation time. Instead, NO INHERIT constraints are now properly
blocked at the hypertable level.
This commit is contained in:
Erik Nordström 2018-06-29 15:28:19 +02:00 committed by Erik Nordström
parent e362e9cf18
commit cbc5e60abe
5 changed files with 107 additions and 7 deletions

View File

@ -581,13 +581,6 @@ chunk_constraint_need_on_chunk(Form_pg_constraint conform)
* of constraints (unique, primary key, and foreign key constraints) * of constraints (unique, primary key, and foreign key constraints)
* are not inherited." * are not inherited."
*/ */
if (conform->connoinherit)
{
ereport(ERROR,
(errcode(ERRCODE_IO_OPERATION_NOT_SUPPORTED),
errmsg("NO INHERIT option not supported on hypertables: %s", conform->conname.data)
));
}
return false; return false;
} }
return true; return true;

View File

@ -11,6 +11,9 @@
#include <nodes/memnodes.h> #include <nodes/memnodes.h>
#include <catalog/namespace.h> #include <catalog/namespace.h>
#include <catalog/pg_inherits_fn.h> #include <catalog/pg_inherits_fn.h>
#include <catalog/pg_constraint_fn.h>
#include <catalog/pg_constraint.h>
#include <catalog/indexing.h>
#include <commands/tablespace.h> #include <commands/tablespace.h>
#include <commands/dbcommands.h> #include <commands/dbcommands.h>
#include <commands/schemacmds.h> #include <commands/schemacmds.h>
@ -849,6 +852,46 @@ hypertable_create_schema(const char *schema_name)
); );
} }
/*
* Check that existing table constraints are supported.
*
* Hypertables do not support some constraints. For instance, NO INHERIT
* constraints cannot be enforced on a hypertable since they only exist on the
* parent table, which will have no tuples.
*/
static void
hypertable_validate_constraints(Oid relid)
{
Relation catalog;
SysScanDesc scan;
ScanKeyData scankey;
HeapTuple tuple;
catalog = heap_open(ConstraintRelationId, AccessShareLock);
ScanKeyInit(&scankey, Anum_pg_constraint_conrelid, BTEqualStrategyNumber,
F_OIDEQ, ObjectIdGetDatum(relid));
scan = systable_beginscan(catalog, ConstraintRelidIndexId, true,
NULL, 1, &scankey);
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
{
Form_pg_constraint form = (Form_pg_constraint) GETSTRUCT(tuple);
if (form->contype == CONSTRAINT_CHECK && form->connoinherit)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("cannot have NO INHERIT constraints on hypertable \"%s\"",
get_rel_name(relid)),
errhint("Remove all NO INHERIT constraints from table \"%s\" before making it a hypertable.",
get_rel_name(relid))));
}
systable_endscan(scan);
heap_close(catalog, AccessShareLock);
}
TS_FUNCTION_INFO_V1(hypertable_create); TS_FUNCTION_INFO_V1(hypertable_create);
/* /*
@ -947,6 +990,9 @@ hypertable_create(PG_FUNCTION_ARGS)
errmsg("invalid relation type"))); errmsg("invalid relation type")));
} }
/* Check that the table doesn't have any unsupported constraints */
hypertable_validate_constraints(table_relid);
table_has_data = table_has_tuples(table_relid, GetActiveSnapshot(), NoLock); table_has_data = table_has_tuples(table_relid, GetActiveSnapshot(), NoLock);
if (!migrate_data && table_has_data) if (!migrate_data && table_has_data)

View File

@ -918,6 +918,13 @@ verify_constraint_hypertable(Hypertable *ht, Node *constr_node)
contype = constr->contype; contype = constr->contype;
keys = (contype == CONSTR_EXCLUSION) ? constr->exclusions : constr->keys; keys = (contype == CONSTR_EXCLUSION) ? constr->exclusions : constr->keys;
indexname = constr->indexname; indexname = constr->indexname;
/* NO INHERIT constraints do not really make sense on a hypertable */
if (constr->is_no_inherit)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("cannot have NO INHERIT constraints on hypertable \"%s\"",
get_rel_name(ht->main_table_relid))));
} }
else if (IsA(constr_node, IndexStmt)) else if (IsA(constr_node, IndexStmt))
{ {

View File

@ -545,3 +545,33 @@ SELECT * FROM create_hypertable('hyper_ex_invalid', 'time', chunk_time_interval=
NOTICE: adding not-null constraint to column "time" NOTICE: adding not-null constraint to column "time"
ERROR: cannot create a unique index without the column "time" (used in partitioning) ERROR: cannot create a unique index without the column "time" (used in partitioning)
\set ON_ERROR_STOP 1 \set ON_ERROR_STOP 1
--- NO INHERIT constraints (not allowed) ----
CREATE TABLE hyper_noinherit (
time BIGINT,
sensor_1 NUMERIC NULL DEFAULT 1 CHECK (sensor_1 > 0) NO INHERIT
);
SELECT * FROM test.show_constraints('hyper_noinherit');
Constraint | Type | Columns | Index | Expr
--------------------------------+------+------------+-------+---------------------------
hyper_noinherit_sensor_1_check | c | {sensor_1} | - | (sensor_1 > (0)::numeric)
(1 row)
\set ON_ERROR_STOP 0
SELECT * FROM create_hypertable('hyper_noinherit', 'time', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
ERROR: cannot have NO INHERIT constraints on hypertable "hyper_noinherit"
\set ON_ERROR_STOP 1
CREATE TABLE hyper_noinherit_alter (
time BIGINT,
sensor_1 NUMERIC NULL DEFAULT 1
);
SELECT * FROM create_hypertable('hyper_noinherit_alter', 'time', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
NOTICE: adding not-null constraint to column "time"
create_hypertable
-------------------
(1 row)
\set ON_ERROR_STOP 0
ALTER TABLE hyper_noinherit_alter ADD CONSTRAINT check_noinherit CHECK (sensor_1 > 0) NO INHERIT;
ERROR: cannot have NO INHERIT constraints on hypertable "hyper_noinherit_alter"
\set ON_ERROR_STOP 1

View File

@ -398,3 +398,27 @@ CREATE TABLE hyper_ex_invalid (
\set ON_ERROR_STOP 0 \set ON_ERROR_STOP 0
SELECT * FROM create_hypertable('hyper_ex_invalid', 'time', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month')); SELECT * FROM create_hypertable('hyper_ex_invalid', 'time', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
\set ON_ERROR_STOP 1 \set ON_ERROR_STOP 1
--- NO INHERIT constraints (not allowed) ----
CREATE TABLE hyper_noinherit (
time BIGINT,
sensor_1 NUMERIC NULL DEFAULT 1 CHECK (sensor_1 > 0) NO INHERIT
);
SELECT * FROM test.show_constraints('hyper_noinherit');
\set ON_ERROR_STOP 0
SELECT * FROM create_hypertable('hyper_noinherit', 'time', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
\set ON_ERROR_STOP 1
CREATE TABLE hyper_noinherit_alter (
time BIGINT,
sensor_1 NUMERIC NULL DEFAULT 1
);
SELECT * FROM create_hypertable('hyper_noinherit_alter', 'time', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
\set ON_ERROR_STOP 0
ALTER TABLE hyper_noinherit_alter ADD CONSTRAINT check_noinherit CHECK (sensor_1 > 0) NO INHERIT;
\set ON_ERROR_STOP 1