-- 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.
\o /dev/null
\ir include/insert_two_partitions.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 PUBLIC."two_Partitions" (
  "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."two_Partitions" (device_id, "timeCustom" DESC NULLS LAST) WHERE device_id IS NOT NULL;
CREATE INDEX ON PUBLIC."two_Partitions" ("timeCustom" DESC NULLS LAST, series_0) WHERE series_0 IS NOT NULL;
CREATE INDEX ON PUBLIC."two_Partitions" ("timeCustom" DESC NULLS LAST, series_1)  WHERE series_1 IS NOT NULL;
CREATE INDEX ON PUBLIC."two_Partitions" ("timeCustom" DESC NULLS LAST, series_2) WHERE series_2 IS NOT NULL;
CREATE INDEX ON PUBLIC."two_Partitions" ("timeCustom" DESC NULLS LAST, series_bool) WHERE series_bool IS NOT NULL;
CREATE INDEX ON PUBLIC."two_Partitions" ("timeCustom" DESC NULLS LAST, device_id);
SELECT * FROM create_hypertable('"public"."two_Partitions"'::regclass, 'timeCustom'::name, 'device_id'::name, associated_schema_name=>'_timescaledb_internal'::text, number_partitions => 2, chunk_time_interval=>_timescaledb_functions.interval_to_usec('1 month'));
\set QUIET off
BEGIN;
\COPY public."two_Partitions" FROM 'data/ds1_dev1_1.tsv' NULL AS '';
COMMIT;
INSERT INTO public."two_Partitions"("timeCustom", device_id, series_0, series_1) VALUES
(1257987600000000000, 'dev1', 1.5, 1),
(1257987600000000000, 'dev1', 1.5, 2),
(1257894000000000000, 'dev2', 1.5, 1),
(1257894002000000000, 'dev1', 2.5, 3);
INSERT INTO "two_Partitions"("timeCustom", device_id, series_0, series_1) VALUES
(1257894000000000000, 'dev2', 1.5, 2);
\set QUIET on
\o
--old chunks
COPY "two_Partitions"("timeCustom", device_id, series_0, series_1) FROM STDIN DELIMITER ',';
\copy "two_Partitions"("timeCustom", device_id, series_0, series_1) FROM STDIN DELIMITER ',';
--new chunks
COPY "two_Partitions"("timeCustom", device_id, series_0, series_1) FROM STDIN DELIMITER ',';
\copy "two_Partitions"("timeCustom", device_id, series_0, series_1) FROM STDIN DELIMITER ',';
COPY (SELECT * FROM "two_Partitions" ORDER BY "timeCustom", device_id, series_0, series_1) TO STDOUT;
1257894000000000000	dev1	1.5	1	2	t
1257894000000000000	dev1	1.5	2	\N	\N
1257894000000000000	dev2	1.5	1	\N	\N
1257894000000000000	dev2	1.5	2	\N	\N
1257894000000000000	dev3	1.5	2	\N	\N
1257894000000000000	dev3	1.5	2	\N	\N
1257894000000001000	dev1	2.5	3	\N	\N
1257894001000000000	dev1	3.5	4	\N	\N
1257894002000000000	dev1	2.5	3	\N	\N
1257894002000000000	dev1	5.5	6	\N	t
1257894002000000000	dev1	5.5	7	\N	f
1257897600000000000	dev1	4.5	5	\N	f
1257987600000000000	dev1	1.5	1	\N	\N
1257987600000000000	dev1	1.5	2	\N	\N
2257894000000000000	dev3	1.5	2	\N	\N
2257894000000000000	dev3	1.5	2	\N	\N
---test hypertable with FK
CREATE TABLE "meta" ("id" serial PRIMARY KEY);
CREATE TABLE "hyper" (
    "meta_id" integer NOT NULL REFERENCES meta(id),
    "time" bigint NOT NULL,
    "value" double precision NOT NULL
);
SELECT create_hypertable('hyper', 'time', chunk_time_interval => 100);
 create_hypertable  
--------------------
 (2,public,hyper,t)

INSERT INTO "meta" ("id") values (1);
\copy hyper (time, meta_id, value) FROM STDIN DELIMITER ',';
COPY hyper (time, meta_id, value) FROM STDIN DELIMITER ',';
\set ON_ERROR_STOP 0
\copy hyper (time, meta_id, value) FROM STDIN DELIMITER ',';
ERROR:  insert or update on table "_hyper_2_6_chunk" violates foreign key constraint "6_1_hyper_meta_id_fkey"
COPY hyper (time, meta_id, value) FROM STDIN DELIMITER ',';
ERROR:  insert or update on table "_hyper_2_6_chunk" violates foreign key constraint "6_1_hyper_meta_id_fkey"
\set ON_ERROR_STOP 1
COPY (SELECT * FROM hyper ORDER BY time, meta_id) TO STDOUT;
1	1	1
1	2	1
--test that copy works with a low setting for max_open_chunks_per_insert
set timescaledb.max_open_chunks_per_insert = 1;
CREATE TABLE "hyper2" (
    "time" bigint NOT NULL,
    "value" double precision NOT NULL
);
SELECT create_hypertable('hyper2', 'time', chunk_time_interval => 10);
  create_hypertable  
---------------------
 (3,public,hyper2,t)

\copy hyper2 from data/copy_data.csv with csv header ;
-- test copy with blocking trigger
CREATE FUNCTION gt_10() RETURNS trigger AS
$func$
BEGIN
    IF NEW."time" < 11
        THEN RETURN NULL;
    END IF;
    RETURN NEW;
END
$func$ LANGUAGE plpgsql;
CREATE TABLE "trigger_test" (
    "time" bigint NOT NULL,
    "value" double precision NOT NULL
);
SELECT create_hypertable('trigger_test', 'time', chunk_time_interval => 10);
     create_hypertable     
---------------------------
 (4,public,trigger_test,t)

CREATE TRIGGER check_time BEFORE INSERT ON trigger_test
FOR EACH ROW EXECUTE FUNCTION gt_10();
\copy trigger_test from data/copy_data.csv with csv header ;
SELECT * FROM trigger_test ORDER BY time;
 time |       value        
------+--------------------
   11 |  0.795640022493899
   12 |  0.631451691035181
   13 | 0.0958626130595803
   14 |  0.929304684977978
   15 |  0.524866581428796
   16 |  0.919249163009226
   17 |  0.878917074296623
   18 |   0.68551931809634
   19 |  0.594833800103515
   20 |  0.819584367796779
   21 |  0.474171321373433
   22 |  0.938535195309669
   23 |  0.333933369256556
   24 |  0.274582070298493
   25 |  0.602348630782217

-- Test that if we copy from stdin to a hypertable and violate a null
-- constraint, it does not crash and generate an appropriate error
-- message.
CREATE TABLE test(a INT NOT NULL, b TIMESTAMPTZ);
SELECT create_hypertable('test', 'b');
 create_hypertable 
-------------------
 (5,public,test,t)

\set ON_ERROR_STOP 0
COPY TEST (a,b) FROM STDIN (delimiter ',', null 'N');
ERROR:  null value in column "a" of relation "_hyper_5_13_chunk" violates not-null constraint
\c :TEST_DBNAME :ROLE_SUPERUSER
SET client_min_messages TO NOTICE;
-- Do a basic test of COPY with a wrong PROGRAM
COPY hyper FROM PROGRAM 'error';
ERROR:  program "error" failed
\set ON_ERROR_STOP 1
----------------------------------------------------------------
-- Testing COPY TO.
----------------------------------------------------------------
-- COPY TO using a hypertable will not copy any tuples, but should
-- show a notice.
COPY hyper TO STDOUT DELIMITER ',';
NOTICE:  hypertable data are in the chunks, no data will be copied
-- COPY TO using a query should display all the tuples and not show a
-- notice.
COPY (SELECT * FROM hyper) TO STDOUT DELIMITER ',';
1,1,1
1,2,1
----------------------------------------------------------------
-- Testing multi-buffer optimization.
----------------------------------------------------------------
CREATE TABLE "hyper_copy" (
    "time" bigint NOT NULL,
    "value" double precision NOT NULL
);
SELECT create_hypertable('hyper_copy', 'time', chunk_time_interval => 2);
    create_hypertable    
-------------------------
 (6,public,hyper_copy,t)

-- First copy call with default client_min_messages, to get rid of the
-- building index "_hyper_XXX_chunk_hyper_copy_time_idx" on table "_hyper_XXX_chunk" serially
-- messages
\copy hyper_copy FROM data/copy_data.csv WITH csv header;
SET client_min_messages TO DEBUG1;
\copy hyper_copy FROM data/copy_data.csv WITH csv header;
DEBUG:  Using optimized multi-buffer copy operation (TS_CIM_MULTI_CONDITIONAL).
SELECT count(*) FROM hyper_copy;
 count 
-------
    50

-- Limit number of open chunks
SET timescaledb.max_open_chunks_per_insert = 1;
\copy hyper_copy FROM data/copy_data.csv WITH csv header;
DEBUG:  Using optimized multi-buffer copy operation (TS_CIM_MULTI_CONDITIONAL).
SELECT count(*) FROM hyper_copy;
 count 
-------
    75

-- Before trigger disable the multi-buffer optimization
CREATE OR REPLACE FUNCTION empty_test_trigger()
    RETURNS TRIGGER LANGUAGE PLPGSQL AS
$BODY$
BEGIN
    IF TG_OP = 'DELETE' THEN
        RETURN OLD;
    END IF;
    RETURN NEW;
END
$BODY$;
-- Before trigger (CIM_SINGLE should be used)
CREATE TRIGGER hyper_copy_trigger_insert_before
    BEFORE INSERT ON hyper_copy
    FOR EACH ROW EXECUTE FUNCTION empty_test_trigger();
\copy hyper_copy FROM data/copy_data.csv WITH csv header;
DEBUG:  Using normal unbuffered copy operation (TS_CIM_SINGLE) because triggers are defined on the destination table.
SELECT count(*) FROM hyper_copy;
 count 
-------
   100

-- Suppress 'DEBUG:  EventTriggerInvoke XXXX' messages
RESET client_min_messages;
DROP TRIGGER hyper_copy_trigger_insert_before ON hyper_copy;
SET client_min_messages TO DEBUG1;
-- After trigger (CIM_MULTI_CONDITIONAL should be used)
CREATE TRIGGER hyper_copy_trigger_insert_after
    AFTER INSERT ON hyper_copy
    FOR EACH ROW EXECUTE FUNCTION empty_test_trigger();
\copy hyper_copy FROM data/copy_data.csv WITH csv header;
DEBUG:  Using optimized multi-buffer copy operation (TS_CIM_MULTI_CONDITIONAL).
SELECT count(*) FROM hyper_copy;
 count 
-------
   125

-- Insert data into the chunks in random order
COPY hyper_copy FROM STDIN DELIMITER ',' NULL AS 'null';
DEBUG:  Using optimized multi-buffer copy operation (TS_CIM_MULTI_CONDITIONAL).
SELECT count(*) FROM hyper_copy;
 count 
-------
   154

RESET client_min_messages;
RESET timescaledb.max_open_chunks_per_insert;
----------------------------------------------------------------
-- Testing multi-buffer optimization
-- (no index on destination hypertable).
----------------------------------------------------------------
CREATE TABLE "hyper_copy_noindex" (
    "time" bigint NOT NULL,
    "value" double precision NOT NULL
);
SELECT create_hypertable('hyper_copy_noindex', 'time', chunk_time_interval => 10, create_default_indexes => false);
        create_hypertable        
---------------------------------
 (7,public,hyper_copy_noindex,t)

-- No trigger
\copy hyper_copy_noindex FROM data/copy_data.csv WITH csv header;
SET client_min_messages TO DEBUG1;
\copy hyper_copy_noindex FROM data/copy_data.csv WITH csv header;
DEBUG:  Using optimized multi-buffer copy operation (TS_CIM_MULTI_CONDITIONAL).
RESET client_min_messages;
SELECT count(*) FROM hyper_copy_noindex;
 count 
-------
    50

-- Before trigger (CIM_SINGLE should be used)
CREATE TRIGGER hyper_copy_trigger_insert_before
    BEFORE INSERT ON hyper_copy_noindex
    FOR EACH ROW EXECUTE FUNCTION empty_test_trigger();
\copy hyper_copy_noindex FROM data/copy_data.csv WITH csv header;
SET client_min_messages TO DEBUG1;
\copy hyper_copy_noindex FROM data/copy_data.csv WITH csv header;
DEBUG:  Using normal unbuffered copy operation (TS_CIM_SINGLE) because triggers are defined on the destination table.
RESET client_min_messages;
SELECT count(*) FROM hyper_copy_noindex;
 count 
-------
   100

-- After trigger (CIM_MULTI_CONDITIONAL should be used)
DROP TRIGGER hyper_copy_trigger_insert_before ON hyper_copy_noindex;
CREATE TRIGGER hyper_copy_trigger_insert_after
    AFTER INSERT ON hyper_copy_noindex
    FOR EACH ROW EXECUTE FUNCTION empty_test_trigger();
\copy hyper_copy_noindex FROM data/copy_data.csv WITH csv header;
SET client_min_messages TO DEBUG1;
\copy hyper_copy_noindex FROM data/copy_data.csv WITH csv header;
DEBUG:  Using optimized multi-buffer copy operation (TS_CIM_MULTI_CONDITIONAL).
RESET client_min_messages;
SELECT count(*) FROM hyper_copy_noindex;
 count 
-------
   150

----------------------------------------------------------------
-- Testing multi-buffer optimization
-- (more chunks than MAX_PARTITION_BUFFERS).
----------------------------------------------------------------
CREATE TABLE "hyper_copy_large" (
    "time" timestamp NOT NULL,
    "value" double precision NOT NULL
);
-- Genate data that will create more than 32 (MAX_PARTITION_BUFFERS)
-- chunks on the 10 second chunk_time_interval partitioned hypertable.
INSERT INTO hyper_copy_large
SELECT time,
random() AS value
FROM
generate_series('2022-01-01', '2022-01-31', INTERVAL '1 hour') AS g1(time)
ORDER BY time;
SELECT COUNT(*) FROM hyper_copy_large;
 count 
-------
   721

-- Migrate data to chunks by using copy
SELECT create_hypertable('hyper_copy_large', 'time',
   chunk_time_interval => INTERVAL '1 hour', migrate_data => 'true');
WARNING:  column type "timestamp without time zone" used for "time" does not follow best practices
NOTICE:  migrating data to chunks
       create_hypertable       
-------------------------------
 (8,public,hyper_copy_large,t)

SELECT COUNT(*) FROM hyper_copy_large;
 count 
-------
   721

----------------------------------------------------------------
-- Testing multi-buffer optimization
-- (triggers on chunks).
----------------------------------------------------------------
CREATE TABLE "table_with_chunk_trigger" (
    "time" bigint NOT NULL,
    "value" double precision NOT NULL
);
-- This trigger counts the already inserted tuples in
-- the table table_with_chunk_trigger.
CREATE OR REPLACE FUNCTION count_test_chunk_trigger()
    RETURNS TRIGGER LANGUAGE PLPGSQL AS
$BODY$
DECLARE
    cnt INTEGER;
BEGIN
    SELECT count(*) FROM table_with_chunk_trigger INTO cnt;
    RAISE WARNING 'Trigger counted % tuples in table table_with_chunk_trigger', cnt;
    IF TG_OP = 'DELETE' THEN
        RETURN OLD;
    END IF;
    RETURN NEW;
END
$BODY$;
-- Create hypertable and chunks
SELECT create_hypertable('table_with_chunk_trigger', 'time', chunk_time_interval => 1);
           create_hypertable           
---------------------------------------
 (9,public,table_with_chunk_trigger,t)

-- Insert data to create all missing chunks
\copy table_with_chunk_trigger from data/copy_data.csv with csv header;
SELECT count(*) FROM table_with_chunk_trigger;
 count 
-------
    25

-- Chunk 1: 1-2, Chunk 2: 2-3, Chunk 3: 3-4, Chunk 4: 4-5
SELECT chunk_schema, chunk_name FROM timescaledb_information.chunks
    WHERE hypertable_name = 'table_with_chunk_trigger' AND range_end_integer=5 \gset
-- Create before trigger on the 4th chunk
CREATE TRIGGER table_with_chunk_trigger_before_trigger
    BEFORE INSERT ON :chunk_schema.:chunk_name
    FOR EACH ROW EXECUTE FUNCTION count_test_chunk_trigger();
-- Insert data
-- 25 tuples are already imported. The trigger is executed before tuples
-- are copied into the 4th chunk. So, the trigger should report 25+3 = 28
-- This test requires that the multi-insert buffers of the other chunks
-- are flushed before the trigger is executed.
SET client_min_messages TO DEBUG1;
\copy table_with_chunk_trigger FROM data/copy_data.csv WITH csv header;
DEBUG:  Using optimized multi-buffer copy operation (TS_CIM_MULTI_CONDITIONAL).
WARNING:  Trigger counted 28 tuples in table table_with_chunk_trigger
RESET client_min_messages;
SELECT count(*) FROM table_with_chunk_trigger;
 count 
-------
    50

DROP TRIGGER table_with_chunk_trigger_before_trigger ON :chunk_schema.:chunk_name;
-- Create after trigger
CREATE TRIGGER table_with_chunk_trigger_after_trigger
    AFTER INSERT ON :chunk_schema.:chunk_name
    FOR EACH ROW EXECUTE FUNCTION count_test_chunk_trigger();
-- Insert data
-- 50 tuples are already imported. The trigger is executed after all
-- tuples are imported. So, the trigger should report 50+25 = 75
SET client_min_messages TO DEBUG1;
\copy table_with_chunk_trigger FROM data/copy_data.csv WITH csv header;
DEBUG:  Using optimized multi-buffer copy operation (TS_CIM_MULTI_CONDITIONAL).
WARNING:  Trigger counted 75 tuples in table table_with_chunk_trigger
RESET client_min_messages;
SELECT count(*) FROM table_with_chunk_trigger;
 count 
-------
    75

-- Hypertable with after row trigger and no index
DROP TABLE table_with_chunk_trigger;
CREATE TABLE "table_with_chunk_trigger" (
    "time" bigint NOT NULL,
    "value" double precision NOT NULL
);
-- Create hypertable and chunks
SELECT create_hypertable('table_with_chunk_trigger', 'time', chunk_time_interval => 1, create_default_indexes => false);
           create_hypertable            
----------------------------------------
 (10,public,table_with_chunk_trigger,t)

-- Insert data to create all missing chunks
\copy table_with_chunk_trigger from data/copy_data.csv with csv header;
SELECT count(*) FROM table_with_chunk_trigger;
 count 
-------
    25

-- Chunk 1: 1-2, Chunk 2: 2-3, Chunk 3: 3-4, Chunk 4: 4-5
SELECT chunk_schema, chunk_name FROM timescaledb_information.chunks
    WHERE hypertable_name = 'table_with_chunk_trigger' AND range_end_integer=5 \gset
-- Create after trigger
CREATE TRIGGER table_with_chunk_trigger_after_trigger
    AFTER INSERT ON :chunk_schema.:chunk_name
    FOR EACH ROW EXECUTE FUNCTION count_test_chunk_trigger();
\copy table_with_chunk_trigger from data/copy_data.csv with csv header;
WARNING:  Trigger counted 50 tuples in table table_with_chunk_trigger
SELECT count(*) FROM table_with_chunk_trigger;
 count 
-------
    50

----------------------------------------------------------------
-- Testing multi-buffer optimization
-- (Hypertable without before insert trigger)
----------------------------------------------------------------
CREATE TABLE "table_without_bf_trigger" (
    "time" bigint NOT NULL,
    "value" double precision NOT NULL
);
SELECT create_hypertable('table_without_bf_trigger', 'time', chunk_time_interval => 1);
           create_hypertable            
----------------------------------------
 (11,public,table_without_bf_trigger,t)

\copy table_without_bf_trigger from data/copy_data.csv with csv header;
SET client_min_messages TO DEBUG1;
\copy table_without_bf_trigger from data/copy_data.csv with csv header;
DEBUG:  Using optimized multi-buffer copy operation (TS_CIM_MULTI_CONDITIONAL).
RESET client_min_messages;
SELECT count(*) FROM table_without_bf_trigger;
 count 
-------
    50

-- After trigger (CIM_MULTI_CONDITIONAL should be used)
CREATE TRIGGER table_with_chunk_trigger_after_trigger
    AFTER INSERT ON table_without_bf_trigger
    FOR EACH ROW EXECUTE FUNCTION empty_test_trigger();
SET client_min_messages TO DEBUG1;
\copy table_without_bf_trigger from data/copy_data.csv with csv header;
DEBUG:  Using optimized multi-buffer copy operation (TS_CIM_MULTI_CONDITIONAL).
RESET client_min_messages;
SELECT count(*) FROM table_without_bf_trigger;
 count 
-------
    75

----------------------------------------------------------------
-- Testing multi-buffer optimization
-- (Chunks with different layouts)
----------------------------------------------------------------
-- Time is not the first attribute of the hypertable
CREATE TABLE "table_with_layout_change" (
    "value1" real NOT NULL DEFAULT 1,
    "value2" smallint DEFAULT NULL,
    "value3" bigint DEFAULT NULL,
    "time" bigint NOT NULL,
    "value4" double precision NOT NULL DEFAULT 4,
    "value5" double precision NOT NULL DEFAULT 5
);
SELECT create_hypertable('table_with_layout_change', 'time', chunk_time_interval => 1);
           create_hypertable            
----------------------------------------
 (12,public,table_with_layout_change,t)

-- Chunk 1 (time = 1)
COPY table_with_layout_change FROM STDIN DELIMITER ',' NULL AS 'null';
SELECT * FROM table_with_layout_change;
 value1 | value2 | value3 | time | value4 | value5 
--------+--------+--------+------+--------+--------
    100 |    200 |    300 |    1 |    400 |    500

-- Drop the first attribute
ALTER TABLE table_with_layout_change DROP COLUMN value1;
SELECT * FROM table_with_layout_change;
 value2 | value3 | time | value4 | value5 
--------+--------+------+--------+--------
    200 |    300 |    1 |    400 |    500

-- COPY into existing chunk (time = 1)
COPY table_with_layout_change FROM STDIN DELIMITER ',' NULL AS 'null';
-- Create new chunk (time = 2)
COPY table_with_layout_change FROM STDIN DELIMITER ',' NULL AS 'null';
SELECT * FROM table_with_layout_change ORDER BY time, value2, value3, value4, value5;
 value2 | value3 | time | value4 | value5 
--------+--------+------+--------+--------
    200 |    300 |    1 |    400 |    500
    201 |    301 |    1 |    401 |    501
    202 |    302 |    2 |    402 |    502

-- Create new chunk (time = 2), insert in different order
COPY table_with_layout_change (time, value5, value4, value3, value2) FROM STDIN DELIMITER ',' NULL AS 'null';
COPY table_with_layout_change (value5, value4, value3, value2, time) FROM STDIN DELIMITER ',' NULL AS 'null';
COPY table_with_layout_change (value5, value4, value3, time, value2) FROM STDIN DELIMITER ',' NULL AS 'null';
SELECT * FROM table_with_layout_change ORDER BY time, value2, value3, value4, value5;
 value2 | value3 | time | value4 | value5 
--------+--------+------+--------+--------
    200 |    300 |    1 |    400 |    500
    201 |    301 |    1 |    401 |    501
    202 |    302 |    2 |    402 |    502
    203 |    303 |    2 |    403 |    503
    204 |    304 |    2 |    404 |    504
    205 |    305 |    2 |    405 |    505

-- Drop the last attribute and add a new one
ALTER TABLE table_with_layout_change DROP COLUMN value5;
ALTER TABLE table_with_layout_change ADD COLUMN value6 double precision NOT NULL default 600;
SELECT * FROM table_with_layout_change ORDER BY time, value2, value3, value4, value6;
 value2 | value3 | time | value4 | value6 
--------+--------+------+--------+--------
    200 |    300 |    1 |    400 |    600
    201 |    301 |    1 |    401 |    600
    202 |    302 |    2 |    402 |    600
    203 |    303 |    2 |    403 |    600
    204 |    304 |    2 |    404 |    600
    205 |    305 |    2 |    405 |    600

-- COPY in first chunk (time = 1)
COPY table_with_layout_change (time, value2, value3, value4, value6) FROM STDIN DELIMITER ',' NULL AS 'null';
-- COPY in second chunk (time = 2)
COPY table_with_layout_change (time, value2, value3, value4, value6) FROM STDIN DELIMITER ',' NULL AS 'null';
-- COPY in new chunk (time = 3)
COPY table_with_layout_change (time, value2, value3, value4, value6) FROM STDIN DELIMITER ',' NULL AS 'null';
-- COPY in all chunks, different attribute order
COPY table_with_layout_change (value3, value4, time, value6, value2) FROM STDIN DELIMITER ',' NULL AS 'null';
SELECT * FROM table_with_layout_change ORDER BY time, value2, value3, value4, value6;
 value2 | value3 | time | value4 | value6 
--------+--------+------+--------+--------
    200 |    300 |    1 |    400 |    600
    201 |    301 |    1 |    401 |    600
    206 |    306 |    1 |    406 |    606
    211 |    311 |    1 |    411 |    611
    202 |    302 |    2 |    402 |    600
    203 |    303 |    2 |    403 |    600
    204 |    304 |    2 |    404 |    600
    205 |    305 |    2 |    405 |    600
    207 |    307 |    2 |    407 |    607
    210 |    310 |    2 |    410 |    610
    208 |    308 |    3 |    408 |    608
    209 |    309 |    3 |    409 |    609

-- Drop first column
ALTER TABLE table_with_layout_change DROP COLUMN value2;
SELECT * FROM table_with_layout_change ORDER BY time, value3, value4, value6;
 value3 | time | value4 | value6 
--------+------+--------+--------
    300 |    1 |    400 |    600
    301 |    1 |    401 |    600
    306 |    1 |    406 |    606
    311 |    1 |    411 |    611
    302 |    2 |    402 |    600
    303 |    2 |    403 |    600
    304 |    2 |    404 |    600
    305 |    2 |    405 |    600
    307 |    2 |    407 |    607
    310 |    2 |    410 |    610
    308 |    3 |    408 |    608
    309 |    3 |    409 |    609

-- COPY in all exiting chunks and create a new one (time 4)
COPY table_with_layout_change (value3, value4, time, value6) FROM STDIN DELIMITER ',' NULL AS 'null';
SELECT * FROM table_with_layout_change ORDER BY time, value3, value4, value6;
 value3 | time | value4 | value6 
--------+------+--------+--------
    300 |    1 |    400 |    600
    301 |    1 |    401 |    600
    306 |    1 |    406 |    606
    311 |    1 |    411 |    611
    315 |    1 |    415 |    615
    302 |    2 |    402 |    600
    303 |    2 |    403 |    600
    304 |    2 |    404 |    600
    305 |    2 |    405 |    600
    307 |    2 |    407 |    607
    310 |    2 |    410 |    610
    313 |    2 |    413 |    613
    308 |    3 |    408 |    608
    309 |    3 |    409 |    609
    312 |    3 |    412 |    612
    314 |    4 |    414 |    614

-- Drop the last two columns
ALTER TABLE table_with_layout_change DROP COLUMN value4;
ALTER TABLE table_with_layout_change DROP COLUMN value6;
-- COPY in all exiting chunks and create a new one (time 5)
COPY table_with_layout_change (value3, time) FROM STDIN DELIMITER ',' NULL AS 'null';
SELECT * FROM table_with_layout_change ORDER BY time, value3;
 value3 | time 
--------+------
    300 |    1
    301 |    1
    306 |    1
    311 |    1
    315 |    1
    317 |    1
    302 |    2
    303 |    2
    304 |    2
    305 |    2
    307 |    2
    310 |    2
    313 |    2
    316 |    2
    308 |    3
    309 |    3
    312 |    3
    318 |    3
    314 |    4
    320 |    4
    319 |    5

-- Drop the last of the initial attributes and add a new one
ALTER TABLE table_with_layout_change DROP COLUMN value3;
ALTER TABLE table_with_layout_change ADD COLUMN value7 double precision NOT NULL default 700;
-- COPY in all exiting chunks and create a new one (time 6)
COPY table_with_layout_change (value7, time) FROM STDIN DELIMITER ',' NULL AS 'null';
SELECT * FROM table_with_layout_change ORDER BY time, value7;
 time | value7 
------+--------
    1 |    700
    1 |    700
    1 |    700
    1 |    700
    1 |    700
    1 |    700
    1 |    722
    2 |    700
    2 |    700
    2 |    700
    2 |    700
    2 |    700
    2 |    700
    2 |    700
    2 |    700
    2 |    721
    3 |    700
    3 |    700
    3 |    700
    3 |    700
    3 |    723
    4 |    700
    4 |    700
    4 |    726
    5 |    700
    5 |    724
    6 |    725

-- verify check constraints work
CREATE TABLE test_check(a INT, b TIMESTAMPTZ);
ALTER TABLE test_check ADD CONSTRAINT c1 CHECK (a > 7);
SELECT table_name FROM create_hypertable('test_check', 'b');
 table_name 
------------
 test_check

COPY test_check(a,b) FROM STDIN (delimiter ',', null 'N');
\set ON_ERROR_STOP 0
COPY test_check(a,b) FROM STDIN (delimiter ',', null 'N');
ERROR:  new row for relation "_hyper_13_832_chunk" violates check constraint "c1"
\set ON_ERROR_STOP 1
