--
-- MULTI_UPGRADE_REFERENCE_TABLE
--
-- Tests around upgrade_reference_table UDF
--
ALTER SEQUENCE pg_catalog.pg_dist_shardid_seq RESTART 1360000;
ALTER SEQUENCE pg_catalog.pg_dist_colocationid_seq RESTART 1360000;
-- We run this twice, once with coordinator node in pg_dist_node and once without.
-- Set client_min_messages to WARNING to discard NOTICE messages by
-- upgrade_to_reference_table() to make the output consistent in both cases.
-- We check that reference table placements were actually replicated by checking
-- pg_dist_placement.
SET client_min_messages TO WARNING;
-- test with not distributed table
CREATE TABLE upgrade_reference_table_local(column1 int);
SELECT upgrade_to_reference_table('upgrade_reference_table_local');
ERROR:  cannot upgrade to reference table
DETAIL:  Relation "upgrade_reference_table_local" is not distributed.
HINT:  Instead, you can use; create_reference_table('upgrade_reference_table_local');
DROP TABLE upgrade_reference_table_local;
-- test with table which has more than one shard
SET citus.shard_count TO 4;
CREATE TABLE upgrade_reference_table_multiple_shard(column1 int);
SELECT create_distributed_table('upgrade_reference_table_multiple_shard', 'column1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SELECT upgrade_to_reference_table('upgrade_reference_table_multiple_shard');
ERROR:  cannot upgrade to reference table
DETAIL:  Relation "upgrade_reference_table_multiple_shard" shard count is not one. Only relations with one shard can be upgraded to reference tables.
DROP TABLE upgrade_reference_table_multiple_shard;
-- test with table which has no shard
CREATE TABLE upgrade_reference_table_no_shard(column1 int);
SELECT create_distributed_table('upgrade_reference_table_no_shard', 'column1', 'append');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

SELECT upgrade_to_reference_table('upgrade_reference_table_no_shard');
ERROR:  cannot upgrade to reference table
DETAIL:  Relation "upgrade_reference_table_no_shard" shard count is not one. Only relations with one shard can be upgraded to reference tables.
DROP TABLE upgrade_reference_table_no_shard;
-- test with table with foreign keys
SET citus.shard_count TO 1;
SET citus.shard_replication_factor TO 1;
CREATE TABLE upgrade_reference_table_referenced(column1 int PRIMARY KEY);
SELECT create_distributed_table('upgrade_reference_table_referenced', 'column1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE upgrade_reference_table_referencing(column1 int REFERENCES upgrade_reference_table_referenced(column1));
SELECT create_distributed_table('upgrade_reference_table_referencing', 'column1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- update replication model to statement-based replication since streaming replicated tables cannot be upgraded to reference tables
UPDATE pg_dist_partition SET repmodel='c' WHERE logicalrelid='upgrade_reference_table_referenced'::regclass;
UPDATE pg_dist_partition SET repmodel='c' WHERE logicalrelid='upgrade_reference_table_referencing'::regclass;
SELECT upgrade_to_reference_table('upgrade_reference_table_referenced');
ERROR:  cannot upgrade to reference table
DETAIL:  Relation "upgrade_reference_table_referenced" is part of a foreign constraint. Foreign key constraints are not allowed from or to reference tables.
SELECT upgrade_to_reference_table('upgrade_reference_table_referencing');
ERROR:  cannot upgrade to reference table
DETAIL:  Relation "upgrade_reference_table_referencing" is part of a foreign constraint. Foreign key constraints are not allowed from or to reference tables.
DROP TABLE upgrade_reference_table_referencing;
DROP TABLE upgrade_reference_table_referenced;
-- test with no healthy placements
CREATE TABLE upgrade_reference_table_unhealthy(column1 int);
SELECT create_distributed_table('upgrade_reference_table_unhealthy', 'column1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

UPDATE pg_dist_partition SET repmodel='c' WHERE logicalrelid='upgrade_reference_table_unhealthy'::regclass;
UPDATE pg_dist_shard_placement SET shardstate = 3
   WHERE shardid = (SELECT shardid FROM pg_dist_shard WHERE logicalrelid = 'upgrade_reference_table_unhealthy'::regclass::oid);
SELECT upgrade_to_reference_table('upgrade_reference_table_unhealthy');
ERROR:  could not find any healthy placement for shard xxxxx
DROP TABLE upgrade_reference_table_unhealthy;
-- test with table containing composite type
CREATE TYPE upgrade_test_composite_type AS (key1 text, key2 text);
SET citus.shard_count TO 1;
SET citus.shard_replication_factor TO 1;
CREATE TABLE upgrade_reference_table_composite(column1 int, column2 upgrade_test_composite_type);
SELECT create_distributed_table('upgrade_reference_table_composite', 'column1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

UPDATE pg_dist_partition SET repmodel='c' WHERE logicalrelid='upgrade_reference_table_composite'::regclass;
SELECT upgrade_to_reference_table('upgrade_reference_table_composite');
 upgrade_to_reference_table
---------------------------------------------------------------------

(1 row)

DROP TABLE upgrade_reference_table_composite;
DROP TYPE upgrade_test_composite_type;
-- test with reference table
CREATE TABLE upgrade_reference_table_reference(column1 int);
SELECT create_reference_table('upgrade_reference_table_reference');
 create_reference_table
---------------------------------------------------------------------

(1 row)

SELECT upgrade_to_reference_table('upgrade_reference_table_reference');
ERROR:  cannot upgrade to reference table
DETAIL:  Relation "upgrade_reference_table_reference" is already a reference table
DROP TABLE upgrade_reference_table_reference;
-- test valid cases, append distributed table
CREATE TABLE upgrade_reference_table_append(column1 int);
SELECT create_distributed_table('upgrade_reference_table_append', 'column1', 'append');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

COPY upgrade_reference_table_append FROM STDIN;
-- situation before upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_append'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 a          | f             |            0 | c
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_append'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360009 | f                   | f
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_append'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
(0 rows)

SELECT count(*) active_primaries FROM pg_dist_node WHERE isactive AND noderole='primary' \gset
SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_append'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360009 | f
(1 row)

SELECT upgrade_to_reference_table('upgrade_reference_table_append');
 upgrade_to_reference_table
---------------------------------------------------------------------

(1 row)

-- situation after upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_append'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 n          | t             |        10004 | t
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_append'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360009 | t                   | t
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_append'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
        10004 |          1 |                -1 |                      0 |                           0
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_append'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360009 | t
(1 row)

DROP TABLE upgrade_reference_table_append;
-- test valid cases, shard exists at one worker
CREATE TABLE upgrade_reference_table_one_worker(column1 int);
SELECT create_distributed_table('upgrade_reference_table_one_worker', 'column1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

UPDATE pg_dist_partition SET repmodel='c' WHERE logicalrelid='upgrade_reference_table_one_worker'::regclass;
-- situation before upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_one_worker'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 h          | f             |      1360001 | c
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_one_worker'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360010 | f                   | f
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_one_worker'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
      1360001 |          1 |                 1 |                     23 |                           0
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_one_worker'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360010 | f
(1 row)

SELECT upgrade_to_reference_table('upgrade_reference_table_one_worker');
 upgrade_to_reference_table
---------------------------------------------------------------------

(1 row)

-- situation after upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_one_worker'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 n          | t             |        10004 | t
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_one_worker'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360010 | t                   | t
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_one_worker'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
        10004 |          1 |                -1 |                      0 |                           0
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_one_worker'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360010 | t
(1 row)

DROP TABLE upgrade_reference_table_one_worker;
-- test valid cases, shard exists at both workers but one is unhealthy
SET citus.shard_replication_factor TO 2;
CREATE TABLE upgrade_reference_table_one_unhealthy(column1 int);
SELECT create_distributed_table('upgrade_reference_table_one_unhealthy', 'column1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

UPDATE pg_dist_shard_placement SET shardstate = 3
WHERE shardid = (SELECT shardid FROM pg_dist_shard WHERE logicalrelid = 'upgrade_reference_table_one_unhealthy'::regclass::oid) AND nodeport = :worker_1_port;
-- situation before upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_one_unhealthy'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 h          | f             |      1360002 | c
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_one_unhealthy'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360011 | f                   | f
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_one_unhealthy'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
      1360002 |          1 |                 2 |                     23 |                           0
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_one_unhealthy'::regclass)
    AND shardstate = 1
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360011 | f
(1 row)

SELECT upgrade_to_reference_table('upgrade_reference_table_one_unhealthy');
 upgrade_to_reference_table
---------------------------------------------------------------------

(1 row)

-- situation after upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_one_unhealthy'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 n          | t             |        10004 | t
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_one_unhealthy'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360011 | t                   | t
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_one_unhealthy'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
        10004 |          1 |                -1 |                      0 |                           0
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_one_unhealthy'::regclass)
    AND shardstate = 1
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360011 | t
(1 row)

DROP TABLE upgrade_reference_table_one_unhealthy;
-- test valid cases, shard exists at both workers and both are healthy
CREATE TABLE upgrade_reference_table_both_healthy(column1 int);
SELECT create_distributed_table('upgrade_reference_table_both_healthy', 'column1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- situation before upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_both_healthy'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 h          | f             |      1360003 | c
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_both_healthy'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360012 | f                   | f
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_both_healthy'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
      1360003 |          1 |                 2 |                     23 |                           0
(1 row)

SELECT
    shardid
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_both_healthy'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid
---------------------------------------------------------------------
 1360012
(1 row)

SELECT upgrade_to_reference_table('upgrade_reference_table_both_healthy');
 upgrade_to_reference_table
---------------------------------------------------------------------

(1 row)

-- situation after upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_both_healthy'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 n          | t             |        10004 | t
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_both_healthy'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360012 | t                   | t
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_both_healthy'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
        10004 |          1 |                -1 |                      0 |                           0
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_both_healthy'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360012 | t
(1 row)

DROP TABLE upgrade_reference_table_both_healthy;
-- test valid cases, do it in transaction and ROLLBACK
SET citus.shard_replication_factor TO 1;
CREATE TABLE upgrade_reference_table_transaction_rollback(column1 int);
SELECT create_distributed_table('upgrade_reference_table_transaction_rollback', 'column1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

UPDATE pg_dist_partition SET repmodel='c' WHERE logicalrelid='upgrade_reference_table_transaction_rollback'::regclass;
-- situation before upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_transaction_rollback'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 h          | f             |      1360004 | c
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_transaction_rollback'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360013 | f                   | f
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_transaction_rollback'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
      1360004 |          1 |                 1 |                     23 |                           0
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_transaction_rollback'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360013 | f
(1 row)

BEGIN;
SELECT upgrade_to_reference_table('upgrade_reference_table_transaction_rollback');
 upgrade_to_reference_table
---------------------------------------------------------------------

(1 row)

ROLLBACK;
-- situation after upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_transaction_rollback'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 h          | f             |      1360004 | c
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_transaction_rollback'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360013 | f                   | f
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_transaction_rollback'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
      1360004 |          1 |                 1 |                     23 |                           0
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_transaction_rollback'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360013 | f
(1 row)

DROP TABLE upgrade_reference_table_transaction_rollback;
-- test valid cases, do it in transaction and COMMIT
SET citus.shard_replication_factor TO 1;
CREATE TABLE upgrade_reference_table_transaction_commit(column1 int);
SELECT create_distributed_table('upgrade_reference_table_transaction_commit', 'column1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

UPDATE pg_dist_partition SET repmodel='c' WHERE logicalrelid='upgrade_reference_table_transaction_commit'::regclass;
-- situation before upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_transaction_commit'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 h          | f             |      1360004 | c
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_transaction_commit'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360014 | f                   | f
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_transaction_commit'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
      1360004 |          1 |                 1 |                     23 |                           0
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_transaction_commit'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360014 | f
(1 row)

BEGIN;
SELECT upgrade_to_reference_table('upgrade_reference_table_transaction_commit');
 upgrade_to_reference_table
---------------------------------------------------------------------

(1 row)

COMMIT;
-- situation after upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_transaction_commit'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 n          | t             |        10004 | t
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_transaction_commit'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360014 | t                   | t
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_transaction_commit'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
        10004 |          1 |                -1 |                      0 |                           0
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_transaction_commit'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360014 | t
(1 row)

-- verify that shard is replicated to other worker
\c - - - :worker_2_port
\dt upgrade_reference_table_transaction_commit_*
                               List of relations
 Schema |                        Name                        | Type  |  Owner
---------------------------------------------------------------------
 public | upgrade_reference_table_transaction_commit_1360014 | table | postgres
(1 row)

\c - - - :master_port
DROP TABLE upgrade_reference_table_transaction_commit;
-- create an mx table
SET citus.shard_count TO 1;
SET citus.shard_replication_factor TO 1;
SET citus.replication_model TO 'streaming';
CREATE TABLE upgrade_reference_table_mx(column1 int);
SELECT create_distributed_table('upgrade_reference_table_mx', 'column1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- verify that streaming replicated tables cannot be upgraded to reference tables
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_mx'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 h          | f             |      1360005 | s
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_mx'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360015 | f                   | f
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_mx'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
      1360005 |          1 |                 1 |                     23 |                           0
(1 row)

SELECT
    shardid
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_mx'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid
---------------------------------------------------------------------
 1360015
(1 row)

SELECT upgrade_to_reference_table('upgrade_reference_table_mx');
ERROR:  cannot upgrade to reference table
DETAIL:  Upgrade is only supported for statement-based replicated tables but "upgrade_reference_table_mx" is streaming replicated
-- situation after upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_mx'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 h          | f             |      1360005 | s
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_mx'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360015 | f                   | f
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_mx'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
      1360005 |          1 |                 1 |                     23 |                           0
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_mx'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360015 | f
(1 row)

DROP TABLE upgrade_reference_table_mx;
-- test valid cases, do it with MX
SET citus.shard_count TO 1;
SET citus.shard_replication_factor TO 2;
RESET citus.replication_model;
CREATE TABLE upgrade_reference_table_mx(column1 int);
SELECT create_distributed_table('upgrade_reference_table_mx', 'column1');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

UPDATE pg_dist_shard_placement SET shardstate = 3
WHERE nodeport = :worker_2_port AND
	shardid IN (SELECT shardid FROM pg_dist_shard WHERE logicalrelid='upgrade_reference_table_mx'::regclass);
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
 start_metadata_sync_to_node
---------------------------------------------------------------------

(1 row)

-- situation before upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_mx'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 h          | f             |      1360006 | c
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_mx'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360016 | f                   | f
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_mx'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
      1360006 |          1 |                 2 |                     23 |                           0
(1 row)

SELECT
    shardid
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_mx'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid
---------------------------------------------------------------------
 1360016
(1 row)

SET client_min_messages TO WARNING;
SELECT upgrade_to_reference_table('upgrade_reference_table_mx');
 upgrade_to_reference_table
---------------------------------------------------------------------

(1 row)

-- situation after upgrade_reference_table
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_mx'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 n          | t             |        10004 | t
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_mx'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360016 | t                   | t
(1 row)

SELECT *
FROM pg_dist_colocation
WHERE colocationid IN
    (SELECT colocationid
     FROM pg_dist_partition
     WHERE logicalrelid = 'upgrade_reference_table_mx'::regclass);
 colocationid | shardcount | replicationfactor | distributioncolumntype | distributioncolumncollation
---------------------------------------------------------------------
        10004 |          1 |                -1 |                      0 |                           0
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_mx'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360016 | t
(1 row)

-- situation on metadata worker
\c - - - :worker_1_port
SELECT
    partmethod, (partkey IS NULL) as partkeyisnull, colocationid, repmodel
FROM
    pg_dist_partition
WHERE
    logicalrelid = 'upgrade_reference_table_mx'::regclass;
 partmethod | partkeyisnull | colocationid | repmodel
---------------------------------------------------------------------
 n          | t             |        10004 | t
(1 row)

SELECT
    shardid, (shardminvalue IS NULL) as shardminvalueisnull, (shardmaxvalue IS NULL) as shardmaxvalueisnull
FROM
    pg_dist_shard
WHERE
    logicalrelid = 'upgrade_reference_table_mx'::regclass;
 shardid | shardminvalueisnull | shardmaxvalueisnull
---------------------------------------------------------------------
 1360016 | t                   | t
(1 row)

SELECT
    shardid, count(distinct nodeport) = :active_primaries
FROM pg_dist_shard_placement
WHERE shardid IN
    (SELECT shardid
     FROM pg_dist_shard
     WHERE logicalrelid = 'upgrade_reference_table_mx'::regclass)
GROUP BY shardid
ORDER BY shardid;
 shardid | ?column?
---------------------------------------------------------------------
 1360016 | t
(1 row)

\c - - - :master_port
DROP TABLE upgrade_reference_table_mx;
SELECT stop_metadata_sync_to_node('localhost', :worker_1_port);
 stop_metadata_sync_to_node
---------------------------------------------------------------------

(1 row)

RESET client_min_messages;
