timescaledb/test/sql/constraint.sql
Erik Nordström aa904fa5d0 Block adding constraints without a constraint name
The current approach of handling alter table commands does not allow
getting the result of the command; for instance, the object address of
a created constraint on a hypertable. Thus there is no way to get the
auto-generated name of a constraint, which is needed when the
corresponding constraints are created on the hypertable's chunks.

Therefore, this change blocks the ability to create constraints
without an explicit name. When a better approach to handling alter
table is deviced, it is possible to remove this restriction.
2017-09-19 09:09:16 +02:00

314 lines
8.8 KiB
SQL

\o /dev/null
\ir include/create_single_db.sql
\o
CREATE TABLE hyper (
time BIGINT NOT NULL,
device_id TEXT NOT NULL,
sensor_1 NUMERIC NULL DEFAULT 1 CHECK (sensor_1 > 10)
);
SELECT * FROM create_hypertable('hyper', 'time', chunk_time_interval => 10);
--check and not-null constraints are inherited through regular inheritance.
\set ON_ERROR_STOP 0
INSERT INTO hyper(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 9);
INSERT INTO hyper(time, device_id,sensor_1) VALUES
(1257987700000000000, NULL, 11);
\set ON_ERROR_STOP 1
INSERT INTO hyper(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 11);
INSERT INTO hyper(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 11);
----------------------- UNIQUE CONSTRAINTS ------------------
CREATE TABLE hyper_unique (
time BIGINT NOT NULL UNIQUE,
device_id TEXT NOT NULL,
sensor_1 NUMERIC NULL DEFAULT 1 CHECK (sensor_1 > 10)
);
SELECT * FROM create_hypertable('hyper_unique', 'time', chunk_time_interval => 10);
INSERT INTO hyper_unique(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 11);
INSERT INTO hyper_unique(time, device_id,sensor_1) VALUES
(1257987800000000000, 'dev2', 11);
\set ON_ERROR_STOP 0
INSERT INTO hyper_unique(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 11);
\set ON_ERROR_STOP 1
\d+ hyper
\d+ hyper_unique
--should have unique constraint not just unique index
\d+ _timescaledb_internal._hyper_2_4_chunk
ALTER TABLE hyper_unique DROP CONSTRAINT hyper_unique_time_key;
\d+ _timescaledb_internal._hyper_2_4_chunk
--uniqueness not enforced
INSERT INTO hyper_unique(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev3', 11);
--shouldn't be able to create constraint
\set ON_ERROR_STOP 0
ALTER TABLE hyper_unique ADD CONSTRAINT hyper_unique_time_key UNIQUE (time);
\set ON_ERROR_STOP 1
DELETE FROM hyper_unique WHERE device_id = 'dev3';
CREATE UNIQUE INDEX ON hyper_unique (time);
\set ON_ERROR_STOP 0
-- Try adding constraint using existing index
ALTER TABLE hyper_unique ADD CONSTRAINT hyper_unique_time_key UNIQUE USING INDEX hyper_unique_time_idx;
-- Try to add constraint without a name
ALTER TABLE hyper_unique ADD UNIQUE (time);
\set ON_ERROR_STOP 1
DROP INDEX hyper_unique_time_idx;
--now can create
ALTER TABLE hyper_unique ADD CONSTRAINT hyper_unique_time_key UNIQUE (time);
\d+ _timescaledb_internal._hyper_2_4_chunk
--test adding constraint with same name to different table -- should fail
\set ON_ERROR_STOP 0
ALTER TABLE hyper ADD CONSTRAINT hyper_unique_time_key UNIQUE (time);
\set ON_ERROR_STOP 1
--uniquness violation fails
\set ON_ERROR_STOP 0
INSERT INTO hyper_unique(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 11);
\set ON_ERROR_STOP 1
--cannot create unique constraint on non-partition column
\set ON_ERROR_STOP 0
ALTER TABLE hyper_unique ADD CONSTRAINT hyper_unique_invalid UNIQUE (device_id);
\set ON_ERROR_STOP 1
----------------------- PRIMARY KEY ------------------
CREATE TABLE hyper_pk (
time BIGINT NOT NULL PRIMARY KEY,
device_id TEXT NOT NULL,
sensor_1 NUMERIC NULL DEFAULT 1 CHECK (sensor_1 > 10)
);
SELECT * FROM create_hypertable('hyper_pk', 'time', chunk_time_interval => 10);
INSERT INTO hyper_pk(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 11);
\set ON_ERROR_STOP 0
INSERT INTO hyper_pk(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 11);
\set ON_ERROR_STOP 1
--should have unique constraint not just unique index
\d+ _timescaledb_internal._hyper_3_6_chunk
ALTER TABLE hyper_pk DROP CONSTRAINT hyper_pk_pkey;
\d+ _timescaledb_internal._hyper_3_6_chunk
--uniqueness not enforced
INSERT INTO hyper_pk(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev3', 11);
--shouldn't be able to create pk
\set ON_ERROR_STOP 0
ALTER TABLE hyper_pk ADD CONSTRAINT hyper_pk_pkey PRIMARY KEY (time);
\set ON_ERROR_STOP 1
DELETE FROM hyper_pk WHERE device_id = 'dev3';
--cannot create pk constraint on non-partition column
\set ON_ERROR_STOP 0
ALTER TABLE hyper_pk ADD CONSTRAINT hyper_pk_invalid PRIMARY KEY (device_id);
\set ON_ERROR_STOP 1
--now can create
ALTER TABLE hyper_pk ADD CONSTRAINT hyper_pk_pkey PRIMARY KEY (time);
\d+ _timescaledb_internal._hyper_3_6_chunk
--test adding constraint with same name to different table -- should fail
\set ON_ERROR_STOP 0
ALTER TABLE hyper ADD CONSTRAINT hyper_pk_pkey UNIQUE (time);
\set ON_ERROR_STOP 1
--uniquness violation fails
\set ON_ERROR_STOP 0
INSERT INTO hyper_pk(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 11);
\set ON_ERROR_STOP 1
----------------------- FOREIGN KEY ------------------
CREATE TABLE devices(
device_id TEXT NOT NULL,
PRIMARY KEY (device_id)
);
CREATE TABLE hyper_fk (
time BIGINT NOT NULL PRIMARY KEY,
device_id TEXT NOT NULL REFERENCES devices(device_id),
sensor_1 NUMERIC NULL DEFAULT 1 CHECK (sensor_1 > 10)
);
SELECT * FROM create_hypertable('hyper_fk', 'time', chunk_time_interval => 10);
--fail fk constraint
\set ON_ERROR_STOP 0
INSERT INTO hyper_fk(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 11);
\set ON_ERROR_STOP 1
INSERT INTO devices VALUES ('dev2');
INSERT INTO hyper_fk(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 11);
--delete should fail
\set ON_ERROR_STOP 0
DELETE FROM devices;
\set ON_ERROR_STOP 1
ALTER TABLE hyper_fk DROP CONSTRAINT hyper_fk_device_id_fkey;
--should now be able to add non-fk rows
INSERT INTO hyper_fk(time, device_id,sensor_1) VALUES
(1257987700000000001, 'dev3', 11);
--can't add fk because of dev3 row
\set ON_ERROR_STOP 0
ALTER TABLE hyper_fk ADD CONSTRAINT hyper_fk_device_id_fkey
FOREIGN KEY (device_id) REFERENCES devices(device_id);
\set ON_ERROR_STOP 1
DELETE FROM hyper_fk WHERE device_id = 'dev3';
ALTER TABLE hyper_fk ADD CONSTRAINT hyper_fk_device_id_fkey
FOREIGN KEY (device_id) REFERENCES devices(device_id);
\set ON_ERROR_STOP 0
INSERT INTO hyper_fk(time, device_id,sensor_1) VALUES
(1257987700000000002, 'dev3', 11);
\set ON_ERROR_STOP 1
----------------------- FOREIGN KEY INTO A HYPERTABLE ------------------
--FOREIGN KEY references into a hypertable are currently broken.
--The referencing table will never find the corresponding row in the hypertable
--since it will only search the parent. Thus any insert will result in an ERROR
--TODO: block such foreign keys or fix. (Hard to block on create table so punting for now)
CREATE TABLE hyper_for_ref (
time BIGINT NOT NULL PRIMARY KEY,
device_id TEXT NOT NULL,
sensor_1 NUMERIC NULL DEFAULT 1 CHECK (sensor_1 > 10)
);
SELECT * FROM create_hypertable('hyper_for_ref', 'time', chunk_time_interval => 10);
\set ON_ERROR_STOP 0
CREATE TABLE referrer (
time BIGINT NOT NULL REFERENCES hyper_for_ref(time)
);
\set ON_ERROR_STOP 1
CREATE TABLE referrer2 (
time BIGINT NOT NULL
);
\set ON_ERROR_STOP 0
ALTER TABLE referrer2 ADD CONSTRAINT hyper_fk_device_id_fkey
FOREIGN KEY (time) REFERENCES hyper_for_ref(time);
\set ON_ERROR_STOP 1
----------------------- EXCLUSION CONSTRAINT ------------------
CREATE TABLE hyper_ex (
time BIGINT,
device_id TEXT NOT NULL REFERENCES devices(device_id),
sensor_1 NUMERIC NULL DEFAULT 1 CHECK (sensor_1 > 10),
canceled boolean DEFAULT false,
EXCLUDE USING btree (
time WITH =, device_id WITH =
) WHERE (not canceled)
);
SELECT * FROM create_hypertable('hyper_ex', 'time', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
INSERT INTO hyper_ex(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 11);
\set ON_ERROR_STOP 0
INSERT INTO hyper_ex(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 12);
\set ON_ERROR_STOP 1
ALTER TABLE hyper_ex DROP CONSTRAINT hyper_ex_time_device_id_excl;
--can now add
INSERT INTO hyper_ex(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 12);
--cannot add because of conflicts
\set ON_ERROR_STOP 0
ALTER TABLE hyper_ex ADD CONSTRAINT hyper_ex_time_device_id_excl
EXCLUDE USING btree (
time WITH =, device_id WITH =
) WHERE (not canceled)
;
\set ON_ERROR_STOP 1
DELETE FROM hyper_ex WHERE sensor_1 = 12;
ALTER TABLE hyper_ex ADD CONSTRAINT hyper_ex_time_device_id_excl
EXCLUDE USING btree (
time WITH =, device_id WITH =
) WHERE (not canceled)
;
\set ON_ERROR_STOP 0
INSERT INTO hyper_ex(time, device_id,sensor_1) VALUES
(1257987700000000000, 'dev2', 12);
\set ON_ERROR_STOP 1
--cannot add exclusion constraint without partition key.
CREATE TABLE hyper_ex_invalid (
time BIGINT,
device_id TEXT NOT NULL REFERENCES devices(device_id),
sensor_1 NUMERIC NULL DEFAULT 1 CHECK (sensor_1 > 10),
canceled boolean DEFAULT false,
EXCLUDE USING btree (
device_id WITH =
) WHERE (not canceled)
);
\set ON_ERROR_STOP 0
SELECT * FROM create_hypertable('hyper_ex_invalid', 'time', chunk_time_interval=>_timescaledb_internal.interval_to_usec('1 month'));
\set ON_ERROR_STOP 1