--
-- Test the CREATE statements related to columnar.
--
-- We cannot create below tables within columnar_create because columnar_create
-- is dropped at the end of this test but unfortunately some other tests depend
-- those tables too.
--
-- However, this file has to be runnable multiple times for flaky test detection;
-- so we create them below --outside columnar_create-- idempotantly.
DO
$$
BEGIN
IF NOT EXISTS (
    SELECT 1 FROM pg_class
    WHERE relname = 'contestant' AND
          relnamespace = (
            SELECT oid FROM pg_namespace WHERE nspname = 'public'
          )
   )
THEN
    -- Create uncompressed table
    CREATE TABLE contestant (handle TEXT, birthdate DATE, rating INT,
        percentile FLOAT, country CHAR(3), achievements TEXT[])
        USING columnar;
    ALTER TABLE contestant SET (columnar.compression = none);

    CREATE INDEX contestant_idx on contestant(handle);

    -- Create zstd compressed table
    CREATE TABLE contestant_compressed (handle TEXT, birthdate DATE, rating INT,
        percentile FLOAT, country CHAR(3), achievements TEXT[])
        USING columnar;

    -- Test that querying an empty table works
    ANALYZE contestant;
END IF;
END
$$
LANGUAGE plpgsql;
SELECT count(*) FROM contestant;
 count
---------------------------------------------------------------------
     0
(1 row)

CREATE SCHEMA columnar_create;
SET search_path TO columnar_create;
-- Should fail: unlogged tables not supported
CREATE UNLOGGED TABLE columnar_unlogged(i int) USING columnar;
ERROR:  unlogged columnar tables are not supported
CREATE TABLE columnar_table_1 (a int) USING columnar;
INSERT INTO columnar_table_1 VALUES (1);
CREATE MATERIALIZED VIEW columnar_table_1_mv USING columnar
AS SELECT * FROM columnar_table_1;
SELECT columnar.get_storage_id(oid) AS columnar_table_1_mv_storage_id
FROM pg_class WHERE relname='columnar_table_1_mv' \gset
-- test columnar_relation_set_new_filelocator
REFRESH MATERIALIZED VIEW columnar_table_1_mv;
SELECT columnar_test_helpers.columnar_metadata_has_storage_id(:columnar_table_1_mv_storage_id);
 columnar_metadata_has_storage_id
---------------------------------------------------------------------
 f
(1 row)

SELECT columnar.get_storage_id(oid) AS columnar_table_1_storage_id
FROM pg_class WHERE relname='columnar_table_1' \gset
BEGIN;
  -- test columnar_relation_nontransactional_truncate
  TRUNCATE columnar_table_1;
  SELECT columnar_test_helpers.columnar_metadata_has_storage_id(:columnar_table_1_storage_id);
 columnar_metadata_has_storage_id
---------------------------------------------------------------------
 f
(1 row)

ROLLBACK;
-- since we rollback'ed above xact, should return true
SELECT columnar_test_helpers.columnar_metadata_has_storage_id(:columnar_table_1_storage_id);
 columnar_metadata_has_storage_id
---------------------------------------------------------------------
 t
(1 row)

BEGIN;
  INSERT INTO columnar_table_1 VALUES (2);
ROLLBACK;
INSERT INTO columnar_table_1 VALUES (3),(4);
INSERT INTO columnar_table_1 VALUES (5),(6);
INSERT INTO columnar_table_1 VALUES (7),(8);
-- Test whether columnar metadata accessors are still fine even
-- when the metadata indexes are not available to them.
BEGIN;
  ALTER INDEX columnar_internal.stripe_first_row_number_idx RENAME TO new_index_name;
  ALTER INDEX columnar_internal.chunk_pkey RENAME TO new_index_name_1;
  ALTER INDEX columnar_internal.stripe_pkey RENAME TO new_index_name_2;
  ALTER INDEX columnar_internal.chunk_group_pkey RENAME TO new_index_name_3;
  CREATE INDEX columnar_table_1_idx ON columnar_table_1(a);
WARNING:  Metadata index stripe_first_row_number_idx is not available, this might mean slower read/writes on columnar tables. This is expected during Postgres upgrades and not expected otherwise.
WARNING:  Metadata index stripe_first_row_number_idx is not available, this might mean slower read/writes on columnar tables. This is expected during Postgres upgrades and not expected otherwise.
WARNING:  Metadata index chunk_pkey is not available, this might mean slower read/writes on columnar tables. This is expected during Postgres upgrades and not expected otherwise.
WARNING:  Metadata index chunk_group_pkey is not available, this might mean slower read/writes on columnar tables. This is expected during Postgres upgrades and not expected otherwise.
  -- make sure that we test index scan
  SET LOCAL columnar.enable_custom_scan TO 'off';
  SET LOCAL enable_seqscan TO off;
  SET LOCAL seq_page_cost TO 10000000;
  SELECT * FROM columnar_table_1 WHERE a = 6;
WARNING:  Metadata index stripe_first_row_number_idx is not available, this might mean slower read/writes on columnar tables. This is expected during Postgres upgrades and not expected otherwise.
 a
---------------------------------------------------------------------
 6
(1 row)

  SELECT * FROM columnar_table_1 WHERE a = 5;
 a
---------------------------------------------------------------------
 5
(1 row)

  SELECT * FROM columnar_table_1 WHERE a = 7;
 a
---------------------------------------------------------------------
 7
(1 row)

  SELECT * FROM columnar_table_1 WHERE a = 3;
 a
---------------------------------------------------------------------
 3
(1 row)

  DROP INDEX columnar_table_1_idx;
  -- Re-shuffle some metadata records to test whether we can
  -- rely on sequential metadata scan when the metadata records
  -- are not ordered by their "first_row_number"s.
  WITH cte AS (
      DELETE FROM columnar_internal.stripe
      WHERE storage_id = columnar.get_storage_id('columnar_table_1')
      RETURNING *
  )
  INSERT INTO columnar_internal.stripe SELECT * FROM cte ORDER BY first_row_number DESC;
  SELECT SUM(a) FROM columnar_table_1;
 sum
---------------------------------------------------------------------
  34
(1 row)

  SELECT * FROM columnar_table_1 WHERE a = 6;
 a
---------------------------------------------------------------------
 6
(1 row)

  -- Run a SELECT query after the INSERT command to force flushing the
  -- data within the xact block.
  INSERT INTO columnar_table_1 VALUES (20);
  SELECT COUNT(*) FROM columnar_table_1;
WARNING:  Metadata index stripe_pkey is not available, this might mean slower read/writes on columnar tables. This is expected during Postgres upgrades and not expected otherwise.
 count
---------------------------------------------------------------------
     8
(1 row)

  DROP TABLE columnar_table_1 CASCADE;
NOTICE:  drop cascades to materialized view columnar_table_1_mv
WARNING:  Metadata index on a columnar metadata table is not available, this might mean slower read/writes on columnar tables. This is expected during Postgres upgrades and not expected otherwise.
ROLLBACK;
-- test dropping columnar table
DROP TABLE columnar_table_1 CASCADE;
NOTICE:  drop cascades to materialized view columnar_table_1_mv
SELECT columnar_test_helpers.columnar_metadata_has_storage_id(:columnar_table_1_storage_id);
 columnar_metadata_has_storage_id
---------------------------------------------------------------------
 f
(1 row)

-- test temporary columnar tables
-- Should work: temporary tables are supported
CREATE TEMPORARY TABLE columnar_temp(i int) USING columnar;
-- reserve some chunks and a stripe
INSERT INTO columnar_temp SELECT i FROM generate_series(1,5) i;
SELECT columnar.get_storage_id(oid) as oid INTO columnar_temp_storage_id
FROM pg_class WHERE relname='columnar_temp';
\c - - - :master_port
SET search_path TO columnar_create;
-- wait until temporary table and its metadata is removed
DO $$
DECLARE
  loop_wait_count integer := 0;
BEGIN
  WHILE (
    (SELECT COUNT(*) > 0 FROM pg_class WHERE relname='columnar_temp') OR
    (SELECT columnar_test_helpers.columnar_metadata_has_storage_id(oid) FROM columnar_temp_storage_id)
  )
  LOOP
    IF loop_wait_count > 1000 THEN
      RAISE EXCEPTION 'Timeout while waiting for temporary table to be dropped';
    END IF;

    PERFORM pg_sleep(0.001);

    loop_wait_count := loop_wait_count + 1;
  END LOOP;
END;
$$ language plpgsql;
DROP TABLE columnar_temp_storage_id;
-- connect to another session and create a temp table with same name
CREATE TEMPORARY TABLE columnar_temp(i int) USING columnar;
-- reserve some chunks and a stripe
INSERT INTO columnar_temp SELECT i FROM generate_series(1,5) i;
-- test basic select
SELECT COUNT(*) FROM columnar_temp WHERE i < 5;
 count
---------------------------------------------------------------------
     4
(1 row)

SELECT columnar.get_storage_id(oid) AS columnar_temp_storage_id
FROM pg_class WHERE relname='columnar_temp' \gset
BEGIN;
  DROP TABLE columnar_temp;
  -- show that we drop stripes properly
  SELECT columnar_test_helpers.columnar_metadata_has_storage_id(:columnar_temp_storage_id);
 columnar_metadata_has_storage_id
---------------------------------------------------------------------
 f
(1 row)

ROLLBACK;
-- make sure that table is not dropped yet since we rollbacked above xact
SELECT COUNT(*)=1 FROM pg_class WHERE relname='columnar_temp';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- show that we preserve the stripe of the temp columanar table after rollback
SELECT columnar_test_helpers.columnar_metadata_has_storage_id(:columnar_temp_storage_id);
 columnar_metadata_has_storage_id
---------------------------------------------------------------------
 t
(1 row)

-- drop it for next tests
DROP TABLE columnar_temp;
BEGIN;
  CREATE TEMPORARY TABLE columnar_temp(i int) USING columnar ON COMMIT DROP;
  -- force flushing stripe
  INSERT INTO columnar_temp SELECT i FROM generate_series(1,150000) i;
  SELECT columnar.get_storage_id(oid) AS columnar_temp_storage_id
  FROM pg_class WHERE relname='columnar_temp' \gset
COMMIT;
-- make sure that table & its stripe is dropped after commiting above xact
SELECT COUNT(*)=0 FROM pg_class WHERE relname='columnar_temp';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT columnar_test_helpers.columnar_metadata_has_storage_id(:columnar_temp_storage_id);
 columnar_metadata_has_storage_id
---------------------------------------------------------------------
 f
(1 row)

BEGIN;
  CREATE TEMPORARY TABLE columnar_temp(i int) USING columnar ON COMMIT DELETE ROWS;
  -- force flushing stripe
  INSERT INTO columnar_temp SELECT i FROM generate_series(1,150000) i;
  SELECT columnar.get_storage_id(oid) AS columnar_temp_storage_id
  FROM pg_class WHERE relname='columnar_temp' \gset
COMMIT;
-- make sure that table is not dropped but its rows's are deleted after commiting above xact
SELECT COUNT(*)=1 FROM pg_class WHERE relname='columnar_temp';
 ?column?
---------------------------------------------------------------------
 t
(1 row)

SELECT COUNT(*)=0 FROM columnar_temp;
 ?column?
---------------------------------------------------------------------
 t
(1 row)

-- since we deleted all the rows, we shouldn't have any stripes for table
SELECT columnar_test_helpers.columnar_metadata_has_storage_id(:columnar_temp_storage_id);
 columnar_metadata_has_storage_id
---------------------------------------------------------------------
 f
(1 row)

-- make sure citus_columnar can be loaded
LOAD 'citus_columnar';
SET client_min_messages TO WARNING;
DROP SCHEMA columnar_create CASCADE;
