From 2cb4be6abd9d00c9e5c973148271c30cc4ee80ee Mon Sep 17 00:00:00 2001 From: Matvey Arye Date: Mon, 2 Jan 2017 17:30:06 -0500 Subject: [PATCH 1/2] Allow time columns to take arbitrary names --- extension/sql/main/chunk.sql | 4 +- extension/sql/main/ioql_optimized_agg.sql | 24 +- extension/sql/main/ioql_optimized_nonagg.sql | 33 +-- extension/sql/main/ioql_sql_gen.sql | 18 +- .../sql/main/ioql_sqlgen_cluster_agg.sql | 2 +- .../sql/main/ioql_sqlgen_cluster_nonagg.sql | 19 +- extension/sql/main/schema_info.sql | 20 ++ extension/sql/main/table_creation.sql | 15 +- .../sql/tests/regression/expected/insert.out | 174 +++++++------- .../sql/tests/regression/expected/query.out | 212 +++++++++--------- extension/sql/tests/regression/insert.sql | 18 +- 11 files changed, 286 insertions(+), 253 deletions(-) diff --git a/extension/sql/main/chunk.sql b/extension/sql/main/chunk.sql index a6df08c4f..63e2fb864 100644 --- a/extension/sql/main/chunk.sql +++ b/extension/sql/main/chunk.sql @@ -26,10 +26,10 @@ DECLARE BEGIN EXECUTE format( $$ - SELECT max("time") + SELECT max(%I) FROM %I.%I $$, - schema_name, table_name) + _sysinternal.time_col_name_for_crn(schema_name, table_name), schema_name, table_name) INTO max_time; RETURN max_time; diff --git a/extension/sql/main/ioql_optimized_agg.sql b/extension/sql/main/ioql_optimized_agg.sql index e4d75e172..1bb7725c2 100644 --- a/extension/sql/main/ioql_optimized_agg.sql +++ b/extension/sql/main/ioql_optimized_agg.sql @@ -26,13 +26,13 @@ SELECT CASE END; $BODY$ LANGUAGE SQL IMMUTABLE STRICT; -CREATE OR REPLACE FUNCTION get_partial_aggregate_sql(items select_item [], agg aggregate_type) +CREATE OR REPLACE FUNCTION get_partial_aggregate_sql(time_col_name NAME, items select_item [], agg aggregate_type) RETURNS TEXT AS $BODY$ SELECT CASE WHEN agg.group_field IS NOT NULL THEN - format('%s, %s as group_time, %s', agg.group_field, get_time_clause(agg.group_time), field_list) + format('%s, %s as group_time, %s', agg.group_field, get_time_clause(time_col_name, agg.group_time), field_list) ELSE - format('%s as group_time, %s', get_time_clause(agg.group_time), field_list) + format('%s as group_time, %s', get_time_clause(time_col_name, agg.group_time), field_list) END FROM ( @@ -216,7 +216,7 @@ DECLARE BEGIN select_clause := - 'SELECT ' || get_partial_aggregate_sql(query.select_items, query.aggregate); + 'SELECT ' || get_partial_aggregate_sql(get_time_field(query.namespace_name), query.select_items, query.aggregate); RETURN base_query_raw( select_clause, @@ -390,7 +390,7 @@ END $BODY$; -CREATE OR REPLACE FUNCTION get_max_time_on_partition(part_replica partition_replica, additional_constraints TEXT) +CREATE OR REPLACE FUNCTION get_max_time_on_partition(time_col_name NAME, part_replica partition_replica, additional_constraints TEXT) RETURNS BIGINT AS $BODY$ DECLARE @@ -404,12 +404,12 @@ BEGIN FROM get_local_chunk_replica_node_for_pr_time_desc(part_replica) LOOP EXECUTE format( $$ - SELECT time - FROM %I.%I - %s - ORDER BY time DESC NULLS LAST + SELECT %1$I + FROM %2$I.%3$I + %4$s + ORDER BY %1$I DESC NULLS LAST LIMIT 1 - $$, crn_row.schema_name, crn_row.table_name, get_where_clause(additional_constraints)) + $$, time_col_name, crn_row.schema_name, crn_row.table_name, get_where_clause(additional_constraints)) INTO time; IF time IS NOT NULL THEN @@ -458,7 +458,7 @@ $BODY$ SELECT (get_time_periods_limit_for_max(max_time.max_time, period_length, num_periods)).* FROM ( - SELECT max(get_max_time_on_partition(pr, additional_constraints)) AS max_time + SELECT max(get_max_time_on_partition(get_time_field(epoch.hypertable_name),pr, additional_constraints)) AS max_time FROM get_partition_replicas(epoch, replica_id) pr ) AS max_time $BODY$; @@ -481,7 +481,7 @@ BEGIN (query.aggregate).group_time, query.limit_time_periods); additional_constraints := combine_predicates( - format('time >= %L AND time <=%L', trange.start_time, trange.end_time), + format('%1$I >= %2$L AND %1$I <=%3$L', get_time_field(query.namespace_name), trange.start_time, trange.end_time), additional_constraints); END IF; diff --git a/extension/sql/main/ioql_optimized_nonagg.sql b/extension/sql/main/ioql_optimized_nonagg.sql index a3f39e328..a858b3de7 100644 --- a/extension/sql/main/ioql_optimized_nonagg.sql +++ b/extension/sql/main/ioql_optimized_nonagg.sql @@ -13,6 +13,7 @@ DECLARE index INT = 0; previous_tables TEXT = ''; code TEXT = ''; + time_col_name NAME; query_sql_scan_base_table TEXT = ''; query_sql_scan TEXT = ''; @@ -20,7 +21,7 @@ DECLARE crn_row chunk_replica_node; partition_row partition; BEGIN - + time_col_name := get_time_field(query.namespace_name); IF epoch.partitioning_field = (query.limit_by_field).field THEN SELECT * @@ -67,10 +68,10 @@ BEGIN get_full_select_clause_nonagg(query), 'FROM %1$s', get_where_clause( - get_time_predicate(query.time_condition) + get_time_predicate(time_col_name, query.time_condition) ), NULL, - 'ORDER BY time DESC NULLS LAST', + format('ORDER BY %I DESC NULLS LAST', time_col_name), format('LIMIT (SELECT count(*) * %L FROM distinct_value)', (query.limit_by_field).count * 2) ); @@ -98,10 +99,10 @@ BEGIN get_where_clause( default_predicates(query, epoch), format('%1$I::text = dv_counts_min_time.value AND %1$I IS NOT NULL', (query.limit_by_field).field), - '(time < dv_counts_min_time.min_time OR dv_counts_min_time.min_time IS NULL)' + format('(%I < dv_counts_min_time.min_time OR dv_counts_min_time.min_time IS NULL)', time_col_name) ), get_groupby_clause(query.aggregate), - 'ORDER BY time DESC NULLS LAST, ' || (query.limit_by_field).field, + 'ORDER BY '||quote_ident(time_col_name)||' DESC NULLS LAST, ' || (query.limit_by_field).field, 'LIMIT dv_counts_min_time.remaining_cnt'); FOR crn_row IN SELECT * @@ -116,7 +117,7 @@ BEGIN FROM ( SELECT - ROW_NUMBER() OVER (PARTITION BY %2$I ORDER BY time DESC NULLS LAST) as rank, + ROW_NUMBER() OVER (PARTITION BY %2$I ORDER BY %5$I DESC NULLS LAST) as rank, res.* FROM (%3$s) as res ) AS with_rank @@ -126,7 +127,8 @@ BEGIN get_full_select_clause_nonagg(query), (query.limit_by_field).field, format(query_sql_scan, format('%I.%I', crn_row.schema_name, crn_row.table_name)), - (query.limit_by_field).count + (query.limit_by_field).count, + time_col_name ); previous_tables := 'SELECT * FROM result_scan'; @@ -138,7 +140,7 @@ BEGIN SELECT original.value AS value, original.cnt - coalesce(existing.cnt, 0) as remaining_cnt, min_time as min_time FROM distinct_value as original LEFT JOIN ( - SELECT %1$s::text AS value, count(*) AS cnt, min(time) AS min_time + SELECT %1$s::text AS value, count(*) AS cnt, min(%5$I) AS min_time FROM (%2$s) AS previous_results GROUP BY %1$s ) as existing on (original.value = existing.value) @@ -153,7 +155,8 @@ BEGIN (query.limit_by_field).field, previous_tables, index, - format(query_sql_jump, format('%I.%I', crn_row.schema_name, crn_row.table_name)) + format(query_sql_jump, format('%I.%I', crn_row.schema_name, crn_row.table_name)), + time_col_name ); previous_tables := previous_tables || format(' UNION ALL SELECT * FROM results_%s', index); @@ -228,12 +231,12 @@ BEGIN FROM ( SELECT - ROW_NUMBER() OVER (PARTITION BY %2$s ORDER BY time DESC NULLS LAST) as rank, + ROW_NUMBER() OVER (PARTITION BY %2$s ORDER BY %7$I DESC NULLS LAST) as rank, combined_node.* FROM (%4$s) as combined_node ) AS node_result WHERE rank <= %5$L - ORDER BY time DESC NULLS LAST, %2$s + ORDER BY %7$I DESC NULLS LAST, %2$s %6$s $$, get_result_column_def_list_nonagg(query), @@ -241,7 +244,8 @@ BEGIN get_result_column_list_nonagg(query), string_agg(code_part, ' UNION ALL '), (query.limit_by_field).count, - get_limit_clause(query.limit_rows) + get_limit_clause(query.limit_rows), + get_time_field(query.namespace_name) ) INTO STRICT code FROM @@ -254,11 +258,12 @@ BEGIN $$ SELECT * FROM (%1$s) AS combined_node - ORDER BY time DESC NULLS LAST + ORDER BY %3$I DESC NULLS LAST %2$s $$, string_agg(code_part, ' UNION ALL '), - get_limit_clause(query.limit_rows) + get_limit_clause(query.limit_rows), + get_time_field(query.namespace_name) ) INTO STRICT code FROM diff --git a/extension/sql/main/ioql_sql_gen.sql b/extension/sql/main/ioql_sql_gen.sql index 309ed797a..6193e5b14 100644 --- a/extension/sql/main/ioql_sql_gen.sql +++ b/extension/sql/main/ioql_sql_gen.sql @@ -1,11 +1,11 @@ -CREATE OR REPLACE FUNCTION get_time_clause(group_time BIGINT) +CREATE OR REPLACE FUNCTION get_time_clause(time_col_name NAME, group_time BIGINT) RETURNS TEXT LANGUAGE SQL IMMUTABLE AS $BODY$ SELECT CASE WHEN group_time IS NOT NULL THEN - format('(time - (time %% %L::bigint))::bigint', group_time) + format('(%1$I - (%1$I %% %2$L::bigint))::bigint', time_col_name, group_time) ELSE - 'time' + format('%I', time_col_name) END; $BODY$; @@ -30,11 +30,11 @@ FROM unnest(clauses) AS clause(val) WHERE val IS NOT NULL; $BODY$; -CREATE OR REPLACE FUNCTION get_time_predicate(cond time_condition_type) +CREATE OR REPLACE FUNCTION get_time_predicate(time_col_name NAME, cond time_condition_type) RETURNS TEXT LANGUAGE SQL IMMUTABLE AS $BODY$ SELECT string_agg(clauses.val, ' AND ') -FROM (VALUES ('time>=' || cond.from_time), ('time<' || cond.to_time)) AS clauses(val); +FROM (VALUES (format('%I >= ', time_col_name) || cond.from_time), (format('%I < ', time_col_name) || cond.to_time)) AS clauses(val); $BODY$; --TODO: Review this @@ -98,7 +98,7 @@ CREATE OR REPLACE FUNCTION default_predicates(query ioql_query, epoch partition_ RETURNS TEXT LANGUAGE SQL STABLE AS $BODY$ SELECT combine_predicates( - get_time_predicate(query.time_condition), + get_time_predicate(get_time_field(query.namespace_name), query.time_condition), get_field_predicate_clause(query.field_condition), get_select_field_predicate(query.select_items), get_partitioning_predicate(query, epoch) @@ -141,9 +141,9 @@ CREATE OR REPLACE FUNCTION get_orderby_clause_nonagg(query ioql_query) $BODY$ SELECT CASE WHEN query.limit_by_field IS NOT NULL THEN - 'ORDER BY time DESC NULLS LAST, ' || (query.limit_by_field).field - ELSE - 'ORDER BY time DESC NULLS LAST' + format('ORDER BY %I DESC NULLS LAST, %s', get_time_field(query.namespace_name), (query.limit_by_field).field) + ELSE + format('ORDER BY %I DESC NULLS LAST', get_time_field(query.namespace_name)) END; $BODY$; diff --git a/extension/sql/main/ioql_sqlgen_cluster_agg.sql b/extension/sql/main/ioql_sqlgen_cluster_agg.sql index 986172e41..b19141ac6 100644 --- a/extension/sql/main/ioql_sqlgen_cluster_agg.sql +++ b/extension/sql/main/ioql_sqlgen_cluster_agg.sql @@ -32,7 +32,7 @@ BEGIN SELECT without_limit.* FROM without_limit, get_time_periods_limit_for_max((SELECT max(time) from without_limit), %4$L, %5$L) limits - WHERE time >= limits.start_time AND time <= limits.end_time + WHERE without_limit.time >= limits.start_time AND without_limit.time <= limits.end_time %2$s %3$s $$, diff --git a/extension/sql/main/ioql_sqlgen_cluster_nonagg.sql b/extension/sql/main/ioql_sqlgen_cluster_nonagg.sql index 801a8d020..a12f5d952 100644 --- a/extension/sql/main/ioql_sqlgen_cluster_nonagg.sql +++ b/extension/sql/main/ioql_sqlgen_cluster_nonagg.sql @@ -9,14 +9,15 @@ BEGIN FROM ioql_exec_query_nodes( %2$L, %5$L, %1$L ) as res(%1$s) - ORDER BY time DESC NULLS LAST + ORDER BY %6$I DESC NULLS LAST %4$s $$, get_result_column_def_list_nonagg(query), query, query.namespace_name, get_limit_clause(query.limit_rows), - epoch + epoch, + get_time_field(query.namespace_name) ); END $BODY$; @@ -31,14 +32,14 @@ BEGIN SELECT %4$s FROM ( SELECT - ROW_NUMBER() OVER (PARTITION BY %2$s ORDER BY time DESC NULLS LAST) AS rank, + ROW_NUMBER() OVER (PARTITION BY %2$s ORDER BY %8$I DESC NULLS LAST) AS rank, * FROM ( %5$s ) as ieq ) as ranked - WHERE rank <= %7$L OR time IS NULL - ORDER BY time DESC NULLS LAST, %2$s + WHERE rank <= %7$L OR %8$I IS NULL + ORDER BY %8$I DESC NULLS LAST, %2$s %6$s $$, get_result_column_def_list_nonagg(query), @@ -47,7 +48,8 @@ BEGIN get_result_column_list_nonagg(query), ioql_query_nonagg_without_limit_sql(query, epoch), get_limit_clause(query.limit_rows), - (query.limit_by_field).count + (query.limit_by_field).count, + get_time_field(query.namespace_name) ); ELSE RETURN format( @@ -56,12 +58,13 @@ BEGIN FROM ( %2$s ) as ieq(%1$s) - ORDER BY time DESC NULLS LAST + ORDER BY %4$I DESC NULLS LAST %3$s $$, get_result_column_list_nonagg(query), ioql_query_nonagg_without_limit_sql(query, epoch), - get_limit_clause(query.limit_rows) + get_limit_clause(query.limit_rows), + get_time_field(query.namespace_name) ); END IF; END; diff --git a/extension/sql/main/schema_info.sql b/extension/sql/main/schema_info.sql index b16aca95f..e36cdea21 100644 --- a/extension/sql/main/schema_info.sql +++ b/extension/sql/main/schema_info.sql @@ -182,4 +182,24 @@ $BODY$ $BODY$; +CREATE OR REPLACE FUNCTION _sysinternal.time_col_name_for_crn( + schema_name NAME, + table_name NAME +) + RETURNS NAME LANGUAGE PLPGSQL STABLE AS +$BODY$ +DECLARE + time_col_name NAME; +BEGIN + SELECT h.time_field_name INTO STRICT time_col_name + FROM hypertable h + INNER JOIN partition_epoch pe ON (pe.hypertable_name = h.name) + INNER JOIN partition p ON (p.epoch_id = pe.id) + INNER JOIN chunk c ON (c.partition_id = p.id) + INNER JOIN chunk_replica_node crn ON (crn.chunk_id = c.id) + WHERE crn.schema_name = time_col_name_for_crn.schema_name AND + crn.table_name = time_col_name_for_crn.table_name; + RETURN time_col_name; +END +$BODY$; diff --git a/extension/sql/main/table_creation.sql b/extension/sql/main/table_creation.sql index 38d476960..4606f3bb4 100644 --- a/extension/sql/main/table_creation.sql +++ b/extension/sql/main/table_creation.sql @@ -234,21 +234,26 @@ BEGIN IF start_time IS NOT NULL AND end_time IS NOT NULL THEN EXECUTE format( $$ - ALTER TABLE %I.%I ADD CONSTRAINT time_range CHECK(time >= %L AND time <= %L) + ALTER TABLE %2$I.%3$I ADD CONSTRAINT time_range CHECK(%1$I >= %4$L AND %1$I <= %5$L) $$, + _sysinternal.time_col_name_for_crn(schema_name, table_name), schema_name, table_name, start_time, end_time); ELSIF start_time IS NOT NULL THEN EXECUTE format( $$ - ALTER TABLE %I.%I ADD CONSTRAINT time_range CHECK(time >= %L) + ALTER TABLE %I.%I ADD CONSTRAINT time_range CHECK(%I >= %L) $$, - schema_name, table_name, start_time); + schema_name, table_name, + _sysinternal.time_col_name_for_crn(schema_name, table_name), + start_time); ELSIF end_time IS NOT NULL THEN EXECUTE format( $$ - ALTER TABLE %I.%I ADD CONSTRAINT time_range CHECK(time <= %L) + ALTER TABLE %I.%I ADD CONSTRAINT time_range CHECK(%I <= %L) $$, - schema_name, table_name, end_time); + schema_name, table_name, + _sysinternal.time_col_name_for_crn(schema_name, table_name), + end_time); END IF; END $BODY$; diff --git a/extension/sql/tests/regression/expected/insert.out b/extension/sql/tests/regression/expected/insert.out index 9d76d0c30..f78ddd40d 100644 --- a/extension/sql/tests/regression/expected/insert.out +++ b/extension/sql/tests/regression/expected/insert.out @@ -40,22 +40,22 @@ SELECT add_node('test2' :: NAME, 'localhost'); \c Test1 CREATE TABLE PUBLIC."testNs" ( - time BIGINT NOT NULL, + "timeCustom" BIGINT NOT NULL, device_id TEXT NOT NULL, series_0 DOUBLE PRECISION NULL, series_1 DOUBLE PRECISION NULL, series_2 DOUBLE PRECISION NULL, series_bool BOOLEAN NULL ); -CREATE INDEX ON PUBLIC."testNs" (device_id, time DESC NULLS LAST) WHERE device_id IS NOT NULL; -CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL; -CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL; -CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL; -CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL; -SELECT * FROM add_hypertable('"public"."testNs"', 'time', 'device_id', hypertable_name=>'testNs', associated_schema_name=>'testNs' ); +CREATE INDEX ON PUBLIC."testNs" (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" ("timeCustom" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" ("timeCustom" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL; +SELECT * FROM add_hypertable('"public"."testNs"', 'timeCustom', 'device_id', hypertable_name=>'testNs', associated_schema_name=>'testNs' ); name | main_schema_name | main_table_name | associated_schema_name | associated_table_prefix | root_schema_name | root_table_name | distinct_schema_name | distinct_table_name | replication_factor | placement | time_field_name | time_field_type | created_on --------+------------------+-----------------+------------------------+-------------------------+------------------+-----------------+----------------------+---------------------+--------------------+-----------+-----------------+-----------------+------------ - testNs | public | testNs | testNs | _hyper_1 | testNs | _hyper_1_root | testNs | _hyper_1_distinct | 1 | STICKY | time | bigint | Test1 + testNs | public | testNs | testNs | _hyper_1 | testNs | _hyper_1_root | testNs | _hyper_1_distinct | 1 | STICKY | timeCustom | bigint | Test1 (1 row) SELECT set_is_distinct_flag('"public"."testNs"', 'device_id', TRUE); @@ -78,87 +78,87 @@ INNER JOIN chunk c ON (c.partition_id = part.id); \c Test1 BEGIN; -INSERT INTO "testNs"(time, device_id, series_0, series_1) VALUES +INSERT INTO "testNs"("timeCustom", device_id, series_0, series_1) VALUES (1257987600000000000, 'dev1', 1.5, 1), (1257987600000000000, 'dev1', 1.5, 2), (1257894002000000000, 'dev1', 2.5, 3); COMMIT; \c test2 BEGIN; -INSERT INTO "testNs"(time, device_id, series_0, series_1) VALUES +INSERT INTO "testNs"("timeCustom", device_id, series_0, series_1) VALUES (1257894000000000000, 'dev2', 1.5, 1), (1257894000000000000, 'dev2', 1.5, 2); COMMIT; \c Test1 \d+ "testNs".* - Index "testNs.1-testNs_device_id_time_idx" - Column | Type | Definition | Storage ------------+--------+------------+---------- - device_id | text | device_id | extended - time | bigint | "time" | plain +Index "testNs.1-testNs_device_id_timeCustom_idx" + Column | Type | Definition | Storage +------------+--------+--------------+---------- + device_id | text | device_id | extended + timeCustom | bigint | "timeCustom" | plain btree, for table "testNs._hyper_1_1_0_1_data", predicate (device_id IS NOT NULL) - Index "testNs.10-testNs_time_series_bool_idx" - Column | Type | Definition | Storage --------------+---------+-------------+--------- - time | bigint | "time" | plain - series_bool | boolean | series_bool | plain +Index "testNs.10-testNs_timeCustom_series_bool_idx" + Column | Type | Definition | Storage +-------------+---------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_bool | boolean | series_bool | plain btree, for table "testNs._hyper_1_1_0_2_data", predicate (series_bool IS NOT NULL) - Index "testNs.2-testNs_time_series_0_idx" - Column | Type | Definition | Storage -----------+------------------+------------+--------- - time | bigint | "time" | plain - series_0 | double precision | series_0 | plain + Index "testNs.2-testNs_timeCustom_series_0_idx" + Column | Type | Definition | Storage +------------+------------------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_0 | double precision | series_0 | plain btree, for table "testNs._hyper_1_1_0_1_data", predicate (series_0 IS NOT NULL) - Index "testNs.3-testNs_time_series_1_idx" - Column | Type | Definition | Storage -----------+------------------+------------+--------- - time | bigint | "time" | plain - series_1 | double precision | series_1 | plain + Index "testNs.3-testNs_timeCustom_series_1_idx" + Column | Type | Definition | Storage +------------+------------------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_1 | double precision | series_1 | plain btree, for table "testNs._hyper_1_1_0_1_data", predicate (series_1 IS NOT NULL) - Index "testNs.4-testNs_time_series_2_idx" - Column | Type | Definition | Storage -----------+------------------+------------+--------- - time | bigint | "time" | plain - series_2 | double precision | series_2 | plain + Index "testNs.4-testNs_timeCustom_series_2_idx" + Column | Type | Definition | Storage +------------+------------------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_2 | double precision | series_2 | plain btree, for table "testNs._hyper_1_1_0_1_data", predicate (series_2 IS NOT NULL) - Index "testNs.5-testNs_time_series_bool_idx" - Column | Type | Definition | Storage --------------+---------+-------------+--------- - time | bigint | "time" | plain - series_bool | boolean | series_bool | plain +Index "testNs.5-testNs_timeCustom_series_bool_idx" + Column | Type | Definition | Storage +-------------+---------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_bool | boolean | series_bool | plain btree, for table "testNs._hyper_1_1_0_1_data", predicate (series_bool IS NOT NULL) - Index "testNs.6-testNs_device_id_time_idx" - Column | Type | Definition | Storage ------------+--------+------------+---------- - device_id | text | device_id | extended - time | bigint | "time" | plain +Index "testNs.6-testNs_device_id_timeCustom_idx" + Column | Type | Definition | Storage +------------+--------+--------------+---------- + device_id | text | device_id | extended + timeCustom | bigint | "timeCustom" | plain btree, for table "testNs._hyper_1_1_0_2_data", predicate (device_id IS NOT NULL) - Index "testNs.7-testNs_time_series_0_idx" - Column | Type | Definition | Storage -----------+------------------+------------+--------- - time | bigint | "time" | plain - series_0 | double precision | series_0 | plain + Index "testNs.7-testNs_timeCustom_series_0_idx" + Column | Type | Definition | Storage +------------+------------------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_0 | double precision | series_0 | plain btree, for table "testNs._hyper_1_1_0_2_data", predicate (series_0 IS NOT NULL) - Index "testNs.8-testNs_time_series_1_idx" - Column | Type | Definition | Storage -----------+------------------+------------+--------- - time | bigint | "time" | plain - series_1 | double precision | series_1 | plain + Index "testNs.8-testNs_timeCustom_series_1_idx" + Column | Type | Definition | Storage +------------+------------------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_1 | double precision | series_1 | plain btree, for table "testNs._hyper_1_1_0_2_data", predicate (series_1 IS NOT NULL) - Index "testNs.9-testNs_time_series_2_idx" - Column | Type | Definition | Storage -----------+------------------+------------+--------- - time | bigint | "time" | plain - series_2 | double precision | series_2 | plain + Index "testNs.9-testNs_timeCustom_series_2_idx" + Column | Type | Definition | Storage +------------+------------------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_2 | double precision | series_2 | plain btree, for table "testNs._hyper_1_1_0_2_data", predicate (series_2 IS NOT NULL) Table "testNs._hyper_1_0_1_distinct_data" @@ -188,7 +188,7 @@ Child tables: "testNs"._hyper_1_0_1_distinct_data Table "testNs._hyper_1_0_replica" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -201,47 +201,47 @@ Child tables: "testNs"._hyper_1_1_0_partition, Table "testNs._hyper_1_1_0_1_data" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | series_2 | double precision | | plain | | series_bool | boolean | | plain | | Indexes: - "1-testNs_device_id_time_idx" btree (device_id, "time" DESC NULLS LAST) WHERE device_id IS NOT NULL - "2-testNs_time_series_0_idx" btree ("time" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL - "3-testNs_time_series_1_idx" btree ("time" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL - "4-testNs_time_series_2_idx" btree ("time" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL - "5-testNs_time_series_bool_idx" btree ("time" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL + "1-testNs_device_id_timeCustom_idx" btree (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL + "2-testNs_timeCustom_series_0_idx" btree ("timeCustom" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL + "3-testNs_timeCustom_series_1_idx" btree ("timeCustom" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL + "4-testNs_timeCustom_series_2_idx" btree ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL + "5-testNs_timeCustom_series_bool_idx" btree ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL Check constraints: "partition" CHECK (get_partition_for_key(device_id, 32768) >= '0'::smallint AND get_partition_for_key(device_id, 32768) <= '16383'::smallint) - "time_range" CHECK ("time" <= '1257983999999999999'::bigint) + "time_range" CHECK ("timeCustom" <= '1257983999999999999'::bigint) Inherits: "testNs"._hyper_1_1_0_partition Table "testNs._hyper_1_1_0_2_data" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | series_2 | double precision | | plain | | series_bool | boolean | | plain | | Indexes: - "10-testNs_time_series_bool_idx" btree ("time" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL - "6-testNs_device_id_time_idx" btree (device_id, "time" DESC NULLS LAST) WHERE device_id IS NOT NULL - "7-testNs_time_series_0_idx" btree ("time" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL - "8-testNs_time_series_1_idx" btree ("time" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL - "9-testNs_time_series_2_idx" btree ("time" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL + "10-testNs_timeCustom_series_bool_idx" btree ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL + "6-testNs_device_id_timeCustom_idx" btree (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL + "7-testNs_timeCustom_series_0_idx" btree ("timeCustom" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL + "8-testNs_timeCustom_series_1_idx" btree ("timeCustom" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL + "9-testNs_timeCustom_series_2_idx" btree ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL Check constraints: "partition" CHECK (get_partition_for_key(device_id, 32768) >= '0'::smallint AND get_partition_for_key(device_id, 32768) <= '16383'::smallint) - "time_range" CHECK ("time" >= '1257984000000000000'::bigint) + "time_range" CHECK ("timeCustom" >= '1257984000000000000'::bigint) Inherits: "testNs"._hyper_1_1_0_partition Table "testNs._hyper_1_1_0_partition" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -256,7 +256,7 @@ Child tables: "testNs"._hyper_1_1_0_1_data, Table "testNs._hyper_1_2_0_partition" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -285,7 +285,7 @@ primary key, btree, for table "testNs._hyper_1_distinct" Table "testNs._hyper_1_root" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -315,7 +315,7 @@ Child tables: "testNs"._hyper_1_0_1_distinct_data Table "testNs._hyper_1_0_replica" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -328,7 +328,7 @@ Child tables: "testNs"._hyper_1_1_0_partition, Foreign table "testNs._hyper_1_1_0_1_data" Column | Type | Modifiers | FDW Options | Storage | Stats target | Description -------------+------------------+-----------+-------------+----------+--------------+------------- - time | bigint | not null | | plain | | + timeCustom | bigint | not null | | plain | | device_id | text | not null | | extended | | series_0 | double precision | | | plain | | series_1 | double precision | | | plain | | @@ -336,7 +336,7 @@ Child tables: "testNs"._hyper_1_1_0_partition, series_bool | boolean | | | plain | | Check constraints: "partition" CHECK (get_partition_for_key(device_id, 32768) >= '0'::smallint AND get_partition_for_key(device_id, 32768) <= '16383'::smallint) - "time_range" CHECK ("time" <= '1257983999999999999'::bigint) + "time_range" CHECK ("timeCustom" <= '1257983999999999999'::bigint) Server: Test1 FDW Options: (schema_name 'testNs', table_name '_hyper_1_1_0_1_data') Inherits: "testNs"._hyper_1_1_0_partition @@ -344,7 +344,7 @@ Inherits: "testNs"._hyper_1_1_0_partition Foreign table "testNs._hyper_1_1_0_2_data" Column | Type | Modifiers | FDW Options | Storage | Stats target | Description -------------+------------------+-----------+-------------+----------+--------------+------------- - time | bigint | not null | | plain | | + timeCustom | bigint | not null | | plain | | device_id | text | not null | | extended | | series_0 | double precision | | | plain | | series_1 | double precision | | | plain | | @@ -352,7 +352,7 @@ Inherits: "testNs"._hyper_1_1_0_partition series_bool | boolean | | | plain | | Check constraints: "partition" CHECK (get_partition_for_key(device_id, 32768) >= '0'::smallint AND get_partition_for_key(device_id, 32768) <= '16383'::smallint) - "time_range" CHECK ("time" >= '1257984000000000000'::bigint) + "time_range" CHECK ("timeCustom" >= '1257984000000000000'::bigint) Server: Test1 FDW Options: (schema_name 'testNs', table_name '_hyper_1_1_0_2_data') Inherits: "testNs"._hyper_1_1_0_partition @@ -360,7 +360,7 @@ Inherits: "testNs"._hyper_1_1_0_partition Table "testNs._hyper_1_1_0_partition" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -375,7 +375,7 @@ Child tables: "testNs"._hyper_1_1_0_1_data, Table "testNs._hyper_1_2_0_partition" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -404,7 +404,7 @@ primary key, btree, for table "testNs._hyper_1_distinct" Table "testNs._hyper_1_root" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -414,7 +414,7 @@ Child tables: "testNs"._hyper_1_0_replica SELECT * FROM "testNs"._hyper_1_0_replica; - time | device_id | series_0 | series_1 | series_2 | series_bool + timeCustom | device_id | series_0 | series_1 | series_2 | series_bool ---------------------+-----------+----------+----------+----------+------------- 1257894000000000000 | dev1 | 1.5 | 1 | 2 | t 1257894000000000000 | dev1 | 1.5 | 2 | | diff --git a/extension/sql/tests/regression/expected/query.out b/extension/sql/tests/regression/expected/query.out index 8553babf9..4e30967b7 100644 --- a/extension/sql/tests/regression/expected/query.out +++ b/extension/sql/tests/regression/expected/query.out @@ -40,22 +40,22 @@ SELECT add_node('test2' :: NAME, 'localhost'); \c Test1 CREATE TABLE PUBLIC."testNs" ( - time BIGINT NOT NULL, + "timeCustom" BIGINT NOT NULL, device_id TEXT NOT NULL, series_0 DOUBLE PRECISION NULL, series_1 DOUBLE PRECISION NULL, series_2 DOUBLE PRECISION NULL, series_bool BOOLEAN NULL ); -CREATE INDEX ON PUBLIC."testNs" (device_id, time DESC NULLS LAST) WHERE device_id IS NOT NULL; -CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL; -CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL; -CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL; -CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL; -SELECT * FROM add_hypertable('"public"."testNs"', 'time', 'device_id', hypertable_name=>'testNs', associated_schema_name=>'testNs' ); +CREATE INDEX ON PUBLIC."testNs" (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" ("timeCustom" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" ("timeCustom" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL; +SELECT * FROM add_hypertable('"public"."testNs"', 'timeCustom', 'device_id', hypertable_name=>'testNs', associated_schema_name=>'testNs' ); name | main_schema_name | main_table_name | associated_schema_name | associated_table_prefix | root_schema_name | root_table_name | distinct_schema_name | distinct_table_name | replication_factor | placement | time_field_name | time_field_type | created_on --------+------------------+-----------------+------------------------+-------------------------+------------------+-----------------+----------------------+---------------------+--------------------+-----------+-----------------+-----------------+------------ - testNs | public | testNs | testNs | _hyper_1 | testNs | _hyper_1_root | testNs | _hyper_1_distinct | 1 | STICKY | time | bigint | Test1 + testNs | public | testNs | testNs | _hyper_1 | testNs | _hyper_1_root | testNs | _hyper_1_distinct | 1 | STICKY | timeCustom | bigint | Test1 (1 row) SELECT set_is_distinct_flag('"public"."testNs"', 'device_id', TRUE); @@ -78,87 +78,87 @@ INNER JOIN chunk c ON (c.partition_id = part.id); \c Test1 BEGIN; -INSERT INTO "testNs"(time, device_id, series_0, series_1) VALUES +INSERT INTO "testNs"("timeCustom", device_id, series_0, series_1) VALUES (1257987600000000000, 'dev1', 1.5, 1), (1257987600000000000, 'dev1', 1.5, 2), (1257894002000000000, 'dev1', 2.5, 3); COMMIT; \c test2 BEGIN; -INSERT INTO "testNs"(time, device_id, series_0, series_1) VALUES +INSERT INTO "testNs"("timeCustom", device_id, series_0, series_1) VALUES (1257894000000000000, 'dev2', 1.5, 1), (1257894000000000000, 'dev2', 1.5, 2); COMMIT; \c Test1 \d+ "testNs".* - Index "testNs.1-testNs_device_id_time_idx" - Column | Type | Definition | Storage ------------+--------+------------+---------- - device_id | text | device_id | extended - time | bigint | "time" | plain +Index "testNs.1-testNs_device_id_timeCustom_idx" + Column | Type | Definition | Storage +------------+--------+--------------+---------- + device_id | text | device_id | extended + timeCustom | bigint | "timeCustom" | plain btree, for table "testNs._hyper_1_1_0_1_data", predicate (device_id IS NOT NULL) - Index "testNs.10-testNs_time_series_bool_idx" - Column | Type | Definition | Storage --------------+---------+-------------+--------- - time | bigint | "time" | plain - series_bool | boolean | series_bool | plain +Index "testNs.10-testNs_timeCustom_series_bool_idx" + Column | Type | Definition | Storage +-------------+---------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_bool | boolean | series_bool | plain btree, for table "testNs._hyper_1_1_0_2_data", predicate (series_bool IS NOT NULL) - Index "testNs.2-testNs_time_series_0_idx" - Column | Type | Definition | Storage -----------+------------------+------------+--------- - time | bigint | "time" | plain - series_0 | double precision | series_0 | plain + Index "testNs.2-testNs_timeCustom_series_0_idx" + Column | Type | Definition | Storage +------------+------------------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_0 | double precision | series_0 | plain btree, for table "testNs._hyper_1_1_0_1_data", predicate (series_0 IS NOT NULL) - Index "testNs.3-testNs_time_series_1_idx" - Column | Type | Definition | Storage -----------+------------------+------------+--------- - time | bigint | "time" | plain - series_1 | double precision | series_1 | plain + Index "testNs.3-testNs_timeCustom_series_1_idx" + Column | Type | Definition | Storage +------------+------------------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_1 | double precision | series_1 | plain btree, for table "testNs._hyper_1_1_0_1_data", predicate (series_1 IS NOT NULL) - Index "testNs.4-testNs_time_series_2_idx" - Column | Type | Definition | Storage -----------+------------------+------------+--------- - time | bigint | "time" | plain - series_2 | double precision | series_2 | plain + Index "testNs.4-testNs_timeCustom_series_2_idx" + Column | Type | Definition | Storage +------------+------------------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_2 | double precision | series_2 | plain btree, for table "testNs._hyper_1_1_0_1_data", predicate (series_2 IS NOT NULL) - Index "testNs.5-testNs_time_series_bool_idx" - Column | Type | Definition | Storage --------------+---------+-------------+--------- - time | bigint | "time" | plain - series_bool | boolean | series_bool | plain +Index "testNs.5-testNs_timeCustom_series_bool_idx" + Column | Type | Definition | Storage +-------------+---------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_bool | boolean | series_bool | plain btree, for table "testNs._hyper_1_1_0_1_data", predicate (series_bool IS NOT NULL) - Index "testNs.6-testNs_device_id_time_idx" - Column | Type | Definition | Storage ------------+--------+------------+---------- - device_id | text | device_id | extended - time | bigint | "time" | plain +Index "testNs.6-testNs_device_id_timeCustom_idx" + Column | Type | Definition | Storage +------------+--------+--------------+---------- + device_id | text | device_id | extended + timeCustom | bigint | "timeCustom" | plain btree, for table "testNs._hyper_1_1_0_2_data", predicate (device_id IS NOT NULL) - Index "testNs.7-testNs_time_series_0_idx" - Column | Type | Definition | Storage -----------+------------------+------------+--------- - time | bigint | "time" | plain - series_0 | double precision | series_0 | plain + Index "testNs.7-testNs_timeCustom_series_0_idx" + Column | Type | Definition | Storage +------------+------------------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_0 | double precision | series_0 | plain btree, for table "testNs._hyper_1_1_0_2_data", predicate (series_0 IS NOT NULL) - Index "testNs.8-testNs_time_series_1_idx" - Column | Type | Definition | Storage -----------+------------------+------------+--------- - time | bigint | "time" | plain - series_1 | double precision | series_1 | plain + Index "testNs.8-testNs_timeCustom_series_1_idx" + Column | Type | Definition | Storage +------------+------------------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_1 | double precision | series_1 | plain btree, for table "testNs._hyper_1_1_0_2_data", predicate (series_1 IS NOT NULL) - Index "testNs.9-testNs_time_series_2_idx" - Column | Type | Definition | Storage -----------+------------------+------------+--------- - time | bigint | "time" | plain - series_2 | double precision | series_2 | plain + Index "testNs.9-testNs_timeCustom_series_2_idx" + Column | Type | Definition | Storage +------------+------------------+--------------+--------- + timeCustom | bigint | "timeCustom" | plain + series_2 | double precision | series_2 | plain btree, for table "testNs._hyper_1_1_0_2_data", predicate (series_2 IS NOT NULL) Table "testNs._hyper_1_0_1_distinct_data" @@ -188,7 +188,7 @@ Child tables: "testNs"._hyper_1_0_1_distinct_data Table "testNs._hyper_1_0_replica" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -201,47 +201,47 @@ Child tables: "testNs"._hyper_1_1_0_partition, Table "testNs._hyper_1_1_0_1_data" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | series_2 | double precision | | plain | | series_bool | boolean | | plain | | Indexes: - "1-testNs_device_id_time_idx" btree (device_id, "time" DESC NULLS LAST) WHERE device_id IS NOT NULL - "2-testNs_time_series_0_idx" btree ("time" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL - "3-testNs_time_series_1_idx" btree ("time" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL - "4-testNs_time_series_2_idx" btree ("time" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL - "5-testNs_time_series_bool_idx" btree ("time" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL + "1-testNs_device_id_timeCustom_idx" btree (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL + "2-testNs_timeCustom_series_0_idx" btree ("timeCustom" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL + "3-testNs_timeCustom_series_1_idx" btree ("timeCustom" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL + "4-testNs_timeCustom_series_2_idx" btree ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL + "5-testNs_timeCustom_series_bool_idx" btree ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL Check constraints: "partition" CHECK (get_partition_for_key(device_id, 32768) >= '0'::smallint AND get_partition_for_key(device_id, 32768) <= '16383'::smallint) - "time_range" CHECK ("time" <= '1257983999999999999'::bigint) + "time_range" CHECK ("timeCustom" <= '1257983999999999999'::bigint) Inherits: "testNs"._hyper_1_1_0_partition Table "testNs._hyper_1_1_0_2_data" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | series_2 | double precision | | plain | | series_bool | boolean | | plain | | Indexes: - "10-testNs_time_series_bool_idx" btree ("time" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL - "6-testNs_device_id_time_idx" btree (device_id, "time" DESC NULLS LAST) WHERE device_id IS NOT NULL - "7-testNs_time_series_0_idx" btree ("time" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL - "8-testNs_time_series_1_idx" btree ("time" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL - "9-testNs_time_series_2_idx" btree ("time" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL + "10-testNs_timeCustom_series_bool_idx" btree ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL + "6-testNs_device_id_timeCustom_idx" btree (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL + "7-testNs_timeCustom_series_0_idx" btree ("timeCustom" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL + "8-testNs_timeCustom_series_1_idx" btree ("timeCustom" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL + "9-testNs_timeCustom_series_2_idx" btree ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL Check constraints: "partition" CHECK (get_partition_for_key(device_id, 32768) >= '0'::smallint AND get_partition_for_key(device_id, 32768) <= '16383'::smallint) - "time_range" CHECK ("time" >= '1257984000000000000'::bigint) + "time_range" CHECK ("timeCustom" >= '1257984000000000000'::bigint) Inherits: "testNs"._hyper_1_1_0_partition Table "testNs._hyper_1_1_0_partition" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -256,7 +256,7 @@ Child tables: "testNs"._hyper_1_1_0_1_data, Table "testNs._hyper_1_2_0_partition" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -285,7 +285,7 @@ primary key, btree, for table "testNs._hyper_1_distinct" Table "testNs._hyper_1_root" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -315,7 +315,7 @@ Child tables: "testNs"._hyper_1_0_1_distinct_data Table "testNs._hyper_1_0_replica" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -328,7 +328,7 @@ Child tables: "testNs"._hyper_1_1_0_partition, Foreign table "testNs._hyper_1_1_0_1_data" Column | Type | Modifiers | FDW Options | Storage | Stats target | Description -------------+------------------+-----------+-------------+----------+--------------+------------- - time | bigint | not null | | plain | | + timeCustom | bigint | not null | | plain | | device_id | text | not null | | extended | | series_0 | double precision | | | plain | | series_1 | double precision | | | plain | | @@ -336,7 +336,7 @@ Child tables: "testNs"._hyper_1_1_0_partition, series_bool | boolean | | | plain | | Check constraints: "partition" CHECK (get_partition_for_key(device_id, 32768) >= '0'::smallint AND get_partition_for_key(device_id, 32768) <= '16383'::smallint) - "time_range" CHECK ("time" <= '1257983999999999999'::bigint) + "time_range" CHECK ("timeCustom" <= '1257983999999999999'::bigint) Server: Test1 FDW Options: (schema_name 'testNs', table_name '_hyper_1_1_0_1_data') Inherits: "testNs"._hyper_1_1_0_partition @@ -344,7 +344,7 @@ Inherits: "testNs"._hyper_1_1_0_partition Foreign table "testNs._hyper_1_1_0_2_data" Column | Type | Modifiers | FDW Options | Storage | Stats target | Description -------------+------------------+-----------+-------------+----------+--------------+------------- - time | bigint | not null | | plain | | + timeCustom | bigint | not null | | plain | | device_id | text | not null | | extended | | series_0 | double precision | | | plain | | series_1 | double precision | | | plain | | @@ -352,7 +352,7 @@ Inherits: "testNs"._hyper_1_1_0_partition series_bool | boolean | | | plain | | Check constraints: "partition" CHECK (get_partition_for_key(device_id, 32768) >= '0'::smallint AND get_partition_for_key(device_id, 32768) <= '16383'::smallint) - "time_range" CHECK ("time" >= '1257984000000000000'::bigint) + "time_range" CHECK ("timeCustom" >= '1257984000000000000'::bigint) Server: Test1 FDW Options: (schema_name 'testNs', table_name '_hyper_1_1_0_2_data') Inherits: "testNs"._hyper_1_1_0_partition @@ -360,7 +360,7 @@ Inherits: "testNs"._hyper_1_1_0_partition Table "testNs._hyper_1_1_0_partition" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -375,7 +375,7 @@ Child tables: "testNs"._hyper_1_1_0_1_data, Table "testNs._hyper_1_2_0_partition" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -404,7 +404,7 @@ primary key, btree, for table "testNs._hyper_1_distinct" Table "testNs._hyper_1_root" Column | Type | Modifiers | Storage | Stats target | Description -------------+------------------+-----------+----------+--------------+------------- - time | bigint | not null | plain | | + timeCustom | bigint | not null | plain | | device_id | text | not null | extended | | series_0 | double precision | | plain | | series_1 | double precision | | plain | | @@ -414,7 +414,7 @@ Child tables: "testNs"._hyper_1_0_replica SELECT * FROM "testNs"._hyper_1_0_replica; - time | device_id | series_0 | series_1 | series_2 | series_bool + timeCustom | device_id | series_0 | series_1 | series_2 | series_bool ---------------------+-----------+----------+----------+----------+------------- 1257894000000000000 | dev1 | 1.5 | 1 | 2 | t 1257894000000000000 | dev1 | 1.5 | 2 | | @@ -439,18 +439,18 @@ FROM "testNs"._hyper_1_0_distinct; \c Test1 SELECT * FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs')); - json ------------------------------------------------------------------------------------------------------------------ - {"time":1257987600000000000,"device_id":"dev1","series_0":1.5,"series_1":1,"series_2":null,"series_bool":null} - {"time":1257987600000000000,"device_id":"dev1","series_0":1.5,"series_1":2,"series_2":null,"series_bool":null} - {"time":1257897600000000000,"device_id":"dev1","series_0":4.5,"series_1":5,"series_2":null,"series_bool":false} - {"time":1257894002000000000,"device_id":"dev1","series_0":2.5,"series_1":3,"series_2":null,"series_bool":null} - {"time":1257894001000000000,"device_id":"dev1","series_0":3.5,"series_1":4,"series_2":null,"series_bool":null} - {"time":1257894000000001000,"device_id":"dev1","series_0":2.5,"series_1":3,"series_2":null,"series_bool":null} - {"time":1257894000000000000,"device_id":"dev2","series_0":1.5,"series_1":2,"series_2":null,"series_bool":null} - {"time":1257894000000000000,"device_id":"dev1","series_0":1.5,"series_1":2,"series_2":null,"series_bool":null} - {"time":1257894000000000000,"device_id":"dev2","series_0":1.5,"series_1":1,"series_2":null,"series_bool":null} - {"time":1257894000000000000,"device_id":"dev1","series_0":1.5,"series_1":1,"series_2":2,"series_bool":true} + json +----------------------------------------------------------------------------------------------------------------------- + {"timeCustom":1257987600000000000,"device_id":"dev1","series_0":1.5,"series_1":1,"series_2":null,"series_bool":null} + {"timeCustom":1257987600000000000,"device_id":"dev1","series_0":1.5,"series_1":2,"series_2":null,"series_bool":null} + {"timeCustom":1257897600000000000,"device_id":"dev1","series_0":4.5,"series_1":5,"series_2":null,"series_bool":false} + {"timeCustom":1257894002000000000,"device_id":"dev1","series_0":2.5,"series_1":3,"series_2":null,"series_bool":null} + {"timeCustom":1257894001000000000,"device_id":"dev1","series_0":3.5,"series_1":4,"series_2":null,"series_bool":null} + {"timeCustom":1257894000000001000,"device_id":"dev1","series_0":2.5,"series_1":3,"series_2":null,"series_bool":null} + {"timeCustom":1257894000000000000,"device_id":"dev2","series_0":1.5,"series_1":2,"series_2":null,"series_bool":null} + {"timeCustom":1257894000000000000,"device_id":"dev1","series_0":1.5,"series_1":2,"series_2":null,"series_bool":null} + {"timeCustom":1257894000000000000,"device_id":"dev2","series_0":1.5,"series_1":1,"series_2":null,"series_bool":null} + {"timeCustom":1257894000000000000,"device_id":"dev1","series_0":1.5,"series_1":1,"series_2":2,"series_bool":true} (10 rows) \set ON_ERROR_STOP 0 @@ -523,10 +523,10 @@ FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs', select_items => ARRAY [new_select_item('series_0')], limit_by_field => new_limit_by_field('device_id', 1) )); - json ----------------------------------------------------------------- - {"time":1257987600000000000,"series_0":1.5,"device_id":"dev1"} - {"time":1257894000000000000,"series_0":1.5,"device_id":"dev2"} + json +---------------------------------------------------------------------- + {"timeCustom":1257987600000000000,"series_0":1.5,"device_id":"dev1"} + {"timeCustom":1257894000000000000,"series_0":1.5,"device_id":"dev2"} (2 rows) SELECT * @@ -534,8 +534,8 @@ FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs', select_items => ARRAY [new_select_item('series_0')], limit_rows => 1 )); - json ---------------------------------------------- - {"time":1257987600000000000,"series_0":1.5} + json +--------------------------------------------------- + {"timeCustom":1257987600000000000,"series_0":1.5} (1 row) diff --git a/extension/sql/tests/regression/insert.sql b/extension/sql/tests/regression/insert.sql index ca17643f3..2cbf52cd9 100644 --- a/extension/sql/tests/regression/insert.sql +++ b/extension/sql/tests/regression/insert.sql @@ -13,20 +13,20 @@ SELECT add_node('test2' :: NAME, 'localhost'); \c Test1 CREATE TABLE PUBLIC."testNs" ( - time BIGINT NOT NULL, + "timeCustom" BIGINT NOT NULL, device_id TEXT NOT NULL, series_0 DOUBLE PRECISION NULL, series_1 DOUBLE PRECISION NULL, series_2 DOUBLE PRECISION NULL, series_bool BOOLEAN NULL ); -CREATE INDEX ON PUBLIC."testNs" (device_id, time DESC NULLS LAST) WHERE device_id IS NOT NULL; -CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL; -CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL; -CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL; -CREATE INDEX ON PUBLIC."testNs" (time DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" ("timeCustom" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" ("timeCustom" DESC NULLS LAST, series_1) WHERE series_1 IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL; +CREATE INDEX ON PUBLIC."testNs" ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL; -SELECT * FROM add_hypertable('"public"."testNs"', 'time', 'device_id', hypertable_name=>'testNs', associated_schema_name=>'testNs' ); +SELECT * FROM add_hypertable('"public"."testNs"', 'timeCustom', 'device_id', hypertable_name=>'testNs', associated_schema_name=>'testNs' ); SELECT set_is_distinct_flag('"public"."testNs"', 'device_id', TRUE); @@ -41,7 +41,7 @@ INNER JOIN chunk c ON (c.partition_id = part.id); \c Test1 BEGIN; -INSERT INTO "testNs"(time, device_id, series_0, series_1) VALUES +INSERT INTO "testNs"("timeCustom", device_id, series_0, series_1) VALUES (1257987600000000000, 'dev1', 1.5, 1), (1257987600000000000, 'dev1', 1.5, 2), (1257894002000000000, 'dev1', 2.5, 3); @@ -49,7 +49,7 @@ COMMIT; \c test2 BEGIN; -INSERT INTO "testNs"(time, device_id, series_0, series_1) VALUES +INSERT INTO "testNs"("timeCustom", device_id, series_0, series_1) VALUES (1257894000000000000, 'dev2', 1.5, 1), (1257894000000000000, 'dev2', 1.5, 2); COMMIT; From c5d826d93199fe0bf6db0895114aaf0059cb51f3 Mon Sep 17 00:00:00 2001 From: Matvey Arye Date: Wed, 4 Jan 2017 16:49:22 -0500 Subject: [PATCH 2/2] support for time columns of type timestamp --- extension/sql/load_order.txt | 1 + extension/sql/main/chunk.sql | 9 +- extension/sql/main/insert.sql | 39 +++-- extension/sql/main/ioql.sql | 10 +- extension/sql/main/ioql_optimized_agg.sql | 39 +++-- extension/sql/main/ioql_optimized_nonagg.sql | 4 +- extension/sql/main/ioql_result_schema_agg.sql | 4 +- extension/sql/main/ioql_sql_gen.sql | 24 ++- .../sql/main/ioql_sqlgen_cluster_agg.sql | 12 +- extension/sql/main/schema_info.sql | 46 +++++- extension/sql/main/table_creation.sql | 27 ++-- extension/sql/main/time_util.sql | 47 ++++++ .../tests/regression/expected/timestamp.out | 142 ++++++++++++++++++ extension/sql/tests/regression/run.sh | 1 + extension/sql/tests/regression/timestamp.sql | 71 +++++++++ 15 files changed, 414 insertions(+), 62 deletions(-) create mode 100644 extension/sql/main/time_util.sql create mode 100644 extension/sql/tests/regression/expected/timestamp.out create mode 100644 extension/sql/tests/regression/timestamp.sql diff --git a/extension/sql/load_order.txt b/extension/sql/load_order.txt index 36df1bad0..fed57fd16 100644 --- a/extension/sql/load_order.txt +++ b/extension/sql/load_order.txt @@ -17,6 +17,7 @@ sql/meta/sync_triggers.sql sql/meta/setup_meta.sql sql/meta/deleted_triggers.sql sql/meta/ddl.sql +sql/main/time_util.sql sql/main/table_creation.sql sql/main/tables.sql sql/main/cluster_user_triggers.sql diff --git a/extension/sql/main/chunk.sql b/extension/sql/main/chunk.sql index 63e2fb864..a93c4382a 100644 --- a/extension/sql/main/chunk.sql +++ b/extension/sql/main/chunk.sql @@ -1,3 +1,4 @@ + CREATE OR REPLACE FUNCTION _sysinternal.lock_for_chunk_close( chunk_id INTEGER ) @@ -26,10 +27,14 @@ DECLARE BEGIN EXECUTE format( $$ - SELECT max(%I) + SELECT max(%s) FROM %I.%I $$, - _sysinternal.time_col_name_for_crn(schema_name, table_name), schema_name, table_name) + _sysinternal.extract_time_sql( + format('%I', _sysinternal.time_col_name_for_crn(schema_name, table_name)), + _sysinternal.time_col_type_for_crn(schema_name, table_name) + ), + schema_name, table_name) INTO max_time; RETURN max_time; diff --git a/extension/sql/main/insert.sql b/extension/sql/main/insert.sql index d0ca7a88a..a9a4b6c4d 100644 --- a/extension/sql/main/insert.sql +++ b/extension/sql/main/insert.sql @@ -74,13 +74,15 @@ BEGIN END $BODY$; --- Gets the value of a field from a given row. +-- Gets the value of the time field from a given row. -- --- field_name - Name of field/column to fetch +-- field_name - Name of time field/column to fetch +-- field_type - Type of the time record -- copy_record - Record/row from a table -- copy_table_name - Name of the relation to cast the record to -CREATE OR REPLACE FUNCTION _sysinternal.get_field_from_record( +CREATE OR REPLACE FUNCTION _sysinternal.get_time_field_from_record( field_name NAME, + field_type REGTYPE, copy_record anyelement, copy_table_name TEXT ) @@ -91,8 +93,8 @@ DECLARE BEGIN EXECUTE format( $$ - SELECT row.%I FROM (SELECT (%L::%s).*) as row LIMIT 1 - $$, field_name, copy_record, copy_table_name) + SELECT %s FROM (SELECT (%L::%s).*) as row LIMIT 1 + $$, _sysinternal.extract_time_sql(format('row.%I', field_name), field_type), copy_record, copy_table_name) INTO STRICT t; RETURN t; @@ -119,6 +121,7 @@ DECLARE distinct_table_oid REGCLASS; time_point BIGINT; time_field_name_point NAME; + time_field_type_point REGTYPE; partition_id INT; distinct_field TEXT; distinct_clauses TEXT; @@ -127,18 +130,20 @@ BEGIN time_point := 1; EXECUTE format( $$ - SELECT _sysinternal.get_field_from_record(h.time_field_name, ct, '%1$s'), h.time_field_name, p.id + SELECT _sysinternal.get_time_field_from_record(h.time_field_name, h.time_field_type, ct, '%1$s'), h.time_field_name, h.time_field_type, p.id FROM ONLY %1$s ct LEFT JOIN hypertable h ON (h.NAME = %2$L) LEFT JOIN partition_epoch pe ON ( pe.hypertable_name = %2$L AND - (pe.start_time <= (SELECT _sysinternal.get_field_from_record(h.time_field_name, ct, '%1$s'))::bigint OR pe.start_time IS NULL) AND - (pe.end_time >= (SELECT _sysinternal.get_field_from_record(h.time_field_name, ct, '%1$s'))::bigint OR pe.end_time IS NULL) + (pe.start_time <= (SELECT _sysinternal.get_time_field_from_record(h.time_field_name, h.time_field_type, ct, '%1$s'))::bigint + OR pe.start_time IS NULL) AND + (pe.end_time >= (SELECT _sysinternal.get_time_field_from_record(h.time_field_name, h.time_field_type, ct, '%1$s'))::bigint + OR pe.end_time IS NULL) ) LEFT JOIN _sysinternal.get_partition_for_epoch_row(pe, ct, '%1$s') AS p ON(true) LIMIT 1 $$, copy_table_oid, hypertable_name) - INTO STRICT time_point, time_field_name_point, partition_id; + INTO STRICT time_point, time_field_name_point, time_field_type_point, partition_id; IF time_point IS NOT NULL AND partition_id IS NULL THEN RAISE EXCEPTION 'Should never happen: could not find partition for insert' USING ERRCODE = 'IO501'; @@ -190,13 +195,15 @@ BEGIN WITH selected AS ( DELETE FROM ONLY %2$s - WHERE (%7$I >= %3$L OR %3$L IS NULL) and (%7$I <= %4$L OR %4$L IS NULL) + WHERE (%7$I >= %3$s OR %3$s IS NULL) and (%7$I <= %4$s OR %4$s IS NULL) RETURNING * )%5$s INSERT INTO %1$s (%6$s) SELECT %6$s FROM selected; $$, format('%I.%I', crn_record.schema_name, crn_record.table_name) :: REGCLASS, - copy_table_oid, crn_record.start_time, crn_record.end_time, + copy_table_oid, + _sysinternal.time_literal_sql(crn_record.start_time, time_field_type_point), + _sysinternal.time_literal_sql(crn_record.end_time, time_field_type_point), distinct_clauses, _sysinternal.get_field_list(hypertable_name), time_field_name_point); @@ -204,18 +211,20 @@ BEGIN EXECUTE format( $$ - SELECT _sysinternal.get_field_from_record(h.time_field_name, ct, '%1$s'), h.time_field_name, p.id + SELECT _sysinternal.get_time_field_from_record(h.time_field_name, h.time_field_type, ct, '%1$s'), h.time_field_name, h.time_field_type, p.id FROM ONLY %1$s ct LEFT JOIN hypertable h ON (h.NAME = %2$L) LEFT JOIN partition_epoch pe ON ( pe.hypertable_name = %2$L AND - (pe.start_time <= (SELECT _sysinternal.get_field_from_record(h.time_field_name, ct, '%1$s'))::bigint OR pe.start_time IS NULL) AND - (pe.end_time >= (SELECT _sysinternal.get_field_from_record(h.time_field_name, ct, '%1$s'))::bigint OR pe.end_time IS NULL) + (pe.start_time <= (SELECT _sysinternal.get_time_field_from_record(h.time_field_name, h.time_field_type, ct, '%1$s'))::bigint + OR pe.start_time IS NULL) AND + (pe.end_time >= (SELECT _sysinternal.get_time_field_from_record(h.time_field_name, h.time_field_type, ct, '%1$s'))::bigint + OR pe.end_time IS NULL) ) LEFT JOIN _sysinternal.get_partition_for_epoch_row(pe, ct, '%1$s') AS p ON(true) LIMIT 1 $$, copy_table_oid, hypertable_name) - INTO time_point, time_field_name_point, partition_id; + INTO time_point, time_field_name_point, time_field_type_point, partition_id; IF time_point IS NOT NULL AND partition_id IS NULL THEN RAISE EXCEPTION 'Should never happen: could not find partition for insert' diff --git a/extension/sql/main/ioql.sql b/extension/sql/main/ioql.sql index 9288a61e4..491eb40b3 100644 --- a/extension/sql/main/ioql.sql +++ b/extension/sql/main/ioql.sql @@ -19,11 +19,17 @@ BEGIN CREATE TYPE limit_by_field_type AS (field TEXT, count INT); - CREATE TYPE aggregate_type AS (group_time BIGINT, group_field TEXT); + --Grouptime is in usec if timestamp type used for time column in the data. + --If time is numeric, unit used by grouptime needs to match units in the data inserted + --(this is determined by user: inserted data can be in sec, usec, nanosec, etc.). + CREATE TYPE aggregate_type AS (group_time BIGINT, group_field TEXT); CREATE TYPE field_condition_type AS (conjunctive predicate_conjunctive, predicates field_predicate []); - CREATE TYPE time_condition_type AS (from_time BIGINT, to_time BIGINT); --from_time inclusive; to_time exclusive\ + --From_time/to_time is in usec if timestamp type used for time column in the data. + --If time is numeric, unit used by these fields needs to match units in the data inserted + --(this is determined by user: inserted data can be in sec, usec, nanosec, etc.). + CREATE TYPE time_condition_type AS (from_time BIGINT, to_time BIGINT); --from_time inclusive; to_time exclusive CREATE TYPE ioql_query AS ( namespace_name TEXT, -- NOT NULL diff --git a/extension/sql/main/ioql_optimized_agg.sql b/extension/sql/main/ioql_optimized_agg.sql index 1bb7725c2..36ea3d58a 100644 --- a/extension/sql/main/ioql_optimized_agg.sql +++ b/extension/sql/main/ioql_optimized_agg.sql @@ -26,13 +26,13 @@ SELECT CASE END; $BODY$ LANGUAGE SQL IMMUTABLE STRICT; -CREATE OR REPLACE FUNCTION get_partial_aggregate_sql(time_col_name NAME, items select_item [], agg aggregate_type) +CREATE OR REPLACE FUNCTION get_partial_aggregate_sql(time_col_name NAME, time_col_type regtype, items select_item [], agg aggregate_type) RETURNS TEXT AS $BODY$ SELECT CASE WHEN agg.group_field IS NOT NULL THEN - format('%s, %s as group_time, %s', agg.group_field, get_time_clause(time_col_name, agg.group_time), field_list) + format('%s, %s as group_time, %s', agg.group_field, get_time_clause(time_col_name, time_col_type, agg.group_time), field_list) ELSE - format('%s as group_time, %s', get_time_clause(time_col_name, agg.group_time), field_list) + format('%s as group_time, %s', get_time_clause(time_col_name, time_col_type, agg.group_time), field_list) END FROM ( @@ -104,13 +104,13 @@ SELECT CASE END; $BODY$ LANGUAGE SQL IMMUTABLE STRICT; -CREATE OR REPLACE FUNCTION get_combine_partial_aggregate_zero_value_sql(items select_item [], agg aggregate_type) +CREATE OR REPLACE FUNCTION get_combine_partial_aggregate_zero_value_sql(time_col_type regtype, items select_item [], agg aggregate_type) RETURNS TEXT AS $BODY$ SELECT CASE WHEN agg.group_field IS NOT NULL THEN - format('NULL::text as %s, NULL::bigint as group_time, %s', agg.group_field, field_list) + format('NULL::text as %s, NULL::%s as group_time, %s', agg.group_field, time_col_type, field_list) ELSE - format('NULL::bigint as group_time, %s', field_list) + format('NULL::%s as group_time, %s', time_col_type, field_list) END FROM ( @@ -145,11 +145,12 @@ CREATE OR REPLACE FUNCTION get_partial_aggregate_column_def(query ioql_query) RETURNS TEXT AS $BODY$ SELECT CASE WHEN (query.aggregate).group_field IS NOT NULL THEN - format('%I %s, group_time bigint, %s', (query.aggregate).group_field, + format('%I %s, group_time %s, %s', (query.aggregate).group_field, get_field_type(query.namespace_name, (query.aggregate).group_field), + get_time_field_type(query.namespace_name), field_list) ELSE - format('group_time bigint, %s', field_list) + format('group_time %s, %s', get_time_field_type(query.namespace_name), field_list) END FROM ( @@ -216,7 +217,7 @@ DECLARE BEGIN select_clause := - 'SELECT ' || get_partial_aggregate_sql(get_time_field(query.namespace_name), query.select_items, query.aggregate); + 'SELECT ' || get_partial_aggregate_sql(get_time_field(query.namespace_name), get_time_field_type(query.namespace_name), query.select_items, query.aggregate); RETURN base_query_raw( select_clause, @@ -390,7 +391,7 @@ END $BODY$; -CREATE OR REPLACE FUNCTION get_max_time_on_partition(time_col_name NAME, part_replica partition_replica, additional_constraints TEXT) +CREATE OR REPLACE FUNCTION get_max_time_on_partition(time_col_name NAME, time_col_type regtype, part_replica partition_replica, additional_constraints TEXT) RETURNS BIGINT AS $BODY$ DECLARE @@ -404,12 +405,12 @@ BEGIN FROM get_local_chunk_replica_node_for_pr_time_desc(part_replica) LOOP EXECUTE format( $$ - SELECT %1$I + SELECT %1$s AS time FROM %2$I.%3$I %4$s - ORDER BY %1$I DESC NULLS LAST + ORDER BY time DESC NULLS LAST LIMIT 1 - $$, time_col_name, crn_row.schema_name, crn_row.table_name, get_where_clause(additional_constraints)) + $$, _sysinternal.extract_time_sql(format('%I',time_col_name), time_col_type), crn_row.schema_name, crn_row.table_name, get_where_clause(additional_constraints)) INTO time; IF time IS NOT NULL THEN @@ -434,7 +435,7 @@ SELECT format('SELECT * FROM (%s) as combined_node ', coalesce( string_agg(code_part, ' UNION ALL '), format('SELECT %s WHERE FALSE', - get_combine_partial_aggregate_zero_value_sql(query.select_items, query.aggregate)) + get_combine_partial_aggregate_zero_value_sql(get_time_field_type(query.namespace_name), query.select_items, query.aggregate)) )) -- query.limit_rows + 1, needed since a group can span across time. +1 guarantees group was closed FROM @@ -458,7 +459,7 @@ $BODY$ SELECT (get_time_periods_limit_for_max(max_time.max_time, period_length, num_periods)).* FROM ( - SELECT max(get_max_time_on_partition(get_time_field(epoch.hypertable_name),pr, additional_constraints)) AS max_time + SELECT max(get_max_time_on_partition(get_time_field(epoch.hypertable_name),get_time_field_type(epoch.hypertable_name),pr, additional_constraints)) AS max_time FROM get_partition_replicas(epoch, replica_id) pr ) AS max_time $BODY$; @@ -473,15 +474,21 @@ DECLARE trange time_range; ungrouped_sql TEXT; grouped_sql TEXT; + time_col_type regtype; BEGIN IF query.limit_time_periods IS NOT NULL THEN + time_col_type := get_time_field_type(query.namespace_name); trange := get_time_periods_limit(epoch, replica_id, combine_predicates(default_predicates(query, epoch), additional_constraints), (query.aggregate).group_time, query.limit_time_periods); additional_constraints := combine_predicates( - format('%1$I >= %2$L AND %1$I <=%3$L', get_time_field(query.namespace_name), trange.start_time, trange.end_time), + format('%1$I >= %2$s AND %1$I <=%3$s', + get_time_field(query.namespace_name), + _sysinternal.time_literal_sql(trange.start_time, time_col_type), + _sysinternal.time_literal_sql(trange.end_time, time_col_type) + ), additional_constraints); END IF; diff --git a/extension/sql/main/ioql_optimized_nonagg.sql b/extension/sql/main/ioql_optimized_nonagg.sql index a858b3de7..b0b829962 100644 --- a/extension/sql/main/ioql_optimized_nonagg.sql +++ b/extension/sql/main/ioql_optimized_nonagg.sql @@ -14,6 +14,7 @@ DECLARE previous_tables TEXT = ''; code TEXT = ''; time_col_name NAME; + time_col_type REGTYPE; query_sql_scan_base_table TEXT = ''; query_sql_scan TEXT = ''; @@ -22,6 +23,7 @@ DECLARE partition_row partition; BEGIN time_col_name := get_time_field(query.namespace_name); + time_col_type := get_time_field_type(query.namespace_name); IF epoch.partitioning_field = (query.limit_by_field).field THEN SELECT * @@ -68,7 +70,7 @@ BEGIN get_full_select_clause_nonagg(query), 'FROM %1$s', get_where_clause( - get_time_predicate(time_col_name, query.time_condition) + get_time_predicate(time_col_name, time_col_type, query.time_condition) ), NULL, format('ORDER BY %I DESC NULLS LAST', time_col_name), diff --git a/extension/sql/main/ioql_result_schema_agg.sql b/extension/sql/main/ioql_result_schema_agg.sql index c4e1a3757..49d19a508 100644 --- a/extension/sql/main/ioql_result_schema_agg.sql +++ b/extension/sql/main/ioql_result_schema_agg.sql @@ -29,10 +29,10 @@ SELECT CASE ARRAY [ format('%I %s', (query.aggregate).group_field, get_field_type(query.namespace_name, (query.aggregate).group_field)), - 'time BIGINT'] || + 'time '|| get_time_field_type(query.namespace_name) ] || field_array ELSE - ARRAY ['time bigint'] || + ARRAY ['time '|| get_time_field_type(query.namespace_name)] || field_array END FROM diff --git a/extension/sql/main/ioql_sql_gen.sql b/extension/sql/main/ioql_sql_gen.sql index 6193e5b14..6ff338598 100644 --- a/extension/sql/main/ioql_sql_gen.sql +++ b/extension/sql/main/ioql_sql_gen.sql @@ -1,11 +1,18 @@ -CREATE OR REPLACE FUNCTION get_time_clause(time_col_name NAME, group_time BIGINT) +CREATE OR REPLACE FUNCTION get_time_clause(time_col_name NAME, time_col_type regtype, group_time BIGINT) RETURNS TEXT LANGUAGE SQL IMMUTABLE AS $BODY$ SELECT CASE - WHEN group_time IS NOT NULL THEN - format('(%1$I - (%1$I %% %2$L::bigint))::bigint', time_col_name, group_time) - ELSE + WHEN group_time IS NULL THEN format('%I', time_col_name) + WHEN time_col_type IN ('BIGINT', 'INTEGER', 'SMALLINT') THEN + format('(%1$I - (%1$I %% %2$L::%3$s))::%3$s', time_col_name, group_time, time_col_type) + WHEN time_col_type IN ('TIMESTAMP', 'TIMESTAMPTZ') THEN + --NOTE: note the conversion at the end. important for timestamp without timezone. right conversion? + format('to_timestamp( ( + (EXTRACT(EPOCH from %1$I)*1e6)::bigint - + ( (EXTRACT(EPOCH from %1$I)*1e6)::bigint %% %2$L::bigint ) + )::double precision / 1e6 + )::%3$s', time_col_name, group_time, time_col_type) --group time is given in us END; $BODY$; @@ -30,11 +37,14 @@ FROM unnest(clauses) AS clause(val) WHERE val IS NOT NULL; $BODY$; -CREATE OR REPLACE FUNCTION get_time_predicate(time_col_name NAME, cond time_condition_type) +CREATE OR REPLACE FUNCTION get_time_predicate(time_col_name NAME, time_col_type regtype, cond time_condition_type) RETURNS TEXT LANGUAGE SQL IMMUTABLE AS $BODY$ SELECT string_agg(clauses.val, ' AND ') -FROM (VALUES (format('%I >= ', time_col_name) || cond.from_time), (format('%I < ', time_col_name) || cond.to_time)) AS clauses(val); +FROM ( + VALUES (format('%I >= ', time_col_name) || NULLIF(_sysinternal.time_literal_sql(cond.from_time, time_col_type), 'NULL')), + (format('%I < ', time_col_name) || NULLIF(_sysinternal.time_literal_sql(cond.to_time, time_col_type), 'NULL')) + ) AS clauses(val); $BODY$; --TODO: Review this @@ -98,7 +108,7 @@ CREATE OR REPLACE FUNCTION default_predicates(query ioql_query, epoch partition_ RETURNS TEXT LANGUAGE SQL STABLE AS $BODY$ SELECT combine_predicates( - get_time_predicate(get_time_field(query.namespace_name), query.time_condition), + get_time_predicate(get_time_field(query.namespace_name), get_time_field_type(query.namespace_name), query.time_condition), get_field_predicate_clause(query.field_condition), get_select_field_predicate(query.select_items), get_partitioning_predicate(query, epoch) diff --git a/extension/sql/main/ioql_sqlgen_cluster_agg.sql b/extension/sql/main/ioql_sqlgen_cluster_agg.sql index b19141ac6..8fbbb3e01 100644 --- a/extension/sql/main/ioql_sqlgen_cluster_agg.sql +++ b/extension/sql/main/ioql_sqlgen_cluster_agg.sql @@ -31,8 +31,8 @@ BEGIN ) SELECT without_limit.* FROM without_limit, - get_time_periods_limit_for_max((SELECT max(time) from without_limit), %4$L, %5$L) limits - WHERE without_limit.time >= limits.start_time AND without_limit.time <= limits.end_time + get_time_periods_limit_for_max((SELECT max(%6$s) from without_limit), %4$L, %5$L) limits + WHERE %7$s >= limits.start_time AND %7$s <= limits.end_time %2$s %3$s $$, @@ -40,9 +40,11 @@ BEGIN get_orderby_clause_agg(query, 'time'), get_limit_clause(query.limit_rows), (query.aggregate).group_time, - query.limit_time_periods - ); - ELSE + query.limit_time_periods, + _sysinternal.extract_time_sql('time', get_time_field_type(query.namespace_name)), + _sysinternal.extract_time_sql('without_limit.time', get_time_field_type(query.namespace_name)) + ); + ELSE RETURN format( $$ SELECT * diff --git a/extension/sql/main/schema_info.sql b/extension/sql/main/schema_info.sql index e36cdea21..3bdb4a76f 100644 --- a/extension/sql/main/schema_info.sql +++ b/extension/sql/main/schema_info.sql @@ -22,6 +22,9 @@ $BODY$ SELECT get_distinct_table_oid(hypertable_name, replica_id, current_database()) $BODY$; +-- Get the name of the time column for a hypertable. +-- +-- hypertable_name - name of the hypertable. CREATE OR REPLACE FUNCTION get_time_field( hypertable_name NAME ) @@ -32,6 +35,21 @@ $BODY$ WHERE h.name = hypertable_name; $BODY$; +-- Get the type of the time column for a hypertable. +-- +-- hypertable_name - name of the hypertable. +CREATE OR REPLACE FUNCTION get_time_field_type( + hypertable_name NAME +) + RETURNS REGTYPE LANGUAGE SQL STABLE AS +$BODY$ + SELECT time_field_type + FROM hypertable h + WHERE h.name = hypertable_name; +$BODY$; + + + CREATE OR REPLACE FUNCTION get_field_names( hypertable_name NAME ) @@ -181,7 +199,9 @@ $BODY$ WHERE c.OID = table_oid; $BODY$; - +-- Get the name of the time column for a chunk_replica_node. +-- +-- schema_name, table_name - name of the schema and table for the table represented by the crn. CREATE OR REPLACE FUNCTION _sysinternal.time_col_name_for_crn( schema_name NAME, table_name NAME @@ -203,3 +223,27 @@ BEGIN END $BODY$; +-- Get the type of the time column for a chunk_replica_node. +-- +-- schema_name, table_name - name of the schema and table for the table represented by the crn. +CREATE OR REPLACE FUNCTION _sysinternal.time_col_type_for_crn( + schema_name NAME, + table_name NAME +) + RETURNS REGTYPE LANGUAGE PLPGSQL STABLE AS +$BODY$ +DECLARE + time_col_type REGTYPE; +BEGIN + SELECT h.time_field_type INTO STRICT time_col_type + FROM hypertable h + INNER JOIN partition_epoch pe ON (pe.hypertable_name = h.name) + INNER JOIN partition p ON (p.epoch_id = pe.id) + INNER JOIN chunk c ON (c.partition_id = p.id) + INNER JOIN chunk_replica_node crn ON (crn.chunk_id = c.id) + WHERE crn.schema_name = time_col_type_for_crn.schema_name AND + crn.table_name = time_col_type_for_crn.table_name; + RETURN time_col_type; +END +$BODY$; + diff --git a/extension/sql/main/table_creation.sql b/extension/sql/main/table_creation.sql index 4606f3bb4..523a9770a 100644 --- a/extension/sql/main/table_creation.sql +++ b/extension/sql/main/table_creation.sql @@ -224,36 +224,41 @@ CREATE OR REPLACE FUNCTION _sysinternal.set_time_constraint( RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS $BODY$ DECLARE + time_col_type regtype; BEGIN + time_col_type := _sysinternal.time_col_type_for_crn(schema_name, table_name); + EXECUTE format( $$ ALTER TABLE %I.%I DROP CONSTRAINT IF EXISTS time_range $$, - schema_name, table_name); + schema_name, table_name); IF start_time IS NOT NULL AND end_time IS NOT NULL THEN EXECUTE format( $$ - ALTER TABLE %2$I.%3$I ADD CONSTRAINT time_range CHECK(%1$I >= %4$L AND %1$I <= %5$L) + ALTER TABLE %2$I.%3$I ADD CONSTRAINT time_range CHECK(%1$I >= %4$s AND %1$I <= %5$s) $$, - _sysinternal.time_col_name_for_crn(schema_name, table_name), - schema_name, table_name, start_time, end_time); + _sysinternal.time_col_name_for_crn(schema_name, table_name), + schema_name, table_name, + _sysinternal.time_literal_sql(start_time, time_col_type), + _sysinternal.time_literal_sql(end_time, time_col_type)); ELSIF start_time IS NOT NULL THEN EXECUTE format( $$ - ALTER TABLE %I.%I ADD CONSTRAINT time_range CHECK(%I >= %L) + ALTER TABLE %I.%I ADD CONSTRAINT time_range CHECK(%I >= %s) $$, schema_name, table_name, - _sysinternal.time_col_name_for_crn(schema_name, table_name), - start_time); - ELSIF end_time IS NOT NULL THEN + _sysinternal.time_col_name_for_crn(schema_name, table_name), + _sysinternal.time_literal_sql(start_time, time_col_type)); + ELSIF end_time IS NOT NULL THEN EXECUTE format( $$ - ALTER TABLE %I.%I ADD CONSTRAINT time_range CHECK(%I <= %L) + ALTER TABLE %I.%I ADD CONSTRAINT time_range CHECK(%I <= %s) $$, schema_name, table_name, - _sysinternal.time_col_name_for_crn(schema_name, table_name), - end_time); + _sysinternal.time_col_name_for_crn(schema_name, table_name), + _sysinternal.time_literal_sql(end_time, time_col_type)); END IF; END $BODY$; diff --git a/extension/sql/main/time_util.sql b/extension/sql/main/time_util.sql new file mode 100644 index 000000000..943fd4679 --- /dev/null +++ b/extension/sql/main/time_util.sql @@ -0,0 +1,47 @@ +-- This file contains utilities for time conversion. +-- Time can be represented in a hypertable as an int* (bigint/integer/smallint) or as a timestamp type ( +-- with or without timezones). In or metatables and other internal systems all time values are stored as bigint. +-- Converting from int* columns to internal representation is a cast to bigint. +-- Converting from timestamps to internal representation is conversion to epoch (in microseconds). + +-- Gets the sql code for extracting the internal (bigint) time value from the identifier with the given field_type. +CREATE OR REPLACE FUNCTION _sysinternal.extract_time_sql( + identifier text, + field_type REGTYPE +) + RETURNS text LANGUAGE PLPGSQL STABLE AS +$BODY$ +DECLARE +BEGIN + CASE field_type + WHEN 'BIGINT'::regtype, 'INTEGER'::regtype, 'SMALLINT'::regtype THEN + RETURN format('%s::bigint', identifier); --scale determined by user. + WHEN 'TIMESTAMP'::regtype, 'TIMESTAMPTZ'::regtype THEN + RETURN format('((EXTRACT(epoch FROM %s)*1e6)::bigint)', identifier); --microseconds + END CASE; +END +$BODY$; + +-- Gets the sql code for representing the literal for the given time value (in the internal representation) as the field_type. +CREATE OR REPLACE FUNCTION _sysinternal.time_literal_sql( + time_value BIGINT, + field_type REGTYPE +) + RETURNS text LANGUAGE PLPGSQL STABLE AS +$BODY$ +DECLARE +BEGIN + IF time_value IS NULL THEN + RETURN format('%L', NULL); + END IF; + CASE field_type + WHEN 'BIGINT'::regtype, 'INTEGER'::regtype, 'SMALLINT'::regtype THEN + RETURN format('%L', time_value); --scale determined by user. + WHEN 'TIMESTAMP'::regtype, 'TIMESTAMPTZ'::regtype THEN + --assume time_value is in microsec + RETURN format('%2$s %1$L', to_timestamp(time_value::double precision / 1e6), field_type); --microseconds + END CASE; +END +$BODY$; + + diff --git a/extension/sql/tests/regression/expected/timestamp.out b/extension/sql/tests/regression/expected/timestamp.out new file mode 100644 index 000000000..830d83814 --- /dev/null +++ b/extension/sql/tests/regression/expected/timestamp.out @@ -0,0 +1,142 @@ + setup_meta +------------ + +(1 row) + + setup_main +------------ + +(1 row) + + setup_main +------------ + +(1 row) + +\c meta +SELECT add_cluster_user('postgres', NULL); + add_cluster_user +------------------ + +(1 row) + +SELECT set_meta('meta' :: NAME, 'localhost'); + set_meta +---------- + +(1 row) + +SELECT add_node('Test1' :: NAME, 'localhost'); + add_node +---------- + +(1 row) + +SELECT add_node('test2' :: NAME, 'localhost'); + add_node +---------- + +(1 row) + +\c Test1 +CREATE TABLE PUBLIC."testNs" ( + "timeCustom" TIMESTAMP NOT NULL, + device_id TEXT NOT NULL, + series_0 DOUBLE PRECISION NULL, + series_1 DOUBLE PRECISION NULL, + series_2 DOUBLE PRECISION NULL, + series_bool BOOLEAN NULL +); +CREATE INDEX ON PUBLIC."testNs" (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL; +SELECT * FROM add_hypertable('"public"."testNs"', 'timeCustom', 'device_id', hypertable_name=>'testNs', associated_schema_name=>'testNs' ); + name | main_schema_name | main_table_name | associated_schema_name | associated_table_prefix | root_schema_name | root_table_name | distinct_schema_name | distinct_table_name | replication_factor | placement | time_field_name | time_field_type | created_on +--------+------------------+-----------------+------------------------+-------------------------+------------------+-----------------+----------------------+---------------------+--------------------+-----------+-----------------+-----------------------------+------------ + testNs | public | testNs | testNs | _hyper_1 | testNs | _hyper_1_root | testNs | _hyper_1_distinct | 1 | STICKY | timeCustom | timestamp without time zone | Test1 +(1 row) + +SELECT set_is_distinct_flag('"public"."testNs"', 'device_id', TRUE); + set_is_distinct_flag +---------------------- + +(1 row) + +\c Test1 +INSERT INTO "testNs"("timeCustom", device_id, series_0, series_1) VALUES +('2009-11-12T01:00:00+00:00', 'dev1', 1.5, 1), +('2009-11-12T01:00:00+00:00', 'dev1', 1.5, 2), +('2009-11-10T23:00:02+00:00', 'dev1', 2.5, 3); +SELECT close_chunk_end(c.id) +FROM get_open_partition_for_key('testNs', 'dev1') part +INNER JOIN chunk c ON (c.partition_id = part.id); + close_chunk_end +----------------- + +(1 row) + +INSERT INTO "testNs"("timeCustom", device_id, series_0, series_1) VALUES +('2009-11-10T23:00:00+00:00', 'dev2', 1.5, 1), +('2009-11-10T23:00:00+00:00', 'dev2', 1.5, 2); +SELECT * FROM PUBLIC."testNs"; + timeCustom | device_id | series_0 | series_1 | series_2 | series_bool +---------------------+-----------+----------+----------+----------+------------- + 2009-11-12 01:00:00 | dev1 | 1.5 | 1 | | + 2009-11-12 01:00:00 | dev1 | 1.5 | 2 | | + 2009-11-10 23:00:02 | dev1 | 2.5 | 3 | | + 2009-11-10 23:00:00 | dev2 | 1.5 | 1 | | + 2009-11-10 23:00:00 | dev2 | 1.5 | 2 | | +(5 rows) + +SELECT * +FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs')); + json +------------------------------------------------------------------------------------------------------------------------ + {"timeCustom":"2009-11-12T01:00:00","device_id":"dev1","series_0":1.5,"series_1":1,"series_2":null,"series_bool":null} + {"timeCustom":"2009-11-12T01:00:00","device_id":"dev1","series_0":1.5,"series_1":2,"series_2":null,"series_bool":null} + {"timeCustom":"2009-11-10T23:00:02","device_id":"dev1","series_0":2.5,"series_1":3,"series_2":null,"series_bool":null} + {"timeCustom":"2009-11-10T23:00:00","device_id":"dev2","series_0":1.5,"series_1":1,"series_2":null,"series_bool":null} + {"timeCustom":"2009-11-10T23:00:00","device_id":"dev2","series_0":1.5,"series_1":2,"series_2":null,"series_bool":null} +(5 rows) + +SELECT * +FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs', + select_items => ARRAY [new_select_item('series_0', 'SUM')], + aggregate => new_aggregate((100 * 60 * 60 * 1e6) :: BIGINT) + )); + json +---------------------------------------------------- + {"time":"2009-11-10T08:00:00","sum(series_0)":8.5} +(1 row) + +SELECT * +FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs', + select_items => ARRAY [new_select_item('series_0', 'SUM')], + aggregate => new_aggregate((1 * 60 * 60 * 1e6) :: BIGINT) + )); + json +---------------------------------------------------- + {"time":"2009-11-10T23:00:00","sum(series_0)":5.5} + {"time":"2009-11-12T01:00:00","sum(series_0)":3} +(2 rows) + +SELECT * +FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs', + time_condition=>new_time_condition(1257894000000000,1257987600000000) --microseconds + )); + json +------------------------------------------------------------------------------------------------------------------------ + {"timeCustom":"2009-11-10T23:00:02","device_id":"dev1","series_0":2.5,"series_1":3,"series_2":null,"series_bool":null} + {"timeCustom":"2009-11-10T23:00:00","device_id":"dev2","series_0":1.5,"series_1":1,"series_2":null,"series_bool":null} + {"timeCustom":"2009-11-10T23:00:00","device_id":"dev2","series_0":1.5,"series_1":2,"series_2":null,"series_bool":null} +(3 rows) + +SELECT * +FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs', + select_items => ARRAY [new_select_item('series_0', 'SUM')], + aggregate => new_aggregate((1 * 60 * 60 * 1e6) :: BIGINT), + limit_time_periods => 2 + )); + json +-------------------------------------------------- + {"time":"2009-11-12T01:00:00","sum(series_0)":3} +(1 row) + diff --git a/extension/sql/tests/regression/run.sh b/extension/sql/tests/regression/run.sh index 4eb46c92b..30e0518b8 100755 --- a/extension/sql/tests/regression/run.sh +++ b/extension/sql/tests/regression/run.sh @@ -28,4 +28,5 @@ golden_test kafka.sql kafka.out golden_test insert.sql insert.out golden_test query.sql query.out golden_test ddl.sql ddl.out +golden_test timestamp.sql timestamp.out echo "Success" diff --git a/extension/sql/tests/regression/timestamp.sql b/extension/sql/tests/regression/timestamp.sql new file mode 100644 index 000000000..e5ff3cb82 --- /dev/null +++ b/extension/sql/tests/regression/timestamp.sql @@ -0,0 +1,71 @@ +\set ON_ERROR_STOP 1 + +\ir create_clustered_db.sql + +\set ECHO ALL +\c meta +SELECT add_cluster_user('postgres', NULL); + +SELECT set_meta('meta' :: NAME, 'localhost'); +SELECT add_node('Test1' :: NAME, 'localhost'); +SELECT add_node('test2' :: NAME, 'localhost'); + +\c Test1 + +CREATE TABLE PUBLIC."testNs" ( + "timeCustom" TIMESTAMP NOT NULL, + device_id TEXT NOT NULL, + series_0 DOUBLE PRECISION NULL, + series_1 DOUBLE PRECISION NULL, + series_2 DOUBLE PRECISION NULL, + series_bool BOOLEAN NULL +); +CREATE INDEX ON PUBLIC."testNs" (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL; +SELECT * FROM add_hypertable('"public"."testNs"', 'timeCustom', 'device_id', hypertable_name=>'testNs', associated_schema_name=>'testNs' ); + +SELECT set_is_distinct_flag('"public"."testNs"', 'device_id', TRUE); + + +\c Test1 +INSERT INTO "testNs"("timeCustom", device_id, series_0, series_1) VALUES +('2009-11-12T01:00:00+00:00', 'dev1', 1.5, 1), +('2009-11-12T01:00:00+00:00', 'dev1', 1.5, 2), +('2009-11-10T23:00:02+00:00', 'dev1', 2.5, 3); + +SELECT close_chunk_end(c.id) +FROM get_open_partition_for_key('testNs', 'dev1') part +INNER JOIN chunk c ON (c.partition_id = part.id); + +INSERT INTO "testNs"("timeCustom", device_id, series_0, series_1) VALUES +('2009-11-10T23:00:00+00:00', 'dev2', 1.5, 1), +('2009-11-10T23:00:00+00:00', 'dev2', 1.5, 2); + +SELECT * FROM PUBLIC."testNs"; + +SELECT * +FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs')); + +SELECT * +FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs', + select_items => ARRAY [new_select_item('series_0', 'SUM')], + aggregate => new_aggregate((100 * 60 * 60 * 1e6) :: BIGINT) + )); + + +SELECT * +FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs', + select_items => ARRAY [new_select_item('series_0', 'SUM')], + aggregate => new_aggregate((1 * 60 * 60 * 1e6) :: BIGINT) + )); + +SELECT * +FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs', + time_condition=>new_time_condition(1257894000000000,1257987600000000) --microseconds + )); +SELECT * +FROM ioql_exec_query(new_ioql_query(namespace_name => 'testNs', + select_items => ARRAY [new_select_item('series_0', 'SUM')], + aggregate => new_aggregate((1 * 60 * 60 * 1e6) :: BIGINT), + limit_time_periods => 2 + )); +