-- This file and its contents are licensed under the Timescale License.
-- Please see the included NOTICE for copyright information and
-- LICENSE-TIMESCALE for a copy of the license.
SET timezone TO 'America/Los_Angeles';
\set PREFIX 'EXPLAIN (buffers off, costs off, summary off, timing off) '
\set ANALYZE  'EXPLAIN (analyze, buffers off, costs off, summary off, timing off) '
CREATE TABLE test1 (timec timestamptz , i integer ,
      b bigint, t text);
SELECT table_name from create_hypertable('test1', 'timec', chunk_time_interval=> INTERVAL '7 days');
 table_name 
------------
 test1

INSERT INTO test1 SELECT q, 10, 11, 'hello' FROM generate_series( '2020-01-03 10:00:00-05', '2020-01-03 12:00:00-05' , '5 min'::interval) q;
ALTER TABLE test1 set (timescaledb.compress,
timescaledb.compress_segmentby = 'b',
timescaledb.compress_orderby = 'timec DESC');
SELECT compress_chunk(c)
FROM show_chunks('test1') c;
             compress_chunk             
----------------------------------------
 _timescaledb_internal._hyper_1_1_chunk

SELECT count(*) FROM  test1;
 count 
-------
    25

--we have 1 compressed row --
SELECT COUNT(*) from _timescaledb_internal.compress_hyper_2_2_chunk;
 count 
-------
     1

-- single and multi row insert into the compressed chunk --
INSERT INTO test1 SELECT '2020-01-02 11:16:00-05' , 11, 16, 'new' ;
SELECT COUNT(*) from _timescaledb_internal.compress_hyper_2_2_chunk;
 count 
-------
     1

INSERT INTO test1 SELECT '2020-01-02 11:16:00-05' , i, i +5, 'clay'
FROM (Select generate_series(10, 20, 1) i ) q;
SELECT COUNT(*) from _timescaledb_internal.compress_hyper_2_2_chunk;
 count 
-------
     1

SELECT count(*) from test1;
 count 
-------
    37

-- single row copy
COPY test1 FROM STDIN DELIMITER ',';
SELECT COUNT(*) from _timescaledb_internal.compress_hyper_2_2_chunk;
 count 
-------
     1

-- multi row copy
COPY test1 FROM STDIN DELIMITER ',';
SELECT COUNT(*) from _timescaledb_internal.compress_hyper_2_2_chunk;
 count 
-------
     1

--Verify that all the data went into the initial chunk
SELECT count(*)
FROM show_chunks('test1') c;
 count 
-------
     1

SELECT * FROM test1 WHERE b = 11 order by i, timec ;
            timec             | i  | b  |   t   
------------------------------+----+----+-------
 Fri Jan 03 07:00:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 07:05:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 07:10:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 07:15:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 07:20:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 07:25:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 07:30:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 07:35:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 07:40:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 07:45:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 07:50:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 07:55:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 08:00:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 08:05:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 08:10:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 08:15:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 08:20:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 08:25:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 08:30:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 08:35:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 08:40:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 08:45:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 08:50:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 08:55:00 2020 PST | 10 | 11 | hello
 Fri Jan 03 09:00:00 2020 PST | 10 | 11 | hello

SELECT * FROM test1 WHERE i = 11 order by 1, 2, 3, 4;
            timec             | i  | b  |     t     
------------------------------+----+----+-----------
 Thu Jan 02 08:16:00 2020 PST | 11 | 16 | clay
 Thu Jan 02 08:16:00 2020 PST | 11 | 16 | copy
 Thu Jan 02 08:16:00 2020 PST | 11 | 16 | multicopy
 Thu Jan 02 08:16:00 2020 PST | 11 | 16 | new

-- insert nulls except for timec
INSERT INTO test1 SELECT '2020-01-02 11:46:00-05' , NULL, NULL, NULL;
SELECT count(*)
FROM show_chunks('test1') c;
 count 
-------
     1

-- copy NULL
COPY test1 FROM STDIN DELIMITER ',' NULL 'NULL';
SELECT count(*)
FROM show_chunks('test1') c;
 count 
-------
     1

SELECT * from test1 WHERE i is NULL;
            timec             | i | b | t 
------------------------------+---+---+---
 Thu Jan 02 08:46:00 2020 PST |   |   | 
 Thu Jan 02 08:46:00 2020 PST |   |   | 

--TEST 2 now alter the table and add a new column to it
ALTER TABLE test1 ADD COLUMN newtcol varchar(400);
--add rows with segments that overlap some of the previous ones
SELECT count(*) from _timescaledb_internal.compress_hyper_2_2_chunk;
 count 
-------
     1

INSERT INTO test1 SELECT '2020-01-02 11:16:00-05' , 100, 101, 'prev101', 'this is the newtcol101';
INSERT INTO test1 SELECT '2020-01-02 11:16:00-05' , i, 16, 'prev16', 'this is the newtcol16'
FROM (Select generate_series(11, 16, 1) i ) q;
SELECT * FROM test1 WHERE b = 16 order by 1, 2, 3, 4, 5;
            timec             | i  | b  |     t     |        newtcol        
------------------------------+----+----+-----------+-----------------------
 Thu Jan 02 08:16:00 2020 PST | 11 | 16 | clay      | 
 Thu Jan 02 08:16:00 2020 PST | 11 | 16 | copy      | 
 Thu Jan 02 08:16:00 2020 PST | 11 | 16 | multicopy | 
 Thu Jan 02 08:16:00 2020 PST | 11 | 16 | new       | 
 Thu Jan 02 08:16:00 2020 PST | 11 | 16 | prev16    | this is the newtcol16
 Thu Jan 02 08:16:00 2020 PST | 12 | 16 | prev16    | this is the newtcol16
 Thu Jan 02 08:16:00 2020 PST | 13 | 16 | prev16    | this is the newtcol16
 Thu Jan 02 08:16:00 2020 PST | 14 | 16 | prev16    | this is the newtcol16
 Thu Jan 02 08:16:00 2020 PST | 15 | 16 | prev16    | this is the newtcol16
 Thu Jan 02 08:16:00 2020 PST | 16 | 16 | prev16    | this is the newtcol16

--number of rows in the chunk
SELECT count(*) from _timescaledb_internal.compress_hyper_2_2_chunk;
 count 
-------
     1

SELECT count(*)
FROM show_chunks('test1') c;
 count 
-------
     1

COPY test1 FROM STDIN DELIMITER ',';
COPY test1 FROM STDIN DELIMITER ',';
--number of rows in the chunk
SELECT count(*) from _timescaledb_internal.compress_hyper_2_2_chunk;
 count 
-------
     1

SELECT count(*)
FROM show_chunks('test1') c;
 count 
-------
     1

SELECT * FROM test1 WHERE newtcol IS NOT NULL ORDER BY 1,2,3;
            timec             |  i  |  b  |    t    |        newtcol         
------------------------------+-----+-----+---------+------------------------
 Thu Jan 02 08:16:00 2020 PST |  11 |  16 | prev16  | this is the newtcol16
 Thu Jan 02 08:16:00 2020 PST |  11 |  16 | prev16  | newtcol16
 Thu Jan 02 08:16:00 2020 PST |  12 |  16 | prev16  | newtcol16
 Thu Jan 02 08:16:00 2020 PST |  12 |  16 | prev16  | this is the newtcol16
 Thu Jan 02 08:16:00 2020 PST |  13 |  16 | prev16  | this is the newtcol16
 Thu Jan 02 08:16:00 2020 PST |  13 |  16 | prev16  | newtcol16
 Thu Jan 02 08:16:00 2020 PST |  14 |  16 | prev16  | this is the newtcol16
 Thu Jan 02 08:16:00 2020 PST |  15 |  16 | prev16  | this is the newtcol16
 Thu Jan 02 08:16:00 2020 PST |  16 |  16 | prev16  | this is the newtcol16
 Thu Jan 02 08:16:00 2020 PST | 100 | 101 | prev101 | newtcol101
 Thu Jan 02 08:16:00 2020 PST | 100 | 101 | prev101 | this is the newtcol101

DROP TABLE test1;
-- TEST 3 add tests with dropped columns on hypertable
-- also tests defaults
CREATE TABLE test2 ( itime integer, b bigint, t text);
SELECT table_name from create_hypertable('test2', 'itime', chunk_time_interval=> 10::integer);
 table_name 
------------
 test2

--create a chunk
INSERT INTO test2 SELECT t, 10,  'first'::text FROM generate_series(1, 7) t;
ALTER TABLE test2 DROP COLUMN b;
ALTER TABLE test2 ADD COLUMN c INT DEFAULT -15;
ALTER TABLE test2 ADD COLUMN d INT;
--create a new chunk
INSERT INTO test2 SELECT t, 'second'::text, 120, 1 FROM generate_series(11, 15) t;
ALTER TABLE test2 set (timescaledb.compress, timescaledb.compress_segmentby = '', timescaledb.compress_orderby = 'c, itime DESC');
SELECT count(*) from ( SELECT compress_chunk(c)
FROM show_chunks('test2') c ) q;
 count 
-------
     2

--write to both old chunks and new chunks
INSERT INTO test2(itime ,t , d)  SELECT 9, '9', 90 ;
INSERT INTO test2(itime ,t , d)  SELECT 17, '17', 1700 ;
COPY test2(itime,t,d) FROM STDIN DELIMITER ',';
SELECT count(*) FROM show_chunks('test2') q;
 count 
-------
     2

SELECT * from test2 WHERE itime >= 9 and itime <= 17
ORDER BY 1,2,3;
 itime |   t    |  c  |  d   
-------+--------+-----+------
     9 | 9      | -15 |   90
     9 | 9copy  | -15 |   90
    11 | second | 120 |    1
    12 | second | 120 |    1
    13 | second | 120 |    1
    14 | second | 120 |    1
    15 | second | 120 |    1
    17 | 17     | -15 | 1700
    17 | 17copy | -15 | 1700

-- now add a column to the compressed hypertable
-- we have dropped columns and newly added columns now
ALTER TABLE test2 ADD COLUMN charcol varchar(45);
INSERT INTO test2(itime ,t , d, charcol)
values (2, '2', 22, 'thisis22'), (17, '17', 1701, 'thisis1700') ;
COPY test2(itime,t,d,charcol) FROM STDIN DELIMITER ',';
SELECT * from test2 where itime = 2 or itime =17
ORDER BY 1, 2, 3, 4, 5;
 itime |   t    |  c  |  d   |  charcol   
-------+--------+-----+------+------------
     2 | 2      | -15 |   22 | thisis22
     2 | 2copy  | -15 |   22 | 22copy
     2 | first  | -15 |      | 
    17 | 17     | -15 | 1700 | 
    17 | 17     | -15 | 1701 | thisis1700
    17 | 17copy | -15 | 1700 | 
    17 | 17copy | -15 | 1701 | 1700copy

DROP TABLE test2;
--- TEST3 tables with defaults ---
--  sequences, generated values, check constraints into compressed chunks
CREATE TABLE test2 (timec timestamptz ,
      i integer CHECK ( i > 10) ,
      b bigint default 20 ,
      t text NOT NULL,
      CONSTRAINT rowconstr CHECK ( b > i )
);
SELECT table_name from create_hypertable('test2', 'timec', chunk_time_interval=> INTERVAL '7 days');
 table_name 
------------
 test2

ALTER TABLE test2 set (timescaledb.compress,
timescaledb.compress_segmentby = 'b',
timescaledb.compress_orderby = 'timec DESC');
INSERT INTO test2 values('2020-01-02 11:16:00-05' , 100, 105, 'first' );
SELECT compress_chunk(c)
FROM show_chunks('test2') c;
             compress_chunk             
----------------------------------------
 _timescaledb_internal._hyper_5_7_chunk

-- test if default value for b is used
INSERT INTO test2(timec, i, t) values('2020-01-02 10:16:00-05' , 11, 'default' );
COPY test2(timec,i,t) FROM STDIN DELIMITER ',';
SELECT b from test2 ORDER BY 1;
  b  
-----
  20
  20
 105

\set ON_ERROR_STOP 0
--null value for t, should fail
INSERT INTO test2 values ( '2020-01-02 01:00:00-05', 100, 200, NULL);
ERROR:  null value in column "t" of relation "_hyper_5_7_chunk" violates not-null constraint
COPY test2 FROM STDIN DELIMITER ',' NULL 'NULL';
ERROR:  null value in column "t" of relation "_hyper_5_7_chunk" violates not-null constraint
-- i=1, should fail
INSERT INTO test2 values ( '2020-01-02 01:00:00-05', 1, 10, 'null i');
ERROR:  new row for relation "_hyper_5_7_chunk" violates check constraint "test2_i_check"
COPY test2 FROM STDIN DELIMITER ',';
ERROR:  new row for relation "_hyper_5_7_chunk" violates check constraint "test2_i_check"
-- b < i, should fail
INSERT INTO test2 values ( '2020-01-02 01:00:00-05', 22, 1, 'null i');
ERROR:  new row for relation "_hyper_5_7_chunk" violates check constraint "rowconstr"
COPY test2 FROM STDIN DELIMITER ',';
ERROR:  new row for relation "_hyper_5_7_chunk" violates check constraint "rowconstr"
\set ON_ERROR_STOP 1
--verify we are still INSERTing into the compressed chunk i.e did not
--create a new chunk
SELECT count(c)
FROM show_chunks('test2') c;
 count 
-------
     1

-- TEST4 with sequence .
CREATE SEQUENCE vessel_id_seq
    INCREMENT 1
    START 1    MINVALUE 1
    MAXVALUE 9223372036854775807
    CACHE 1;
CREATE TABLE vessels (timec timestamptz ,
      id bigint NOT NULL DEFAULT nextval('vessel_id_seq'::regclass),
      i integer CHECK ( i > 10) ,
      b bigint default 20 ,
      t text NOT NULL,
      CONSTRAINT rowconstr CHECK ( b > i )
);
SELECT table_name from create_hypertable('vessels', 'timec', chunk_time_interval=> INTERVAL '7 days');
 table_name 
------------
 vessels

ALTER TABLE vessels set (timescaledb.compress,
timescaledb.compress_segmentby = 'b',
timescaledb.compress_orderby = 'timec DESC');
INSERT INTO vessels(timec, i, b, t) values('2020-01-02 11:16:00-05' , 100, 105, 'first' );
SELECT compress_chunk(c)
FROM show_chunks('vessels') c;
             compress_chunk             
----------------------------------------
 _timescaledb_internal._hyper_7_9_chunk

-- test if default value for b and sequence value for id is used
INSERT INTO vessels(timec, i, t) values('2020-01-02 10:16:00-05' , 11, 'default' );
COPY vessels(timec,i,t )FROM STDIN DELIMITER ',';
SELECT timec, id, b from vessels order by 2, 1;
            timec             | id |  b  
------------------------------+----+-----
 Thu Jan 02 08:16:00 2020 PST |  1 | 105
 Thu Jan 02 07:16:00 2020 PST |  2 |  20
 Thu Jan 02 07:16:00 2020 PST |  3 |  20

-- TEST5 generated values
CREATE table test_gen (
    id int generated by default AS IDENTITY ,
    payload text
);
SELECT create_hypertable('test_gen', 'id', chunk_time_interval=>10);
   create_hypertable   
-----------------------
 (9,public,test_gen,t)

ALTER TABLE test_gen set (timescaledb.compress);
INSERT into test_gen (payload) SELECT generate_series(1,15) ;
SELECT max(id) from test_gen;
 max 
-----
  15

SELECT compress_chunk(c)
FROM show_chunks('test_gen') c;
             compress_chunk              
-----------------------------------------
 _timescaledb_internal._hyper_9_11_chunk
 _timescaledb_internal._hyper_9_12_chunk

INSERT INTO test_gen (payload) values(17);
SELECT * from test_gen WHERE id = (Select max(id) from test_gen);
 id | payload 
----+---------
 16 | 17

COPY test_gen(payload) FROM STDIN DELIMITER ',';
SELECT * from test_gen WHERE id = (Select max(id) from test_gen);
 id | payload 
----+---------
 17 | 18

-- TEST triggers
-- insert into compressed hypertables with triggers
CREATE OR REPLACE FUNCTION row_trig_value_gt_0() RETURNS TRIGGER AS $$
BEGIN
  RAISE NOTICE 'Trigger % % % % on %: % %', TG_NAME, TG_WHEN, TG_OP, TG_LEVEL, TG_TABLE_NAME, NEW, OLD;
  IF NEW.value <= 0 THEN
    RAISE NOTICE 'Skipping insert';
    RETURN NULL;
  END IF;
  RETURN NEW;
END
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION row_trig_value_mod() RETURNS TRIGGER AS $$
BEGIN
  RAISE NOTICE 'Trigger % % % % on %: % %', TG_NAME, TG_WHEN, TG_OP, TG_LEVEL, TG_TABLE_NAME, NEW, OLD;
  NEW.value = NEW.value + 100;
  RETURN NEW;
END
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION stmt_trig_info() RETURNS TRIGGER AS $$
BEGIN
  RAISE NOTICE 'Trigger % % % % on %: % %', TG_NAME, TG_WHEN, TG_OP, TG_LEVEL, TG_TABLE_NAME, NEW, OLD;
  RETURN NEW;
END
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION stmt_trig_error() RETURNS TRIGGER AS $$
BEGIN
  RAISE EXCEPTION 'Trigger % % % % on %: % %', TG_NAME, TG_WHEN, TG_OP, TG_LEVEL, TG_TABLE_NAME, NEW, OLD;
  RETURN NULL;
END
$$ LANGUAGE plpgsql;
CREATE TABLE trigger_test(time timestamptz NOT NULL, device int, value int, dropcol1 int);
SELECT create_hypertable('trigger_test','time');
     create_hypertable      
----------------------------
 (11,public,trigger_test,t)

--create chunk and compress
--the first chunk is created with dropcol1
INSERT INTO trigger_test(time, device, value,dropcol1) SELECT '2000-01-01',1,1,1;
-- drop the column before we compress
ALTER TABLE trigger_test DROP COLUMN dropcol1;
ALTER TABLE trigger_test SET (timescaledb.compress,timescaledb.compress_segmentby='device');
SELECT compress_chunk(c) FROM show_chunks('trigger_test') c;
              compress_chunk              
------------------------------------------
 _timescaledb_internal._hyper_11_15_chunk

-- BEFORE ROW trigger
CREATE TRIGGER t1 BEFORE INSERT ON trigger_test FOR EACH ROW EXECUTE FUNCTION row_trig_value_gt_0();
-- should be 1
SELECT count(*) FROM trigger_test;
 count 
-------
     1

-- try insert that gets skipped by trigger
INSERT INTO trigger_test SELECT '2000-01-01',1,0;
NOTICE:  Trigger t1 BEFORE INSERT ROW on _hyper_11_15_chunk: ("Sat Jan 01 00:00:00 2000 PST",1,0) <NULL>
NOTICE:  Skipping insert
COPY trigger_test FROM STDIN DELIMITER ',';
NOTICE:  Trigger t1 BEFORE INSERT ROW on _hyper_11_15_chunk: ("Fri Dec 31 22:00:00 1999 PST",1,0) <NULL>
NOTICE:  Skipping insert
-- should not insert rows. count is 1
SELECT count(*) FROM trigger_test;
 count 
-------
     1

-- try again without being skipped
BEGIN;
INSERT INTO trigger_test SELECT '2000-01-01',1,1;
NOTICE:  Trigger t1 BEFORE INSERT ROW on _hyper_11_15_chunk: ("Sat Jan 01 00:00:00 2000 PST",1,1) <NULL>
COPY trigger_test FROM STDIN DELIMITER ',';
NOTICE:  Trigger t1 BEFORE INSERT ROW on _hyper_11_15_chunk: ("Fri Dec 31 22:00:00 1999 PST",1,1) <NULL>
-- should be 3
SELECT count(*) FROM trigger_test;
 count 
-------
     3

ROLLBACK;
DROP TRIGGER t1 ON trigger_test;
-- BEFORE ROW trigger that modifies tuple
CREATE TRIGGER t1_mod BEFORE INSERT ON trigger_test FOR EACH ROW EXECUTE FUNCTION row_trig_value_mod();
BEGIN;
INSERT INTO trigger_test SELECT '2000-01-01',1,11;
NOTICE:  Trigger t1_mod BEFORE INSERT ROW on _hyper_11_15_chunk: ("Sat Jan 01 00:00:00 2000 PST",1,11) <NULL>
COPY trigger_test FROM STDIN DELIMITER ',';
NOTICE:  Trigger t1_mod BEFORE INSERT ROW on _hyper_11_15_chunk: ("Fri Dec 31 22:00:00 1999 PST",1,12) <NULL>
-- value for both new tuples should be > 100
SELECT * FROM trigger_test ORDER BY 3;
             time             | device | value 
------------------------------+--------+-------
 Sat Jan 01 00:00:00 2000 PST |      1 |     1
 Sat Jan 01 00:00:00 2000 PST |      1 |   111
 Fri Dec 31 22:00:00 1999 PST |      1 |   112

ROLLBACK;
DROP TRIGGER t1_mod ON trigger_test;
-- BEFORE ROW conditional trigger
CREATE TRIGGER t1_cond BEFORE INSERT ON trigger_test FOR EACH ROW WHEN (NEW.value > 10) EXECUTE FUNCTION row_trig_value_mod();
-- test with condition being false
BEGIN;
INSERT INTO trigger_test SELECT '2000-01-01',1,1;
COPY trigger_test FROM STDIN DELIMITER ',';
-- value for both new tuples should not be > 100
SELECT * FROM trigger_test ORDER BY 3;
             time             | device | value 
------------------------------+--------+-------
 Sat Jan 01 00:00:00 2000 PST |      1 |     1
 Sat Jan 01 00:00:00 2000 PST |      1 |     1
 Fri Dec 31 22:00:00 1999 PST |      1 |     2

ROLLBACK;
-- test with condition being true
BEGIN;
INSERT INTO trigger_test SELECT '2000-01-01',1,11;
NOTICE:  Trigger t1_cond BEFORE INSERT ROW on _hyper_11_15_chunk: ("Sat Jan 01 00:00:00 2000 PST",1,11) <NULL>
COPY trigger_test FROM STDIN DELIMITER ',';
NOTICE:  Trigger t1_cond BEFORE INSERT ROW on _hyper_11_15_chunk: ("Fri Dec 31 22:00:00 1999 PST",1,12) <NULL>
-- value for both new tuples should be > 100
SELECT * FROM trigger_test ORDER BY 3;
             time             | device | value 
------------------------------+--------+-------
 Sat Jan 01 00:00:00 2000 PST |      1 |     1
 Sat Jan 01 00:00:00 2000 PST |      1 |   111
 Fri Dec 31 22:00:00 1999 PST |      1 |   112

ROLLBACK;
DROP TRIGGER t1_cond ON trigger_test;
-- BEFORE ROW error in trigger
CREATE TRIGGER t1_error BEFORE INSERT ON trigger_test FOR EACH ROW EXECUTE FUNCTION stmt_trig_error();
\set ON_ERROR_STOP 0
INSERT INTO trigger_test SELECT '2000-01-01',1,11;
ERROR:  Trigger t1_error BEFORE INSERT ROW on _hyper_11_15_chunk: ("Sat Jan 01 00:00:00 2000 PST",1,11) <NULL>
COPY trigger_test FROM STDIN DELIMITER ',';
ERROR:  Trigger t1_error BEFORE INSERT ROW on _hyper_11_15_chunk: ("Fri Dec 31 22:00:00 1999 PST",1,12) <NULL>
\set ON_ERROR_STOP 1
-- should not insert rows. count is 1
SELECT count(*) FROM trigger_test;
 count 
-------
     1

DROP TRIGGER t1_error ON trigger_test;
-- BEFORE STATEMENT trigger
CREATE TRIGGER t2 BEFORE INSERT ON trigger_test FOR EACH STATEMENT EXECUTE FUNCTION stmt_trig_info();
BEGIN;
INSERT INTO trigger_test SELECT '2000-01-01',1,0;
NOTICE:  Trigger t2 BEFORE INSERT STATEMENT on trigger_test: <NULL> <NULL>
COPY trigger_test FROM STDIN DELIMITER ',';
NOTICE:  Trigger t2 BEFORE INSERT STATEMENT on trigger_test: <NULL> <NULL>
-- should be 3
SELECT count(*) FROM trigger_test;
 count 
-------
     3

ROLLBACK;
DROP TRIGGER t2 ON trigger_test;
-- BEFORE STATEMENT error in trigger
CREATE TRIGGER t2_error BEFORE INSERT ON trigger_test FOR EACH STATEMENT EXECUTE FUNCTION stmt_trig_error();
\set ON_ERROR_STOP 0
INSERT INTO trigger_test SELECT '2000-01-01',1,11;
ERROR:  Trigger t2_error BEFORE INSERT STATEMENT on trigger_test: <NULL> <NULL>
COPY trigger_test FROM STDIN DELIMITER ',';
ERROR:  Trigger t2_error BEFORE INSERT STATEMENT on trigger_test: <NULL> <NULL>
\set ON_ERROR_STOP 1
-- should not insert rows. count is 1
SELECT count(*) FROM trigger_test;
 count 
-------
     1

DROP TRIGGER t2_error ON trigger_test;
-- AFTER STATEMENT trigger
CREATE TRIGGER t3 AFTER INSERT ON trigger_test FOR EACH STATEMENT EXECUTE FUNCTION stmt_trig_info();
BEGIN;
INSERT INTO trigger_test SELECT '2000-01-01',1,0;
NOTICE:  Trigger t3 AFTER INSERT STATEMENT on trigger_test: <NULL> <NULL>
COPY trigger_test FROM STDIN DELIMITER ',';
NOTICE:  Trigger t3 AFTER INSERT STATEMENT on trigger_test: <NULL> <NULL>
-- should be 3
SELECT count(*) FROM trigger_test;
 count 
-------
     3

ROLLBACK;
DROP TRIGGER t3 ON trigger_test;
-- AFTER STATEMENT error in trigger
CREATE TRIGGER t3_error AFTER INSERT ON trigger_test FOR EACH STATEMENT EXECUTE FUNCTION stmt_trig_error();
\set ON_ERROR_STOP 0
INSERT INTO trigger_test SELECT '2000-01-01',1,11;
ERROR:  Trigger t3_error AFTER INSERT STATEMENT on trigger_test: <NULL> <NULL>
COPY trigger_test FROM STDIN DELIMITER ',';
ERROR:  Trigger t3_error AFTER INSERT STATEMENT on trigger_test: <NULL> <NULL>
\set ON_ERROR_STOP 1
-- should not insert rows. count is 1
SELECT count(*) FROM trigger_test;
 count 
-------
     1

DROP TRIGGER t3_error ON trigger_test;
-- test unsupported features are blocked
-- INSTEAD OF INSERT is only supported for VIEWs
\set ON_ERROR_STOP 0
CREATE TRIGGER t4_instead INSTEAD OF INSERT ON trigger_test FOR EACH STATEMENT EXECUTE FUNCTION stmt_trig_info();
ERROR:  "trigger_test" is a table
\set ON_ERROR_STOP 1
-- AFTER INSERT ROW trigger not supported on compressed chunk
CREATE TRIGGER t4_ar AFTER INSERT ON trigger_test FOR EACH ROW EXECUTE FUNCTION stmt_trig_info();
\set ON_ERROR_STOP 0
\set VERBOSITY default
INSERT INTO trigger_test SELECT '2000-01-01',1,0;
NOTICE:  Trigger t4_ar AFTER INSERT ROW on _hyper_11_15_chunk: ("Sat Jan 01 00:00:00 2000 PST",1,0) <NULL>
COPY trigger_test FROM STDIN DELIMITER ',';
NOTICE:  Trigger t4_ar AFTER INSERT ROW on _hyper_11_15_chunk: ("Fri Dec 31 22:00:00 1999 PST",1,0) <NULL>
\set VERBOSITY terse
\set ON_ERROR_STOP 1
-- should not insert rows. count is 1
SELECT count(*) FROM trigger_test;
 count 
-------
     3

BEGIN;
INSERT INTO trigger_test SELECT '2001-01-01',1,0;
NOTICE:  Trigger t4_ar AFTER INSERT ROW on _hyper_11_17_chunk: ("Mon Jan 01 00:00:00 2001 PST",1,0) <NULL>
COPY trigger_test FROM STDIN DELIMITER ',';
NOTICE:  Trigger t4_ar AFTER INSERT ROW on _hyper_11_17_chunk: ("Sun Dec 31 22:00:00 2000 PST",1,0) <NULL>
-- insert into new uncompressed chunk should not be blocked
SELECT count(*) FROM trigger_test;
 count 
-------
     5

ROLLBACK;
DROP TRIGGER t4_ar ON trigger_test;
-- CONSTRAINT trigger not supported on compressed chunk
CREATE CONSTRAINT TRIGGER t4_constraint AFTER INSERT ON trigger_test FOR EACH ROW EXECUTE FUNCTION stmt_trig_info();
\set ON_ERROR_STOP 0
INSERT INTO trigger_test SELECT '2000-01-01',1,0;
NOTICE:  Trigger t4_constraint AFTER INSERT ROW on _hyper_11_15_chunk: ("Sat Jan 01 00:00:00 2000 PST",1,0) <NULL>
COPY trigger_test FROM STDIN DELIMITER ',';
NOTICE:  Trigger t4_constraint AFTER INSERT ROW on _hyper_11_15_chunk: ("Fri Dec 31 22:00:00 1999 PST",1,0) <NULL>
\set ON_ERROR_STOP 1
-- should not insert rows. count is 1
SELECT count(*) FROM trigger_test;
 count 
-------
     5

DROP trigger t4_constraint ON trigger_test;
-- test row triggers after adding/dropping columns
-- now add a new column to the table and insert into a new chunk
ALTER TABLE trigger_test ADD COLUMN addcolv varchar(10);
ALTER TABLE trigger_test ADD COLUMN addcoli integer;
INSERT INTO trigger_test(time, device, value, addcolv, addcoli)
VALUES ( '2010-01-01', 10, 10, 'ten', 222);
SELECT compress_chunk(c, true) FROM show_chunks('trigger_test') c;
              compress_chunk              
------------------------------------------
 _timescaledb_internal._hyper_11_15_chunk
 _timescaledb_internal._hyper_11_18_chunk

CREATE TRIGGER t1_mod BEFORE INSERT ON trigger_test FOR EACH ROW EXECUTE FUNCTION row_trig_value_mod();
SELECT count(*) FROM trigger_test;
 count 
-------
     6

BEGIN;
INSERT INTO trigger_test VALUES
                   ( '2000-01-01',1,11, 'eleven', 111),
                   ( '2010-01-01',10,10, 'ten', 222);
NOTICE:  Trigger t1_mod BEFORE INSERT ROW on _hyper_11_15_chunk: ("Sat Jan 01 00:00:00 2000 PST",1,11,eleven,111) <NULL>
NOTICE:  Trigger t1_mod BEFORE INSERT ROW on _hyper_11_18_chunk: ("Fri Jan 01 00:00:00 2010 PST",10,10,ten,222) <NULL>
SELECT * FROM trigger_test ORDER BY 1 ,2, 3, 5;
             time             | device | value | addcolv | addcoli 
------------------------------+--------+-------+---------+---------
 Fri Dec 31 22:00:00 1999 PST |      1 |     0 |         |        
 Fri Dec 31 22:00:00 1999 PST |      1 |     0 |         |        
 Sat Jan 01 00:00:00 2000 PST |      1 |     0 |         |        
 Sat Jan 01 00:00:00 2000 PST |      1 |     0 |         |        
 Sat Jan 01 00:00:00 2000 PST |      1 |     1 |         |        
 Sat Jan 01 00:00:00 2000 PST |      1 |   111 | eleven  |     111
 Fri Jan 01 00:00:00 2010 PST |     10 |    10 | ten     |     222
 Fri Jan 01 00:00:00 2010 PST |     10 |   110 | ten     |     222

ROLLBACK;
DROP TABLE trigger_test;
-- test interaction between newly inserted batches and pathkeys/ordered append
--
-- The following test operates on a small relation. By using the
-- timescaledb.enable_decompression_sorted_merge optimization, we are pushing a sort node
-- below the DecompressChunk node, which operates on the batches. This could lead to flaky
-- tests because the input data is small and PostgreSQL switches from IndexScans to
-- SequentialScans. Disable the optimization for the following test to ensure we have
-- stable query plans in all CI environments.
SET timescaledb.enable_decompression_sorted_merge = 0;
CREATE TABLE test_ordering(time int);
SELECT table_name FROM create_hypertable('test_ordering','time',chunk_time_interval:=100);
  table_name   
---------------
 test_ordering

ALTER TABLE test_ordering SET (timescaledb.compress,timescaledb.compress_orderby='time desc');
INSERT INTO test_ordering VALUES (5),(4),(3);
-- should be ordered append
:PREFIX SELECT * FROM test_ordering ORDER BY 1;
--- QUERY PLAN ---
 Index Only Scan Backward using _hyper_13_20_chunk_test_ordering_time_idx on _hyper_13_20_chunk

SELECT compress_chunk(format('%I.%I',chunk_schema,chunk_name), true) FROM timescaledb_information.chunks WHERE hypertable_name = 'test_ordering';
              compress_chunk              
------------------------------------------
 _timescaledb_internal._hyper_13_20_chunk

VACUUM ANALYZE test_ordering;
-- should be ordered append
:PREFIX SELECT * FROM test_ordering ORDER BY 1;
--- QUERY PLAN ---
 Custom Scan (ColumnarScan) on _hyper_13_20_chunk
   ->  Sort
         Sort Key: compress_hyper_14_21_chunk._ts_meta_min_1, compress_hyper_14_21_chunk._ts_meta_max_1
         ->  Seq Scan on compress_hyper_14_21_chunk

INSERT INTO test_ordering SELECT 1;
VACUUM ANALYZE test_ordering;
-- should not be ordered append
-- regression introduced by #5599:
-- for the case of a single chunk, there is an additional redundant sort node below decompress chunk
-- this is due to pushing down the sort node below decompress chunk. In most cases that is beneficial,
-- but here a more optimal plan would have been a mergeAppend.
-- It was hard to include a path without pushed down sort for consideration, as `add_path` would reject
-- the path with sort pushdown, which is desirable in most cases
:PREFIX SELECT * FROM test_ordering ORDER BY 1;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on test_ordering
   Order: test_ordering."time"
   ->  Merge Append
         Sort Key: test_ordering."time"
         ->  Custom Scan (ColumnarScan) on _hyper_13_20_chunk
               ->  Sort
                     Sort Key: compress_hyper_14_21_chunk._ts_meta_min_1, compress_hyper_14_21_chunk._ts_meta_max_1
                     ->  Seq Scan on compress_hyper_14_21_chunk
         ->  Index Only Scan Backward using _hyper_13_20_chunk_test_ordering_time_idx on _hyper_13_20_chunk

INSERT INTO test_ordering VALUES (105),(104),(103);
VACUUM ANALYZE test_ordering;
-- should be ordered append
:PREFIX SELECT * FROM test_ordering ORDER BY 1;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on test_ordering
   Order: test_ordering."time"
   ->  Merge Append
         Sort Key: test_ordering."time"
         ->  Custom Scan (ColumnarScan) on _hyper_13_20_chunk
               ->  Sort
                     Sort Key: compress_hyper_14_21_chunk._ts_meta_min_1, compress_hyper_14_21_chunk._ts_meta_max_1
                     ->  Seq Scan on compress_hyper_14_21_chunk
         ->  Index Only Scan Backward using _hyper_13_20_chunk_test_ordering_time_idx on _hyper_13_20_chunk
   ->  Index Only Scan Backward using _hyper_13_22_chunk_test_ordering_time_idx on _hyper_13_22_chunk

--insert into compressed + uncompressed chunk
INSERT INTO test_ordering VALUES (21), (22),(113);
SELECT count(*) FROM test_ordering;
 count 
-------
    10

INSERT INTO test_ordering VALUES (106) RETURNING *;
 time 
------
  106

-- insert into compressed chunk does support RETURNING
INSERT INTO test_ordering VALUES (23), (24), (115) RETURNING *;
 time 
------
   23
   24
  115

INSERT INTO test_ordering VALUES (23), (24), (115) RETURNING tableoid::regclass, *;
                 tableoid                 | time 
------------------------------------------+------
 _timescaledb_internal._hyper_13_20_chunk |   23
 _timescaledb_internal._hyper_13_20_chunk |   24
 _timescaledb_internal._hyper_13_22_chunk |  115

SELECT compress_chunk(format('%I.%I',chunk_schema,chunk_name), true) FROM timescaledb_information.chunks WHERE hypertable_name = 'test_ordering';
              compress_chunk              
------------------------------------------
 _timescaledb_internal._hyper_13_20_chunk
 _timescaledb_internal._hyper_13_22_chunk

VACUUM ANALYZE test_ordering;
-- should be ordered append
:PREFIX SELECT * FROM test_ordering ORDER BY 1;
--- QUERY PLAN ---
 Custom Scan (ChunkAppend) on test_ordering
   Order: test_ordering."time"
   ->  Custom Scan (ColumnarScan) on _hyper_13_20_chunk
         ->  Sort
               Sort Key: compress_hyper_14_21_chunk._ts_meta_min_1, compress_hyper_14_21_chunk._ts_meta_max_1
               ->  Seq Scan on compress_hyper_14_21_chunk
   ->  Custom Scan (ColumnarScan) on _hyper_13_22_chunk
         ->  Sort
               Sort Key: compress_hyper_14_23_chunk._ts_meta_min_1, compress_hyper_14_23_chunk._ts_meta_max_1
               ->  Seq Scan on compress_hyper_14_23_chunk

SET timescaledb.enable_decompression_sorted_merge = 1;
-- TEST cagg triggers with insert into compressed chunk
CREATE TABLE conditions (
      timec        TIMESTAMPTZ       NOT NULL,
      temperature DOUBLE PRECISION  NULL,
      humidity    DOUBLE PRECISION  NULL
    );
SELECT table_name from create_hypertable( 'conditions', 'timec');
 table_name 
------------
 conditions

INSERT INTO conditions
SELECT generate_series('2010-01-01 09:00:00-08'::timestamptz, '2010-01-03 09:00:00-08'::timestamptz, '1 day'), 55 , 45;
CREATE MATERIALIZED VIEW cagg_conditions WITH (timescaledb.continuous,
   timescaledb.materialized_only = true)
AS
SELECT time_bucket( '7 days', timec) bkt, count(*) cnt, sum(temperature) sumb
FROM conditions
GROUP BY time_bucket('7 days', timec);
NOTICE:  refreshing continuous aggregate "cagg_conditions"
SELECT * FROM cagg_conditions ORDER BY 1;
             bkt              | cnt | sumb 
------------------------------+-----+------
 Sun Dec 27 16:00:00 2009 PST |   3 |  165

ALTER TABLE conditions SET (timescaledb.compress);
SELECT  compress_chunk(ch) FROM show_chunks('conditions') ch;
              compress_chunk              
------------------------------------------
 _timescaledb_internal._hyper_15_24_chunk

SELECT chunk_name, range_start, range_end, is_compressed
FROM timescaledb_information.chunks
WHERE hypertable_name = 'conditions';
     chunk_name     |         range_start          |          range_end           | is_compressed 
--------------------+------------------------------+------------------------------+---------------
 _hyper_15_24_chunk | Wed Dec 30 16:00:00 2009 PST | Wed Jan 06 16:00:00 2010 PST | t

--now insert into compressed chunk
INSERT INTO conditions VALUES('2010-01-01 12:00:00-08', 10, 20);
INSERT INTO conditions VALUES('2010-01-01 12:00:00-08', 10, 20);
--refresh cagg, should have updated info
CALL refresh_continuous_aggregate('cagg_conditions', NULL, '2011-01-01 12:00:00-08' );
SELECT * FROM cagg_conditions ORDER BY 1;
             bkt              | cnt | sumb 
------------------------------+-----+------
 Sun Dec 27 16:00:00 2009 PST |   5 |  185

-- TEST cagg triggers with copy into compressed chunk
COPY conditions FROM STDIN DELIMITER ',';
--refresh cagg, should have updated info
CALL refresh_continuous_aggregate('cagg_conditions', NULL, '2011-01-01 12:00:00-08' );
SELECT * FROM cagg_conditions ORDER BY 1;
             bkt              | cnt | sumb 
------------------------------+-----+------
 Sun Dec 27 16:00:00 2009 PST |   8 |  485

-- TEST direct insert into internal compressed hypertable should be blocked
CREATE TABLE direct_insert(time timestamptz not null);
SELECT table_name FROM create_hypertable('direct_insert','time');
  table_name   
---------------
 direct_insert

ALTER TABLE direct_insert SET(timescaledb.compress);
SELECT
  format('%I.%I', ht.schema_name, ht.table_name) AS "TABLENAME"
FROM
  _timescaledb_catalog.hypertable ht
  INNER JOIN _timescaledb_catalog.hypertable uncompress ON (ht.id = uncompress.compressed_hypertable_id
      AND uncompress.table_name = 'direct_insert') \gset
\set ON_ERROR_STOP 0
INSERT INTO :TABLENAME SELECT;
ERROR:  direct insert into internal compressed hypertable is not supported
\set ON_ERROR_STOP 1
-- Test that inserting into a compressed table works even when the
-- column has been dropped.
CREATE TABLE test4 (
    timestamp timestamp without time zone not null,
    ident text not null,
    one double precision,
    two double precision
);
SELECT * FROM create_hypertable('test4', 'timestamp');
WARNING:  column type "timestamp without time zone" used for "timestamp" does not follow best practices
 hypertable_id | schema_name | table_name | created 
---------------+-------------+------------+---------
            20 | public      | test4      | t

INSERT INTO test4 ( timestamp, ident ) VALUES ( '2021-10-14 17:50:16.207', '2' );
INSERT INTO test4 ( timestamp, ident ) VALUES ( '2021-11-14 17:50:16.207', '1' );
INSERT INTO test4 ( timestamp, ident ) VALUES ( '2021-12-14 17:50:16.207', '3' );
INSERT INTO test4 ( timestamp, ident ) VALUES ( '2022-01-14 17:50:16.207', '4' );
INSERT INTO test4 ( timestamp, ident ) VALUES ( '2022-02-14 17:50:16.207', '5' );
INSERT INTO test4 ( timestamp, ident ) VALUES ( '2022-03-14 17:50:16.207', '6' );
INSERT INTO test4 ( timestamp, ident ) VALUES ( '2022-04-14 17:50:16.207', '7' );
ALTER TABLE test4 SET (
    timescaledb.compress,
    timescaledb.compress_orderby = 'timestamp',
    timescaledb.compress_segmentby = 'ident'
);
select count(compress_chunk(ch)) FROM show_chunks('test4') ch;
 count 
-------
     7

ALTER TABLE test4 DROP COLUMN two;
INSERT INTO test4 VALUES ('2021-10-14 17:50:16.207', '7', NULL);
INSERT INTO test4 (timestamp, ident) VALUES ('2021-10-14 17:50:16.207', '7');
DROP TABLE test4;
-- Test COPY when trying to flush an empty buffer
-- In this case we send an empty slot used to
-- search for compressed tuples.
CREATE TABLE test_copy (
    timestamp int not null,
    id bigint
);
CREATE UNIQUE INDEX timestamp_id_idx ON test_copy(timestamp, id);
SELECT * FROM create_hypertable('test_copy', 'timestamp', chunk_time_interval=>10);
 hypertable_id | schema_name | table_name | created 
---------------+-------------+------------+---------
            22 | public      | test_copy  | t

ALTER TABLE test_copy SET (
    timescaledb.compress,
    timescaledb.compress_orderby = 'timestamp',
    timescaledb.compress_segmentby = 'id'
);
INSERT INTO test_copy SELECT generate_series(1,25,1), -1;
SELECT count(compress_chunk(ch)) FROM show_chunks('test_copy') ch;
 count 
-------
     3

\copy test_copy FROM data/copy_data.csv WITH CSV HEADER;
-- Also test the code path where the chunk insert state goes out of cache.
set timescaledb.max_open_chunks_per_insert = 1;
truncate table test_copy;
INSERT INTO test_copy SELECT generate_series(1,25,1), -1;
SELECT count(compress_chunk(ch)) FROM show_chunks('test_copy') ch;
 count 
-------
     3

\copy test_copy FROM data/copy_data.csv WITH CSV HEADER;
reset timescaledb.max_open_chunks_per_insert;
DROP TABLE test_copy;
-- Text limitting decompressed tuple during an insert
CREATE TABLE test_limit (
    timestamp int not null,
    id bigint
);
SELECT * FROM create_hypertable('test_limit', 'timestamp', chunk_time_interval=>1000);
 hypertable_id | schema_name | table_name | created 
---------------+-------------+------------+---------
            24 | public      | test_limit | t

INSERT INTO test_limit SELECT t, i FROM generate_series(1,10000,1) t CROSS JOIN generate_series(1,3,1) i;
CREATE UNIQUE INDEX timestamp_id_idx ON test_limit(timestamp, id);
ALTER TABLE test_limit SET (
    timescaledb.compress,
    timescaledb.compress_segmentby = '',
    timescaledb.compress_orderby = 'timestamp'
);
WARNING:  column "id" should be used for segmenting or ordering
SELECT count(compress_chunk(ch)) FROM show_chunks('test_limit') ch;
 count 
-------
    11

SET timescaledb.max_tuples_decompressed_per_dml_transaction = 1;
\set VERBOSITY default
\set ON_ERROR_STOP 0
-- Inserting in the same period should decompress tuples
INSERT INTO test_limit SELECT t, 2 FROM generate_series(1,6000,1000) t;
ERROR:  duplicate key value violates unique constraint "_hyper_24_53_chunk_timestamp_id_idx"
-- Setting to 0 should remove the limit.
SET timescaledb.max_tuples_decompressed_per_dml_transaction = 0;
INSERT INTO test_limit SELECT t, 2 FROM generate_series(1,6000,1000) t;
ERROR:  duplicate key value violates unique constraint "_hyper_24_53_chunk_timestamp_id_idx"
\set ON_ERROR_STOP 1
DROP TABLE test_limit;
RESET timescaledb.max_tuples_decompressed_per_dml_transaction;
-- test multiple unique constraints
CREATE TABLE multi_unique (time timestamptz NOT NULL, u1 int, u2 int, value float, unique(time, u1), unique(time, u2));
SELECT table_name FROM create_hypertable('multi_unique', 'time');
  table_name  
--------------
 multi_unique

ALTER TABLE multi_unique SET (timescaledb.compress, timescaledb.compress_segmentby = 'u1, u2');
INSERT INTO multi_unique VALUES('2024-01-01', 0, 0, 1.0);
SELECT count(compress_chunk(c)) FROM show_chunks('multi_unique') c;
 count 
-------
     1

\set ON_ERROR_STOP 0
-- all INSERTS should fail with constraint violation
BEGIN; INSERT INTO multi_unique VALUES('2024-01-01', 0, 0, 1.0); ROLLBACK;
ERROR:  duplicate key value violates unique constraint "75_1_multi_unique_time_u1_key"
DETAIL:  Key ("time", u1)=(Mon Jan 01 00:00:00 2024 PST, 0) already exists.
BEGIN; INSERT INTO multi_unique VALUES('2024-01-01', 0, 1, 1.0); ROLLBACK;
ERROR:  duplicate key value violates unique constraint "75_1_multi_unique_time_u1_key"
DETAIL:  Key ("time", u1)=(Mon Jan 01 00:00:00 2024 PST, 0) already exists.
BEGIN; INSERT INTO multi_unique VALUES('2024-01-01', 1, 0, 1.0); ROLLBACK;
ERROR:  duplicate key value violates unique constraint "75_2_multi_unique_time_u2_key"
DETAIL:  Key ("time", u2)=(Mon Jan 01 00:00:00 2024 PST, 0) already exists.
\set ON_ERROR_STOP 1
DROP TABLE multi_unique;
-- test insert with unique constraints and NULLs
CREATE TABLE unique_null(time timestamptz NOT NULL, u1 int, u2 int, value float, unique(time, u1, u2));
SELECT table_name FROM create_hypertable('unique_null', 'time');
 table_name  
-------------
 unique_null

ALTER TABLE unique_null SET (timescaledb.compress, timescaledb.compress_segmentby = 'u1, u2');
INSERT INTO unique_null VALUES('2024-01-01', 0, 0, 1.0);
SELECT count(compress_chunk(c)) FROM show_chunks('unique_null') c;
 count 
-------
     1

\set ON_ERROR_STOP 0
-- all INSERTS should fail with constraint violation
BEGIN; INSERT INTO unique_null VALUES('2024-01-01', 0, 0, 1.0); ROLLBACK;
ERROR:  duplicate key value violates unique constraint "77_3_unique_null_time_u1_u2_key"
\set ON_ERROR_STOP 1
-- neither of these should need to decompress
:ANALYZE INSERT INTO unique_null VALUES('2024-01-01', NULL, 1, 1.0);
--- QUERY PLAN ---
 Custom Scan (ModifyHypertable) (actual rows=0.00 loops=1)
   ->  Insert on unique_null (actual rows=0.00 loops=1)
         ->  Result (actual rows=1.00 loops=1)

SELECT count(*) FROM unique_null;
 count 
-------
     2

:ANALYZE INSERT INTO unique_null VALUES('2024-01-01', 1, NULL, 1.0);
--- QUERY PLAN ---
 Custom Scan (ModifyHypertable) (actual rows=0.00 loops=1)
   ->  Insert on unique_null (actual rows=0.00 loops=1)
         ->  Result (actual rows=1.00 loops=1)

SELECT count(*) FROM unique_null;
 count 
-------
     3

:ANALYZE INSERT INTO unique_null VALUES('2024-01-01', NULL, NULL, 1.0);
--- QUERY PLAN ---
 Custom Scan (ModifyHypertable) (actual rows=0.00 loops=1)
   ->  Insert on unique_null (actual rows=0.00 loops=1)
         ->  Result (actual rows=1.00 loops=1)

SELECT count(*) FROM unique_null;
 count 
-------
     4

INSERT INTO unique_null VALUES('2024-01-01', NULL, NULL, 1.0);
SELECT count(*) FROM unique_null;
 count 
-------
     5

DROP TABLE unique_null;
-- test insert with UNIQUE constraint and all compression algorithms
set timescaledb.enable_bool_compression = on;
CREATE TABLE unique_all(
	time timestamptz NOT NULL,
	device_id int,
	bool_type bool,
	numeric_type numeric,
	float_type float,
	text_type text,
	bigint_type bigint,
	jsonb_type jsonb
);
-- Since we don't test uniqueness when we detect a NULL value, making the constraint
-- with NULLS NOT DISTINCT
CREATE UNIQUE INDEX ultimate_unique ON unique_all(time, device_id, bool_type, numeric_type, float_type, text_type, bigint_type, jsonb_type) NULLS NOT DISTINCT;
SELECT table_name FROM create_hypertable('unique_all', 'time');
 table_name 
------------
 unique_all

ALTER TABLE unique_all SET (tsdb.compress, tsdb.compress_segmentby = 'device_id', tsdb.compress_orderby = 'time');
WARNING:  column "bool_type" should be used for segmenting or ordering
WARNING:  column "numeric_type" should be used for segmenting or ordering
WARNING:  column "float_type" should be used for segmenting or ordering
WARNING:  column "text_type" should be used for segmenting or ordering
WARNING:  column "bigint_type" should be used for segmenting or ordering
WARNING:  column "jsonb_type" should be used for segmenting or ordering
INSERT INTO unique_all VALUES('2024-01-01 00:00', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:01', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:02', 1, false, 1.0, 1.0, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:03', 1, true, 2.0, 1.0, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:04', 1, true, 1.0, 2.0, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:05', 1, true, 1.0, 1.0, 'second', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:06', 1, true, 1.0, 1.0, 'first', 2, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:07', 1, true, 1.0, 1.0, 'first', 1, '{"second":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:08', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:09', 1, NULL, 1.0, 1.0, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:10', 1, true, NULL, 1.0, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:11', 1, true, 1.0, NULL, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:12', 1, true, 1.0, 1.0, NULL, 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:13', 1, true, 1.0, 1.0, 'first', NULL, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:14', 1, true, 1.0, 1.0, 'first', 1, NULL);
SELECT count(compress_chunk(c)) FROM show_chunks('unique_all') c;
 count 
-------
     1

-- test duplicates
\set ON_ERROR_STOP 0
INSERT INTO unique_all VALUES('2024-01-01 00:00', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:01', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:02', 1, false, 1.0, 1.0, 'first', 1, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:03', 1, true, 2.0, 1.0, 'first', 1, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:04', 1, true, 1.0, 2.0, 'first', 1, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:05', 1, true, 1.0, 1.0, 'second', 1, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:06', 1, true, 1.0, 1.0, 'first', 2, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:07', 1, true, 1.0, 1.0, 'first', 1, '{"second":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:08', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:09', 1, NULL, 1.0, 1.0, 'first', 1, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:10', 1, true, NULL, 1.0, 'first', 1, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:11', 1, true, 1.0, NULL, 'first', 1, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:12', 1, true, 1.0, 1.0, NULL, 1, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:13', 1, true, 1.0, 1.0, 'first', NULL, '{"first":true}');
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:14', 1, true, 1.0, 1.0, 'first', 1, NULL);
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
\set ON_ERROR_STOP 1
-- test non-duplicates
INSERT INTO unique_all VALUES('2024-01-01 00:01:01', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:02', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:03', 1, true, 3.0, 1.0, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:04', 1, true, 1.0, 3.0, 'first', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:05', 1, true, 1.0, 1.0, 'third', 1, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:06', 1, true, 1.0, 1.0, 'first', 3, '{"first":true}');
INSERT INTO unique_all VALUES('2024-01-01 00:07', 1, true, 1.0, 1.0, 'first', 1, '{"third":true}');
-- test non-duplicates with non-NULL default values
ALTER TABLE unique_all ADD COLUMN added_non_null int DEFAULT 4;
DROP INDEX ultimate_unique;
CREATE UNIQUE INDEX ultimate_unique ON unique_all(time, device_id, bool_type, numeric_type, float_type, text_type, bigint_type, jsonb_type, added_non_null) NULLS NOT DISTINCT;
\set ON_ERROR_STOP 0
INSERT INTO unique_all VALUES('2024-01-01 00:00', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}', 4);
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
\set ON_ERROR_STOP 1
INSERT INTO unique_all VALUES('2024-01-01 00:00', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}', 5);
-- make sure everything is correct after recompressing the chunk
SELECT count(decompress_chunk(c)) FROM show_chunks('unique_all') c;
 count 
-------
     1

SELECT count(compress_chunk(c)) FROM show_chunks('unique_all') c;
 count 
-------
     1

\set ON_ERROR_STOP 0
INSERT INTO unique_all VALUES('2024-01-01 00:00', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}', 4);
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
\set ON_ERROR_STOP 1
-- test non-duplicates with NULL default values
ALTER TABLE unique_all ADD COLUMN added_null int DEFAULT NULL;
DROP INDEX ultimate_unique;
CREATE UNIQUE INDEX ultimate_unique ON unique_all(time, device_id, bool_type, numeric_type, float_type, text_type, bigint_type, jsonb_type, added_non_null, added_null) NULLS NOT DISTINCT;
\set ON_ERROR_STOP 0
INSERT INTO unique_all VALUES('2024-01-01 00:00', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}', 4, NULL);
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:00', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}', 5, NULL);
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
\set ON_ERROR_STOP 1
INSERT INTO unique_all VALUES('2024-01-01 00:00', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}', 6, NULL);
-- make sure everything is correct after recompressing the chunk
SELECT count(decompress_chunk(c)) FROM show_chunks('unique_all') c;
 count 
-------
     1

SELECT count(compress_chunk(c)) FROM show_chunks('unique_all') c;
 count 
-------
     1

\set ON_ERROR_STOP 0
INSERT INTO unique_all VALUES('2024-01-01 00:00', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}', 4, NULL);
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
INSERT INTO unique_all VALUES('2024-01-01 00:00', 1, true, 1.0, 1.0, 'first', 1, '{"first":true}', 5, NULL);
ERROR:  duplicate key value violates unique constraint "_hyper_30_79_chunk_ultimate_unique"
\set ON_ERROR_STOP 1
DROP TABLE unique_all;
-- test NULL compression algorithm
CREATE TABLE unique_null(
	time timestamptz NOT NULL,
	device_id int,
	tag text,
	tag2 text,
	value float
);
CREATE UNIQUE INDEX unique_nulls ON unique_null(time, device_id, tag, tag2) NULLS NOT DISTINCT;
SELECT table_name FROM create_hypertable('unique_null', 'time');
 table_name  
-------------
 unique_null

ALTER TABLE unique_null SET (tsdb.compress, tsdb.compress_segmentby = 'device_id', tsdb.compress_orderby = 'time');
WARNING:  column "tag" should be used for segmenting or ordering
WARNING:  column "tag2" should be used for segmenting or ordering
INSERT INTO unique_null VALUES
('2024-01-01 00:00', 1, NULL, '1', 1),
('2024-01-01 00:00', 1, NULL, '2', 2),
('2024-01-01 00:00', 1, NULL, '3', 3);
SELECT count(compress_chunk(c)) FROM show_chunks('unique_null') c;
 count 
-------
     1

\set ON_ERROR_STOP 0
INSERT INTO unique_null VALUES ('2024-01-01 00:00', 1, NULL, '1', 1);
ERROR:  duplicate key value violates unique constraint "_hyper_32_83_chunk_unique_nulls"
\set ON_ERROR_STOP 1
ALTER TABLE unique_null ADD COLUMN tag3 text DEFAULT 'default value';
DROP INDEX unique_nulls;
CREATE UNIQUE INDEX unique_nulls ON unique_null(time, device_id, tag, tag2, tag3) NULLS NOT DISTINCT;
\set ON_ERROR_STOP 0
INSERT INTO unique_null VALUES ('2024-01-01 00:00', 1, NULL, '1', 1, 'default value');
ERROR:  duplicate key value violates unique constraint "_hyper_32_83_chunk_unique_nulls"
\set ON_ERROR_STOP 1
INSERT INTO unique_null VALUES
	('2024-01-01 00:01', 1, NULL, '1', 1, 'default value'),
	('2024-01-01 00:00', 2, NULL, '1', 1, 'default value');
DROP TABLE unique_null;
-- test NUMERIC data type
CREATE TABLE unique_numeric(
	time timestamptz NOT NULL,
	device_id numeric(6,2) NOT NULL,
	tag text,
	tag2 text,
	value float
);
CREATE UNIQUE INDEX unique_numeric_idx ON unique_numeric(time, device_id, tag, tag2);
SELECT table_name FROM create_hypertable('unique_numeric', 'time');
   table_name   
----------------
 unique_numeric

ALTER TABLE unique_numeric SET (tsdb.compress, tsdb.compress_segmentby = 'device_id', tsdb.compress_orderby = 'time');
WARNING:  column "tag" should be used for segmenting or ordering
WARNING:  column "tag2" should be used for segmenting or ordering
INSERT INTO unique_numeric VALUES
('2024-01-01 00:00', 1.1, NULL, '1', 1),
('2024-01-01 00:00', 1.2, NULL, '2', 2),
('2024-01-01 00:00', 1.3, NULL, '3', 3);
SELECT count(compress_chunk(c)) FROM show_chunks('unique_numeric') c;
 count 
-------
     1

INSERT INTO unique_numeric VALUES ('2024-01-01 00:00', 1.4, NULL, '1', 1);
DROP TABLE unique_numeric;
-- test UUID data type
CREATE TABLE unique_uuid(
	time timestamptz NOT NULL,
	device_id UUID NOT NULL,
	tag text,
	tag2 text,
	value float
);
CREATE UNIQUE INDEX unique_uuid_idx ON unique_uuid(time, device_id, tag, tag2);
SELECT table_name FROM create_hypertable('unique_uuid', 'time');
 table_name  
-------------
 unique_uuid

ALTER TABLE unique_uuid SET (tsdb.compress, tsdb.compress_segmentby = 'device_id', tsdb.compress_orderby = 'time');
WARNING:  column "tag" should be used for segmenting or ordering
WARNING:  column "tag2" should be used for segmenting or ordering
INSERT INTO unique_uuid VALUES
('2024-01-01 00:00', '018a0d1a-8e6a-7000-8000-000000000000', NULL, '1', 1),
('2024-01-01 00:00', '018a0d1a-8e6a-7000-8000-000000000000', NULL, '1', 2),
('2024-01-01 00:00', '018a0d1a-8e6a-7000-8000-000000000001', NULL, '1', 1),
('2024-01-01 00:00', '018a0d1a-8e6a-7000-8000-000000000001', NULL, '1', 2);
SELECT count(compress_chunk(c)) FROM show_chunks('unique_uuid') c;
 count 
-------
     1

INSERT INTO unique_uuid VALUES ('2024-01-01 00:00', '018a0d1a-8e6a-7000-8000-000000000001', NULL, '1', 3);
DROP TABLE unique_uuid;
-- regression test for SDC 3006
CREATE TABLE t_1sec(
	"timestamp"                         timestamp with time zone NOT NULL,
	device_id                           text,
	speed                               double precision,
	derived                             boolean
);
ALTER TABLE t_1sec ADD CONSTRAINT unique_device_timestamp_sensor_derived
	UNIQUE (device_id, "timestamp", derived);
CREATE INDEX t_1sec_timestamp_idx
	ON t_1sec
	USING btree ("timestamp" DESC);
SELECT create_hypertable(
	relation => 't_1sec',
	time_column_name => 'timestamp',
	chunk_time_interval => interval '06:00:00',
	create_default_indexes => false
);
  create_hypertable   
----------------------
 (38,public,t_1sec,t)

ALTER TABLE t_1sec SET (
	timescaledb.compress,
	timescaledb.compress_segmentby = 'device_id',
	timescaledb.compress_orderby='"timestamp"'
);
WARNING:  column "derived" should be used for segmenting or ordering
insert into t_1sec ( "timestamp", device_id, speed, derived) values
( '2025-06-06 10:00:00', 'device_id_1', 100, true),
( '2025-06-06 10:01:00', 'device_id_2', 100, true),
( '2025-06-06 10:02:00', 'device_id_3', 100, true);
SELECT compress_chunk(show_chunks('t_1sec'));
              compress_chunk              
------------------------------------------
 _timescaledb_internal._hyper_38_89_chunk

insert into t_1sec ( "timestamp", device_id, speed, derived) values
( '2025-06-06 10:03:00', 'device_id_1', 100, true),
( '2025-06-06 10:00:00', 'device_id_1', 110, true),
( '2025-06-06 10:00:00', 'device_id_1', 110, false)
ON CONFLICT DO NOTHING;
DROP TABLE t_1sec;
-- regression test for SDC 3210
CREATE TABLE gen_column(
	"timestamp"                         timestamp with time zone NOT NULL,
	device_id                           text,
	device_id_generated 				text GENERATED ALWAYS AS (device_id) STORED,
	speed                               double precision
);
ALTER TABLE gen_column ADD CONSTRAINT unique_device_timestamp_sensor
	UNIQUE (device_id_generated, "timestamp");
CREATE INDEX gen_column_timestamp_idx
	ON gen_column
	USING btree ("timestamp" DESC);
SELECT create_hypertable(
	relation => 'gen_column',
	time_column_name => 'timestamp',
	chunk_time_interval => interval '06:00:00',
	create_default_indexes => false
);
    create_hypertable     
--------------------------
 (40,public,gen_column,t)

ALTER TABLE gen_column SET (
	timescaledb.compress,
	timescaledb.compress_segmentby = 'device_id_generated',
	timescaledb.compress_orderby='"timestamp"'
);
insert into gen_column ( "timestamp", device_id, speed) values
( '2025-06-06 10:00:00', 'device_id_1', 100),
( '2025-06-06 10:01:00', 'device_id_2', 100),
( '2025-06-06 10:02:00', 'device_id_3', 100);
SELECT compress_chunk(show_chunks('gen_column'));
              compress_chunk              
------------------------------------------
 _timescaledb_internal._hyper_40_91_chunk

insert into gen_column ( "timestamp", device_id, speed) values
( '2025-06-06 10:03:00', 'device_id_1', 100),
( '2025-06-06 10:00:00', 'device_id_1', 110),
( '2025-06-06 10:00:00', 'device_id_1', 110)
ON CONFLICT DO NOTHING;
-- should contain 2 rows for device_1 and one per any other device
SELECT device_id_generated, count(*)
FROM gen_column
GROUP BY 1
ORDER BY 1;
 device_id_generated | count 
---------------------+-------
 device_id_1         |     2
 device_id_2         |     1
 device_id_3         |     1

SELECT decompress_chunk(show_chunks('gen_column'));
             decompress_chunk             
------------------------------------------
 _timescaledb_internal._hyper_40_91_chunk

ALTER TABLE gen_column SET (
	timescaledb.compress,
	timescaledb.compress_segmentby = '',
	timescaledb.compress_orderby='"timestamp"'
);
SELECT compress_chunk(show_chunks('gen_column'));
              compress_chunk              
------------------------------------------
 _timescaledb_internal._hyper_40_91_chunk

insert into gen_column ( "timestamp", device_id, speed) values
( '2025-06-06 10:04:00', 'device_id_1', 100),
( '2025-06-06 10:00:00', 'device_id_1', 110),
( '2025-06-06 10:00:00', 'device_id_1', 110)
ON CONFLICT DO NOTHING;
-- should contain 3 rows for device_1 and one per any other device
SELECT device_id_generated, count(*)
FROM gen_column
GROUP BY 1
ORDER BY 1;
 device_id_generated | count 
---------------------+-------
 device_id_1         |     3
 device_id_2         |     1
 device_id_3         |     1

DROP TABLE gen_column;
-- regression test for SDC 3721
create table generated_with_dropped (
    timestamp timestamp with time zone not null,
    a numeric(15,10),
    b numeric(15,10),
    c numeric(15,10) generated always as (a+b) stored,
    to_be_dropped bigint not null,
    d jsonb,
    e bigint,
    f text not null);
select create_hypertable('generated_with_dropped', by_range('timestamp', '1 week'::interval));
 create_hypertable 
-------------------
 (42,t)

-- Dropping a column to verify we are using the correct
-- tuple desc when generating generated column.
alter table generated_with_dropped drop column to_be_dropped;
-- populate the table with some data
insert into generated_with_dropped (timestamp, a, b, d, e, f) values
('2026-01-18 22:55:39+00', -104.8180690000, 39.7653270000, '{"test": 5}', 397000, 'test');
-- compress everything
ALTER TABLE generated_with_dropped SET(
    timescaledb.enable_columnstore,
    timescaledb.orderby = 'timestamp'
);
select compress_chunk(chunk) from show_chunks('generated_with_dropped') as chunk;
              compress_chunk              
------------------------------------------
 _timescaledb_internal._hyper_42_94_chunk

-- This should not segfault
insert into generated_with_dropped (f, timestamp, a, b, d, e) values
('test1', '2026-01-18 22:56:08+00', -118.1709590000, 33.9069520000, '{"test": 5}', 327000);
DROP TABLE generated_with_dropped;
-- test insert into compressed chunk directly works
-- to ensure maintenance operations work unhindered we dont
-- want to block direct inserts into compressed chunks
CREATE TABLE direct_compressed_insert (time timestamptz) WITH (tsdb.hypertable);
NOTICE:  using column "time" as partitioning column
HINT:  Use "timescaledb.partition_column" to specify a different column to use as partitioning column.
INSERT INTO direct_compressed_insert SELECT generate_series('2024-01-01'::timestamptz, '2024-01-01 1:00:00'::timestamptz, '1 second');
SELECT count(compress_chunk(c)) FROM show_chunks('direct_compressed_insert') c;
 count 
-------
     1

SELECT format('%I.%I', schema_name, table_name) AS "CHUNK" FROM _timescaledb_catalog.chunk ORDER BY id DESC LIMIT 1 \gset
CREATE TABLE compressed_batches AS SELECT * FROM :CHUNK;
SELECT _ts_meta_count, count(*) FROM :CHUNK GROUP BY _ts_meta_count ORDER BY 1 DESC;
 _ts_meta_count | count 
----------------+-------
           1000 |     3
            601 |     1

-- should have not ModifyHypertable node
EXPLAIN (costs off,timing off, summary off) INSERT INTO :CHUNK SELECT * FROM compressed_batches;
--- QUERY PLAN ---
 Insert on compress_hyper_45_97_chunk
   ->  Seq Scan on compressed_batches

INSERT INTO :CHUNK SELECT * FROM compressed_batches;
SELECT _ts_meta_count, count(*) FROM :CHUNK GROUP BY _ts_meta_count ORDER BY 1 DESC;
 _ts_meta_count | count 
----------------+-------
           1000 |     6
            601 |     2

