Skip to content

Commit

Permalink
Allow setting partitioning function
Browse files Browse the repository at this point in the history
Users might want to implement their own partitioning function
or use the legacy one included with TimescaleDB. This change
adds support for setting the partitioning function in
create_hypertable() and add_dimension().
  • Loading branch information
erimatnor committed Oct 31, 2017
1 parent 4a0a0d8 commit 4532650
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 34 deletions.
16 changes: 11 additions & 5 deletions sql/ddl_api.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
-- associated_schema_name - (Optional) Schema for internal hypertable tables
-- associated_table_prefix - (Optional) Prefix for internal hypertable table names
-- chunk_time_interval - (Optional) Initial time interval for a chunk
-- create_default_indexes - (Optional) Whether or not to create the default indexes.
-- create_default_indexes - (Optional) Whether or not to create the default indexes
-- if_not_exists - (Optional) Do not fail if table is already a hypertable
-- partitioning_func - (Optional) The partitioning function to use for spatial partitioning
CREATE OR REPLACE FUNCTION create_hypertable(
main_table REGCLASS,
time_column_name NAME,
Expand All @@ -19,7 +21,8 @@ CREATE OR REPLACE FUNCTION create_hypertable(
associated_table_prefix NAME = NULL,
chunk_time_interval anyelement = NULL::bigint,
create_default_indexes BOOLEAN = TRUE,
if_not_exists BOOLEAN = FALSE
if_not_exists BOOLEAN = FALSE,
partitioning_func REGPROC = NULL
)
RETURNS VOID LANGUAGE PLPGSQL VOLATILE
SECURITY DEFINER SET search_path = ''
Expand Down Expand Up @@ -102,7 +105,8 @@ BEGIN
associated_schema_name,
associated_table_prefix,
chunk_time_interval_actual,
tablespace_name
tablespace_name,
partitioning_func
);
EXCEPTION
WHEN unique_violation THEN
Expand All @@ -128,7 +132,8 @@ CREATE OR REPLACE FUNCTION add_dimension(
main_table REGCLASS,
column_name NAME,
number_partitions INTEGER = NULL,
interval_length BIGINT = NULL
interval_length BIGINT = NULL,
partitioning_func REGPROC = NULL
)
RETURNS VOID LANGUAGE PLPGSQL VOLATILE
SECURITY DEFINER SET search_path = ''
Expand Down Expand Up @@ -162,7 +167,8 @@ BEGIN
hypertable_row,
column_name,
number_partitions,
interval_length);
interval_length,
partitioning_func);
END
$BODY$;

Expand Down
22 changes: 17 additions & 5 deletions sql/ddl_internal.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ CREATE OR REPLACE FUNCTION _timescaledb_internal.create_hypertable_row(
associated_schema_name NAME,
associated_table_prefix NAME,
chunk_time_interval BIGINT,
tablespace NAME
tablespace NAME,
partitioning_func REGPROC
)
RETURNS _timescaledb_catalog.hypertable LANGUAGE PLPGSQL VOLATILE AS
$BODY$
Expand Down Expand Up @@ -63,6 +64,7 @@ BEGIN
time_column_name,
NULL,
chunk_time_interval,
NULL,
FALSE);

IF partitioning_column IS NOT NULL THEN
Expand All @@ -71,7 +73,8 @@ BEGIN
hypertable_row,
partitioning_column,
number_partitions,
NULL);
NULL,
partitioning_func);
END IF;

-- Verify indexes
Expand Down Expand Up @@ -146,12 +149,13 @@ CREATE OR REPLACE FUNCTION _timescaledb_internal.add_dimension(
column_name NAME,
num_slices INTEGER = NULL,
interval_length BIGINT = NULL,
partitioning_func REGPROC = NULL,
increment_num_dimensions BOOLEAN = TRUE
)
RETURNS _timescaledb_catalog.dimension LANGUAGE PLPGSQL VOLATILE AS
$BODY$
DECLARE
partitioning_func _timescaledb_catalog.dimension.partitioning_func%TYPE = 'get_partition_hash';
partitioning_func_name _timescaledb_catalog.dimension.partitioning_func%TYPE = 'get_partition_hash';
partitioning_func_schema _timescaledb_catalog.dimension.partitioning_func_schema%TYPE = '_timescaledb_internal';
aligned BOOL;
column_type REGTYPE;
Expand Down Expand Up @@ -182,7 +186,7 @@ BEGIN
END IF;

IF num_slices IS NULL THEN
partitioning_func := NULL;
partitioning_func_name := NULL;
partitioning_func_schema := NULL;
aligned = TRUE;
ELSE
Expand All @@ -192,6 +196,14 @@ BEGIN
USING ERRCODE ='IO101';
END IF;
aligned = FALSE;

IF partitioning_func IS NOT NULL THEN
SELECT n.nspname, p.proname
FROM pg_proc p, pg_namespace n
WHERE p.pronamespace = n.oid
AND p.oid = partitioning_func
INTO STRICT partitioning_func_schema, partitioning_func_name;
END IF;
END IF;

BEGIN
Expand All @@ -201,7 +213,7 @@ BEGIN
interval_length
) VALUES (
hypertable_row.id, column_name, column_type, aligned,
num_slices::smallint, partitioning_func_schema, partitioning_func,
num_slices::smallint, partitioning_func_schema, partitioning_func_name,
interval_length
) RETURNING * INTO dimension_row;
EXCEPTION
Expand Down
6 changes: 6 additions & 0 deletions sql/updates/pre-0.6.0--0.7.0-dev.sql
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ INNER JOIN pg_constraint pg_hypertable_con ON (
INNER JOIN pg_class pg_hypertable_index_class ON (
pg_hypertable_con.conindid = pg_hypertable_index_class.oid
);

-- Upgrade support for setting partitioning function
DROP FUNCTION create_hypertable(regclass,name,name,integer,name,name,anyelement,boolean,boolean);
DROP FUNCTION add_dimension(regclass,name,integer,bigint);
DROP FUNCTION _timescaledb_internal.create_hypertable_row(regclass,name,name,name,name,integer,name,name,bigint,name);
DROP FUNCTION _timescaledb_internal.add_dimension(regclass,_timescaledb_catalog.hypertable,name,integer,bigint,boolean);
48 changes: 34 additions & 14 deletions test/expected/partitioning.out
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
CREATE TABLE part_legacy(time timestamptz, temp float, device int);
SELECT create_hypertable('part_legacy', 'time', 'device', 2);
SELECT create_hypertable('part_legacy', 'time', 'device', 2, partitioning_func => '_timescaledb_internal.get_partition_for_key');
create_hypertable
-------------------

(1 row)

SELECT * FROM _timescaledb_catalog.dimension;
id | hypertable_id | column_name | column_type | aligned | num_slices | partitioning_func_schema | partitioning_func | interval_length
----+---------------+-------------+--------------------------+---------+------------+--------------------------+--------------------+-----------------
1 | 1 | time | timestamp with time zone | t | | | | 2592000000000
2 | 1 | device | integer | f | 2 | _timescaledb_internal | get_partition_hash |
(2 rows)

\c single :ROLE_SUPERUSER
UPDATE _timescaledb_catalog.dimension SET partitioning_func = 'get_partition_for_key'
WHERE partitioning_func IS NOT NULL;
\c single :ROLE_DEFAULT_PERM_USER
-- Show updated partitioning function
-- Show legacy partitioning function is used
SELECT * FROM _timescaledb_catalog.dimension;
id | hypertable_id | column_name | column_type | aligned | num_slices | partitioning_func_schema | partitioning_func | interval_length
----+---------------+-------------+--------------------------+---------+------------+--------------------------+-----------------------+-----------------
Expand Down Expand Up @@ -143,7 +132,7 @@ SELECT create_hypertable('part_new_convert1', 'time', 'temp', 2);

INSERT INTO part_new_convert1 VALUES ('2017-03-22T09:18:23', 1.0, 2);
\set ON_ERROR_STOP 0
-- Changing the type of a hash-partitioned column should be unsupported
-- Changing the type of a hash-partitioned column should not be supported
ALTER TABLE part_new_convert1 ALTER COLUMN temp TYPE numeric;
ERROR: Cannot change the type of a hash-partitioned column
\set ON_ERROR_STOP 1
Expand All @@ -164,3 +153,34 @@ Check constraints:
"constraint_8" CHECK (_timescaledb_internal.get_partition_hash(temp) >= 0 AND _timescaledb_internal.get_partition_hash(temp) < 1073741823)
Inherits: part_new_convert1

CREATE TABLE part_add_dim(time timestamptz, temp float8, device int, location int);
SELECT create_hypertable('part_add_dim', 'time', 'temp', 2);
create_hypertable
-------------------

(1 row)

\set ON_ERROR_STOP 0
SELECT add_dimension('part_add_dim', 'location', 2, partitioning_func => 'bad_func');
ERROR: function "bad_func" does not exist at character 74
\set ON_ERROR_STOP 1
SELECT add_dimension('part_add_dim', 'location', 2, partitioning_func => '_timescaledb_internal.get_partition_for_key');
add_dimension
---------------

(1 row)

SELECT * FROM _timescaledb_catalog.dimension;
id | hypertable_id | column_name | column_type | aligned | num_slices | partitioning_func_schema | partitioning_func | interval_length
----+---------------+-------------+-----------------------------+---------+------------+--------------------------+-----------------------+-----------------
1 | 1 | time | timestamp with time zone | t | | | | 2592000000000
2 | 1 | device | integer | f | 2 | _timescaledb_internal | get_partition_for_key |
3 | 2 | time | timestamp with time zone | t | | | | 2592000000000
4 | 2 | device | integer | f | 2 | _timescaledb_internal | get_partition_hash |
6 | 3 | temp | double precision | f | 2 | _timescaledb_internal | get_partition_hash |
5 | 3 | time | timestamp without time zone | t | | | | 2592000000000
7 | 4 | time | timestamp with time zone | t | | | | 2592000000000
8 | 4 | temp | double precision | f | 2 | _timescaledb_internal | get_partition_hash |
9 | 4 | location | integer | f | 2 | _timescaledb_internal | get_partition_for_key |
(9 rows)

23 changes: 13 additions & 10 deletions test/sql/partitioning.sql
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
CREATE TABLE part_legacy(time timestamptz, temp float, device int);
SELECT create_hypertable('part_legacy', 'time', 'device', 2);
SELECT create_hypertable('part_legacy', 'time', 'device', 2, partitioning_func => '_timescaledb_internal.get_partition_for_key');

SELECT * FROM _timescaledb_catalog.dimension;

\c single :ROLE_SUPERUSER
UPDATE _timescaledb_catalog.dimension SET partitioning_func = 'get_partition_for_key'
WHERE partitioning_func IS NOT NULL;
\c single :ROLE_DEFAULT_PERM_USER

-- Show updated partitioning function
-- Show legacy partitioning function is used
SELECT * FROM _timescaledb_catalog.dimension;

INSERT INTO part_legacy VALUES ('2017-03-22T09:18:23', 23.4, 1);
Expand Down Expand Up @@ -45,11 +38,21 @@ SELECT create_hypertable('part_new_convert1', 'time', 'temp', 2);

INSERT INTO part_new_convert1 VALUES ('2017-03-22T09:18:23', 1.0, 2);
\set ON_ERROR_STOP 0
-- Changing the type of a hash-partitioned column should be unsupported
-- Changing the type of a hash-partitioned column should not be supported
ALTER TABLE part_new_convert1 ALTER COLUMN temp TYPE numeric;
\set ON_ERROR_STOP 1

-- Should be able to change if not hash partitioned though
ALTER TABLE part_new_convert1 ALTER COLUMN time TYPE timestamp;

\d+ _timescaledb_internal._hyper_3_*_chunk

CREATE TABLE part_add_dim(time timestamptz, temp float8, device int, location int);
SELECT create_hypertable('part_add_dim', 'time', 'temp', 2);

\set ON_ERROR_STOP 0
SELECT add_dimension('part_add_dim', 'location', 2, partitioning_func => 'bad_func');
\set ON_ERROR_STOP 1

SELECT add_dimension('part_add_dim', 'location', 2, partitioning_func => '_timescaledb_internal.get_partition_for_key');
SELECT * FROM _timescaledb_catalog.dimension;

0 comments on commit 4532650

Please sign in to comment.