mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-17 02:53:51 +08:00
This PR fixes handling of one space partition. It avoids creating a CHECK constraint and also fixes the logic in default dimension range creation.
256 lines
8.2 KiB
PL/PgSQL
256 lines
8.2 KiB
PL/PgSQL
-- This file contains functions associated with creating new
|
|
-- hypertables.
|
|
|
|
-- Creates a new schema if it does not exist.
|
|
CREATE OR REPLACE FUNCTION _timescaledb_internal.create_schema(
|
|
schema_name NAME
|
|
)
|
|
RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS
|
|
$BODY$
|
|
BEGIN
|
|
EXECUTE format(
|
|
$$
|
|
CREATE SCHEMA IF NOT EXISTS %I
|
|
$$, schema_name);
|
|
END
|
|
$BODY$
|
|
SET client_min_messages = WARNING -- suppress NOTICE on IF EXISTS
|
|
;
|
|
|
|
CREATE OR REPLACE FUNCTION _timescaledb_internal.chunk_create_table(
|
|
chunk_id INT,
|
|
tablespace_name NAME
|
|
)
|
|
RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS
|
|
$BODY$
|
|
DECLARE
|
|
chunk_row _timescaledb_catalog.chunk;
|
|
hypertable_row _timescaledb_catalog.hypertable;
|
|
tablespace_clause TEXT := '';
|
|
table_owner NAME;
|
|
tablespace_oid OID;
|
|
BEGIN
|
|
SELECT * INTO STRICT chunk_row
|
|
FROM _timescaledb_catalog.chunk
|
|
WHERE id = chunk_id;
|
|
|
|
SELECT * INTO STRICT hypertable_row
|
|
FROM _timescaledb_catalog.hypertable
|
|
WHERE id = chunk_row.hypertable_id;
|
|
|
|
SELECT t.oid
|
|
INTO tablespace_oid
|
|
FROM pg_catalog.pg_tablespace t
|
|
WHERE t.spcname = tablespace_name;
|
|
|
|
SELECT tableowner
|
|
INTO STRICT table_owner
|
|
FROM pg_catalog.pg_tables
|
|
WHERE schemaname = hypertable_row.schema_name
|
|
AND tablename = hypertable_row.table_name;
|
|
|
|
IF tablespace_oid IS NOT NULL THEN
|
|
tablespace_clause := format('TABLESPACE %s', tablespace_name);
|
|
ELSIF tablespace_name IS NOT NULL THEN
|
|
RAISE EXCEPTION 'No tablespace % in database %', tablespace_name, current_database()
|
|
USING ERRCODE = 'IO501';
|
|
END IF;
|
|
|
|
EXECUTE format(
|
|
$$
|
|
CREATE TABLE IF NOT EXISTS %1$I.%2$I () INHERITS(%3$I.%4$I) %5$s;
|
|
$$,
|
|
chunk_row.schema_name, chunk_row.table_name,
|
|
hypertable_row.schema_name, hypertable_row.table_name, tablespace_clause
|
|
);
|
|
|
|
EXECUTE format(
|
|
$$
|
|
ALTER TABLE %1$I.%2$I OWNER TO %3$I
|
|
$$,
|
|
chunk_row.schema_name, chunk_row.table_name,
|
|
table_owner
|
|
);
|
|
END
|
|
$BODY$;
|
|
|
|
CREATE OR REPLACE FUNCTION _timescaledb_internal.dimension_is_finite(
|
|
val BIGINT
|
|
)
|
|
RETURNS BOOLEAN LANGUAGE SQL IMMUTABLE PARALLEL SAFE AS
|
|
$BODY$
|
|
--end values of bigint reserved for infinite
|
|
SELECT val > (-9223372036854775808)::bigint AND val < 9223372036854775807::bigint
|
|
$BODY$;
|
|
|
|
|
|
CREATE OR REPLACE FUNCTION _timescaledb_internal.dimension_slice_get_constraint_sql(
|
|
dimension_slice_id INTEGER
|
|
)
|
|
RETURNS TEXT LANGUAGE PLPGSQL VOLATILE AS
|
|
$BODY$
|
|
DECLARE
|
|
dimension_slice_row _timescaledb_catalog.dimension_slice;
|
|
dimension_row _timescaledb_catalog.dimension;
|
|
parts TEXT[];
|
|
BEGIN
|
|
SELECT * INTO STRICT dimension_slice_row
|
|
FROM _timescaledb_catalog.dimension_slice
|
|
WHERE id = dimension_slice_id;
|
|
|
|
SELECT * INTO STRICT dimension_row
|
|
FROM _timescaledb_catalog.dimension
|
|
WHERE id = dimension_slice_row.dimension_id;
|
|
|
|
IF dimension_row.partitioning_func IS NOT NULL THEN
|
|
|
|
IF _timescaledb_internal.dimension_is_finite(dimension_slice_row.range_start) THEN
|
|
parts = parts || format(
|
|
$$
|
|
%1$I.%2$I(%3$I) >= %4$L
|
|
$$,
|
|
dimension_row.partitioning_func_schema,
|
|
dimension_row.partitioning_func,
|
|
dimension_row.column_name,
|
|
dimension_slice_row.range_start);
|
|
END IF;
|
|
|
|
IF _timescaledb_internal.dimension_is_finite(dimension_slice_row.range_end) THEN
|
|
parts = parts || format(
|
|
$$
|
|
%1$I.%2$I(%3$I) < %4$L
|
|
$$,
|
|
dimension_row.partitioning_func_schema,
|
|
dimension_row.partitioning_func,
|
|
dimension_row.column_name,
|
|
dimension_slice_row.range_end);
|
|
END IF;
|
|
|
|
IF array_length(parts, 1) = 0 THEN
|
|
RETURN NULL;
|
|
END IF;
|
|
return array_to_string(parts, 'AND');
|
|
ELSE
|
|
--TODO: only works with time for now
|
|
IF _timescaledb_internal.time_literal_sql(dimension_slice_row.range_start, dimension_row.column_type) =
|
|
_timescaledb_internal.time_literal_sql(dimension_slice_row.range_end, dimension_row.column_type) THEN
|
|
RAISE 'Time based constraints have the same start and end values for column "%": %',
|
|
dimension_row.column_name,
|
|
_timescaledb_internal.time_literal_sql(dimension_slice_row.range_end, dimension_row.column_type);
|
|
END IF;
|
|
|
|
parts = ARRAY[]::text[];
|
|
|
|
IF _timescaledb_internal.dimension_is_finite(dimension_slice_row.range_start) THEN
|
|
parts = parts || format(
|
|
$$
|
|
%1$I >= %2$s
|
|
$$,
|
|
dimension_row.column_name,
|
|
_timescaledb_internal.time_literal_sql(dimension_slice_row.range_start, dimension_row.column_type));
|
|
END IF;
|
|
|
|
IF _timescaledb_internal.dimension_is_finite(dimension_slice_row.range_end) THEN
|
|
parts = parts || format(
|
|
$$
|
|
%1$I < %2$s
|
|
$$,
|
|
dimension_row.column_name,
|
|
_timescaledb_internal.time_literal_sql(dimension_slice_row.range_end, dimension_row.column_type));
|
|
END IF;
|
|
|
|
return array_to_string(parts, 'AND');
|
|
END IF;
|
|
END
|
|
$BODY$;
|
|
|
|
-- Outputs the create_hypertable command to recreate the given hypertable.
|
|
--
|
|
-- This is currently used internally for our single hypertable backup tool
|
|
-- so that it knows how to restore the hypertable without user intervention.
|
|
--
|
|
-- It only works for hypertables with up to 2 dimensions.
|
|
CREATE OR REPLACE FUNCTION _timescaledb_internal.get_create_command(
|
|
table_name NAME
|
|
)
|
|
RETURNS TEXT LANGUAGE PLPGSQL VOLATILE AS
|
|
$BODY$
|
|
DECLARE
|
|
h_id INTEGER;
|
|
schema_name NAME;
|
|
time_column NAME;
|
|
time_interval BIGINT;
|
|
space_column NAME;
|
|
space_partitions INTEGER;
|
|
dimension_cnt INTEGER;
|
|
dimension_row record;
|
|
ret TEXT;
|
|
BEGIN
|
|
SELECT h.id, h.schema_name
|
|
FROM _timescaledb_catalog.hypertable AS h
|
|
WHERE h.table_name = get_create_command.table_name
|
|
INTO h_id, schema_name;
|
|
|
|
IF h_id IS NULL THEN
|
|
RAISE EXCEPTION 'hypertable % not found', table_name
|
|
USING ERRCODE = 'IO101';
|
|
END IF;
|
|
|
|
SELECT COUNT(*)
|
|
FROM _timescaledb_catalog.dimension d
|
|
WHERE d.hypertable_id = h_id
|
|
INTO STRICT dimension_cnt;
|
|
|
|
IF dimension_cnt > 2 THEN
|
|
RAISE EXCEPTION 'get_create_command only supports hypertables with up to 2 dimensions'
|
|
USING ERRCODE = 'IO101';
|
|
END IF;
|
|
|
|
FOR dimension_row IN
|
|
SELECT *
|
|
FROM _timescaledb_catalog.dimension d
|
|
WHERE d.hypertable_id = h_id
|
|
LOOP
|
|
IF dimension_row.interval_length IS NOT NULL THEN
|
|
time_column := dimension_row.column_name;
|
|
time_interval := dimension_row.interval_length;
|
|
ELSIF dimension_row.num_slices IS NOT NULL THEN
|
|
space_column := dimension_row.column_name;
|
|
space_partitions := dimension_row.num_slices;
|
|
END IF;
|
|
END LOOP;
|
|
|
|
ret := format($$SELECT create_hypertable('%I.%I', '%I'$$, schema_name, table_name, time_column);
|
|
IF space_column IS NOT NULL THEN
|
|
ret := ret || format($$, '%I', %s$$, space_column, space_partitions);
|
|
END IF;
|
|
ret := ret || format($$, chunk_time_interval => %s, create_default_indexes=>FALSE);$$, time_interval);
|
|
|
|
RETURN ret;
|
|
END
|
|
$BODY$;
|
|
|
|
-- Used to make sure all time dimension columns are set as NOT NULL.
|
|
CREATE OR REPLACE FUNCTION _timescaledb_internal.set_time_columns_not_null()
|
|
RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS
|
|
$BODY$
|
|
DECLARE
|
|
ht_time_column RECORD;
|
|
BEGIN
|
|
|
|
FOR ht_time_column IN
|
|
SELECT ht.schema_name, ht.table_name, d.column_name
|
|
FROM _timescaledb_catalog.hypertable ht, _timescaledb_catalog.dimension d
|
|
WHERE ht.id = d.hypertable_id AND d.partitioning_func IS NULL
|
|
LOOP
|
|
EXECUTE format(
|
|
$$
|
|
ALTER TABLE %I.%I ALTER %I SET NOT NULL
|
|
$$, ht_time_column.schema_name, ht_time_column.table_name, ht_time_column.column_name);
|
|
END LOOP;
|
|
END
|
|
$BODY$;
|
|
|
|
CREATE OR REPLACE FUNCTION _timescaledb_internal.validate_triggers(main_table REGCLASS) RETURNS VOID
|
|
AS '$libdir/timescaledb', 'hypertable_validate_triggers' LANGUAGE C STRICT;
|