Validate existing indexes before adding a new dimension

If the argument column of add_dimension is not in all
of hypertable indexes that have UNIQUE, PRIMARY KEY
or EXCLUSION constraints, then add_dimension call
should fail.
This commit enforces the above.
This commit is contained in:
Narek Galstyan 2018-07-30 15:28:43 -04:00 committed by RobAtticus
parent 005813da21
commit ed379c3dd8
3 changed files with 121 additions and 0 deletions

View File

@ -17,6 +17,7 @@
#include "dimension.h"
#include "dimension_slice.h"
#include "hypertable.h"
#include "indexing.h"
#include "hypertable_cache.h"
#include "partitioning.h"
#include "scanner.h"
@ -1004,6 +1005,16 @@ dimension_add(PG_FUNCTION_ARGS)
*/
hypertable_set_num_dimensions(info.ht, info.ht->space->num_dimensions + 1);
dimension_add_from_info(&info);
/* Verify that existing indexes are compatible with a hypertable */
/*
* Need to get a fresh copy of hypertable from the database as cache
* does not reflect the changes in the previous 2 lines which add a
* new dimenison
*/
info.ht = hypertable_get_by_id(info.ht->fd.id);
indexing_verify_indexes(info.ht);
}
cache_release(hcache);

View File

@ -194,3 +194,70 @@ SELECT * FROM test.show_subtables('part_custom_func');
_timescaledb_internal._hyper_5_7_chunk |
(2 rows)
-- Test that index creation is handled correctly.
CREATE TABLE hyper_with_index(time timestamptz, temp float, device int);
CREATE UNIQUE INDEX temp_index ON hyper_with_index(temp);
\set ON_ERROR_STOP 0
SELECT create_hypertable('hyper_with_index', 'time');
NOTICE: adding not-null constraint to column "time"
ERROR: cannot create a unique index without the column "time" (used in partitioning)
SELECT create_hypertable('hyper_with_index', 'time', 'device', 2);
NOTICE: adding not-null constraint to column "time"
ERROR: cannot create a unique index without the column "time" (used in partitioning)
SELECT create_hypertable('hyper_with_index', 'time', 'temp', 2);
NOTICE: adding not-null constraint to column "time"
ERROR: cannot create a unique index without the column "time" (used in partitioning)
\set ON_ERROR_STOP 1
DROP INDEX temp_index;
CREATE UNIQUE INDEX time_index ON hyper_with_index(time);
\set ON_ERROR_STOP 0
-- should error because device not in index
SELECT create_hypertable('hyper_with_index', 'time', 'device', 4);
NOTICE: adding not-null constraint to column "time"
ERROR: cannot create a unique index without the column "device" (used in partitioning)
\set ON_ERROR_STOP 1
SELECT create_hypertable('hyper_with_index', 'time');
NOTICE: adding not-null constraint to column "time"
create_hypertable
-------------------
(1 row)
-- make sure user created index is used.
-- not using \d or \d+ because output syntax differs
-- between postgres 9 and postgres 10.
SELECT indexname FROM pg_indexes WHERE tablename = 'hyper_with_index';
indexname
------------
time_index
(1 row)
\set ON_ERROR_STOP 0
SELECT add_dimension('hyper_with_index', 'device', 4);
ERROR: cannot create a unique index without the column "device" (used in partitioning)
\set ON_ERROR_STOP 1
DROP INDEX time_index;
CREATE UNIQUE INDEX time_space_index ON hyper_with_index(time, device);
SELECT add_dimension('hyper_with_index', 'device', 4);
add_dimension
---------------
(1 row)
CREATE TABLE hyper_with_primary(time TIMESTAMPTZ PRIMARY KEY, temp float, device int);
\set ON_ERROR_STOP 0
SELECT create_hypertable('hyper_with_primary', 'time', 'device', 4);
ERROR: cannot create a unique index without the column "device" (used in partitioning)
\set ON_ERROR_STOP 1
SELECT create_hypertable('hyper_with_primary', 'time');
create_hypertable
-------------------
(1 row)
\set ON_ERROR_STOP 0
SELECT add_dimension('hyper_with_primary', 'device', 4);
ERROR: cannot create a unique index without the column "device" (used in partitioning)
\set ON_ERROR_STOP 1
-- NON-unique indexes can still be created
CREATE INDEX temp_index ON hyper_with_index(temp);

View File

@ -83,3 +83,46 @@ INSERT INTO part_custom_func VALUES ('2017-03-22T09:18:23', 23.4, 'dev1'),
('2017-03-22T09:18:23', 23.4, 'dev7');
SELECT * FROM test.show_subtables('part_custom_func');
-- Test that index creation is handled correctly.
CREATE TABLE hyper_with_index(time timestamptz, temp float, device int);
CREATE UNIQUE INDEX temp_index ON hyper_with_index(temp);
\set ON_ERROR_STOP 0
SELECT create_hypertable('hyper_with_index', 'time');
SELECT create_hypertable('hyper_with_index', 'time', 'device', 2);
SELECT create_hypertable('hyper_with_index', 'time', 'temp', 2);
\set ON_ERROR_STOP 1
DROP INDEX temp_index;
CREATE UNIQUE INDEX time_index ON hyper_with_index(time);
\set ON_ERROR_STOP 0
-- should error because device not in index
SELECT create_hypertable('hyper_with_index', 'time', 'device', 4);
\set ON_ERROR_STOP 1
SELECT create_hypertable('hyper_with_index', 'time');
-- make sure user created index is used.
-- not using \d or \d+ because output syntax differs
-- between postgres 9 and postgres 10.
SELECT indexname FROM pg_indexes WHERE tablename = 'hyper_with_index';
\set ON_ERROR_STOP 0
SELECT add_dimension('hyper_with_index', 'device', 4);
\set ON_ERROR_STOP 1
DROP INDEX time_index;
CREATE UNIQUE INDEX time_space_index ON hyper_with_index(time, device);
SELECT add_dimension('hyper_with_index', 'device', 4);
CREATE TABLE hyper_with_primary(time TIMESTAMPTZ PRIMARY KEY, temp float, device int);
\set ON_ERROR_STOP 0
SELECT create_hypertable('hyper_with_primary', 'time', 'device', 4);
\set ON_ERROR_STOP 1
SELECT create_hypertable('hyper_with_primary', 'time');
\set ON_ERROR_STOP 0
SELECT add_dimension('hyper_with_primary', 'device', 4);
\set ON_ERROR_STOP 1
-- NON-unique indexes can still be created
CREATE INDEX temp_index ON hyper_with_index(temp);