--
-- Test the TRUNCATE TABLE command for columnar tables.
--
-- CREATE a columnar table, fill with some data --
CREATE TABLE columnar_truncate_test (a int, b int) USING columnar;
CREATE TABLE columnar_truncate_test_second (a int, b int) USING columnar;
-- COMPRESSED
CREATE TABLE columnar_truncate_test_compressed (a int, b int) USING columnar;
CREATE TABLE columnar_truncate_test_regular (a int, b int);
SELECT count(distinct storage_id) AS columnar_data_files_before_truncate FROM columnar.stripe \gset
INSERT INTO columnar_truncate_test select a, a from generate_series(1, 10) a;
set columnar.compression = 'pglz';
INSERT INTO columnar_truncate_test_compressed select a, a from generate_series(1, 10) a;
INSERT INTO columnar_truncate_test_compressed select a, a from generate_series(1, 10) a;
set columnar.compression to default;
-- query rows
SELECT * FROM columnar_truncate_test;
 a  | b
---------------------------------------------------------------------
  1 |  1
  2 |  2
  3 |  3
  4 |  4
  5 |  5
  6 |  6
  7 |  7
  8 |  8
  9 |  9
 10 | 10
(10 rows)

SELECT * FROM columnar_test_helpers.chunk_group_consistency;
 consistent
---------------------------------------------------------------------
 t
(1 row)

select
  version_major, version_minor, reserved_stripe_id, reserved_row_number
  from columnar_test_helpers.columnar_storage_info('columnar_truncate_test');
 version_major | version_minor | reserved_stripe_id | reserved_row_number
---------------------------------------------------------------------
             2 |             0 |                  2 |              150001
(1 row)

TRUNCATE TABLE columnar_truncate_test;
select
  version_major, version_minor, reserved_stripe_id, reserved_row_number
  from columnar_test_helpers.columnar_storage_info('columnar_truncate_test');
 version_major | version_minor | reserved_stripe_id | reserved_row_number
---------------------------------------------------------------------
             2 |             0 |                  1 |                   1
(1 row)

SELECT * FROM columnar_test_helpers.chunk_group_consistency;
 consistent
---------------------------------------------------------------------
 t
(1 row)

SELECT * FROM columnar_truncate_test;
 a | b
---------------------------------------------------------------------
(0 rows)

SELECT COUNT(*) from columnar_truncate_test;
 count
---------------------------------------------------------------------
     0
(1 row)

SELECT count(*) FROM columnar_truncate_test_compressed;
 count
---------------------------------------------------------------------
    20
(1 row)

TRUNCATE TABLE columnar_truncate_test_compressed;
SELECT count(*) FROM columnar_truncate_test_compressed;
 count
---------------------------------------------------------------------
     0
(1 row)

SELECT pg_relation_size('columnar_truncate_test_compressed');
 pg_relation_size
---------------------------------------------------------------------
            16384
(1 row)

INSERT INTO columnar_truncate_test select a, a from generate_series(1, 10) a;
INSERT INTO columnar_truncate_test_regular select a, a from generate_series(10, 20) a;
INSERT INTO columnar_truncate_test_second select a, a from generate_series(20, 30) a;
SELECT * from columnar_truncate_test;
 a  | b
---------------------------------------------------------------------
  1 |  1
  2 |  2
  3 |  3
  4 |  4
  5 |  5
  6 |  6
  7 |  7
  8 |  8
  9 |  9
 10 | 10
(10 rows)

SELECT * from columnar_truncate_test_second;
 a  | b
---------------------------------------------------------------------
 20 | 20
 21 | 21
 22 | 22
 23 | 23
 24 | 24
 25 | 25
 26 | 26
 27 | 27
 28 | 28
 29 | 29
 30 | 30
(11 rows)

SELECT * from columnar_truncate_test_regular;
 a  | b
---------------------------------------------------------------------
 10 | 10
 11 | 11
 12 | 12
 13 | 13
 14 | 14
 15 | 15
 16 | 16
 17 | 17
 18 | 18
 19 | 19
 20 | 20
(11 rows)

SELECT * FROM columnar_test_helpers.chunk_group_consistency;
 consistent
---------------------------------------------------------------------
 t
(1 row)

-- make sure multi truncate works
-- notice that the same table might be repeated
TRUNCATE TABLE columnar_truncate_test,
			   columnar_truncate_test_regular,
			   columnar_truncate_test_second,
   			   columnar_truncate_test;
SELECT * FROM columnar_test_helpers.chunk_group_consistency;
 consistent
---------------------------------------------------------------------
 t
(1 row)

SELECT * from columnar_truncate_test;
 a | b
---------------------------------------------------------------------
(0 rows)

SELECT * from columnar_truncate_test_second;
 a | b
---------------------------------------------------------------------
(0 rows)

SELECT * from columnar_truncate_test_regular;
 a | b
---------------------------------------------------------------------
(0 rows)

-- test if truncate on empty table works
TRUNCATE TABLE columnar_truncate_test;
SELECT * from columnar_truncate_test;
 a | b
---------------------------------------------------------------------
(0 rows)

-- make sure TRUNATE deletes metadata for old relfilenode
SELECT :columnar_data_files_before_truncate - count(distinct storage_id) FROM columnar.stripe;
 ?column?
---------------------------------------------------------------------
        0
(1 row)

-- test if truncation in the same transaction that created the table works properly
BEGIN;
CREATE TABLE columnar_same_transaction_truncate(a int) USING columnar;
INSERT INTO columnar_same_transaction_truncate SELECT * FROM generate_series(1, 100);
TRUNCATE columnar_same_transaction_truncate;
INSERT INTO columnar_same_transaction_truncate SELECT * FROM generate_series(20, 23);
COMMIT;
-- should output "1" for the newly created relation
SELECT count(distinct storage_id) - :columnar_data_files_before_truncate FROM columnar_internal.stripe;
 ?column?
---------------------------------------------------------------------
        1
(1 row)

SELECT * FROM columnar_same_transaction_truncate;
 a
---------------------------------------------------------------------
 20
 21
 22
 23
(4 rows)

DROP TABLE columnar_same_transaction_truncate;
-- test if a cached truncate from a pl/pgsql function works
CREATE FUNCTION columnar_truncate_test_regular_func() RETURNS void AS $$
BEGIN
	INSERT INTO columnar_truncate_test_regular select a, a from generate_series(1, 10) a;
	TRUNCATE TABLE columnar_truncate_test_regular;
END;$$
LANGUAGE plpgsql;
SELECT columnar_truncate_test_regular_func();
 columnar_truncate_test_regular_func
---------------------------------------------------------------------

(1 row)

-- the cached plans are used stating from the second call
SELECT columnar_truncate_test_regular_func();
 columnar_truncate_test_regular_func
---------------------------------------------------------------------

(1 row)

DROP FUNCTION columnar_truncate_test_regular_func();
DROP TABLE columnar_truncate_test, columnar_truncate_test_second;
DROP TABLE columnar_truncate_test_regular;
DROP TABLE columnar_truncate_test_compressed;
-- test truncate with schema
CREATE SCHEMA truncate_schema;
-- COMPRESSED
CREATE TABLE truncate_schema.truncate_tbl (id int) USING columnar;
set columnar.compression = 'pglz';
INSERT INTO truncate_schema.truncate_tbl SELECT generate_series(1, 100);
set columnar.compression to default;
SELECT COUNT(*) FROM truncate_schema.truncate_tbl;
 count
---------------------------------------------------------------------
   100
(1 row)

TRUNCATE TABLE truncate_schema.truncate_tbl;
SELECT COUNT(*) FROM truncate_schema.truncate_tbl;
 count
---------------------------------------------------------------------
     0
(1 row)

set columnar.compression = 'pglz';
INSERT INTO truncate_schema.truncate_tbl SELECT generate_series(1, 100);
set columnar.compression to default;
-- create a user that can not truncate
CREATE USER truncate_user;
GRANT USAGE ON SCHEMA truncate_schema TO truncate_user;
GRANT SELECT ON TABLE truncate_schema.truncate_tbl TO truncate_user;
REVOKE TRUNCATE ON TABLE truncate_schema.truncate_tbl FROM truncate_user;
SELECT current_user \gset
\c - truncate_user
-- verify truncate command fails and check number of rows
SELECT count(*) FROM truncate_schema.truncate_tbl;
 count
---------------------------------------------------------------------
   100
(1 row)

TRUNCATE TABLE truncate_schema.truncate_tbl;
ERROR:  permission denied for table truncate_tbl
SELECT count(*) FROM truncate_schema.truncate_tbl;
 count
---------------------------------------------------------------------
   100
(1 row)

-- switch to super user, grant truncate to truncate_user
\c - :current_user
GRANT TRUNCATE ON TABLE truncate_schema.truncate_tbl TO truncate_user;
-- verify truncate_user can truncate now
\c - truncate_user
SELECT count(*) FROM truncate_schema.truncate_tbl;
 count
---------------------------------------------------------------------
   100
(1 row)

TRUNCATE TABLE truncate_schema.truncate_tbl;
SELECT count(*) FROM truncate_schema.truncate_tbl;
 count
---------------------------------------------------------------------
     0
(1 row)

\c - :current_user
SELECT * FROM columnar_test_helpers.chunk_group_consistency;
 consistent
---------------------------------------------------------------------
 t
(1 row)

-- cleanup
DROP SCHEMA truncate_schema CASCADE;
NOTICE:  drop cascades to table truncate_schema.truncate_tbl
DROP USER truncate_user;
