-- 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.
-- Set this variable to avoid using a hard-coded path each time query
-- results are compared
\set QUERY_RESULT_TEST_EQUAL_RELPATH 'include/query_result_test_equal.sql'
-- DROP a table's column before making it a hypertable
CREATE TABLE alter_before(id serial, time timestamp, temp float, colorid integer, notes text, notes_2 text);
ALTER TABLE alter_before DROP COLUMN id;
ALTER TABLE alter_before ALTER COLUMN temp SET (n_distinct = 10);
ALTER TABLE alter_before ALTER COLUMN colorid SET (n_distinct = 11);
ALTER TABLE alter_before ALTER COLUMN colorid RESET (n_distinct);
ALTER TABLE alter_before ALTER COLUMN temp SET STATISTICS 100;
ALTER TABLE alter_before ALTER COLUMN notes SET STORAGE EXTERNAL;
SELECT create_hypertable('alter_before', 'time', chunk_time_interval => 2628000000000);
WARNING:  column type "timestamp without time zone" used for "time" does not follow best practices
     create_hypertable     
---------------------------
 (1,public,alter_before,t)

-- Test error hint for invalid timescaledb options on ALTER TABLE
\set ON_ERROR_STOP 0
-- Invalid timescaledb option should show hint with valid options
\set VERBOSITY default
ALTER TABLE alter_before SET (tsdb.invalid_option = true);
ERROR:  unrecognized parameter "tsdb.invalid_option"
HINT:  Valid timescaledb parameters are: chunk_interval, compress, compress_segmentby, compress_orderby, compress_chunk_interval, compress_index
ALTER TABLE alter_before SET (timescaledb.nonexistent = false);
ERROR:  unrecognized parameter "timescaledb.nonexistent"
HINT:  Valid timescaledb parameters are: chunk_interval, compress, compress_segmentby, compress_orderby, compress_chunk_interval, compress_index
\set ON_ERROR_STOP 1
\set VERBOSITY terse
INSERT INTO alter_before VALUES ('2017-03-22T09:18:22', 23.5, 1);
SELECT * FROM alter_before;
           time           | temp | colorid | notes | notes_2 
--------------------------+------+---------+-------+---------
 Wed Mar 22 09:18:22 2017 | 23.5 |       1 |       | 

-- Show that deleted column is marked as dropped and that attnums are
-- now different for the root table and the chunk
-- PG17 made attstattarget NULLABLE and changed the default from -1 to NULL
SELECT c.relname, a.attname, a.attnum, a.attoptions, CASE WHEN a.attstattarget = -1 OR (a.attisdropped AND a.attstattarget = 0) THEN NULL ELSE a.attstattarget END attstattarget, a.attstorage FROM pg_attribute a, pg_class c
WHERE a.attrelid = c.oid
AND (c.relname LIKE '_hyper_1%_chunk' OR c.relname = 'alter_before')
AND a.attnum > 0
ORDER BY c.relname, a.attnum;
     relname      |           attname            | attnum |   attoptions    | attstattarget | attstorage 
------------------+------------------------------+--------+-----------------+---------------+------------
 _hyper_1_1_chunk | time                         |      1 |                 |               | p
 _hyper_1_1_chunk | temp                         |      2 | {n_distinct=10} |           100 | p
 _hyper_1_1_chunk | colorid                      |      3 |                 |               | p
 _hyper_1_1_chunk | notes                        |      4 |                 |               | e
 _hyper_1_1_chunk | notes_2                      |      5 |                 |               | x
 alter_before     | ........pg.dropped.1........ |      1 |                 |               | p
 alter_before     | time                         |      2 |                 |               | p
 alter_before     | temp                         |      3 | {n_distinct=10} |           100 | p
 alter_before     | colorid                      |      4 |                 |               | p
 alter_before     | notes                        |      5 |                 |               | e
 alter_before     | notes_2                      |      6 |                 |               | x

-- DROP a table's column after making it a hypertable and having data
CREATE TABLE alter_after(id serial, time timestamp, temp float, colorid integer, notes text, notes_2 text);
SELECT create_hypertable('alter_after', 'time', chunk_time_interval => 2628000000000);
WARNING:  column type "timestamp without time zone" used for "time" does not follow best practices
    create_hypertable     
--------------------------
 (2,public,alter_after,t)

-- Create first chunk
INSERT INTO alter_after (time, temp, colorid) VALUES ('2017-03-22T09:18:22', 23.5, 1);
ALTER TABLE alter_after DROP COLUMN id;
ALTER TABLE alter_after ALTER COLUMN temp SET (n_distinct = 10);
ALTER TABLE alter_after ALTER COLUMN colorid SET (n_distinct = 11);
ALTER TABLE alter_after ALTER COLUMN colorid RESET (n_distinct);
ALTER TABLE alter_after ALTER COLUMN colorid SET STATISTICS 101;
ALTER TABLE alter_after ALTER COLUMN notes_2 SET STORAGE EXTERNAL;
-- Creating new chunks after dropping a column should work just fine
INSERT INTO alter_after VALUES ('2017-03-22T09:18:23', 21.5, 1),
                               ('2017-05-22T09:18:22', 36.2, 2),
                               ('2017-05-22T09:18:23', 15.2, 2);
-- Make sure tuple conversion also works with COPY
\COPY alter_after FROM 'data/alter.tsv' NULL AS '';
-- Data should look OK
SELECT * FROM alter_after;
           time           | temp | colorid | notes | notes_2 
--------------------------+------+---------+-------+---------
 Wed Mar 22 09:18:22 2017 | 23.5 |       1 |       | 
 Wed Mar 22 09:18:23 2017 | 21.5 |       1 |       | 
 Mon May 22 09:18:22 2017 | 36.2 |       2 |       | 
 Mon May 22 09:18:23 2017 | 15.2 |       2 |       | 
 Tue Aug 22 09:19:22 2017 | 21.4 |       3 | nr1   | n2r1
 Wed Aug 23 09:20:17 2017 | 31.5 |       2 | nr2   | n2r2

-- Show that attnums are different for chunks created after DROP
-- column
SELECT c.relname, a.attname, a.attnum FROM pg_attribute a, pg_class c
WHERE a.attrelid = c.oid
AND (c.relname LIKE '_hyper_2%_chunk' OR c.relname = 'alter_after')
AND a.attnum > 0
ORDER BY c.relname, a.attnum;
     relname      |           attname            | attnum 
------------------+------------------------------+--------
 _hyper_2_2_chunk | ........pg.dropped.1........ |      1
 _hyper_2_2_chunk | time                         |      2
 _hyper_2_2_chunk | temp                         |      3
 _hyper_2_2_chunk | colorid                      |      4
 _hyper_2_2_chunk | notes                        |      5
 _hyper_2_2_chunk | notes_2                      |      6
 _hyper_2_3_chunk | time                         |      1
 _hyper_2_3_chunk | temp                         |      2
 _hyper_2_3_chunk | colorid                      |      3
 _hyper_2_3_chunk | notes                        |      4
 _hyper_2_3_chunk | notes_2                      |      5
 _hyper_2_4_chunk | time                         |      1
 _hyper_2_4_chunk | temp                         |      2
 _hyper_2_4_chunk | colorid                      |      3
 _hyper_2_4_chunk | notes                        |      4
 _hyper_2_4_chunk | notes_2                      |      5
 alter_after      | ........pg.dropped.1........ |      1
 alter_after      | time                         |      2
 alter_after      | temp                         |      3
 alter_after      | colorid                      |      4
 alter_after      | notes                        |      5
 alter_after      | notes_2                      |      6

-- Add an ID column again
ALTER TABLE alter_after ADD COLUMN id serial;
INSERT INTO alter_after (time, temp, colorid) VALUES ('2017-08-22T09:19:14', 12.5, 3);
--test thing that we are allowed to do on chunks
ALTER TABLE  _timescaledb_internal._hyper_2_3_chunk ALTER COLUMN temp RESET (n_distinct);
ALTER TABLE  _timescaledb_internal._hyper_2_4_chunk ALTER COLUMN temp SET (n_distinct = 20);
ALTER TABLE  _timescaledb_internal._hyper_2_4_chunk ALTER COLUMN temp SET STATISTICS 201;
ALTER TABLE  _timescaledb_internal._hyper_2_4_chunk ALTER COLUMN notes SET STORAGE EXTERNAL;
-- PG17 made attstattarget NULLABLE and changed the default from -1 to NULL
SELECT c.relname, a.attname, a.attnum, a.attoptions, CASE WHEN a.attstattarget = -1 OR (a.attisdropped AND a.attstattarget = 0) THEN NULL ELSE a.attstattarget END attstattarget, a.attstorage FROM pg_attribute a, pg_class c
WHERE a.attrelid = c.oid
AND (c.relname LIKE '_hyper_2%_chunk' OR c.relname = 'alter_after')
AND a.attnum > 0
ORDER BY c.relname, a.attnum;
     relname      |           attname            | attnum |   attoptions    | attstattarget | attstorage 
------------------+------------------------------+--------+-----------------+---------------+------------
 _hyper_2_2_chunk | ........pg.dropped.1........ |      1 |                 |               | p
 _hyper_2_2_chunk | time                         |      2 |                 |               | p
 _hyper_2_2_chunk | temp                         |      3 | {n_distinct=10} |               | p
 _hyper_2_2_chunk | colorid                      |      4 |                 |           101 | p
 _hyper_2_2_chunk | notes                        |      5 |                 |               | x
 _hyper_2_2_chunk | notes_2                      |      6 |                 |               | e
 _hyper_2_2_chunk | id                           |      7 |                 |               | p
 _hyper_2_3_chunk | time                         |      1 |                 |               | p
 _hyper_2_3_chunk | temp                         |      2 |                 |               | p
 _hyper_2_3_chunk | colorid                      |      3 |                 |           101 | p
 _hyper_2_3_chunk | notes                        |      4 |                 |               | x
 _hyper_2_3_chunk | notes_2                      |      5 |                 |               | e
 _hyper_2_3_chunk | id                           |      6 |                 |               | p
 _hyper_2_4_chunk | time                         |      1 |                 |               | p
 _hyper_2_4_chunk | temp                         |      2 | {n_distinct=20} |           201 | p
 _hyper_2_4_chunk | colorid                      |      3 |                 |           101 | p
 _hyper_2_4_chunk | notes                        |      4 |                 |               | e
 _hyper_2_4_chunk | notes_2                      |      5 |                 |               | e
 _hyper_2_4_chunk | id                           |      6 |                 |               | p
 alter_after      | ........pg.dropped.1........ |      1 |                 |               | p
 alter_after      | time                         |      2 |                 |               | p
 alter_after      | temp                         |      3 | {n_distinct=10} |               | p
 alter_after      | colorid                      |      4 |                 |           101 | p
 alter_after      | notes                        |      5 |                 |               | x
 alter_after      | notes_2                      |      6 |                 |               | e
 alter_after      | id                           |      7 |                 |               | p

SELECT * FROM alter_after;
           time           | temp | colorid | notes | notes_2 | id 
--------------------------+------+---------+-------+---------+----
 Wed Mar 22 09:18:22 2017 | 23.5 |       1 |       |         |  1
 Wed Mar 22 09:18:23 2017 | 21.5 |       1 |       |         |  2
 Mon May 22 09:18:22 2017 | 36.2 |       2 |       |         |  3
 Mon May 22 09:18:23 2017 | 15.2 |       2 |       |         |  4
 Tue Aug 22 09:19:22 2017 | 21.4 |       3 | nr1   | n2r1    |  5
 Wed Aug 23 09:20:17 2017 | 31.5 |       2 | nr2   | n2r2    |  6
 Tue Aug 22 09:19:14 2017 | 12.5 |       3 |       |         |  7

-- test setting reloptions
ALTER TABLE  _timescaledb_internal._hyper_2_3_chunk SET (parallel_workers=2);
ALTER TABLE  _timescaledb_internal._hyper_2_4_chunk SET (parallel_workers=4);
ALTER TABLE  _timescaledb_internal._hyper_2_4_chunk RESET (parallel_workers);
SELECT relname, reloptions FROM pg_class WHERE relname IN ('_hyper_2_3_chunk','_hyper_2_4_chunk');
     relname      |      reloptions      
------------------+----------------------
 _hyper_2_3_chunk | {parallel_workers=2}
 _hyper_2_4_chunk | 

-- Need superuser to ALTER chunks in _timescaledb_internal schema
\c :TEST_DBNAME :ROLE_SUPERUSER
SELECT id, hypertable_id, schema_name, table_name, compressed_chunk_id, dropped, status, osm_chunk FROM _timescaledb_catalog.chunk WHERE id = 2;
 id | hypertable_id |      schema_name      |    table_name    | compressed_chunk_id | dropped | status | osm_chunk 
----+---------------+-----------------------+------------------+---------------------+---------+--------+-----------
  2 |             2 | _timescaledb_internal | _hyper_2_2_chunk |                     | f       |      0 | f

-- Rename chunk
ALTER TABLE _timescaledb_internal._hyper_2_2_chunk RENAME TO new_chunk_name;
SELECT id, hypertable_id, schema_name, table_name, compressed_chunk_id, dropped, status, osm_chunk FROM _timescaledb_catalog.chunk WHERE id = 2;
 id | hypertable_id |      schema_name      |   table_name   | compressed_chunk_id | dropped | status | osm_chunk 
----+---------------+-----------------------+----------------+---------------------+---------+--------+-----------
  2 |             2 | _timescaledb_internal | new_chunk_name |                     | f       |      0 | f

-- Set schema
ALTER TABLE _timescaledb_internal.new_chunk_name SET SCHEMA public;
SELECT id, hypertable_id, schema_name, table_name, compressed_chunk_id, dropped, status, osm_chunk FROM _timescaledb_catalog.chunk WHERE id = 2;
 id | hypertable_id | schema_name |   table_name   | compressed_chunk_id | dropped | status | osm_chunk 
----+---------------+-------------+----------------+---------------------+---------+--------+-----------
  2 |             2 | public      | new_chunk_name |                     | f       |      0 | f

-- Test that we cannot rename chunk columns
\set ON_ERROR_STOP 0
ALTER TABLE public.new_chunk_name RENAME COLUMN time TO newtime;
ERROR:  cannot rename column "time" of hypertable chunk "new_chunk_name"
\set ON_ERROR_STOP 1
-- Test that we can set tablespace of a hypertable
\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;
--test hypertable with tables space
CREATE TABLESPACE tablespace1 OWNER :ROLE_DEFAULT_PERM_USER LOCATION :TEST_TABLESPACE1_PATH;
CREATE TABLESPACE tablespace2 OWNER :ROLE_DEFAULT_PERM_USER LOCATION :TEST_TABLESPACE2_PATH;
\c :TEST_DBNAME :ROLE_DEFAULT_PERM_USER
-- Test that we can directly change chunk tablespace
ALTER TABLE public.new_chunk_name SET TABLESPACE tablespace1;
SELECT tablespace FROM pg_tables WHERE tablename = 'new_chunk_name';
 tablespace  
-------------
 tablespace1

-- drop all tables to make checking the tests below easier
DROP TABLE alter_before;
DROP TABLE alter_after;
-- should return 0 rows
SELECT tablename, tablespace FROM pg_tables
WHERE tablename = 'hyper_in_space' OR tablename LIKE '\_hyper\__\__\_chunk' ORDER BY tablename;
 tablename | tablespace 
-----------+------------

CREATE TABLE hyper_in_space(time bigint, temp float, device int);
SELECT create_hypertable('hyper_in_space', 'time', 'device', 4, chunk_time_interval=>1);
      create_hypertable      
-----------------------------
 (3,public,hyper_in_space,t)

INSERT INTO hyper_in_space(time, temp, device) VALUES (1, 20, 1);
INSERT INTO hyper_in_space(time, temp, device) VALUES (3, 21, 2);
INSERT INTO hyper_in_space(time, temp, device) VALUES (5, 23, 1);
SELECT tablename FROM pg_tables WHERE tablespace = 'tablespace1' ORDER BY tablename;
 tablename 
-----------

SET default_tablespace = tablespace1;
-- should be inserted in tablespace1 which is now default
INSERT INTO hyper_in_space(time, temp, device) VALUES (11, 24, 3);
SELECT tablename, tablespace FROM pg_tables
WHERE tablename = 'hyper_in_space' OR tablename LIKE '\_hyper\__\__\_chunk' ORDER BY tablename;
    tablename     | tablespace  
------------------+-------------
 _hyper_3_5_chunk | 
 _hyper_3_6_chunk | 
 _hyper_3_7_chunk | 
 _hyper_3_8_chunk | tablespace1
 hyper_in_space   | 

SET default_tablespace TO DEFAULT;
ALTER TABLE hyper_in_space SET TABLESPACE tablespace1;
SELECT tablename FROM pg_tables WHERE tablespace = 'tablespace1' ORDER BY tablename;
    tablename     
------------------
 _hyper_3_5_chunk
 _hyper_3_6_chunk
 _hyper_3_7_chunk
 _hyper_3_8_chunk
 hyper_in_space

-- should be inserted in an existing chunk in the new tablespace,
-- no new chunks
INSERT INTO hyper_in_space(time, temp, device) VALUES (5, 27, 1);
-- the new chunk should be create in the new tablespace
INSERT INTO hyper_in_space(time, temp, device) VALUES (8, 24, 2);
SELECT tablename, tablespace FROM pg_tables
WHERE tablename = 'hyper_in_space' OR tablename LIKE '\_hyper\__\__\_chunk' ORDER BY tablename;
    tablename     | tablespace  
------------------+-------------
 _hyper_3_5_chunk | tablespace1
 _hyper_3_6_chunk | tablespace1
 _hyper_3_7_chunk | tablespace1
 _hyper_3_8_chunk | tablespace1
 _hyper_3_9_chunk | tablespace1
 hyper_in_space   | tablespace1

-- should not fail (unlike attach_tablespace)
ALTER TABLE hyper_in_space SET TABLESPACE tablespace1;
\set ON_ERROR_STOP 0
-- not an empty tablespace
DROP TABLESPACE tablespace1;
ERROR:  tablespace "tablespace1" is still attached to 1 hypertables
\set ON_ERROR_STOP 1
-- show_chunks and drop_chunks output should be the same
\set QUERY1 'SELECT show_chunks(\'hyper_in_space\', 22)::NAME'
\set QUERY2 'SELECT drop_chunks(\'hyper_in_space\', 22)::NAME'
\set ECHO errors
 Different Rows | Total Rows from Query 1 | Total Rows from Query 2 
----------------+-------------------------+-------------------------
              0 |                       5 |                       5

SELECT tablename, tablespace FROM pg_tables WHERE tablespace = 'tablespace1' ORDER BY tablename;
   tablename    | tablespace  
----------------+-------------
 hyper_in_space | tablespace1

\set ON_ERROR_STOP 0
-- should not be able to drop tablespace if a hypertable depends on it
-- even when there are no chunks
DROP TABLESPACE tablespace1;
ERROR:  tablespace "tablespace1" is still attached to 1 hypertables
\set ON_ERROR_STOP 1
DROP TABLE hyper_in_space;
CREATE TABLE hyper_in_space(time bigint, temp float, device int) TABLESPACE tablespace1;
SELECT create_hypertable('hyper_in_space', 'time', 'device', 4, chunk_time_interval=>1);
      create_hypertable      
-----------------------------
 (4,public,hyper_in_space,t)

INSERT INTO hyper_in_space(time, temp, device) VALUES (1, 20, 1);
INSERT INTO hyper_in_space(time, temp, device) VALUES (3, 21, 2);
INSERT INTO hyper_in_space(time, temp, device) VALUES (5, 23, 1);
SELECT tablename, tablespace FROM pg_tables
WHERE tablename = 'hyper_in_space' OR tablename ~ '_hyper_\d+_\d+_chunk' ORDER BY tablename;
     tablename     | tablespace  
-------------------+-------------
 _hyper_4_10_chunk | tablespace1
 _hyper_4_11_chunk | tablespace1
 _hyper_4_12_chunk | tablespace1
 hyper_in_space    | tablespace1

SELECT attach_tablespace('tablespace2', 'hyper_in_space');
 attach_tablespace 
-------------------
 

\set ON_ERROR_STOP 0
-- should fail as >1 tablespaces are attached
ALTER TABLE hyper_in_space SET TABLESPACE tablespace1;
ERROR:  cannot set new tablespace when multiple tablespaces are attached to hypertable "hyper_in_space"
\set ON_ERROR_STOP 1
SELECT detach_tablespace('tablespace2', 'hyper_in_space');
 detach_tablespace 
-------------------
                 1

SELECT * FROM _timescaledb_catalog.tablespace;
 id | hypertable_id | tablespace_name 
----+---------------+-----------------
  3 |             4 | tablespace1

-- make sure when using ALTER TABLE, table spaces are not accumulated
-- as in case of attach_tablespace
-- should have one result
SELECT * FROM _timescaledb_catalog.tablespace;
 id | hypertable_id | tablespace_name 
----+---------------+-----------------
  3 |             4 | tablespace1

ALTER TABLE hyper_in_space SET TABLESPACE tablespace2;
-- should have one result
SELECT * FROM _timescaledb_catalog.tablespace;
 id | hypertable_id | tablespace_name 
----+---------------+-----------------
  5 |             4 | tablespace2

ALTER TABLE hyper_in_space SET TABLESPACE tablespace1;
-- should have one result, (same as the first in the block)
SELECT * FROM _timescaledb_catalog.tablespace;
 id | hypertable_id | tablespace_name 
----+---------------+-----------------
  6 |             4 | tablespace1

SELECT tablename, tablespace FROM pg_tables
WHERE tablename = 'hyper_in_space' OR tablename ~ '_hyper_\d+_\d+_chunk' ORDER BY tablename;
     tablename     | tablespace  
-------------------+-------------
 _hyper_4_10_chunk | tablespace1
 _hyper_4_11_chunk | tablespace1
 _hyper_4_12_chunk | tablespace1
 hyper_in_space    | tablespace1

-- attach tb2 <-> ALTER SET tb1 <-> detach tb1 should work
SELECT detach_tablespace('tablespace1', 'hyper_in_space');
 detach_tablespace 
-------------------
                 1

INSERT INTO hyper_in_space(time, temp, device) VALUES (5, 23, 1);
INSERT INTO hyper_in_space(time, temp, device) VALUES (7, 23, 1);
-- Since we have detached tablespace1 the new chunk should not be
-- placed there.
SELECT tablename, tablespace FROM pg_tables
WHERE tablename = 'hyper_in_space' OR tablename ~ '_hyper_\d+_\d+_chunk' ORDER BY tablename;
     tablename     | tablespace  
-------------------+-------------
 _hyper_4_10_chunk | tablespace1
 _hyper_4_11_chunk | tablespace1
 _hyper_4_12_chunk | tablespace1
 _hyper_4_13_chunk | 
 hyper_in_space    | 

SELECT * FROM _timescaledb_catalog.tablespace;
 id | hypertable_id | tablespace_name 
----+---------------+-----------------

-- tablespace functions should handle the default tablespace just as they do others
SELECT attach_tablespace('pg_default', 'hyper_in_space');
 attach_tablespace 
-------------------
 

SELECT attach_tablespace('tablespace2', 'hyper_in_space');
 attach_tablespace 
-------------------
 

SELECT tablename, tablespace FROM pg_tables
WHERE tablename = 'hyper_in_space' OR tablename ~ '_hyper_\d+_\d+_chunk' ORDER BY tablename;
     tablename     | tablespace  
-------------------+-------------
 _hyper_4_10_chunk | tablespace1
 _hyper_4_11_chunk | tablespace1
 _hyper_4_12_chunk | tablespace1
 _hyper_4_13_chunk | 
 hyper_in_space    | tablespace2

SELECT * FROM _timescaledb_catalog.tablespace;
 id | hypertable_id | tablespace_name 
----+---------------+-----------------
  7 |             4 | pg_default
  8 |             4 | tablespace2

INSERT INTO hyper_in_space(time, temp, device) VALUES (12, 22, 1);
INSERT INTO hyper_in_space(time, temp, device) VALUES (13, 23, 3);
SELECT tablename, tablespace FROM pg_tables
WHERE tablename = 'hyper_in_space' OR tablename ~ '_hyper_\d+_\d+_chunk' ORDER BY tablename;
     tablename     | tablespace  
-------------------+-------------
 _hyper_4_10_chunk | tablespace1
 _hyper_4_11_chunk | tablespace1
 _hyper_4_12_chunk | tablespace1
 _hyper_4_13_chunk | 
 _hyper_4_14_chunk | 
 _hyper_4_15_chunk | tablespace2
 hyper_in_space    | tablespace2

SELECT detach_tablespace('pg_default', 'hyper_in_space');
 detach_tablespace 
-------------------
                 1

ALTER TABLE hyper_in_space SET TABLESPACE pg_default;
SELECT tablename, tablespace FROM pg_tables
WHERE tablename = 'hyper_in_space' OR tablename ~ '_hyper_\d+_\d+_chunk' ORDER BY tablename;
     tablename     | tablespace 
-------------------+------------
 _hyper_4_10_chunk | 
 _hyper_4_11_chunk | 
 _hyper_4_12_chunk | 
 _hyper_4_13_chunk | 
 _hyper_4_14_chunk | 
 _hyper_4_15_chunk | 
 hyper_in_space    | 

SELECT detach_tablespace('pg_default', 'hyper_in_space');
 detach_tablespace 
-------------------
                 1

DROP TABLE hyper_in_space;
-- test altering tablespace on index, issue #903
CREATE TABLE series(
  time timestamptz not null,
  device int,
  value float,
  CONSTRAINT series_pk PRIMARY KEY (time, device) USING INDEX TABLESPACE tablespace1);
SELECT create_hypertable('series', 'time', create_default_indexes => FALSE);
  create_hypertable  
---------------------
 (5,public,series,t)

INSERT INTO series VALUES ('2019-04-21 10:12', 1, 1.01);
CREATE INDEX series_value ON series (value, time) TABLESPACE tablespace2;
SELECT schemaname, tablename, indexname, tablespace
FROM pg_indexes
WHERE indexname LIKE '%series%'
ORDER BY indexname;
      schemaname       |     tablename     |           indexname            | tablespace  
-----------------------+-------------------+--------------------------------+-------------
 _timescaledb_internal | _hyper_5_16_chunk | 16_1_series_pk                 | tablespace1
 _timescaledb_internal | _hyper_5_16_chunk | _hyper_5_16_chunk_series_value | tablespace2
 public                | series            | series_pk                      | tablespace1
 public                | series            | series_value                   | tablespace2

ALTER INDEX series_pk SET TABLESPACE tablespace2;
CREATE INDEX ON series (time) TABLESPACE tablespace1;
ALTER INDEX series_value SET TABLESPACE pg_default;
INSERT INTO series VALUES ('2019-04-29 10:12', 2, 1.31);
SELECT schemaname, tablename, indexname, tablespace
FROM pg_indexes
WHERE indexname LIKE '%series%'
ORDER BY indexname;
      schemaname       |     tablename     |             indexname             | tablespace  
-----------------------+-------------------+-----------------------------------+-------------
 _timescaledb_internal | _hyper_5_16_chunk | 16_1_series_pk                    | tablespace2
 _timescaledb_internal | _hyper_5_17_chunk | 17_2_series_pk                    | tablespace2
 _timescaledb_internal | _hyper_5_16_chunk | _hyper_5_16_chunk_series_time_idx | tablespace1
 _timescaledb_internal | _hyper_5_16_chunk | _hyper_5_16_chunk_series_value    | 
 _timescaledb_internal | _hyper_5_17_chunk | _hyper_5_17_chunk_series_time_idx | tablespace1
 _timescaledb_internal | _hyper_5_17_chunk | _hyper_5_17_chunk_series_value    | 
 public                | series            | series_pk                         | tablespace2
 public                | series            | series_time_idx                   | tablespace1
 public                | series            | series_value                      | 

DROP TABLE series;
DROP TABLESPACE tablespace1;
DROP TABLESPACE tablespace2;
-- Make sure we handle ALTER SCHEMA RENAME for hypertable schemas
\c :TEST_DBNAME :ROLE_SUPERUSER
CREATE SCHEMA IF NOT EXISTS original_name;
CREATE TABLE original_name.my_table (
  date timestamp with time zone NOT NULL,
  quantity double precision
);
SELECT create_hypertable('original_name.my_table','date');
      create_hypertable       
------------------------------
 (6,original_name,my_table,t)

INSERT INTO original_name.my_table (date, quantity) VALUES ('2018-07-04T21:00:00+00:00', 8);
ALTER SCHEMA original_name RENAME TO new_name;
DROP TABLE new_name.my_table;
DROP SCHEMA new_name;
-- Now make sure schema is renamed for multiple hypertables, but not hypertables not in the schema
CREATE SCHEMA IF NOT EXISTS original_name;
CREATE TABLE original_name.my_table (
  date timestamp with time zone NOT NULL,
  quantity double precision
);
CREATE TABLE original_name.my_table2 (
  date timestamp with time zone NOT NULL,
  quantity double precision
);
CREATE TABLE regular_table (
  date timestamp with time zone NOT NULL,
  quantity double precision
);
SELECT create_hypertable('original_name.my_table','date');
      create_hypertable       
------------------------------
 (7,original_name,my_table,t)

SELECT create_hypertable('original_name.my_table2','date');
       create_hypertable       
-------------------------------
 (8,original_name,my_table2,t)

SELECT create_hypertable('regular_table','date');
     create_hypertable      
----------------------------
 (9,public,regular_table,t)

INSERT INTO original_name.my_table (date, quantity) VALUES ('2018-07-04T21:00:00+00:00', 8);
INSERT INTO original_name.my_table2 (date, quantity) VALUES ('2018-07-04T21:00:00+00:00', 8);
INSERT INTO regular_table (date, quantity) VALUES ('2018-07-04T21:00:00+00:00', 8);
ALTER SCHEMA original_name RENAME TO new_name;
DROP TABLE new_name.my_table;
DROP TABLE new_name.my_table2;
DROP TABLE regular_table;
DROP SCHEMA new_name;
-- These tables should also drop when we drop the whole schema
CREATE SCHEMA IF NOT EXISTS original_name;
CREATE TABLE original_name.my_table (
  date timestamp with time zone NOT NULL,
  quantity double precision
);
CREATE TABLE original_name.my_table2 (
  date timestamp with time zone NOT NULL,
  quantity double precision
);
SELECT create_hypertable('original_name.my_table','date');
       create_hypertable       
-------------------------------
 (10,original_name,my_table,t)

SELECT create_hypertable('original_name.my_table2','date');
       create_hypertable        
--------------------------------
 (11,original_name,my_table2,t)

INSERT INTO original_name.my_table (date, quantity) VALUES ('2018-07-04T21:00:00+00:00', 8);
INSERT INTO original_name.my_table2 (date, quantity) VALUES ('2018-07-04T21:00:00+00:00', 8);
ALTER SCHEMA original_name RENAME TO new_name;
DROP SCHEMA new_name CASCADE;
NOTICE:  drop cascades to 4 other objects
SELECT * FROM test.relation WHERE schema = 'new_name';
 schema | name | type | owner 
--------+------+------+-------

-- Make sure we can't rename internal schemas
\set ON_ERROR_STOP 0
ALTER SCHEMA _timescaledb_internal RENAME TO my_new_schema_name;
ERROR:  cannot rename schemas used by the TimescaleDB extension
ALTER SCHEMA _timescaledb_catalog RENAME TO my_new_schema_name;
ERROR:  cannot rename schemas used by the TimescaleDB extension
ALTER SCHEMA _timescaledb_cache RENAME TO my_new_schema_name;
ERROR:  cannot rename schemas used by the TimescaleDB extension
\set ON_ERROR_STOP 1
-- Make sure we can rename associated schemas
CREATE TABLE my_table (
  date timestamp with time zone NOT NULL,
  quantity double precision
);
SELECT create_hypertable('my_table','date', associated_schema_name => 'my_associated_schema');
   create_hypertable    
------------------------
 (12,public,my_table,t)

INSERT INTO my_table (date, quantity) VALUES ('2018-07-04T21:00:00+00:00', 8);
ALTER SCHEMA my_associated_schema RENAME TO new_associated_schema;
INSERT INTO my_table (date, quantity) VALUES ('2018-08-10T23:00:00+00:00', 20);
-- Make sure the schema name is changed in both catalog tables
SELECT * from _timescaledb_catalog.hypertable;
 id | schema_name | table_name | associated_schema_name | associated_table_prefix | num_dimensions | chunk_sizing_func_schema |  chunk_sizing_func_name  | chunk_target_size | compression_state | compressed_hypertable_id | status 
----+-------------+------------+------------------------+-------------------------+----------------+--------------------------+--------------------------+-------------------+-------------------+--------------------------+--------
 12 | public      | my_table   | new_associated_schema  | _hyper_12               |              1 | _timescaledb_functions   | calculate_chunk_interval |                 0 |                 0 |                          |      0

SELECT id, hypertable_id, schema_name, table_name, compressed_chunk_id, dropped, status, osm_chunk from _timescaledb_catalog.chunk;
 id | hypertable_id |      schema_name      |     table_name     | compressed_chunk_id | dropped | status | osm_chunk 
----+---------------+-----------------------+--------------------+---------------------+---------+--------+-----------
 24 |            12 | new_associated_schema | _hyper_12_24_chunk |                     | f       |      0 | f
 25 |            12 | new_associated_schema | _hyper_12_25_chunk |                     | f       |      0 | f

DROP TABLE my_table;
-- test renaming unique constraints/indexes
CREATE TABLE t_hypertable ( id INTEGER NOT NULL, time TIMESTAMPTZ NOT NULL, value FLOAT NOT NULL CHECK (value > 0), UNIQUE(id, time));
SELECT create_hypertable('t_hypertable', 'time');
     create_hypertable      
----------------------------
 (13,public,t_hypertable,t)

INSERT INTO t_hypertable AS h VALUES ( 1, '2020-01-01 00:00:00', 3.2) ON CONFLICT (id, time) DO UPDATE SET value = h.value + EXCLUDED.value;
INSERT INTO t_hypertable AS h VALUES ( 1, '2021-01-01 00:00:00', 3.2) ON CONFLICT (id, time) DO UPDATE SET value = h.value + EXCLUDED.value;
BEGIN;
ALTER INDEX t_hypertable_id_time_key RENAME TO t_new_constraint;
-- chunk_constraint should have updated constraint names
SELECT hypertable_constraint_name, constraint_name from _timescaledb_catalog.chunk_constraint WHERE hypertable_constraint_name = 't_new_constraint' ORDER BY 1,2;
 hypertable_constraint_name |           constraint_name           
----------------------------+-------------------------------------
 t_new_constraint           | _hyper_13_26_chunk_t_new_constraint
 t_new_constraint           | _hyper_13_27_chunk_t_new_constraint

INSERT INTO t_hypertable AS h VALUES ( 1, '2020-01-01 00:01:00', 3.2) ON CONFLICT (id, time) DO UPDATE SET value = h.value + EXCLUDED.value;
ROLLBACK;
BEGIN;
ALTER TABLE t_hypertable RENAME CONSTRAINT t_hypertable_id_time_key TO t_new_constraint;
-- chunk_constraint should have updated constraint names
SELECT hypertable_constraint_name, constraint_name from _timescaledb_catalog.chunk_constraint WHERE hypertable_constraint_name = 't_new_constraint' ORDER BY 1,2;
 hypertable_constraint_name |    constraint_name    
----------------------------+-----------------------
 t_new_constraint           | 26_5_t_new_constraint
 t_new_constraint           | 27_6_t_new_constraint

INSERT INTO t_hypertable AS h VALUES ( 1, '2020-01-01 00:01:00', 3.2) ON CONFLICT (id, time) DO UPDATE SET value = h.value + EXCLUDED.value;
ROLLBACK;
-- predicate reconstruction when attnos are different in hypertable and chunk
CREATE TABLE p_hypertable (a integer not null, b integer, c integer);
SELECT create_hypertable('p_hypertable', 'a', chunk_time_interval => int '3');
     create_hypertable      
----------------------------
 (14,public,p_hypertable,t)

BEGIN;
ALTER TABLE p_hypertable DROP COLUMN b, ADD COLUMN d boolean;
CREATE INDEX idx_ht ON p_hypertable(a, c) WHERE d = FALSE;
END;
INSERT INTO p_hypertable(a, c, d) VALUES (1, 1, FALSE);
\d _timescaledb_internal._hyper_14_28_chunk
 Table "_timescaledb_internal._hyper_14_28_chunk"
 Column |  Type   | Collation | Nullable | Default 
--------+---------+-----------+----------+---------
 a      | integer |           | not null | 
 c      | integer |           |          | 
 d      | boolean |           |          | 
Indexes:
    "_hyper_14_28_chunk_idx_ht" btree (a, c) WHERE NOT d
    "_hyper_14_28_chunk_p_hypertable_a_idx" btree (a DESC)
Check constraints:
    "constraint_34" CHECK (a >= 0 AND a < 3)
Inherits: p_hypertable

DROP TABLE p_hypertable;
-- check none of our hooks interact badly with normal alter view handling
CREATE VIEW v1 AS SELECT random();
\set ON_ERROR_STOP 0
-- should error with unrecognized parameter
ALTER VIEW v1 SET (autovacuum_enabled = false);
ERROR:  unrecognized parameter "autovacuum_enabled"
\set ON_ERROR_STOP 1
-- issue 4474
-- test hypertable with non-default statistics target
-- and chunk creation triggered by non-owner
CREATE ROLE role_4474;
CREATE TABLE i4474(time timestamptz NOT NULL);
SELECT table_name FROM public.create_hypertable( 'i4474', 'time');
 table_name 
------------
 i4474

GRANT SELECT, INSERT on i4474 TO role_4474;
-- create chunk as owner
INSERT INTO i4474 SELECT '2020-01-01';
-- set statistics
ALTER TABLE i4474 ALTER COLUMN time SET statistics 10;
-- create chunk as non-owner
SET ROLE role_4474;
INSERT INTO i4474 SELECT '2021-01-01';
RESET ROLE;
DROP TABLE i4474 CASCADE;
DROP ROLE role_4474;
-- verify that setting replica identity works and chunks inherit the
-- root table's setting
CREATE TABLE replid(time timestamptz, value int);
SELECT create_hypertable('replid', 'time', chunk_time_interval => interval '1 day', create_default_indexes => false);
  create_hypertable   
----------------------
 (16,public,replid,t)

-- replica identity set to default
SELECT relreplident FROM pg_class WHERE relname = 'replid';
 relreplident 
--------------
 d

INSERT INTO replid VALUES ('2023-01-01', 1);
-- the new chunk should have the same replica identity setting
SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname;
      relname       | relreplident 
--------------------+--------------
 _hyper_16_31_chunk | d

-- test change to replica identity full
ALTER TABLE replid REPLICA IDENTITY FULL;
SELECT relname, relreplident FROM pg_class WHERE relname = 'replid' ORDER BY relname;
 relname | relreplident 
---------+--------------
 replid  | f

-- the chunk's setting should also change to FULL
SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname;
      relname       | relreplident 
--------------------+--------------
 _hyper_16_31_chunk | f

-- change to replica identity index
CREATE UNIQUE INDEX time_key ON replid (time);
ALTER TABLE replid REPLICA IDENTITY USING INDEX time_key;
SELECT relname, relreplident FROM pg_class WHERE relname = 'replid' ORDER BY relname;
 relname | relreplident 
---------+--------------
 replid  | i

SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname;
      relname       | relreplident 
--------------------+--------------
 _hyper_16_31_chunk | i

SELECT indexrelid::regclass::text AS index_name
FROM show_chunks('replid') chid
INNER JOIN pg_index i ON (i.indrelid = chid) AND indisreplident=true
ORDER BY index_name;
                    index_name                     
---------------------------------------------------
 _timescaledb_internal._hyper_16_31_chunk_time_key

INSERT INTO replid VALUES ('2023-01-02', 2);
-- the new chunk will also have replica identity "index"
SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname;
      relname       | relreplident 
--------------------+--------------
 _hyper_16_31_chunk | i
 _hyper_16_32_chunk | i

SELECT indexrelid::regclass::text AS index_name
FROM show_chunks('replid') chid
INNER JOIN pg_index i ON (i.indrelid = chid) AND indisreplident=true
ORDER BY index_name;
                    index_name                     
---------------------------------------------------
 _timescaledb_internal._hyper_16_31_chunk_time_key
 _timescaledb_internal._hyper_16_32_chunk_time_key

-- drop the replica identity index and create a new chunk. The new
-- chunk should have replica identity "NOTHING" since this is the
-- behavior of replica identity index when the index is dropped.
DROP INDEX time_key;
INSERT INTO replid VALUES ('2023-01-03', 3);
-- no indexes left
SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname;
      relname       | relreplident 
--------------------+--------------
 _hyper_16_31_chunk | i
 _hyper_16_32_chunk | i
 _hyper_16_33_chunk | n

SELECT indexrelid::regclass::text AS index_name
FROM show_chunks('replid') chid
INNER JOIN pg_index i ON (i.indrelid = chid) AND indisreplident=true
ORDER BY index_name;
 index_name 
------------

-- Alter replica identity directly on a chunk is not supported
SELECT ch AS chunk_name FROM show_chunks('replid') ch ORDER BY chunk_name LIMIT 1 \gset
\set ON_ERROR_STOP 0
ALTER TABLE :chunk_name REPLICA IDENTITY FULL;
ERROR:  operation not supported on chunk tables
\set ON_ERROR_STOP 1
SELECT relname, relreplident FROM show_chunks('replid') ch INNER JOIN pg_class c ON (ch = c.oid) ORDER BY relname;
      relname       | relreplident 
--------------------+--------------
 _hyper_16_31_chunk | i
 _hyper_16_32_chunk | i
 _hyper_16_33_chunk | n

-- test implicit constraints gh issue #9132
CREATE TABLE i9132(time timestamptz) WITH (tsdb.hypertable);
NOTICE:  using column "time" as partitioning column
INSERT INTO i9132 VALUES ('2024-01-01'), ('2024-02-02');
ALTER TABLE i9132 ADD COLUMN id serial, ADD CONSTRAINT implicit_pk PRIMARY KEY (id, time);
