diff --git a/sql/dimensions.sql b/sql/dimensions.sql new file mode 100644 index 000000000..24b0ced52 --- /dev/null +++ b/sql/dimensions.sql @@ -0,0 +1,26 @@ +-- Add a new partition epoch with equally sized partitions +CREATE OR REPLACE FUNCTION _timescaledb_internal.find_chunk( + time_dimension_id INTEGER, + time_value BIGINT, + space_dimension_id INTEGER, + space_dimension_hash BIGINT +) + RETURNS _timescaledb_catalog.chunk LANGUAGE SQL STABLE AS +$BODY$ +SELECT * +FROM _timescaledb_catalog.chunk +WHERE +id = ( +SELECT cc.chunk_id +FROM _timescaledb_catalog.dimension_slice ds +INNER JOIN _timescaledb_catalog.chunk_constraint cc ON (ds.id = cc.dimension_slice_id) +WHERE ds.dimension_id = time_dimension_id and ds.range_start <= time_value and ds.range_end >= time_value + +INTERSECT + +SELECT cc.chunk_id +FROM _timescaledb_catalog.dimension_slice ds +INNER JOIN _timescaledb_catalog.chunk_constraint cc ON (ds.id = cc.dimension_slice_id) +WHERE ds.dimension_id = space_dimension_id and ds.range_start <= space_dimension_hash and ds.range_end >= space_dimension_hash +) +$BODY$; diff --git a/sql/tables.sql b/sql/tables.sql index 1e6404392..16078e87b 100644 --- a/sql/tables.sql +++ b/sql/tables.sql @@ -23,71 +23,58 @@ CREATE TABLE IF NOT EXISTS _timescaledb_catalog.hypertable ( SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.hypertable', ''); SELECT pg_catalog.pg_extension_config_dump(pg_get_serial_sequence('_timescaledb_catalog.hypertable','id'), ''); --- A partition_epoch represents a different partitioning of the data. --- It has a start and end time (data time). Data needs to be placed in the correct epoch by time. --- Partitionings are defined by a function, column, and modulo: --- 1) partitioning_func - Takes the partitioning_column and returns a number --- which is modulo'd to place the data correctly --- 2) partitioning_mod - Number used in modulo operation --- 3) partitioning_column - column in data to partition by (input to partitioning_func) --- --- Changing a data's partitioning, and thus creating a new epoch, should be done --- INFREQUENTLY as it's expensive operation. -CREATE TABLE IF NOT EXISTS _timescaledb_catalog.partition_epoch ( - id SERIAL NOT NULL PRIMARY KEY, +CREATE TABLE _timescaledb_catalog.dimension ( + id SERIAL NOT NULL PRIMARY KEY, hypertable_id INTEGER NOT NULL REFERENCES _timescaledb_catalog.hypertable(id) ON DELETE CASCADE, - start_time BIGINT NULL CHECK (start_time >= 0), - end_time BIGINT NULL CHECK (end_time >= 0), - num_partitions SMALLINT NOT NULL CHECK (num_partitions >= 0), + column_name NAME NOT NULL, + time_type BOOLEAN NOT NULL, + -- space-columns + num_slices SMALLINT NULL, partitioning_func_schema NAME NULL, - partitioning_func NAME NULL, -- function name of a function of the form func(data_value, partitioning_mod) -> [0, partitioning_mod) - partitioning_mod INT NOT NULL CHECK (partitioning_mod < 65536), - partitioning_column NAME NULL, - UNIQUE (hypertable_id, start_time), - UNIQUE (hypertable_id, end_time), - CHECK (start_time <= end_time), - CHECK (num_partitions <= partitioning_mod), - CHECK ((partitioning_func_schema IS NULL AND partitioning_func IS NULL) OR (partitioning_func_schema IS NOT NULL AND partitioning_func IS NOT NULL)) -); -CREATE INDEX ON _timescaledb_catalog.partition_epoch(hypertable_id, start_time, end_time); -SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.partition_epoch', ''); -SELECT pg_catalog.pg_extension_config_dump(pg_get_serial_sequence('_timescaledb_catalog.partition_epoch','id'), ''); + partitioning_func NAME NULL, -- function name of a function of the form func(data_value) -> [0, 65535) + -- time-columns + interval_length BIGINT NULL, --- A partition defines a partition witin a partition_epoch. --- For any partition the keyspace is defined as [keyspace_start, keyspace_end]. --- For any epoch, there must be a partition that covers every element in the --- keyspace, i.e. from [0, partition_epoch.partitioning_mod]. --- Parent: "hypertable.schema_name"."hypertable.table_name" --- Children: "chunk.schema_name"."chunk.table_name" -CREATE TABLE IF NOT EXISTS _timescaledb_catalog.partition ( - id SERIAL NOT NULL PRIMARY KEY, - epoch_id INT NOT NULL REFERENCES _timescaledb_catalog.partition_epoch (id) ON DELETE CASCADE, - keyspace_start SMALLINT NOT NULL CHECK (keyspace_start >= 0), -- start inclusive - keyspace_end SMALLINT NOT NULL CHECK (keyspace_end > 0), -- end inclusive; compatible with between operator - tablespace NAME NULL, - UNIQUE (epoch_id, keyspace_start), - CHECK (keyspace_end > keyspace_start) + CHECK ( + (partitioning_func_schema IS NULL AND partitioning_func IS NULL) OR + (partitioning_func_schema IS NOT NULL AND partitioning_func IS NOT NULL) + ), + CHECK ( + (time_type AND interval_length IS NOT NULL) OR + (NOT time_type AND num_slices IS NOT NULL) + ) ); -CREATE INDEX ON _timescaledb_catalog.partition(epoch_id); -SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.partition', ''); -SELECT pg_catalog.pg_extension_config_dump(pg_get_serial_sequence('_timescaledb_catalog.partition','id'), ''); +SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.dimension', ''); +SELECT pg_catalog.pg_extension_config_dump(pg_get_serial_sequence('_timescaledb_catalog.dimension','id'), ''); + +CREATE TABLE _timescaledb_catalog.dimension_slice ( + id SERIAL NOT NULL PRIMARY KEY, + dimension_id INTEGER NOT NULL REFERENCES _timescaledb_catalog.dimension(id) ON DELETE CASCADE, + range_start BIGINT NOT NULL CHECK (range_start >= 0), + range_end BIGINT NOT NULL CHECK (range_end >= 0), + CHECK (range_start <= range_end), + UNIQUE (dimension_id, range_start, range_end) +); +SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.dimension_slice', ''); +SELECT pg_catalog.pg_extension_config_dump(pg_get_serial_sequence('_timescaledb_catalog.dimension_slice','id'), ''); + + +CREATE TABLE _timescaledb_catalog.chunk_constraint( + dimension_slice_id INTEGER NOT NULL REFERENCES _timescaledb_catalog.dimension(id) ON DELETE CASCADE, + chunk_id INTEGER NOT NULL REFERENCES _timescaledb_catalog.chunk(id) ON DELETE CASCADE, + PRIMARY KEY(dimension_slice_id, chunk_id) +); +SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.chunk_constraint', ''); -- Represent a chunk of data, which is data in a hypertable that is -- partitioned by both the partition_column and time. CREATE TABLE IF NOT EXISTS _timescaledb_catalog.chunk ( id SERIAL NOT NULL PRIMARY KEY, partition_id INT NOT NULL REFERENCES _timescaledb_catalog.partition (id) ON DELETE CASCADE, - start_time BIGINT NOT NULL CHECK (start_time >= 0), - end_time BIGINT NOT NULL CHECK (end_time >= 0), schema_name NAME NOT NULL, table_name NAME NOT NULL, UNIQUE (schema_name, table_name), - UNIQUE (partition_id, start_time), - UNIQUE (partition_id, end_time), - CHECK (start_time <= end_time) ); -CREATE UNIQUE INDEX ON _timescaledb_catalog.chunk (partition_id) WHERE start_time IS NULL; -CREATE UNIQUE INDEX ON _timescaledb_catalog.chunk (partition_id) WHERE end_time IS NULL; CREATE INDEX ON _timescaledb_catalog.chunk(partition_id, start_time, end_time); SELECT pg_catalog.pg_extension_config_dump('_timescaledb_catalog.chunk', ''); SELECT pg_catalog.pg_extension_config_dump(pg_get_serial_sequence('_timescaledb_catalog.chunk','id'), ''); diff --git a/src/catalog.c b/src/catalog.c index 244c3c067..5271713bb 100644 --- a/src/catalog.c +++ b/src/catalog.c @@ -9,8 +9,6 @@ static const char *catalog_table_names[_MAX_CATALOG_TABLES] = { [HYPERTABLE] = HYPERTABLE_TABLE_NAME, - [PARTITION] = PARTITION_TABLE_NAME, - [PARTITION_EPOCH] = PARTITION_EPOCH_TABLE_NAME, [CHUNK] = CHUNK_TABLE_NAME }; @@ -28,20 +26,6 @@ const static TableIndexDef catalog_table_index_definitions[_MAX_CATALOG_TABLES] [HYPERTABLE_NAME_INDEX] = "hypertable_schema_name_table_name_key", } }, - [PARTITION] = { - .length = _MAX_PARTITION_INDEX, - .names = (char *[]) { - [PARTITION_ID_INDEX] = "partition_pkey", - [PARTITION_PARTITION_EPOCH_ID_INDEX] = "partition_epoch_id_idx", - } - }, - [PARTITION_EPOCH] = { - .length = _MAX_PARTITION_EPOCH_INDEX, - .names = (char *[]) { - [PARTITION_EPOCH_ID_INDEX] = "partition_epoch_pkey", - [PARTITION_EPOCH_TIME_INDEX] = "partition_epoch_hypertable_id_start_time_end_time_idx", - } - }, [CHUNK] = { .length = _MAX_CHUNK_INDEX, .names = (char *[]) { diff --git a/src/catalog.h b/src/catalog.h index 75e315f9a..f9a10fb27 100644 --- a/src/catalog.h +++ b/src/catalog.h @@ -21,8 +21,6 @@ enum CatalogTable { HYPERTABLE = 0, - PARTITION_EPOCH, - PARTITION, CHUNK, _MAX_CATALOG_TABLES, }; @@ -83,90 +81,6 @@ enum Anum_hypertable_name_idx #define Natts_hypertable_name_idx (_Anum_hypertable_name_max - 1) -/*********************************** - * - * Partition epoch table definitions - * - ***********************************/ - -#define PARTITION_EPOCH_TABLE_NAME "partition_epoch" - -enum -{ - PARTITION_EPOCH_ID_INDEX = 0, - PARTITION_EPOCH_TIME_INDEX, - _MAX_PARTITION_EPOCH_INDEX, -}; - -enum Anum_partition_epoch -{ - Anum_partition_epoch_id = 1, - Anum_partition_epoch_hypertable_id, - Anum_partition_epoch_start_time, - Anum_partition_epoch_end_time, - Anum_partition_epoch_num_partitions, - Anum_partition_epoch_partitioning_func_schema, - Anum_partition_epoch_partitioning_func, - Anum_partition_epoch_partitioning_mod, - Anum_partition_epoch_partitioning_column, - _Anum_partition_epoch_max, -}; - -#define Natts_partition_epoch \ - (_Anum_partition_epoch_max - 1) - -enum Anum_partition_epoch_hypertable_start_time_end_time_idx -{ - Anum_partition_epoch_hypertable_start_time_end_time_idx_hypertable_id = 1, - Anum_partition_epoch_hypertable_start_time_end_time_idx_start_time, - Anum_partition_epoch_hypertable_start_time_end_time_idx_end_time, - _Anum_partition_epoch_hypertable_start_time_end_time_idx_max, -}; - -#define Natts_partition_epoch_hypertable_start_time_end_time_idx \ - (_Anum_partition_epoch_hypertable_start_time_end_time_idx_max - 1) - -enum Anum_partition_epoch_id_idx -{ - Anum_partition_epoch_id_idx_epoch_id = 1, - _Anum_partition_epoch_id_idx_max, -}; - -#define Natts_partition_epoch_id_idx \ - (_Anum_partition_epoch_id_idx_max - 1) - - -/***************************** - * - * Partition table definitions - * - *****************************/ - -#define PARTITION_TABLE_NAME "partition" - -enum -{ - PARTITION_ID_INDEX = 0, - PARTITION_PARTITION_EPOCH_ID_INDEX, - _MAX_PARTITION_INDEX, -}; - -enum Anum_partition -{ - Anum_partition_id = 1, - Anum_partition_partition_epoch_id, - Anum_partition_keyspace_start, - Anum_partition_keyspace_end, - Anum_partition_tablespace, - Anum_partition_schema_name, - Anum_partition_table_name, - _Anum_partition_max, -}; - -#define Natts_partition \ - (_Anum_partition_max - 1) - - /************************* * * Chunk table definitions @@ -186,8 +100,6 @@ enum Anum_chunk { Anum_chunk_id = 1, Anum_chunk_partition_id, - Anum_chunk_start_time, - Anum_chunk_end_time, Anum_chunk_schema_name, Anum_chunk_table_name, _Anum_chunk_max, @@ -196,29 +108,12 @@ enum Anum_chunk #define Natts_chunk \ (_Anum_chunk_max - 1) -enum Anum_chunk_partition_start_time_end_time_idx -{ - Anum_chunk_partition_start_time_end_time_idx_partition_id = 1, - Anum_chunk_partition_start_time_end_time_idx_start_time, - Anum_chunk_partition_start_time_end_time_idx_end_time, - _Anum_chunk_partition_start_time_end_time_idx_max, -}; - -#define Natts_chunk_partition_start_time_end_time_idx \ - (_Anum_chunk_partition_start_time_end_time_idx_max -1) - -/************************************** - * - * Chunk replica node table definitions - * - **************************************/ #define MAX(a, b) \ ((long)(a) > (long)(b) ? (a) : (b)) #define _MAX_TABLE_INDEXES MAX(_MAX_HYPERTABLE_INDEX,\ - MAX(_MAX_PARTITION_EPOCH_INDEX, \ - MAX(_MAX_PARTITION_INDEX, _MAX_CHUNK_INDEX))) + _MAX_CHUNK_INDEX) typedef enum CacheType {