CREATE SCHEMA local_shard_execution;
SET search_path TO local_shard_execution;
SET citus.shard_count TO 4;
SET citus.shard_replication_factor TO 1;
SET citus.replication_model TO 'streaming';
SET citus.next_shard_id TO 1470000;
CREATE TABLE reference_table (key int PRIMARY KEY);
SELECT create_reference_table('reference_table');
 create_reference_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE distributed_table (key int PRIMARY KEY , value text, age bigint CHECK (age > 10), FOREIGN KEY (key) REFERENCES reference_table(key) ON DELETE CASCADE);
SELECT create_distributed_table('distributed_table','key');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE second_distributed_table (key int PRIMARY KEY , value text, FOREIGN KEY (key) REFERENCES distributed_table(key) ON DELETE CASCADE);
SELECT create_distributed_table('second_distributed_table','key');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

-- ingest some data to enable some tests with data
INSERT INTO reference_table VALUES (1);
INSERT INTO distributed_table VALUES (1, '1', 20);
INSERT INTO second_distributed_table VALUES (1, '1');
-- a simple test for
CREATE TABLE collections_list (
	key bigserial,
	ser bigserial,
	ts timestamptz,
	collection_id integer,
	value numeric,
	PRIMARY KEY(key, collection_id)
) PARTITION BY LIST (collection_id );
SELECT create_distributed_table('collections_list', 'key');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE TABLE collections_list_0
	PARTITION OF collections_list (key, ser, ts, collection_id, value)
	FOR VALUES IN ( 0 );
-- connection worker and get ready for the tests
\c - - - :worker_1_port
SET search_path TO local_shard_execution;
-- returns true of the distribution key filter
-- on the distributed tables (e.g., WHERE key = 1), we'll hit a shard
-- placement which is local to this not
CREATE OR REPLACE FUNCTION shard_of_distribution_column_is_local(dist_key int) RETURNS bool AS $$

		DECLARE shard_is_local BOOLEAN := FALSE;

		BEGIN

		  	WITH  local_shard_ids 			  AS (SELECT get_shard_id_for_distribution_column('local_shard_execution.distributed_table', dist_key)),
				  all_local_shard_ids_on_node AS (SELECT shardid FROM pg_dist_placement WHERE groupid IN (SELECT groupid FROM pg_dist_local_group))
		SELECT
			true INTO shard_is_local
		FROM
			local_shard_ids
		WHERE
			get_shard_id_for_distribution_column IN (SELECT * FROM all_local_shard_ids_on_node);

		IF shard_is_local IS NULL THEN
			shard_is_local = FALSE;
		END IF;

		RETURN shard_is_local;
        END;
$$ LANGUAGE plpgsql;
-- pick some example values that reside on the shards locally and remote
-- distribution key values of 1,6, 500 and 701 are LOCAL to shards,
-- we'll use these values in the tests
SELECT shard_of_distribution_column_is_local(1);
 shard_of_distribution_column_is_local
---------------------------------------------------------------------
 t
(1 row)

SELECT shard_of_distribution_column_is_local(6);
 shard_of_distribution_column_is_local
---------------------------------------------------------------------
 t
(1 row)

SELECT shard_of_distribution_column_is_local(500);
 shard_of_distribution_column_is_local
---------------------------------------------------------------------
 t
(1 row)

SELECT shard_of_distribution_column_is_local(701);
 shard_of_distribution_column_is_local
---------------------------------------------------------------------
 t
(1 row)

-- distribution key values of 11 and 12 are REMOTE to shards
SELECT shard_of_distribution_column_is_local(11);
 shard_of_distribution_column_is_local
---------------------------------------------------------------------
 f
(1 row)

SELECT shard_of_distribution_column_is_local(12);
 shard_of_distribution_column_is_local
---------------------------------------------------------------------
 f
(1 row)

--- enable logging to see which tasks are executed locally
SET citus.log_local_commands TO ON;
-- first, make sure that local execution works fine
-- with simple queries that are not in transcation blocks
SELECT count(*) FROM distributed_table WHERE key = 1;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     1
(1 row)

-- multiple tasks both of which are local should NOT use local execution
-- because local execution means executing the tasks locally, so the executor
-- favors parallel execution even if everyting is local to node
SELECT count(*) FROM distributed_table WHERE key IN (1,6);
 count
---------------------------------------------------------------------
     1
(1 row)

-- queries that hit any remote shards should NOT use local execution
SELECT count(*) FROM distributed_table WHERE key IN (1,11);
 count
---------------------------------------------------------------------
     1
(1 row)

SELECT count(*) FROM distributed_table;
 count
---------------------------------------------------------------------
     1
(1 row)

-- modifications also follow the same rules
INSERT INTO reference_table VALUES (1) ON CONFLICT DO NOTHING;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 AS citus_table_alias (key) VALUES (1) ON CONFLICT DO NOTHING
INSERT INTO distributed_table VALUES (1, '1', 21) ON CONFLICT DO NOTHING;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '1'::text, 21) ON CONFLICT DO NOTHING
-- local query
DELETE FROM distributed_table WHERE key = 1 AND age = 21;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((key OPERATOR(pg_catalog.=) 1) AND (age OPERATOR(pg_catalog.=) 21))
-- hitting multiple shards, so should be a distributed execution
DELETE FROM distributed_table WHERE age = 21;
-- although both shards are local, the executor choose the parallel execution
-- over the wire because as noted above local execution is sequential
DELETE FROM second_distributed_table WHERE key IN (1,6);
-- similarly, any multi-shard query just follows distributed execution
DELETE FROM second_distributed_table;
-- load some more data for the following tests
INSERT INTO second_distributed_table VALUES (1, '1');
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.second_distributed_table_1470005 (key, value) VALUES (1, '1'::text)
-- INSERT .. SELECT hitting a single single (co-located) shard(s) should
-- be executed locally
INSERT INTO distributed_table
SELECT
	distributed_table.*
FROM
	distributed_table, second_distributed_table
WHERE
	distributed_table.key = 1 and distributed_table.key=second_distributed_table.key
ON CONFLICT(key) DO UPDATE SET value = '22'
RETURNING *;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470001 distributed_table, local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE (((distributed_table.key OPERATOR(pg_catalog.=) 1) AND (distributed_table.key OPERATOR(pg_catalog.=) second_distributed_table.key)) AND ((worker_hash(distributed_table.key) OPERATOR(pg_catalog.>=) '-2147483648'::integer) AND (worker_hash(distributed_table.key) OPERATOR(pg_catalog.<=) '-1073741825'::integer))) ON CONFLICT(key) DO UPDATE SET value = '22'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age
 key | value | age
---------------------------------------------------------------------
   1 | 22    |  20
(1 row)

-- INSERT .. SELECT hitting multi-shards should go thourgh distributed execution
INSERT INTO distributed_table
SELECT
	distributed_table.*
FROM
	distributed_table, second_distributed_table
WHERE
	distributed_table.key != 1 and distributed_table.key=second_distributed_table.key
ON CONFLICT(key) DO UPDATE SET value = '22'
RETURNING *;
 key | value | age
---------------------------------------------------------------------
(0 rows)

-- INSERT..SELECT via coordinator consists of two steps, select + COPY
-- that's why it is disallowed to use local execution even if the SELECT
-- can be executed locally
INSERT INTO distributed_table SELECT * FROM distributed_table WHERE key = 1 OFFSET 0 ON CONFLICT DO NOTHING;
INSERT INTO distributed_table SELECT 1, '1',15 FROM distributed_table WHERE key = 2 LIMIT 1 ON CONFLICT DO NOTHING;
-- sanity check: multi-shard INSERT..SELECT pushdown goes through distributed execution
INSERT INTO distributed_table SELECT * FROM distributed_table ON CONFLICT DO NOTHING;
-- EXPLAIN for local execution just works fine
-- though going through distributed execution
EXPLAIN (COSTS OFF) SELECT * FROM distributed_table WHERE key = 1 AND age = 20;
                                                 QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (Citus Adaptive)
   Task Count: 1
   Tasks Shown: All
   ->  Task
         Node: host=localhost port=xxxxx dbname=regression
         ->  Index Scan using distributed_table_pkey_1470001 on distributed_table_1470001 distributed_table
               Index Cond: (key = 1)
               Filter: (age = 20)
(8 rows)

EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)   SELECT * FROM distributed_table WHERE key = 1 AND age = 20;
                                                             QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (Citus Adaptive) (actual rows=1 loops=1)
   Task Count: 1
   Tasks Shown: All
   ->  Task
         Node: host=localhost port=xxxxx dbname=regression
         ->  Index Scan using distributed_table_pkey_1470001 on distributed_table_1470001 distributed_table (actual rows=1 loops=1)
               Index Cond: (key = 1)
               Filter: (age = 20)
(8 rows)

EXPLAIN (COSTS OFF) DELETE FROM distributed_table WHERE key = 1 AND age = 20;
                                                    QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (Citus Adaptive)
   Task Count: 1
   Tasks Shown: All
   ->  Task
         Node: host=localhost port=xxxxx dbname=regression
         ->  Delete on distributed_table_1470001 distributed_table
               ->  Index Scan using distributed_table_pkey_1470001 on distributed_table_1470001 distributed_table
                     Index Cond: (key = 1)
                     Filter: (age = 20)
(9 rows)

EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) DELETE FROM distributed_table WHERE key = 1 AND age = 20;
                                                                QUERY PLAN
---------------------------------------------------------------------
 Custom Scan (Citus Adaptive) (actual rows=0 loops=1)
   Task Count: 1
   Tasks Shown: All
   ->  Task
         Node: host=localhost port=xxxxx dbname=regression
         ->  Delete on distributed_table_1470001 distributed_table (actual rows=0 loops=1)
               ->  Index Scan using distributed_table_pkey_1470001 on distributed_table_1470001 distributed_table (actual rows=0 loops=1)
                     Index Cond: (key = 1)
                     Filter: (age = 20)
(9 rows)

-- show that EXPLAIN ANALYZE deleted the row and cascades deletes
SELECT * FROM distributed_table WHERE key = 1 AND age = 20 ORDER BY 1,2,3;
NOTICE:  executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((key OPERATOR(pg_catalog.=) 1) AND (age OPERATOR(pg_catalog.=) 20)) ORDER BY key, value, age
 key | value | age
---------------------------------------------------------------------
(0 rows)

SELECT * FROM second_distributed_table WHERE key = 1 ORDER BY 1,2;
NOTICE:  executing the command locally: SELECT key, value FROM local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value
 key | value
---------------------------------------------------------------------
(0 rows)

-- Put rows back for other tests
INSERT INTO distributed_table VALUES (1, '22', 20);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 (key, value, age) VALUES (1, '22'::text, 20)
INSERT INTO second_distributed_table VALUES (1, '1');
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.second_distributed_table_1470005 (key, value) VALUES (1, '1'::text)
-- copy always happens via distributed execution irrespective of the
-- shards that are accessed
COPY reference_table FROM STDIN;
COPY distributed_table FROM STDIN WITH CSV;
COPY second_distributed_table FROM STDIN WITH CSV;
-- the behaviour in transaction blocks is the following:
	-- (a) Unless the first query is a local query, always use distributed execution.
	-- (b) If the executor has used local execution, it has to use local execution
	--     for the remaining of the transaction block. If that's not possible, the
	-- 	   executor has to error out (e.g., TRUNCATE is a utility command and we
	--	   currently do not support local execution of utility commands)
-- rollback should be able to rollback local execution
BEGIN;
	INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age
 key | value | age
---------------------------------------------------------------------
   1 | 29    |  20
(1 row)

	SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3;
NOTICE:  executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age
 key | value | age
---------------------------------------------------------------------
   1 | 29    |  20
(1 row)

ROLLBACK;
-- make sure that the value is rollbacked
SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3;
NOTICE:  executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age
 key | value | age
---------------------------------------------------------------------
   1 | 22    |  20
(1 row)

-- rollback should be able to rollback both the local and distributed executions
BEGIN;
	INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age
 key | value | age
---------------------------------------------------------------------
   1 | 29    |  20
(1 row)

	DELETE FROM distributed_table;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table
	-- DELETE should cascade, and we should not see any rows
	SELECT count(*) FROM second_distributed_table;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE true
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470007 second_distributed_table WHERE true
 count
---------------------------------------------------------------------
     0
(1 row)

ROLLBACK;
-- make sure that everything is rollbacked
SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3;
NOTICE:  executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age
 key | value | age
---------------------------------------------------------------------
   1 | 22    |  20
(1 row)

SELECT count(*) FROM second_distributed_table;
 count
---------------------------------------------------------------------
     2
(1 row)

SELECT * FROM second_distributed_table;
 key | value
---------------------------------------------------------------------
   1 | 1
   6 | '6'
(2 rows)

-- very simple examples, an SELECTs should see the modifications
-- that has done before
BEGIN;
	-- INSERT is executed locally
	INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '23' RETURNING *;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '23'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age
 key | value | age
---------------------------------------------------------------------
   1 | 23    |  20
(1 row)

	-- since the INSERT is executed locally, the SELECT should also be
	-- executed locally and see the changes
	SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3;
NOTICE:  executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age
 key | value | age
---------------------------------------------------------------------
   1 | 23    |  20
(1 row)

	-- multi-shard SELECTs are now forced to use local execution on
	-- the shards that reside on this node
	SELECT * FROM distributed_table WHERE value = '23' ORDER BY 1,2,3;
NOTICE:  executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text)
NOTICE:  executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text)
 key | value | age
---------------------------------------------------------------------
   1 | 23    |  20
(1 row)

	-- similarly, multi-shard modifications should use local exection
	-- on the shards that reside on this node
	DELETE FROM distributed_table WHERE value = '23';
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text)
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text)
	-- make sure that the value is deleted
	SELECT * FROM distributed_table WHERE value = '23' ORDER BY 1,2,3;
NOTICE:  executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text)
NOTICE:  executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.=) '23'::text)
 key | value | age
---------------------------------------------------------------------
(0 rows)

COMMIT;
-- make sure that we've committed everything
SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3;
NOTICE:  executing the command locally: SELECT key, value, age FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1) ORDER BY key, value, age
 key | value | age
---------------------------------------------------------------------
(0 rows)

-- if we start with a distributed execution, we should keep
-- using that and never switch back to local execution
BEGIN;
	DELETE FROM distributed_table WHERE value = '11';
	-- although this command could have been executed
	-- locally, it is not going to be executed locally
	SELECT * FROM distributed_table WHERE key = 1 ORDER BY 1,2,3;
 key | value | age
---------------------------------------------------------------------
(0 rows)

	-- but we can still execute parallel queries, even if
	-- they are utility commands
	TRUNCATE distributed_table CASCADE;
NOTICE:  truncate cascades to table "second_distributed_table"
	-- TRUNCATE cascaded into second_distributed_table
	SELECT count(*) FROM second_distributed_table;
 count
---------------------------------------------------------------------
     0
(1 row)

ROLLBACK;
-- load some data so that foreign keys won't complain with the next tests
INSERT INTO reference_table SELECT i FROM generate_series(500, 600) i;
-- a very similar set of operation, but this time use
-- COPY as the first command
BEGIN;
	INSERT INTO distributed_table SELECT i, i::text, i % 10 + 25 FROM generate_series(500, 600) i;
	-- this could go through local execution, but doesn't because we've already
	-- done distributed execution
	SELECT * FROM distributed_table WHERE key = 500 ORDER BY 1,2,3;
 key | value | age
---------------------------------------------------------------------
 500 | 500   |  25
(1 row)

	-- utility commands could still use distributed execution
	TRUNCATE distributed_table CASCADE;
NOTICE:  truncate cascades to table "second_distributed_table"
	-- ensure that TRUNCATE made it
	SELECT * FROM distributed_table WHERE key = 500 ORDER BY 1,2,3;
 key | value | age
---------------------------------------------------------------------
(0 rows)

ROLLBACK;
-- show that cascading foreign keys just works fine with local execution
BEGIN;
	INSERT INTO reference_table VALUES (701);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (701)
	INSERT INTO distributed_table VALUES (701, '701', 701);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 (key, value, age) VALUES (701, '701'::text, 701)
	INSERT INTO second_distributed_table VALUES (701, '701');
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.second_distributed_table_1470005 (key, value) VALUES (701, '701'::text)
	DELETE FROM reference_table WHERE key = 701;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table WHERE (key OPERATOR(pg_catalog.=) 701)
	SELECT count(*) FROM distributed_table WHERE key = 701;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 701)
 count
---------------------------------------------------------------------
     0
(1 row)

	SELECT count(*) FROM second_distributed_table WHERE key = 701;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.second_distributed_table_1470005 second_distributed_table WHERE (key OPERATOR(pg_catalog.=) 701)
 count
---------------------------------------------------------------------
     0
(1 row)

	-- multi-shard commands should also see the changes
	SELECT count(*) FROM distributed_table WHERE key > 700;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700)
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.>) 700)
 count
---------------------------------------------------------------------
     0
(1 row)

	-- we can still do multi-shard commands
	DELETE FROM distributed_table;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table
ROLLBACK;
-- multiple queries hitting different shards can be executed locally
BEGIN;
	SELECT count(*) FROM distributed_table WHERE key = 1;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     0
(1 row)

	SELECT count(*) FROM distributed_table WHERE key = 6;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6)
 count
---------------------------------------------------------------------
     1
(1 row)

	SELECT count(*) FROM distributed_table WHERE key = 500;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500)
 count
---------------------------------------------------------------------
     0
(1 row)

ROLLBACK;
-- a local query is followed by a command that cannot be executed locally
BEGIN;
	SELECT count(*) FROM distributed_table WHERE key = 1;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     0
(1 row)

	TRUNCATE distributed_table CASCADE;
NOTICE:  truncate cascades to table "second_distributed_table"
ERROR:  cannot execute command because a local execution has accessed a placement in the transaction
DETAIL:  Some parallel commands cannot be executed if a previous command has already been executed locally
HINT:  Try re-running the transaction with "SET LOCAL citus.enable_local_execution TO OFF;"
ROLLBACK;
-- a local query is followed by a command that cannot be executed locally
BEGIN;
	SELECT count(*) FROM distributed_table WHERE key = 1;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     0
(1 row)

	-- even no need to supply any data
	COPY distributed_table FROM STDIN WITH CSV;
ERROR:  cannot execute command because a local execution has accessed a placement in the transaction
DETAIL:  Some parallel commands cannot be executed if a previous command has already been executed locally
HINT:  Try re-running the transaction with "SET LOCAL citus.enable_local_execution TO OFF;"
ROLLBACK;
-- a local query is followed by a command that cannot be executed locally
BEGIN;
	SELECT count(*) FROM distributed_table WHERE key = 1;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     0
(1 row)

	INSERT INTO distributed_table (key) SELECT i FROM generate_series(1,10)i;
ERROR:  cannot execute command because a local execution has accessed a placement in the transaction
DETAIL:  Some parallel commands cannot be executed if a previous command has already been executed locally
HINT:  Try re-running the transaction with "SET LOCAL citus.enable_local_execution TO OFF;"
ROLLBACK;
-- a local query is followed by a command that cannot be executed locally
BEGIN;
	SELECT count(*) FROM distributed_table WHERE key = 1;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     0
(1 row)

	INSERT INTO distributed_table (key) SELECT key+1 FROM distributed_table;
ERROR:  cannot execute command because a local execution has accessed a placement in the transaction
DETAIL:  Some parallel commands cannot be executed if a previous command has already been executed locally
HINT:  Try re-running the transaction with "SET LOCAL citus.enable_local_execution TO OFF;"
ROLLBACK;
INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age
 key | value | age
---------------------------------------------------------------------
   1 | 11    |  21
(1 row)

BEGIN;
	DELETE FROM distributed_table WHERE key = 1;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
	EXPLAIN ANALYZE DELETE FROM distributed_table WHERE key = 1;
ERROR:  cannot execute command because a local execution has accessed a placement in the transaction
DETAIL:  Some parallel commands cannot be executed if a previous command has already been executed locally
HINT:  Try re-running the transaction with "SET LOCAL citus.enable_local_execution TO OFF;"
ROLLBACK;
BEGIN;
	INSERT INTO distributed_table VALUES (11, '111',29) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *;
 key | value | age
---------------------------------------------------------------------
  11 | 29    | 121
(1 row)

	-- this is already disallowed on the nodes, adding it in case we
	-- support DDLs from the worker nodes in the future
	ALTER TABLE distributed_table ADD COLUMN x INT;
ERROR:  operation is not allowed on this node
HINT:  Connect to the coordinator and run it again.
ROLLBACK;
BEGIN;
	INSERT INTO distributed_table VALUES (11, '111',29) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *;
 key | value | age
---------------------------------------------------------------------
  11 | 29    | 121
(1 row)

	-- this is already disallowed because VACUUM cannot be executed in tx block
	-- adding in case this is supported some day
	VACUUM second_distributed_table;
ERROR:  VACUUM cannot run inside a transaction block
ROLLBACK;
-- make sure that functions can use local execution
CREATE OR REPLACE PROCEDURE only_local_execution() AS $$
		DECLARE cnt INT;
		BEGIN
			INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29';
			SELECT count(*) INTO cnt FROM distributed_table WHERE key = 1;
			DELETE FROM distributed_table WHERE key = 1;
        END;
$$ LANGUAGE plpgsql;
CALL only_local_execution();
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text
CONTEXT:  SQL statement "INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'"
PL/pgSQL function only_local_execution() line 4 at SQL statement
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
CONTEXT:  SQL statement "SELECT count(*)          FROM distributed_table WHERE key = 1"
PL/pgSQL function only_local_execution() line 5 at SQL statement
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
CONTEXT:  SQL statement "DELETE FROM distributed_table WHERE key = 1"
PL/pgSQL function only_local_execution() line 6 at SQL statement
CREATE OR REPLACE PROCEDURE only_local_execution_with_params(int) AS $$
		DECLARE cnt INT;
		BEGIN
			INSERT INTO distributed_table VALUES ($1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29';
			SELECT count(*) INTO cnt FROM distributed_table WHERE key = $1;
			DELETE FROM distributed_table WHERE key = $1;
        END;
$$ LANGUAGE plpgsql;
CALL only_local_execution_with_params(1);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '29'::text
CONTEXT:  SQL statement "INSERT INTO distributed_table VALUES ($1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'"
PL/pgSQL function only_local_execution_with_params(integer) line 4 at SQL statement
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
CONTEXT:  SQL statement "SELECT count(*)          FROM distributed_table WHERE key = $1"
PL/pgSQL function only_local_execution_with_params(integer) line 5 at SQL statement
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
CONTEXT:  SQL statement "DELETE FROM distributed_table WHERE key = $1"
PL/pgSQL function only_local_execution_with_params(integer) line 6 at SQL statement
CREATE OR REPLACE PROCEDURE local_execution_followed_by_dist() AS $$
		DECLARE cnt INT;
		BEGIN
			INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29';
			SELECT count(*) INTO cnt FROM distributed_table WHERE key = 1;
			DELETE FROM distributed_table;
			SELECT count(*) INTO cnt FROM distributed_table;
        END;
$$ LANGUAGE plpgsql;
CALL local_execution_followed_by_dist();
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text
CONTEXT:  SQL statement "INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29'"
PL/pgSQL function local_execution_followed_by_dist() line 4 at SQL statement
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
CONTEXT:  SQL statement "SELECT count(*)          FROM distributed_table WHERE key = 1"
PL/pgSQL function local_execution_followed_by_dist() line 5 at SQL statement
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table
CONTEXT:  SQL statement "DELETE FROM distributed_table"
PL/pgSQL function local_execution_followed_by_dist() line 6 at SQL statement
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table
CONTEXT:  SQL statement "DELETE FROM distributed_table"
PL/pgSQL function local_execution_followed_by_dist() line 6 at SQL statement
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true
CONTEXT:  SQL statement "SELECT count(*)          FROM distributed_table"
PL/pgSQL function local_execution_followed_by_dist() line 7 at SQL statement
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true
CONTEXT:  SQL statement "SELECT count(*)          FROM distributed_table"
PL/pgSQL function local_execution_followed_by_dist() line 7 at SQL statement
-- test CTEs, including modifying CTEs
WITH local_insert AS (INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *),
distributed_local_mixed AS (SELECT * FROM reference_table WHERE key IN (SELECT key FROM local_insert))
SELECT * FROM local_insert, distributed_local_mixed;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age
NOTICE:  executing the command locally: SELECT key FROM local_shard_execution.reference_table_1470000 reference_table WHERE (key OPERATOR(pg_catalog.=) ANY (SELECT local_insert.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert))
NOTICE:  executing the command locally: SELECT local_insert.key, local_insert.value, local_insert.age, distributed_local_mixed.key FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT intermediate_result.key FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_local_mixed
 key | value | age | key
---------------------------------------------------------------------
   1 | 11    |  21 |   1
(1 row)

-- since we start with parallel execution, we do not switch back to local execution in the
-- latter CTEs
WITH distributed_local_mixed AS (SELECT * FROM distributed_table),
local_insert AS (INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '29' RETURNING *)
SELECT * FROM local_insert, distributed_local_mixed ORDER BY 1,2,3,4,5;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '29'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age
NOTICE:  executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470001 distributed_table) distributed_local_mixed) worker_subquery
NOTICE:  executing the command locally: SELECT worker_column_1 AS key, worker_column_2 AS value, worker_column_3 AS age, worker_column_4 AS key, worker_column_5 AS value, worker_column_6 AS age FROM (SELECT local_insert.key AS worker_column_1, local_insert.value AS worker_column_2, local_insert.age AS worker_column_3, distributed_local_mixed.key AS worker_column_4, distributed_local_mixed.value AS worker_column_5, distributed_local_mixed.age AS worker_column_6 FROM (SELECT intermediate_result.key, intermediate_result.value, intermediate_result.age FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text, age bigint)) local_insert, (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470003 distributed_table) distributed_local_mixed) worker_subquery
 key | value | age | key | value | age
---------------------------------------------------------------------
   1 | 29    |  21 |   1 | 11    |  21
(1 row)

-- router CTE pushdown
WITH all_data AS (SELECT * FROM distributed_table WHERE key = 1)
SELECT
	count(*)
FROM
	distributed_table, all_data
WHERE
	distributed_table.key = all_data.key AND distributed_table.key = 1;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table, (SELECT distributed_table_1.key, distributed_table_1.value, distributed_table_1.age FROM local_shard_execution.distributed_table_1470001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)) all_data WHERE ((distributed_table.key OPERATOR(pg_catalog.=) all_data.key) AND (distributed_table.key OPERATOR(pg_catalog.=) 1))
 count
---------------------------------------------------------------------
     1
(1 row)

INSERT INTO reference_table VALUES (2);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (2)
INSERT INTO distributed_table VALUES (2, '29', 29);
INSERT INTO second_distributed_table VALUES (2, '29');
-- single shard that is not a local query followed by a local query
WITH all_data AS (SELECT * FROM second_distributed_table WHERE key = 2)
SELECT
	distributed_table.key
FROM
	distributed_table, all_data
WHERE
	distributed_table.value = all_data.value AND distributed_table.key = 1
ORDER BY
	1 DESC;
NOTICE:  executing the command locally: SELECT distributed_table.key FROM local_shard_execution.distributed_table_1470001 distributed_table, (SELECT intermediate_result.key, intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer, value text)) all_data WHERE ((distributed_table.value OPERATOR(pg_catalog.=) all_data.value) AND (distributed_table.key OPERATOR(pg_catalog.=) 1)) ORDER BY distributed_table.key DESC
 key
---------------------------------------------------------------------
   1
(1 row)

-- multi-shard CTE is followed by a query which could be executed locally, but
-- since the query started with a parallel query, it doesn't use local execution
-- note that if we allow Postgres to inline the CTE (e.g., not have the EXISTS
-- subquery), then it'd pushdown the filters and the query becomes single-shard,
-- locally executable query
WITH all_data AS (SELECT * FROM distributed_table)
SELECT
	count(*)
FROM
	distributed_table, all_data
WHERE
	distributed_table.key = all_data.key AND distributed_table.key = 1
	AND EXISTS (SELECT * FROM all_data);
 count
---------------------------------------------------------------------
     1
(1 row)

-- in pg12, the following CTE can be inlined, still the query becomes
-- a subquery that needs to be recursively planned and a parallel
-- query, so do not use local execution
WITH all_data AS (SELECT age FROM distributed_table)
SELECT
	count(*)
FROM
	distributed_table, all_data
WHERE
	distributed_table.key = all_data.age AND distributed_table.key = 1;
 count
---------------------------------------------------------------------
     0
(1 row)

-- get ready for the next commands
TRUNCATE reference_table, distributed_table, second_distributed_table;
-- local execution of returning of reference tables
INSERT INTO reference_table VALUES (1),(2),(3),(4),(5),(6) RETURNING *;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 AS citus_table_alias (key) VALUES (1), (2), (3), (4), (5), (6) RETURNING citus_table_alias.key
 key
---------------------------------------------------------------------
   1
   2
   3
   4
   5
   6
(6 rows)

-- local execution of multi-row INSERTs
INSERT INTO distributed_table VALUES (1, '11',21), (5,'55',22) ON CONFLICT(key) DO UPDATE SET value = (EXCLUDED.value::int + 1)::text RETURNING *;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'11'::text,'21'::bigint), (5,'55'::text,'22'::bigint) ON CONFLICT(key) DO UPDATE SET value = (((excluded.value)::integer OPERATOR(pg_catalog.+) 1))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age
 key | value | age
---------------------------------------------------------------------
   1 | 11    |  21
   5 | 55    |  22
(2 rows)

-- distributed execution of multi-rows INSERTs, where some part of the execution
-- could have been done via local execution but the executor choose the other way around
-- because the command is a multi-shard query
INSERT INTO distributed_table VALUES (1, '11',21), (2,'22',22), (3,'33',33), (4,'44',44),(5,'55',55) ON CONFLICT(key) DO UPDATE SET value = (EXCLUDED.value::int + 1)::text RETURNING *;
 key | value | age
---------------------------------------------------------------------
   1 | 12    |  21
   2 | 22    |  22
   3 | 33    |  33
   4 | 44    |  44
   5 | 56    |  22
(5 rows)

PREPARE local_prepare_no_param AS SELECT count(*) FROM distributed_table WHERE key = 1;
PREPARE local_prepare_no_param_subquery AS
SELECT DISTINCT trim(value) FROM (
    SELECT value FROM distributed_table
    WHERE
        key IN (1, 6, 500, 701)
        AND (select 2) > random()
        order by 1
        limit 2
    ) t;
PREPARE local_prepare_param (int) AS SELECT count(*) FROM distributed_table WHERE key = $1;
PREPARE remote_prepare_param (int) AS SELECT count(*) FROM distributed_table WHERE key != $1;
BEGIN;
	-- 6 local execution without params
	EXECUTE local_prepare_no_param;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     1
(1 row)

	EXECUTE local_prepare_no_param;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     1
(1 row)

	EXECUTE local_prepare_no_param;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     1
(1 row)

	EXECUTE local_prepare_no_param;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     1
(1 row)

	EXECUTE local_prepare_no_param;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     1
(1 row)

	EXECUTE local_prepare_no_param;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     1
(1 row)

	-- 6 local execution without params and some subqueries
	EXECUTE local_prepare_no_param_subquery;
NOTICE:  executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint
NOTICE:  executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint
NOTICE:  executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t
 btrim
---------------------------------------------------------------------
 12
(1 row)

	EXECUTE local_prepare_no_param_subquery;
NOTICE:  executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint
NOTICE:  executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint
NOTICE:  executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t
 btrim
---------------------------------------------------------------------
 12
(1 row)

	EXECUTE local_prepare_no_param_subquery;
NOTICE:  executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint
NOTICE:  executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint
NOTICE:  executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t
 btrim
---------------------------------------------------------------------
 12
(1 row)

	EXECUTE local_prepare_no_param_subquery;
NOTICE:  executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint
NOTICE:  executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint
NOTICE:  executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t
 btrim
---------------------------------------------------------------------
 12
(1 row)

	EXECUTE local_prepare_no_param_subquery;
NOTICE:  executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint
NOTICE:  executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint
NOTICE:  executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t
 btrim
---------------------------------------------------------------------
 12
(1 row)

	EXECUTE local_prepare_no_param_subquery;
NOTICE:  executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint
NOTICE:  executing the command locally: SELECT worker_column_1 AS value FROM (SELECT distributed_table.value AS worker_column_1 FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE ((distributed_table.key OPERATOR(pg_catalog.=) ANY (ARRAY[1, 6, 500, 701])) AND (((SELECT 2))::double precision OPERATOR(pg_catalog.>) random()))) worker_subquery ORDER BY worker_column_1 LIMIT '2'::bigint
NOTICE:  executing the command locally: SELECT DISTINCT btrim(value) AS btrim FROM (SELECT intermediate_result.value FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(value text)) t
 btrim
---------------------------------------------------------------------
 12
(1 row)

	-- 6 local executions with params
	EXECUTE local_prepare_param(1);
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     1
(1 row)

	EXECUTE local_prepare_param(5);
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 5)
 count
---------------------------------------------------------------------
     1
(1 row)

	EXECUTE local_prepare_param(6);
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6)
 count
---------------------------------------------------------------------
     0
(1 row)

	EXECUTE local_prepare_param(1);
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     1
(1 row)

	EXECUTE local_prepare_param(5);
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.=) 5)
 count
---------------------------------------------------------------------
     1
(1 row)

	EXECUTE local_prepare_param(6);
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 6)
 count
---------------------------------------------------------------------
     0
(1 row)

	-- followed by a non-local execution
	EXECUTE remote_prepare_param(1);
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1)
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 1)
 count
---------------------------------------------------------------------
     4
(1 row)

COMMIT;
PREPARE local_insert_prepare_no_param AS INSERT INTO distributed_table VALUES (1+0*random(), '11',21::int) ON CONFLICT(key) DO UPDATE SET value = '29' || '28' RETURNING *, key + 1, value || '30', age * 15;
PREPARE local_insert_prepare_param (int) AS INSERT INTO distributed_table VALUES ($1+0*random(), '11',21::int) ON CONFLICT(key) DO UPDATE SET value = '29' || '28' RETURNING *, key + 1, value || '30', age * 15;
BEGIN;
	-- 6 local execution without params
	EXECUTE local_insert_prepare_no_param;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15)
 key | value | age | ?column? | ?column? | ?column?
---------------------------------------------------------------------
   1 | 2928  |  21 |        2 | 292830   |      315
(1 row)

	EXECUTE local_insert_prepare_no_param;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15)
 key | value | age | ?column? | ?column? | ?column?
---------------------------------------------------------------------
   1 | 2928  |  21 |        2 | 292830   |      315
(1 row)

	EXECUTE local_insert_prepare_no_param;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15)
 key | value | age | ?column? | ?column? | ?column?
---------------------------------------------------------------------
   1 | 2928  |  21 |        2 | 292830   |      315
(1 row)

	EXECUTE local_insert_prepare_no_param;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15)
 key | value | age | ?column? | ?column? | ?column?
---------------------------------------------------------------------
   1 | 2928  |  21 |        2 | 292830   |      315
(1 row)

	EXECUTE local_insert_prepare_no_param;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15)
 key | value | age | ?column? | ?column? | ?column?
---------------------------------------------------------------------
   1 | 2928  |  21 |        2 | 292830   |      315
(1 row)

	EXECUTE local_insert_prepare_no_param;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15)
 key | value | age | ?column? | ?column? | ?column?
---------------------------------------------------------------------
   1 | 2928  |  21 |        2 | 292830   |      315
(1 row)

	-- 6 local executions with params
	EXECUTE local_insert_prepare_param(1);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15)
 key | value | age | ?column? | ?column? | ?column?
---------------------------------------------------------------------
   1 | 2928  |  21 |        2 | 292830   |      315
(1 row)

	EXECUTE local_insert_prepare_param(5);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15)
 key | value | age | ?column? | ?column? | ?column?
---------------------------------------------------------------------
   5 | 2928  |  22 |        6 | 292830   |      330
(1 row)

	EXECUTE local_insert_prepare_param(6);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15)
 key | value | age | ?column? | ?column? | ?column?
---------------------------------------------------------------------
   6 | 11    |  21 |        7 | 1130     |      315
(1 row)

	EXECUTE local_insert_prepare_param(1);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15)
 key | value | age | ?column? | ?column? | ?column?
---------------------------------------------------------------------
   1 | 2928  |  21 |        2 | 292830   |      315
(1 row)

	EXECUTE local_insert_prepare_param(5);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15)
 key | value | age | ?column? | ?column? | ?column?
---------------------------------------------------------------------
   5 | 2928  |  22 |        6 | 292830   |      330
(1 row)

	EXECUTE local_insert_prepare_param(6);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6, '11'::text, '21'::bigint) ON CONFLICT(key) DO UPDATE SET value = '2928'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age, (citus_table_alias.key OPERATOR(pg_catalog.+) 1), (citus_table_alias.value OPERATOR(pg_catalog.||) '30'::text), (citus_table_alias.age OPERATOR(pg_catalog.*) 15)
 key | value | age | ?column? | ?column? | ?column?
---------------------------------------------------------------------
   6 | 2928  |  21 |        7 | 292830   |      315
(1 row)

	-- followed by a non-local execution
	EXECUTE remote_prepare_param(2);
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2)
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.<>) 2)
 count
---------------------------------------------------------------------
     5
(1 row)

COMMIT;
PREPARE local_multi_row_insert_prepare_no_param AS
	INSERT INTO distributed_table VALUES (1,'55', 21), (5,'15',33) ON CONFLICT (key) WHERE key > 3 and key < 4 DO UPDATE SET value = '88' || EXCLUDED.value;
PREPARE local_multi_row_insert_prepare_no_param_multi_shard AS
	INSERT INTO distributed_table VALUES (6,'55', 21), (5,'15',33) ON CONFLICT (key) WHERE key > 3 AND key < 4 DO UPDATE SET value = '88' || EXCLUDED.value;;
PREPARE local_multi_row_insert_prepare_params(int,int) AS
	INSERT INTO distributed_table VALUES ($1,'55', 21), ($2,'15',33) ON CONFLICT (key) WHERE key > 3 and key < 4 DO UPDATE SET value = '88' || EXCLUDED.value;;
INSERT INTO reference_table VALUES (11);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (11)
BEGIN;
	EXECUTE local_multi_row_insert_prepare_no_param;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_no_param;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_no_param;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_no_param;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_no_param;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_no_param;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_no_param_multi_shard;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_no_param_multi_shard;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_no_param_multi_shard;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_no_param_multi_shard;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_no_param_multi_shard;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_no_param_multi_shard;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_params(1,6);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_params(1,5);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1,'55'::text,'21'::bigint), (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_params(6,5);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_params(5,1);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint), (1,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_params(5,6);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470003 AS citus_table_alias (key, value, age) VALUES (6,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	EXECUTE local_multi_row_insert_prepare_params(5,1);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint), (1,'15'::text,'33'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
	-- one task is remote
	EXECUTE local_multi_row_insert_prepare_params(5,11);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (5,'55'::text,'21'::bigint) ON CONFLICT(key) WHERE ((key OPERATOR(pg_catalog.>) 3) AND (key OPERATOR(pg_catalog.<) 4)) DO UPDATE SET value = ('88'::text OPERATOR(pg_catalog.||) excluded.value)
ROLLBACK;
-- failures of local execution should rollback both the
-- local execution and remote executions
-- fail on a local execution
BEGIN;
	INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age
 key | value | age
---------------------------------------------------------------------
   1 | 100   |  21
(1 row)

	UPDATE distributed_table SET value = '200';
NOTICE:  executing the command locally: UPDATE local_shard_execution.distributed_table_1470001 distributed_table SET value = '200'::text
NOTICE:  executing the command locally: UPDATE local_shard_execution.distributed_table_1470003 distributed_table SET value = '200'::text
	INSERT INTO distributed_table VALUES (1, '100',21) ON CONFLICT(key) DO UPDATE SET value = (1 / (100.0 - EXCLUDED.value::int))::text RETURNING *;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '100'::text, 21) ON CONFLICT(key) DO UPDATE SET value = (((1)::numeric OPERATOR(pg_catalog./) (100.0 OPERATOR(pg_catalog.-) ((excluded.value)::integer)::numeric)))::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age
ERROR:  division by zero
ROLLBACK;
-- we've rollbacked everything
SELECT count(*) FROM distributed_table WHERE value = '200';
 count
---------------------------------------------------------------------
     0
(1 row)

-- RETURNING should just work fine for reference tables
INSERT INTO reference_table VALUES (500) RETURNING *;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (500) RETURNING key
 key
---------------------------------------------------------------------
 500
(1 row)

DELETE FROM reference_table WHERE key = 500 RETURNING *;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table WHERE (key OPERATOR(pg_catalog.=) 500) RETURNING key
 key
---------------------------------------------------------------------
 500
(1 row)

-- should be able to skip local execution even if in a sequential mode of execution
BEGIN;
	SET LOCAL citus.multi_shard_modify_mode TO sequential ;
	DELETE FROM distributed_table;
	INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *;
 key | value | age
---------------------------------------------------------------------
   1 | 11    |  21
(1 row)

ROLLBACK;
-- sequential execution should just work fine after a local execution
BEGIN;
	SET citus.multi_shard_modify_mode TO sequential ;
	INSERT INTO distributed_table VALUES (1, '11',21) ON CONFLICT(key) DO UPDATE SET value = '100' RETURNING *;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 AS citus_table_alias (key, value, age) VALUES (1, '11'::text, 21) ON CONFLICT(key) DO UPDATE SET value = '100'::text RETURNING citus_table_alias.key, citus_table_alias.value, citus_table_alias.age
 key | value | age
---------------------------------------------------------------------
   1 | 100   |  21
(1 row)

	DELETE FROM distributed_table;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table
ROLLBACK;
-- load some data so that foreign keys won't complain with the next tests
TRUNCATE reference_table CASCADE;
NOTICE:  truncate cascades to table "distributed_table"
NOTICE:  truncate cascades to table "second_distributed_table"
INSERT INTO reference_table SELECT i FROM generate_series(500, 600) i;
INSERT INTO distributed_table SELECT i, i::text, i % 10 + 25 FROM generate_series(500, 600) i;
-- show that both local, and mixed local-distributed executions
-- calculate rows processed correctly
BEGIN;
	DELETE FROM distributed_table WHERE key = 500;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500)
	DELETE FROM distributed_table WHERE value != '123123213123213';
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text)
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (value OPERATOR(pg_catalog.<>) '123123213123213'::text)
ROLLBACK;
BEGIN;
	DELETE FROM reference_table WHERE key = 500 RETURNING *;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table WHERE (key OPERATOR(pg_catalog.=) 500) RETURNING key
 key
---------------------------------------------------------------------
 500
(1 row)

	DELETE FROM reference_table;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table
ROLLBACK;
-- task-tracker select execution
BEGIN;
	DELETE FROM distributed_table WHERE key = 500;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500)
	SET LOCAL citus.task_executor_type = 'task-tracker';
	SELECT count(*) FROM distributed_table;
ERROR:  cannot execute command because a local execution has accessed a placement in the transaction
DETAIL:  Some parallel commands cannot be executed if a previous command has already been executed locally
HINT:  Try re-running the transaction with "SET LOCAL citus.enable_local_execution TO OFF;"
ROLLBACK;
-- local execution should not be executed locally
-- becase a task-tracker query has already been executed
BEGIN;
	SET LOCAL citus.task_executor_type = 'task-tracker';
	SET LOCAL client_min_messages TO INFO;
	SELECT count(*) FROM distributed_table;
 count
---------------------------------------------------------------------
   101
(1 row)

	SET LOCAL client_min_messages TO LOG;
	DELETE FROM distributed_table WHERE key = 500;
ROLLBACK;
-- probably not a realistic case since views are not very
-- well supported with MX
CREATE VIEW v_local_query_execution AS
SELECT * FROM distributed_table WHERE key = 500;
SELECT * FROM v_local_query_execution;
NOTICE:  executing the command locally: SELECT key, value, age FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (distributed_table.key OPERATOR(pg_catalog.=) 500)) v_local_query_execution
 key | value | age
---------------------------------------------------------------------
 500 | 500   |  25
(1 row)

-- similar test, but this time the view itself is a non-local
-- query, but the query on the view is local
CREATE VIEW v_local_query_execution_2 AS
SELECT * FROM distributed_table;
SELECT * FROM v_local_query_execution_2 WHERE key = 500;
NOTICE:  executing the command locally: SELECT key, value, age FROM (SELECT distributed_table.key, distributed_table.value, distributed_table.age FROM local_shard_execution.distributed_table_1470003 distributed_table) v_local_query_execution_2 WHERE (key OPERATOR(pg_catalog.=) 500)
 key | value | age
---------------------------------------------------------------------
 500 | 500   |  25
(1 row)

-- even if we switch from remote execution -> local execution,
-- we are able to use remote execution after rollback
BEGIN;
	SAVEPOINT my_savepoint;
	SELECT count(*) FROM distributed_table;
 count
---------------------------------------------------------------------
   101
(1 row)

    DELETE FROM distributed_table WHERE key = 500;
    ROLLBACK TO SAVEPOINT my_savepoint;
	DELETE FROM distributed_table WHERE key = 500;
COMMIT;
-- even if we switch from local execution -> remote execution,
-- we are able to use local execution after rollback
BEGIN;
	SAVEPOINT my_savepoint;
    DELETE FROM distributed_table WHERE key = 500;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500)
	SELECT count(*) FROM distributed_table;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470001 distributed_table WHERE true
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE true
 count
---------------------------------------------------------------------
   100
(1 row)

    ROLLBACK TO SAVEPOINT my_savepoint;
	DELETE FROM distributed_table WHERE key = 500;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table WHERE (key OPERATOR(pg_catalog.=) 500)
COMMIT;
-- sanity check: local execution on partitions
INSERT INTO collections_list (collection_id) VALUES (0) RETURNING *;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('3940649673949185'::bigint, '3940649673949185'::bigint, 0) RETURNING key, ser, ts, collection_id, value
       key        |       ser        | ts | collection_id | value
---------------------------------------------------------------------
 3940649673949185 | 3940649673949185 |    |             0 |
(1 row)

BEGIN;
	INSERT INTO collections_list (key, collection_id) VALUES (1,0);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('1'::bigint, '3940649673949186'::bigint, 0)
	SELECT count(*) FROM collections_list_0 WHERE key = 1;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.collections_list_0_1470013 collections_list_0 WHERE (key OPERATOR(pg_catalog.=) 1)
 count
---------------------------------------------------------------------
     1
(1 row)

	SELECT count(*) FROM collections_list;
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.collections_list_1470009 collections_list WHERE true
NOTICE:  executing the command locally: SELECT count(*) AS count FROM local_shard_execution.collections_list_1470011 collections_list WHERE true
 count
---------------------------------------------------------------------
     2
(1 row)

	SELECT * FROM collections_list ORDER BY 1,2,3,4;
NOTICE:  executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution.collections_list_1470009 collections_list WHERE true
NOTICE:  executing the command locally: SELECT key, ser, ts, collection_id, value FROM local_shard_execution.collections_list_1470011 collections_list WHERE true
       key        |       ser        | ts | collection_id | value
---------------------------------------------------------------------
                1 | 3940649673949186 |    |             0 |
 3940649673949185 | 3940649673949185 |    |             0 |
(2 rows)

COMMIT;
TRUNCATE collections_list;
-- make sure that even if local execution is used, the sequence values
-- are generated locally
ALTER SEQUENCE collections_list_key_seq NO MINVALUE NO MAXVALUE;
PREPARE serial_prepared_local AS INSERT INTO collections_list (collection_id) VALUES (0) RETURNING key, ser;
SELECT setval('collections_list_key_seq', 4);
 setval
---------------------------------------------------------------------
      4
(1 row)

EXECUTE serial_prepared_local;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('5'::bigint, '3940649673949187'::bigint, 0) RETURNING key, ser
 key |       ser
---------------------------------------------------------------------
   5 | 3940649673949187
(1 row)

SELECT setval('collections_list_key_seq', 5);
 setval
---------------------------------------------------------------------
      5
(1 row)

EXECUTE serial_prepared_local;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('6'::bigint, '3940649673949188'::bigint, 0) RETURNING key, ser
 key |       ser
---------------------------------------------------------------------
   6 | 3940649673949188
(1 row)

SELECT setval('collections_list_key_seq', 499);
 setval
---------------------------------------------------------------------
    499
(1 row)

EXECUTE serial_prepared_local;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('500'::bigint, '3940649673949189'::bigint, 0) RETURNING key, ser
 key |       ser
---------------------------------------------------------------------
 500 | 3940649673949189
(1 row)

SELECT setval('collections_list_key_seq', 700);
 setval
---------------------------------------------------------------------
    700
(1 row)

EXECUTE serial_prepared_local;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('701'::bigint, '3940649673949190'::bigint, 0) RETURNING key, ser
 key |       ser
---------------------------------------------------------------------
 701 | 3940649673949190
(1 row)

SELECT setval('collections_list_key_seq', 708);
 setval
---------------------------------------------------------------------
    708
(1 row)

EXECUTE serial_prepared_local;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.collections_list_1470011 (key, ser, collection_id) VALUES ('709'::bigint, '3940649673949191'::bigint, 0) RETURNING key, ser
 key |       ser
---------------------------------------------------------------------
 709 | 3940649673949191
(1 row)

SELECT setval('collections_list_key_seq', 709);
 setval
---------------------------------------------------------------------
    709
(1 row)

EXECUTE serial_prepared_local;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.collections_list_1470009 (key, ser, collection_id) VALUES ('710'::bigint, '3940649673949192'::bigint, 0) RETURNING key, ser
 key |       ser
---------------------------------------------------------------------
 710 | 3940649673949192
(1 row)

-- and, one remote test
SELECT setval('collections_list_key_seq', 10);
 setval
---------------------------------------------------------------------
     10
(1 row)

EXECUTE serial_prepared_local;
 key |       ser
---------------------------------------------------------------------
  11 | 3940649673949193
(1 row)

-- the final queries for the following CTEs are going to happen on the intermediate results only
-- one of them will be executed remotely, and the other is locally
-- Citus currently doesn't allow using task_assignment_policy for intermediate results
WITH distributed_local_mixed AS (INSERT INTO reference_table VALUES (1000) RETURNING *) SELECT * FROM distributed_local_mixed;
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (1000) RETURNING key
NOTICE:  executing the command locally: SELECT key FROM (SELECT intermediate_result.key FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(key integer)) distributed_local_mixed
 key
---------------------------------------------------------------------
 1000
(1 row)

-- clean the table for the next tests
SET search_path TO local_shard_execution;
TRUNCATE distributed_table CASCADE;
NOTICE:  truncate cascades to table "second_distributed_table"
-- load some data on a remote shard
INSERT INTO reference_table (key) VALUES (1), (2);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 AS citus_table_alias (key) VALUES (1), (2)
INSERT INTO distributed_table (key) VALUES (2);
BEGIN;
    -- local execution followed by a distributed query
    INSERT INTO distributed_table (key) VALUES (1);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.distributed_table_1470001 (key) VALUES (1)
    DELETE FROM distributed_table RETURNING key;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470001 distributed_table RETURNING key
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.distributed_table_1470003 distributed_table RETURNING key
 key
---------------------------------------------------------------------
   1
   2
(2 rows)

COMMIT;
-- a similar test with a reference table
TRUNCATE reference_table CASCADE;
NOTICE:  truncate cascades to table "distributed_table"
NOTICE:  truncate cascades to table "second_distributed_table"
-- load some data on a remote shard
INSERT INTO reference_table (key) VALUES (2);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (2)
BEGIN;
    -- local execution followed by a distributed query
    INSERT INTO reference_table (key) VALUES (1);
NOTICE:  executing the command locally: INSERT INTO local_shard_execution.reference_table_1470000 (key) VALUES (1)
    DELETE FROM reference_table RETURNING key;
NOTICE:  executing the command locally: DELETE FROM local_shard_execution.reference_table_1470000 reference_table RETURNING key
 key
---------------------------------------------------------------------
   1
   2
(2 rows)

COMMIT;
-- however complex the query, local execution can handle
SET client_min_messages TO LOG;
SET citus.log_local_commands TO ON;
WITH cte_1 AS
  (SELECT *
   FROM
     (WITH cte_1 AS
        (SELECT *
         FROM distributed_table
         WHERE key = 1) SELECT *
      FROM cte_1) AS foo)
SELECT count(*)
FROM cte_1
JOIN distributed_table USING (key)
WHERE distributed_table.key = 1
  AND distributed_table.key IN
    (SELECT key
     FROM distributed_table
     WHERE key = 1);
NOTICE:  executing the command locally: SELECT count(*) AS count FROM ((SELECT foo.key, foo.value, foo.age FROM (SELECT cte_1_1.key, cte_1_1.value, cte_1_1.age FROM (SELECT distributed_table_1.key, distributed_table_1.value, distributed_table_1.age FROM local_shard_execution.distributed_table_1470001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1)) cte_1_1) foo) cte_1 JOIN local_shard_execution.distributed_table_1470001 distributed_table(key, value, age) USING (key)) WHERE ((distributed_table.key OPERATOR(pg_catalog.=) 1) AND (distributed_table.key OPERATOR(pg_catalog.=) ANY (SELECT distributed_table_1.key FROM local_shard_execution.distributed_table_1470001 distributed_table_1 WHERE (distributed_table_1.key OPERATOR(pg_catalog.=) 1))))
 count
---------------------------------------------------------------------
     0
(1 row)

RESET client_min_messages;
RESET citus.log_local_commands;
\c - - - :master_port
SET citus.next_shard_id TO 1480000;
-- local execution with custom type
SET citus.replication_model TO "streaming";
SET citus.shard_replication_factor TO 1;
CREATE TYPE invite_resp AS ENUM ('yes', 'no', 'maybe');
CREATE TABLE event_responses (
  event_id int,
  user_id int,
  response invite_resp,
  primary key (event_id, user_id)
);
SELECT create_distributed_table('event_responses', 'event_id');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE OR REPLACE PROCEDURE register_for_event(p_event_id int, p_user_id int, p_choice invite_resp)
LANGUAGE plpgsql AS $fn$
BEGIN
   INSERT INTO event_responses VALUES (p_event_id, p_user_id, p_choice)
   ON CONFLICT (event_id, user_id)
   DO UPDATE SET response = EXCLUDED.response;

   PERFORM count(*) FROM event_responses WHERE event_id = p_event_id;

   PERFORM count(*) FROM event_responses WHERE event_id = p_event_id AND false;

   UPDATE event_responses SET response = p_choice WHERE event_id = p_event_id;

END;
$fn$;
SELECT create_distributed_function('register_for_event(int,int,invite_resp)', 'p_event_id', 'event_responses');
 create_distributed_function
---------------------------------------------------------------------

(1 row)

-- call 7 times to make sure it works after the 5th time(postgres binds values after the 5th time)
-- after 6th, the local execution caches the local plans and uses it
-- execute it both locally and remotely
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
\c - - - :worker_2_port
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
CALL register_for_event(16, 1, 'yes');
-- values 16, 17 and 19 hits the same
-- shard, so we're re-using the same cached
-- plans per statement across different distribution
--  key values
CALL register_for_event(17, 1, 'yes');
CALL register_for_event(19, 1, 'yes');
CALL register_for_event(17, 1, 'yes');
CALL register_for_event(19, 1, 'yes');
-- should work fine if the logs are enabled
\set VERBOSITY terse
SET citus.log_local_commands TO ON;
SET client_min_messages TO DEBUG2;
CALL register_for_event(19, 1, 'yes');
NOTICE:  executing the command locally: INSERT INTO public.event_responses_1480001 AS citus_table_alias (event_id, user_id, response) VALUES (19, 1, 'yes'::public.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response
NOTICE:  executing the command locally: SELECT count(*) AS count FROM public.event_responses_1480001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 19)
NOTICE:  executing the command locally: SELECT count(*) AS count FROM (SELECT NULL::integer AS event_id, NULL::integer AS user_id, NULL::public.invite_resp AS response WHERE false) event_responses(event_id, user_id, response) WHERE ((event_id OPERATOR(pg_catalog.=) 19) AND false)
NOTICE:  executing the command locally: UPDATE public.event_responses_1480001 event_responses SET response = 'yes'::public.invite_resp WHERE (event_id OPERATOR(pg_catalog.=) 19)
-- should be fine even if no parameters exists in the query
SELECT count(*) FROM event_responses WHERE event_id = 16;
DEBUG:  Distributed planning for a fast-path router query
DEBUG:  Creating router plan
DEBUG:  Plan is router executable
NOTICE:  executing the command locally: SELECT count(*) AS count FROM public.event_responses_1480001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 16)
 count
---------------------------------------------------------------------
     1
(1 row)

SELECT count(*) FROM event_responses WHERE event_id = 16;
DEBUG:  Distributed planning for a fast-path router query
DEBUG:  Creating router plan
DEBUG:  Plan is router executable
NOTICE:  executing the command locally: SELECT count(*) AS count FROM public.event_responses_1480001 event_responses WHERE (event_id OPERATOR(pg_catalog.=) 16)
 count
---------------------------------------------------------------------
     1
(1 row)

UPDATE event_responses SET response = 'no' WHERE event_id = 16;
DEBUG:  Distributed planning for a fast-path router query
DEBUG:  Creating router plan
DEBUG:  Plan is router executable
NOTICE:  executing the command locally: UPDATE public.event_responses_1480001 event_responses SET response = 'no'::public.invite_resp WHERE (event_id OPERATOR(pg_catalog.=) 16)
INSERT INTO event_responses VALUES (16, 666, 'maybe')
ON CONFLICT (event_id, user_id)
DO UPDATE SET response = EXCLUDED.response RETURNING *;
DEBUG:  Creating router plan
DEBUG:  Plan is router executable
NOTICE:  executing the command locally: INSERT INTO public.event_responses_1480001 AS citus_table_alias (event_id, user_id, response) VALUES (16, 666, 'maybe'::public.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response RETURNING citus_table_alias.event_id, citus_table_alias.user_id, citus_table_alias.response
 event_id | user_id | response
---------------------------------------------------------------------
       16 |     666 | maybe
(1 row)

-- multi row INSERTs hitting the same shard
INSERT INTO event_responses VALUES (16, 666, 'maybe'), (17, 777, 'no')
ON CONFLICT (event_id, user_id)
DO UPDATE SET response = EXCLUDED.response RETURNING *;
DEBUG:  Creating router plan
DEBUG:  Plan is router executable
NOTICE:  executing the command locally: INSERT INTO public.event_responses_1480001 AS citus_table_alias (event_id, user_id, response) VALUES (16,666,'maybe'::public.invite_resp), (17,777,'no'::public.invite_resp) ON CONFLICT(event_id, user_id) DO UPDATE SET response = excluded.response RETURNING citus_table_alias.event_id, citus_table_alias.user_id, citus_table_alias.response
 event_id | user_id | response
---------------------------------------------------------------------
       16 |     666 | maybe
       17 |     777 | no
(2 rows)

-- now, similar tests with some settings changed
SET citus.enable_local_execution TO false;
SET citus.enable_fast_path_router_planner TO false;
CALL register_for_event(19, 1, 'yes');
-- should be fine even if no parameters exists in the query
SELECT count(*) FROM event_responses WHERE event_id = 16;
DEBUG:  Creating router plan
DEBUG:  Plan is router executable
 count
---------------------------------------------------------------------
     2
(1 row)

SELECT count(*) FROM event_responses WHERE event_id = 16;
DEBUG:  Creating router plan
DEBUG:  Plan is router executable
 count
---------------------------------------------------------------------
     2
(1 row)

UPDATE event_responses SET response = 'no' WHERE event_id = 16;
DEBUG:  Creating router plan
DEBUG:  Plan is router executable
INSERT INTO event_responses VALUES (16, 666, 'maybe')
ON CONFLICT (event_id, user_id)
DO UPDATE SET response = EXCLUDED.response RETURNING *;
DEBUG:  Creating router plan
DEBUG:  Plan is router executable
 event_id | user_id | response
---------------------------------------------------------------------
       16 |     666 | maybe
(1 row)

-- multi row INSERTs hitting the same shard
INSERT INTO event_responses VALUES (16, 666, 'maybe'), (17, 777, 'no')
ON CONFLICT (event_id, user_id)
DO UPDATE SET response = EXCLUDED.response RETURNING *;
DEBUG:  Creating router plan
DEBUG:  Plan is router executable
 event_id | user_id | response
---------------------------------------------------------------------
       16 |     666 | maybe
       17 |     777 | no
(2 rows)

\c - - - :master_port
SET client_min_messages TO ERROR;
SET search_path TO public;
DROP SCHEMA local_shard_execution CASCADE;
