mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-21 21:21:22 +08:00
When creating an index with IF NOT EXISTS we still tried to create indexes for all the chunks but since no index was created on the parent table the meta data did not have the object id of the main table index leading to an error when trying to open the main table index. This patch adjusts the logic to check for IF NOT EXISTS and does an early return when no index was created on the parent table.
264 lines
11 KiB
SQL
264 lines
11 KiB
SQL
-- This file and its contents are licensed under the Apache License 2.0.
|
|
-- Please see the included NOTICE for copyright information and
|
|
-- LICENSE-APACHE for a copy of the license.
|
|
|
|
CREATE TABLE index_test(time timestamptz, temp float);
|
|
|
|
SELECT create_hypertable('index_test', 'time');
|
|
|
|
-- Default indexes created
|
|
SELECT * FROM test.show_indexes('index_test');
|
|
|
|
DROP TABLE index_test;
|
|
CREATE TABLE index_test(time timestamptz, device integer, temp float);
|
|
|
|
-- Create index before create_hypertable()
|
|
CREATE UNIQUE INDEX index_test_time_idx ON index_test (time);
|
|
|
|
\set ON_ERROR_STOP 0
|
|
-- Creating a hypertable from a table with an index that doesn't cover
|
|
-- all partitioning columns should fail
|
|
SELECT create_hypertable('index_test', 'time', 'device', 2);
|
|
\set ON_ERROR_STOP 1
|
|
|
|
-- Partitioning on only time should work
|
|
SELECT create_hypertable('index_test', 'time');
|
|
|
|
INSERT INTO index_test VALUES ('2017-01-20T09:00:01', 1, 17.5);
|
|
|
|
-- Check that index is also created on chunk
|
|
SELECT * FROM test.show_indexes('index_test');
|
|
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
|
|
SELECT * FROM _timescaledb_catalog.chunk_index ORDER BY index_name, hypertable_index_name;
|
|
|
|
-- Create another chunk
|
|
INSERT INTO index_test VALUES ('2017-05-20T09:00:01', 3, 17.5);
|
|
|
|
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
|
|
SELECT * FROM _timescaledb_catalog.chunk_index ORDER BY index_name, hypertable_index_name;
|
|
|
|
-- Delete the index on only one chunk
|
|
DROP INDEX _timescaledb_internal._hyper_3_1_chunk_index_test_time_idx;
|
|
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
|
|
SELECT * FROM _timescaledb_catalog.chunk_index ORDER BY index_name, hypertable_index_name;
|
|
|
|
-- Recreate table with new partitioning
|
|
DROP TABLE index_test;
|
|
CREATE TABLE index_test(id serial, time timestamptz, device integer, temp float);
|
|
SELECT * FROM test.show_columns('index_test');
|
|
|
|
-- Test that we can handle difference in attnos across hypertable and
|
|
-- chunks by dropping the ID column
|
|
ALTER TABLE index_test DROP COLUMN id;
|
|
SELECT * FROM test.show_columns('index_test');
|
|
|
|
-- No pre-existing UNIQUE index, so partitioning on two columns should work
|
|
SELECT create_hypertable('index_test', 'time', 'device', 2);
|
|
|
|
INSERT INTO index_test VALUES ('2017-01-20T09:00:01', 1, 17.5);
|
|
|
|
\set ON_ERROR_STOP 0
|
|
-- Create unique index without all partitioning columns should fail
|
|
CREATE UNIQUE INDEX index_test_time_device_idx ON index_test (time);
|
|
\set ON_ERROR_STOP 1
|
|
|
|
CREATE UNIQUE INDEX index_test_time_device_idx ON index_test (time, device);
|
|
|
|
-- Regular index need not cover all partitioning columns
|
|
CREATE INDEX ON index_test (time, temp);
|
|
|
|
-- Create another chunk
|
|
INSERT INTO index_test VALUES ('2017-04-20T09:00:01', 1, 17.5);
|
|
|
|
-- New index should have been recursed to chunks
|
|
SELECT * FROM test.show_indexes('index_test');
|
|
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
|
|
SELECT * FROM _timescaledb_catalog.chunk_index ORDER BY index_name, hypertable_index_name;
|
|
|
|
ALTER INDEX index_test_time_idx RENAME TO index_test_time_idx2;
|
|
|
|
-- Metadata and index should have changed name
|
|
SELECT * FROM test.show_indexes('index_test');
|
|
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
|
|
SELECT * FROM _timescaledb_catalog.chunk_index ORDER BY index_name, hypertable_index_name;
|
|
|
|
DROP INDEX index_test_time_idx2;
|
|
DROP INDEX index_test_time_device_idx;
|
|
|
|
-- Index should have been dropped
|
|
SELECT * FROM test.show_indexes('index_test');
|
|
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
|
|
SELECT * FROM _timescaledb_catalog.chunk_index ORDER BY index_name, hypertable_index_name;
|
|
|
|
-- Create index with long name to see how this is handled on chunks
|
|
CREATE INDEX a_hypertable_index_with_a_very_very_long_name_that_truncates ON index_test (time, temp);
|
|
CREATE INDEX a_hypertable_index_with_a_very_very_long_name_that_truncates_2 ON index_test (time, temp);
|
|
|
|
SELECT * FROM test.show_indexes('index_test');
|
|
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
|
|
|
|
DROP INDEX a_hypertable_index_with_a_very_very_long_name_that_truncates;
|
|
DROP INDEX a_hypertable_index_with_a_very_very_long_name_that_truncates_2;
|
|
|
|
\set ON_ERROR_STOP 0
|
|
-- Create index CONCURRENTLY
|
|
CREATE UNIQUE INDEX CONCURRENTLY index_test_time_device_idx ON index_test (time, device);
|
|
\set ON_ERROR_STOP 1
|
|
|
|
-- Test tablespaces. Chunk indexes should end up in same tablespace as
|
|
-- main index.
|
|
\c :TEST_DBNAME :ROLE_SUPERUSER
|
|
SET client_min_messages = ERROR;
|
|
DROP TABLESPACE IF EXISTS tablespace1;
|
|
DROP TABLESPACE IF EXISTS tablespace2;
|
|
SET client_min_messages = NOTICE;
|
|
|
|
CREATE TABLESPACE tablespace1 OWNER :ROLE_DEFAULT_PERM_USER LOCATION :TEST_TABLESPACE1_PATH;
|
|
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
|
|
CREATE INDEX index_test_time_idx ON index_test (time) TABLESPACE tablespace1;
|
|
|
|
SELECT * FROM test.show_indexes('index_test');
|
|
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
|
|
|
|
\c :TEST_DBNAME :ROLE_SUPERUSER
|
|
CREATE TABLESPACE tablespace2 OWNER :ROLE_DEFAULT_PERM_USER LOCATION :TEST_TABLESPACE2_PATH;
|
|
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
|
|
ALTER INDEX index_test_time_idx SET TABLESPACE tablespace2;
|
|
|
|
SELECT * FROM test.show_indexes('index_test');
|
|
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
|
|
|
|
-- Add constraint index
|
|
ALTER TABLE index_test ADD UNIQUE (time, device);
|
|
|
|
SELECT * FROM test.show_indexes('index_test');
|
|
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
|
|
|
|
-- Constraint indexes are added to chunk_index table.
|
|
SELECT * FROM _timescaledb_catalog.chunk_index ORDER BY index_name, hypertable_index_name;
|
|
SELECT * FROM _timescaledb_catalog.chunk_constraint;
|
|
|
|
DROP TABLE index_test;
|
|
|
|
-- Metadata removed
|
|
SELECT * FROM _timescaledb_catalog.chunk_index ORDER BY index_name, hypertable_index_name;
|
|
|
|
-- Create table in a tablespace
|
|
CREATE TABLE index_test(time timestamptz, temp float, device int) TABLESPACE tablespace1;
|
|
|
|
-- Default indexes should be in the table's tablespace
|
|
SELECT create_hypertable('index_test', 'time');
|
|
|
|
-- Explicitly defining an index tablespace should work and propagate
|
|
-- to chunks
|
|
CREATE INDEX ON index_test (time, device) TABLESPACE tablespace2;
|
|
|
|
-- New indexes without explicit tablespaces should use the default
|
|
-- tablespace
|
|
CREATE INDEX ON index_test (device);
|
|
|
|
-- Create chunk
|
|
INSERT INTO index_test VALUES ('2017-01-20T09:00:01', 17.5);
|
|
|
|
-- Check that the tablespaces of chunk indexes match the tablespace of
|
|
-- the main index
|
|
SELECT * FROM test.show_indexes('index_test');
|
|
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
|
|
|
|
-- Creating a new index should propagate to existing chunks, including
|
|
-- the given tablespace
|
|
CREATE INDEX ON index_test (time, temp) TABLESPACE tablespace2;
|
|
|
|
SELECT * FROM test.show_indexes('index_test');
|
|
SELECT * FROM test.show_indexesp('_timescaledb_internal._hyper%_chunk');
|
|
|
|
-- Cleanup
|
|
DROP TABLE index_test CASCADE;
|
|
\c :TEST_DBNAME :ROLE_SUPERUSER
|
|
DROP TABLESPACE tablespace1;
|
|
DROP TABLESPACE tablespace2;
|
|
|
|
-- Test expression indexes
|
|
CREATE TABLE index_expr_test(id serial, time timestamptz, temp float, meta jsonb);
|
|
|
|
-- Screw up the attribute numbers
|
|
ALTER TABLE index_expr_test DROP COLUMN id;
|
|
|
|
CREATE INDEX ON index_expr_test ((meta ->> 'field')) ;
|
|
INSERT INTO index_expr_test VALUES ('2017-01-20T09:00:01', 17.5, '{"field": "value1"}');
|
|
INSERT INTO index_expr_test VALUES ('2017-01-20T09:00:01', 17.5, '{"field": "value2"}');
|
|
|
|
EXPLAIN (verbose, costs off)
|
|
SELECT * FROM index_expr_test WHERE meta ->> 'field' = 'value1';
|
|
SELECT * FROM index_expr_test WHERE meta ->> 'field' = 'value1';
|
|
|
|
-- Test INDEX DROP error for multiple objects
|
|
CREATE TABLE index_test(time timestamptz, temp float);
|
|
CREATE UNIQUE INDEX index_test_idx ON index_test (time, temp);
|
|
SELECT create_hypertable('index_test', 'time');
|
|
|
|
CREATE TABLE index_test_2(time timestamptz, temp float);
|
|
CREATE UNIQUE INDEX index_test_2_idx ON index_test_2 (time, temp);
|
|
|
|
\set ON_ERROR_STOP 0
|
|
DROP INDEX index_test_idx, index_test_2_idx;
|
|
\set ON_ERROR_STOP 1
|
|
|
|
-- test expression index with dropped columns
|
|
CREATE TABLE idx_expr_test(filler int, time timestamptz, meta text);
|
|
SELECT table_name FROM create_hypertable('idx_expr_test', 'time');
|
|
ALTER TABLE idx_expr_test DROP COLUMN filler;
|
|
CREATE INDEX tag_idx ON idx_expr_test(('foo'||meta));
|
|
INSERT INTO idx_expr_test(time, meta) VALUES ('2000-01-01', 'bar');
|
|
DROP TABLE idx_expr_test CASCADE;
|
|
|
|
-- test multicolumn expression index with dropped columns
|
|
CREATE TABLE idx_expr_test(filler int, time timestamptz, t1 text, t2 text, t3 text);
|
|
SELECT table_name FROM create_hypertable('idx_expr_test', 'time');
|
|
ALTER TABLE idx_expr_test DROP COLUMN filler;
|
|
CREATE INDEX tag_idx ON idx_expr_test((t1||t2||t3));
|
|
INSERT INTO idx_expr_test(time, t1, t2, t3) VALUES ('2000-01-01', 'foo', 'bar', 'baz');
|
|
DROP TABLE idx_expr_test CASCADE;
|
|
|
|
-- test index with predicate and dropped columns
|
|
CREATE TABLE idx_predicate_test(filler int, time timestamptz);
|
|
SELECT table_name FROM create_hypertable('idx_predicate_test', 'time');
|
|
ALTER TABLE idx_predicate_test DROP COLUMN filler;
|
|
ALTER TABLE idx_predicate_test ADD COLUMN b1 bool;
|
|
CREATE INDEX idx_predicate_test_b1 ON idx_predicate_test(b1) WHERE b1=true;
|
|
INSERT INTO idx_predicate_test VALUES ('2000-01-01',true);
|
|
DROP TABLE idx_predicate_test;
|
|
|
|
-- test index with table references
|
|
CREATE TABLE idx_tableref_test(time timestamptz);
|
|
SELECT table_name FROM create_hypertable('idx_tableref_test', 'time');
|
|
-- we use security definer to prevent function inlining
|
|
CREATE OR REPLACE FUNCTION tableref_func(t idx_tableref_test) RETURNS timestamptz LANGUAGE SQL IMMUTABLE SECURITY DEFINER AS $f$ SELECT t.time; $f$;
|
|
-- try creating index with no existing chunks
|
|
CREATE INDEX tableref_idx ON idx_tableref_test(tableref_func(idx_tableref_test));
|
|
-- insert data to trigger chunk creation
|
|
INSERT INTO idx_tableref_test SELECT '2000-01-01';
|
|
DROP INDEX tableref_idx;
|
|
-- try creating index on hypertable with existing chunks
|
|
CREATE INDEX tableref_idx ON idx_tableref_test(tableref_func(idx_tableref_test));
|
|
|
|
-- test index creation with if not exists
|
|
CREATE TABLE idx_exists(time timestamptz NOT NULL);
|
|
SELECT table_name FROM create_hypertable('idx_exists', 'time');
|
|
-- should be skipped since this index was already created by create_hypertable
|
|
CREATE INDEX IF NOT EXISTS idx_exists_time_idx ON idx_exists(time DESC);
|
|
-- should create index
|
|
CREATE INDEX IF NOT EXISTS idx_exists_time_asc_idx ON idx_exists(time ASC);
|
|
-- should be skipped since it was created in previous command
|
|
CREATE INDEX IF NOT EXISTS idx_exists_time_asc_idx ON idx_exists(time ASC);
|
|
DROP INDEX idx_exists_time_asc_idx;
|
|
|
|
INSERT INTO idx_exists VALUES ('2000-01-01'),('2001-01-01');
|
|
-- should create index
|
|
CREATE INDEX IF NOT EXISTS idx_exists_time_asc_idx ON idx_exists(time ASC);
|
|
-- should be skipped since it was created in previous command
|
|
CREATE INDEX IF NOT EXISTS idx_exists_time_asc_idx ON idx_exists(time ASC);
|
|
|
|
|
|
|