Skip to content

Commit

Permalink
Sync FK behaviour when creating hypertable
Browse files Browse the repository at this point in the history
We now allow FKs to hypertables but the initial check when creating
the hypertable was not adjusted so tables with pre-existing FKs
would not be allowed to be changed into hypertable while creating
the FK constraint afterwards succeeded.
  • Loading branch information
svenklemm committed Sep 30, 2024
1 parent b7a1074 commit e673468
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 9 deletions.
1 change: 1 addition & 0 deletions .unreleased/pr_7301
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixes: #7301 Make foreign key behaviour for hypertables consistent
19 changes: 11 additions & 8 deletions src/hypertable.c
Original file line number Diff line number Diff line change
Expand Up @@ -1319,14 +1319,17 @@ hypertable_validate_constraints(Oid relid)
{
Form_pg_constraint form = (Form_pg_constraint) GETSTRUCT(tuple);

if (form->contype == CONSTRAINT_FOREIGN)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("cannot have FOREIGN KEY constraints to hypertable \"%s\"",
get_rel_name(relid)),
errhint("Remove all FOREIGN KEY constraints to table \"%s\" before "
"making it a hypertable.",
get_rel_name(relid))));
/*
* Hypertable <-> hypertable foreign keys are not supported.
*/
if (form->contype == CONSTRAINT_FOREIGN && ts_hypertable_relid_to_id(form->conrelid) != -1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("cannot have FOREIGN KEY constraints to hypertable \"%s\"",
get_rel_name(relid)),
errhint("Remove all FOREIGN KEY constraints to table \"%s\" before "
"making it a hypertable.",
get_rel_name(relid))));
}

systable_endscan(scan);
Expand Down
3 changes: 2 additions & 1 deletion test/sql/create_hypertable.sql
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,6 @@ select * from tidrangescan_test where time > '2023-02-12 00:00:00+02:40'::timest

drop table tidrangescan_test;

\set ON_ERROR_STOP 0
\set VERBOSITY default
set client_min_messages = WARNING;
-- test creating a hypertable from table referenced by a foreign key fails with
Expand All @@ -643,6 +642,8 @@ create table test_schema.fk_child(
id int,
foreign key (time, id) references test_schema.fk_parent(time, id)
);
select create_hypertable ('test_schema.fk_child', 'time');
\set ON_ERROR_STOP 0
select create_hypertable ('test_schema.fk_parent', 'time');
\set ON_ERROR_STOP 1

Expand Down
31 changes: 31 additions & 0 deletions tsl/test/expected/foreign_keys.out
Original file line number Diff line number Diff line change
Expand Up @@ -1025,3 +1025,34 @@ SELECT create_hypertable('i7226', 'time');

CREATE TABLE i7226_valid(time timestamptz NOT NULL,device_id int NOT NULL, FOREIGN KEY(time, device_id) REFERENCES i7226(time, device_id));
INSERT INTO i7226 VALUES ('2024-08-29 12:00:00+00', 1);
-- test foreign key constraints that have been created before hypertable conversion
create table converted_pk(time timestamptz, id int, unique(time, id));
create table converted_fk(time timestamptz, id int, foreign key (time, id) references converted_pk(time, id));
select table_name FROM create_hypertable ('converted_pk', 'time');
NOTICE: adding not-null constraint to column "time"
table_name
--------------
converted_pk
(1 row)

\set ON_ERROR_STOP 0
-- should fail
INSERT INTO converted_fk SELECT '2020-01-01', 1;
ERROR: insert or update on table "converted_fk" violates foreign key constraint "converted_fk_time_id_fkey"
\set ON_ERROR_STOP 1
INSERT INTO converted_pk SELECT '2020-01-01 0:01', 1;
\set ON_ERROR_STOP 0
-- should still fail
INSERT INTO converted_fk SELECT '2020-01-01', 1;
ERROR: insert or update on table "converted_fk" violates foreign key constraint "converted_fk_time_id_fkey"
\set ON_ERROR_STOP 1
INSERT INTO converted_fk SELECT '2020-01-01 0:01', 1;
\set ON_ERROR_STOP 0
-- should fail
DELETE FROM converted_pk WHERE time = '2020-01-01 0:01';
ERROR: update or delete on table "_hyper_16_27_chunk" violates foreign key constraint "converted_fk_time_id_fkey1" on table "converted_fk"
TRUNCATE converted_pk;
ERROR: cannot truncate a table referenced in a foreign key constraint
\set ON_ERROR_STOP 1
DELETE FROM converted_fk;
DELETE FROM converted_pk WHERE time = '2020-01-01 0:01';
28 changes: 28 additions & 0 deletions tsl/test/sql/foreign_keys.sql
Original file line number Diff line number Diff line change
Expand Up @@ -650,3 +650,31 @@ SELECT create_hypertable('i7226', 'time');
CREATE TABLE i7226_valid(time timestamptz NOT NULL,device_id int NOT NULL, FOREIGN KEY(time, device_id) REFERENCES i7226(time, device_id));
INSERT INTO i7226 VALUES ('2024-08-29 12:00:00+00', 1);

-- test foreign key constraints that have been created before hypertable conversion
create table converted_pk(time timestamptz, id int, unique(time, id));
create table converted_fk(time timestamptz, id int, foreign key (time, id) references converted_pk(time, id));

select table_name FROM create_hypertable ('converted_pk', 'time');

\set ON_ERROR_STOP 0
-- should fail
INSERT INTO converted_fk SELECT '2020-01-01', 1;
\set ON_ERROR_STOP 1

INSERT INTO converted_pk SELECT '2020-01-01 0:01', 1;

\set ON_ERROR_STOP 0
-- should still fail
INSERT INTO converted_fk SELECT '2020-01-01', 1;
\set ON_ERROR_STOP 1
INSERT INTO converted_fk SELECT '2020-01-01 0:01', 1;

\set ON_ERROR_STOP 0
-- should fail
DELETE FROM converted_pk WHERE time = '2020-01-01 0:01';
TRUNCATE converted_pk;
\set ON_ERROR_STOP 1

DELETE FROM converted_fk;
DELETE FROM converted_pk WHERE time = '2020-01-01 0:01';

0 comments on commit e673468

Please sign in to comment.