Skip to content

Commit

Permalink
Fix non-default tablespaces with constraints
Browse files Browse the repository at this point in the history
If a hypertable uses a non-default tablespace for its primary or
unique constraints with additional DEFERRABLE or INITIALLY DEFERRED
characteristics then any chunk creation will fail with syntax error. We
now set the tablespace via a separate command for such constraints for
the chunks.

Fixes #6338
  • Loading branch information
nikkhils committed Nov 23, 2023
1 parent 8745063 commit 51d92a3
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 6 deletions.
2 changes: 2 additions & 0 deletions .unreleased/fix_6339
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixes: #6339 Fix tablespace with constraints
Thanks: @lyp-bobi for reporting the issue
16 changes: 12 additions & 4 deletions sql/chunk_constraint.sql
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ BEGIN

def := pg_get_constraintdef(constraint_oid);

IF indx_tablespace IS NOT NULL THEN
def := format('%s USING INDEX TABLESPACE %I', def, indx_tablespace);
END IF;

ELSIF constraint_type = 't' THEN
-- constraint triggers are copied separately with normal triggers
def := NULL;
Expand All @@ -63,6 +59,18 @@ BEGIN
$$ ALTER TABLE %I.%I ADD CONSTRAINT %I %s $$,
chunk_row.schema_name, chunk_row.table_name, chunk_constraint_row.constraint_name, def
);

-- if constraint (primary or unique) needs a tablespace then add it
-- via a separate ALTER INDEX SET TABLESPACE command. We cannot append it
-- to the "def" string above since it leads to a SYNTAX error when
-- "DEFERRABLE" or "INITIALLY DEFERRED" are used in the constraint
IF indx_tablespace IS NOT NULL THEN
EXECUTE pg_catalog.format(
$$ ALTER INDEX %I.%I SET TABLESPACE %I $$,
chunk_row.schema_name, chunk_constraint_row.constraint_name, indx_tablespace
);
END IF;

END IF;
END
$BODY$ SET search_path TO pg_catalog, pg_temp;
69 changes: 69 additions & 0 deletions sql/updates/reverse-dev.sql
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,72 @@ BEGIN
END LOOP;
END;
$$ LANGUAGE PLPGSQL;

DROP FUNCTION _timescaledb_functions.chunk_constraint_add_table_constraint(
chunk_constraint_row _timescaledb_catalog.chunk_constraint
);

CREATE FUNCTION _timescaledb_functions.chunk_constraint_add_table_constraint(
chunk_constraint_row _timescaledb_catalog.chunk_constraint
)
RETURNS VOID LANGUAGE PLPGSQL AS
$BODY$
DECLARE
chunk_row _timescaledb_catalog.chunk;
hypertable_row _timescaledb_catalog.hypertable;
constraint_oid OID;
constraint_type CHAR;
check_sql TEXT;
def TEXT;
indx_tablespace NAME;
tablespace_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
RAISE 'cannot create dimension constraint %', chunk_constraint_row;
ELSIF chunk_constraint_row.hypertable_constraint_name IS NOT NULL THEN

SELECT oid, contype INTO STRICT constraint_oid, constraint_type 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;

IF constraint_type IN ('p','u') THEN
-- since primary keys and unique constraints are backed by an index
-- they might have an index tablespace assigned
-- the tablspace is not part of the constraint definition so
-- we have to append it explicitly to preserve it
SELECT T.spcname INTO indx_tablespace
FROM pg_constraint C, pg_class I, pg_tablespace T
WHERE C.oid = constraint_oid AND C.contype IN ('p', 'u') AND I.oid = C.conindid AND I.reltablespace = T.oid;

def := pg_get_constraintdef(constraint_oid);

IF indx_tablespace IS NOT NULL THEN
def := format('%s USING INDEX TABLESPACE %I', def, indx_tablespace);
END IF;

ELSIF constraint_type = 't' THEN
-- constraint triggers are copied separately with normal triggers
def := NULL;
ELSE
def := pg_get_constraintdef(constraint_oid);
END IF;

ELSE
RAISE 'unknown constraint type';
END IF;

IF def IS NOT NULL THEN
-- to allow for custom types with operators outside of pg_catalog
-- we set search_path to @extschema@
SET LOCAL search_path TO @extschema@, pg_temp;
EXECUTE pg_catalog.format(
$$ ALTER TABLE %I.%I ADD CONSTRAINT %I %s $$,
chunk_row.schema_name, chunk_row.table_name, chunk_constraint_row.constraint_name, def
);

END IF;
END
$BODY$ SET search_path TO pg_catalog, pg_temp;
2 changes: 1 addition & 1 deletion test/expected/constraint.out
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ CREATE TABLE tbl (
fk_id int,
id int,
time timestamp,
CONSTRAINT pk PRIMARY KEY (time, id) USING INDEX TABLESPACE tablespace1);
CONSTRAINT pk PRIMARY KEY (time, id) USING INDEX TABLESPACE tablespace1 DEFERRABLE INITIALLY DEFERRED);
SELECT create_hypertable('tbl', 'time');
WARNING: column type "timestamp without time zone" used for "time" does not follow best practices
create_hypertable
Expand Down
2 changes: 1 addition & 1 deletion test/sql/constraint.sql
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ CREATE TABLE tbl (
fk_id int,
id int,
time timestamp,
CONSTRAINT pk PRIMARY KEY (time, id) USING INDEX TABLESPACE tablespace1);
CONSTRAINT pk PRIMARY KEY (time, id) USING INDEX TABLESPACE tablespace1 DEFERRABLE INITIALLY DEFERRED);

SELECT create_hypertable('tbl', 'time');

Expand Down

0 comments on commit 51d92a3

Please sign in to comment.