SET citus.log_remote_commands TO OFF; DROP SCHEMA IF EXISTS forcepushdown_schema CASCADE; NOTICE: schema "forcepushdown_schema" does not exist, skipping CREATE SCHEMA forcepushdown_schema; SET search_path TO 'forcepushdown_schema'; SET citus.shard_replication_factor = 1; SET citus.shard_count = 32; SET citus.next_shard_id TO 900000; CREATE TABLE test_forcepushdown(intcol int PRIMARY KEY, data char(50) default 'default'); SELECT create_distributed_table('test_forcepushdown', 'intcol', colocate_with := 'none'); create_distributed_table --------------------------------------------------------------------- (1 row) -- --Table in a different colocation group -- CREATE TABLE test_forcepushdown_noncolocate(intcol int PRIMARY KEY); SELECT create_distributed_table('test_forcepushdown_noncolocate', 'intcol', colocate_with := 'none'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE FUNCTION insert_data(a integer) RETURNS void LANGUAGE plpgsql AS $fn$ BEGIN INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (a); END; $fn$; CREATE FUNCTION insert_data_non_distarg(a integer) RETURNS void LANGUAGE plpgsql AS $fn$ BEGIN INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (a+1); END; $fn$; CREATE FUNCTION update_data_nonlocal(a integer) RETURNS void LANGUAGE plpgsql AS $fn$ BEGIN UPDATE forcepushdown_schema.test_forcepushdown SET data = 'non-default'; END; $fn$; CREATE FUNCTION insert_data_noncolocation(a int) RETURNS void LANGUAGE plpgsql AS $fn$ BEGIN -- Insert into a different table than the function is colocated with INSERT INTO forcepushdown_schema.test_forcepushdown_noncolocate VALUES (a); END; $fn$; SELECT create_distributed_function( 'insert_data(int)', 'a', colocate_with := 'test_forcepushdown', force_delegation := true ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'insert_data_non_distarg(int)', 'a', colocate_with := 'test_forcepushdown', force_delegation := true ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'update_data_nonlocal(int)', 'a', colocate_with := 'test_forcepushdown', force_delegation := true ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'insert_data_noncolocation(int)', 'a', colocate_with := 'test_forcepushdown', force_delegation := true ); create_distributed_function --------------------------------------------------------------------- (1 row) SET client_min_messages TO DEBUG1; --SET citus.log_remote_commands TO on; SELECT public.wait_until_metadata_sync(30000); wait_until_metadata_sync --------------------------------------------------------------------- (1 row) SELECT 'Transaction with no errors' Testing; testing --------------------------------------------------------------------- Transaction with no errors (1 row) BEGIN; INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (1); -- This call will insert both the rows locally on the remote worker SELECT insert_data(2); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call insert_data --------------------------------------------------------------------- (1 row) INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (3); COMMIT; SELECT 'Transaction with duplicate error in the remote function' Testing; testing --------------------------------------------------------------------- Transaction with duplicate error in the remote function (1 row) BEGIN; INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (4); -- This call will fail with duplicate error on the remote worker SELECT insert_data(3); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: duplicate key value violates unique constraint "test_forcepushdown_pkey_900015" DETAIL: Key (intcol)=(3) already exists. CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (a)" PL/pgSQL function forcepushdown_schema.insert_data(integer) line XX at SQL statement while executing command on localhost:xxxxx INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (5); ERROR: current transaction is aborted, commands ignored until end of transaction block COMMIT; SELECT 'Transaction with duplicate error in the local statement' Testing; testing --------------------------------------------------------------------- Transaction with duplicate error in the local statement (1 row) BEGIN; INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (6); -- This call will insert both the rows locally on the remote worker SELECT insert_data(7); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call insert_data --------------------------------------------------------------------- (1 row) INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (8); -- This will fail INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (8); ERROR: duplicate key value violates unique constraint "test_forcepushdown_pkey_900000" DETAIL: Key (intcol)=(8) already exists. CONTEXT: while executing command on localhost:xxxxx COMMIT; SELECT 'Transaction with function using non-distribution argument' Testing; testing --------------------------------------------------------------------- Transaction with function using non-distribution argument (1 row) BEGIN; -- This should fail SELECT insert_data_non_distarg(9); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (a+1)" PL/pgSQL function forcepushdown_schema.insert_data_non_distarg(integer) line XX at SQL statement while executing command on localhost:xxxxx COMMIT; SELECT 'Transaction with function doing remote connection' Testing; testing --------------------------------------------------------------------- Transaction with function doing remote connection (1 row) BEGIN; -- This statement will pass INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (11); -- This call will try to update rows locally and on remote node(s) SELECT update_data_nonlocal(12); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "UPDATE forcepushdown_schema.test_forcepushdown SET data = 'non-default'" PL/pgSQL function forcepushdown_schema.update_data_nonlocal(integer) line XX at SQL statement while executing command on localhost:xxxxx INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (13); ERROR: current transaction is aborted, commands ignored until end of transaction block COMMIT; SELECT 'Transaction with no errors but with a rollback' Testing; testing --------------------------------------------------------------------- Transaction with no errors but with a rollback (1 row) BEGIN; INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (14); -- This call will insert both the rows locally on the remote worker SELECT insert_data(15); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call insert_data --------------------------------------------------------------------- (1 row) INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (16); ROLLBACK; -- -- Add function with pushdown=true in the targetList of a query -- BEGIN; -- Query gets delegated to the node of the shard xx_900001 for the key=1, -- and the function inserts value (1+17) locally on the shard xx_900031 -- which is not allowed because this is not a regular pushdown SELECT insert_data(intcol+17) from test_forcepushdown where intcol = 1; ERROR: cannot execute a distributed query from a query on a shard DETAIL: Executing a distributed query in a function call that may be pushed to a remote node can lead to incorrect results. HINT: Avoid nesting of distributed queries or use alter user current_user set citus.allow_nested_distributed_execution to on to allow it with possible incorrectness. CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (a)" PL/pgSQL function forcepushdown_schema.insert_data(integer) line XX at SQL statement while executing command on localhost:xxxxx COMMIT; -- -- Access a table with the same shard key as distribution argument but in a -- different colocation group. -- BEGIN; SELECT insert_data_noncolocation(19); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.test_forcepushdown_noncolocate VALUES (a)" PL/pgSQL function forcepushdown_schema.insert_data_noncolocation(integer) line XX at SQL statement while executing command on localhost:xxxxx COMMIT; SELECT insert_data_noncolocation(19); DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.test_forcepushdown_noncolocate VALUES (a)" PL/pgSQL function forcepushdown_schema.insert_data_noncolocation(integer) line XX at SQL statement while executing command on localhost:xxxxx -- This should have only the first 3 rows as all other transactions were rolled back. SELECT * FROM forcepushdown_schema.test_forcepushdown ORDER BY 1; intcol | data --------------------------------------------------------------------- 1 | default 2 | default 3 | default (3 rows) -- -- Nested call, function with pushdown=false calling function with pushdown=true -- CREATE TABLE test_nested (id int, name text); SELECT create_distributed_table('test_nested','id'); create_distributed_table --------------------------------------------------------------------- (1 row) INSERT INTO test_nested VALUES (100,'hundred'); INSERT INTO test_nested VALUES (200,'twohundred'); INSERT INTO test_nested VALUES (300,'threehundred'); INSERT INTO test_nested VALUES (400,'fourhundred'); INSERT INTO test_nested VALUES (512,'fivetwelve'); CREATE OR REPLACE FUNCTION inner_force_delegation_function(int) RETURNS NUMERIC AS $$ DECLARE ret_val NUMERIC; BEGIN SELECT max(id)::numeric+1 INTO ret_val FROM forcepushdown_schema.test_nested WHERE id = $1; RAISE NOTICE 'inner_force_delegation_function():%', ret_val; RETURN ret_val; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands CREATE OR REPLACE FUNCTION func_calls_forcepush_func() RETURNS NUMERIC AS $$ DECLARE incremented_val NUMERIC; BEGIN -- Constant distribution argument SELECT inner_force_delegation_function INTO incremented_val FROM inner_force_delegation_function(100); RETURN incremented_val; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function('func_calls_forcepush_func()'); NOTICE: procedure forcepushdown_schema.func_calls_forcepush_func is already distributed DETAIL: Citus distributes procedures with CREATE [PROCEDURE|FUNCTION|AGGREGATE] commands create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function('inner_force_delegation_function(int)', '$1', colocate_with := 'test_nested', force_delegation := true); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) SELECT public.wait_until_metadata_sync(30000); wait_until_metadata_sync --------------------------------------------------------------------- (1 row) BEGIN; SELECT func_calls_forcepush_func(); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT inner_force_delegation_function FROM inner_force_delegation_function(100)" PL/pgSQL function func_calls_forcepush_func() line XX at SQL statement DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT inner_force_delegation_function FROM inner_force_delegation_function(100)" PL/pgSQL function func_calls_forcepush_func() line XX at SQL statement NOTICE: inner_force_delegation_function():101 DETAIL: from localhost:xxxxx CONTEXT: SQL statement "SELECT inner_force_delegation_function FROM inner_force_delegation_function(100)" PL/pgSQL function func_calls_forcepush_func() line XX at SQL statement func_calls_forcepush_func --------------------------------------------------------------------- 101 (1 row) COMMIT; SELECT func_calls_forcepush_func(); NOTICE: inner_force_delegation_function():101 DETAIL: from localhost:xxxxx CONTEXT: SQL statement "SELECT inner_force_delegation_function FROM inner_force_delegation_function(100)" PL/pgSQL function func_calls_forcepush_func() line XX at SQL statement func_calls_forcepush_func --------------------------------------------------------------------- 101 (1 row) -- Block distributing that function as distributing it causes -- different test output on PG 14. SET citus.enable_metadata_sync TO OFF; CREATE OR REPLACE FUNCTION get_val() RETURNS INT AS $$ BEGIN RETURN 100::INT; END; $$ LANGUAGE plpgsql; RESET citus.enable_metadata_sync; -- -- UDF calling another UDF in a FROM clause -- fn() -- { -- select res into var from fn(); -- } -- CREATE OR REPLACE FUNCTION func_calls_forcepush_func_infrom() RETURNS NUMERIC AS $$ DECLARE incremented_val NUMERIC; DECLARE add_val INT; BEGIN add_val := get_val(); SELECT inner_force_delegation_function INTO incremented_val FROM inner_force_delegation_function(add_val + 100); RETURN incremented_val; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT func_calls_forcepush_func_infrom(); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT inner_force_delegation_function FROM inner_force_delegation_function(add_val + 100)" PL/pgSQL function func_calls_forcepush_func_infrom() line XX at SQL statement DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT inner_force_delegation_function FROM inner_force_delegation_function(add_val + 100)" PL/pgSQL function func_calls_forcepush_func_infrom() line XX at SQL statement NOTICE: inner_force_delegation_function():201 DETAIL: from localhost:xxxxx CONTEXT: SQL statement "SELECT inner_force_delegation_function FROM inner_force_delegation_function(add_val + 100)" PL/pgSQL function func_calls_forcepush_func_infrom() line XX at SQL statement func_calls_forcepush_func_infrom --------------------------------------------------------------------- 201 (1 row) BEGIN; SELECT func_calls_forcepush_func_infrom(); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT inner_force_delegation_function FROM inner_force_delegation_function(add_val + 100)" PL/pgSQL function func_calls_forcepush_func_infrom() line XX at SQL statement DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT inner_force_delegation_function FROM inner_force_delegation_function(add_val + 100)" PL/pgSQL function func_calls_forcepush_func_infrom() line XX at SQL statement NOTICE: inner_force_delegation_function():201 DETAIL: from localhost:xxxxx CONTEXT: SQL statement "SELECT inner_force_delegation_function FROM inner_force_delegation_function(add_val + 100)" PL/pgSQL function func_calls_forcepush_func_infrom() line XX at SQL statement func_calls_forcepush_func_infrom --------------------------------------------------------------------- 201 (1 row) COMMIT; -- -- UDF calling another UDF in the SELECT targetList -- fn() -- { -- select fn() into var; -- } -- CREATE OR REPLACE FUNCTION func_calls_forcepush_func_intarget() RETURNS NUMERIC AS $$ DECLARE incremented_val NUMERIC; DECLARE add_val INT; BEGIN add_val := get_val(); SELECT inner_force_delegation_function(100 + 100) INTO incremented_val OFFSET 0; RETURN incremented_val; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT func_calls_forcepush_func_intarget(); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT inner_force_delegation_function(100 + 100) OFFSET 0" PL/pgSQL function func_calls_forcepush_func_intarget() line XX at SQL statement DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT inner_force_delegation_function(100 + 100) OFFSET 0" PL/pgSQL function func_calls_forcepush_func_intarget() line XX at SQL statement NOTICE: inner_force_delegation_function():201 DETAIL: from localhost:xxxxx CONTEXT: SQL statement "SELECT inner_force_delegation_function(100 + 100) OFFSET 0" PL/pgSQL function func_calls_forcepush_func_intarget() line XX at SQL statement func_calls_forcepush_func_intarget --------------------------------------------------------------------- 201 (1 row) BEGIN; SELECT func_calls_forcepush_func_intarget(); NOTICE: inner_force_delegation_function():201 DETAIL: from localhost:xxxxx CONTEXT: SQL statement "SELECT inner_force_delegation_function(100 + 100) OFFSET 0" PL/pgSQL function func_calls_forcepush_func_intarget() line XX at SQL statement func_calls_forcepush_func_intarget --------------------------------------------------------------------- 201 (1 row) COMMIT; -- -- Recursive function call with pushdown=true -- CREATE OR REPLACE FUNCTION test_recursive(inp integer) RETURNS INT AS $$ DECLARE var INT; BEGIN RAISE NOTICE 'input:%', inp; if (inp > 1) then inp := inp - 1; var := forcepushdown_schema.test_recursive(inp); RETURN var; else RETURN inp; END if; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function('test_recursive(int)', '$1', colocate_with := 'test_nested', force_delegation := true); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) BEGIN; SELECT test_recursive(5); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call NOTICE: input:5 DETAIL: from localhost:xxxxx NOTICE: input:4 DETAIL: from localhost:xxxxx NOTICE: input:3 DETAIL: from localhost:xxxxx NOTICE: input:2 DETAIL: from localhost:xxxxx NOTICE: input:1 DETAIL: from localhost:xxxxx test_recursive --------------------------------------------------------------------- 1 (1 row) END; -- -- Distributed function gets delegated indirectly (as part of a query) -- BEGIN; -- Query lands on the shard with key = 300(shard __900089) and the function inserts locally -- which is not allowed because this is not a regular pushdown SELECT inner_force_delegation_function(id) FROM test_nested WHERE id = 300; ERROR: cannot execute a distributed query from a query on a shard DETAIL: Executing a distributed query in a function call that may be pushed to a remote node can lead to incorrect results. HINT: Avoid nesting of distributed queries or use alter user current_user set citus.allow_nested_distributed_execution to on to allow it with possible incorrectness. CONTEXT: SQL statement "SELECT max(id)::numeric+1 FROM forcepushdown_schema.test_nested WHERE id = $1" PL/pgSQL function forcepushdown_schema.inner_force_delegation_function(integer) line XX at SQL statement while executing command on localhost:xxxxx END; -- -- Non constant distribution arguments -- -- Param(PARAM_EXEC) node e.g. SELECT fn((SELECT col from test_nested where col=val)) BEGIN; SELECT inner_force_delegation_function((SELECT id+112 FROM test_nested WHERE id=400)); ERROR: cannot execute a distributed query from a query on a shard DETAIL: Executing a distributed query in a function call that may be pushed to a remote node can lead to incorrect results. HINT: Avoid nesting of distributed queries or use alter user current_user set citus.allow_nested_distributed_execution to on to allow it with possible incorrectness. CONTEXT: SQL statement "SELECT max(id)::numeric+1 FROM forcepushdown_schema.test_nested WHERE id = $1" PL/pgSQL function forcepushdown_schema.inner_force_delegation_function(integer) line XX at SQL statement while executing command on localhost:xxxxx END; BEGIN; SET LOCAL citus.propagate_set_commands TO 'local'; SET LOCAL citus.allow_nested_distributed_execution TO on; SELECT inner_force_delegation_function((SELECT id+112 FROM test_nested WHERE id=400)); NOTICE: inner_force_delegation_function():513 DETAIL: from localhost:xxxxx inner_force_delegation_function --------------------------------------------------------------------- 513 (1 row) END; CREATE OR REPLACE FUNCTION test_non_constant(x int, y bigint) RETURNS int AS $$ DECLARE BEGIN RAISE NOTICE 'test_non_constant: % %', x, y; RETURN x + y; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'test_non_constant(int,bigint)', '$1', colocate_with := 'test_forcepushdown', force_delegation := true); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) SELECT count(*) FROM test_nested; count --------------------------------------------------------------------- 5 (1 row) -- Result should print 99, count(*) from test_nested WITH c AS (SELECT count(*) FROM test_nested), b as (SELECT test_non_constant(99::int, (SELECT COUNT FROM c))) SELECT COUNT(*) FROM b; DEBUG: CTE c is going to be inlined via distributed planning DEBUG: generating subplan XXX_1 for CTE b: SELECT forcepushdown_schema.test_non_constant(99, (SELECT c.count FROM (SELECT count(*) AS count FROM forcepushdown_schema.test_nested) c)) AS test_non_constant DEBUG: generating subplan XXX_1 for subquery SELECT count(*) AS count FROM forcepushdown_schema.test_nested DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT forcepushdown_schema.test_non_constant(99, (SELECT c.count FROM (SELECT intermediate_result.count FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) c)) AS test_non_constant DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result.test_non_constant FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(test_non_constant integer)) b DEBUG: arguments in a distributed function must not contain subqueries NOTICE: test_non_constant: 99 5 CONTEXT: PL/pgSQL function test_non_constant(integer,bigint) line XX at RAISE count --------------------------------------------------------------------- 1 (1 row) CREATE TABLE emp ( empname text NOT NULL, salary integer ); CREATE TABLE emp_audit( operation char(1) NOT NULL, stamp timestamp NOT NULL, userid text NOT NULL, empname text NOT NULL, salary integer ); SELECT create_distributed_table('emp','empname'); create_distributed_table --------------------------------------------------------------------- (1 row) SELECT create_distributed_table('emp_audit','empname'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE OR REPLACE FUNCTION inner_emp(empname text) RETURNS void AS $$ DECLARE BEGIN INSERT INTO emp VALUES (empname, 33); END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands CREATE OR REPLACE FUNCTION outer_emp() RETURNS void AS $$ DECLARE BEGIN PERFORM inner_emp('hello'); END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function('inner_emp(text)','empname', force_delegation := true); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) SELECT outer_emp(); DEBUG: Skipping pushdown of function from a PL/PgSQL simple expression CONTEXT: SQL statement "SELECT inner_emp('hello')" PL/pgSQL function outer_emp() line XX at PERFORM outer_emp --------------------------------------------------------------------- (1 row) SELECT * from emp; empname | salary --------------------------------------------------------------------- hello | 33 (1 row) -- -- INSERT..SELECT -- CREATE FUNCTION insert_select_data(a integer) RETURNS void LANGUAGE plpgsql AS $fn$ BEGIN INSERT INTO forcepushdown_schema.test_forcepushdown SELECT(a+1); END; $fn$; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'insert_select_data(int)', 'a', colocate_with := 'test_forcepushdown', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) -- Function lands on worker1 and issues COPY ... INSERT on the worker2 into the shard_900021 BEGIN; INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (30); -- This will fail SELECT insert_select_data(20); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: cannot execute a distributed query from a query on a shard DETAIL: Executing a distributed query in a function call that may be pushed to a remote node can lead to incorrect results. HINT: Avoid nesting of distributed queries or use alter user current_user set citus.allow_nested_distributed_execution to on to allow it with possible incorrectness. CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.test_forcepushdown SELECT(a+1)" PL/pgSQL function forcepushdown_schema.insert_select_data(integer) line XX at SQL statement while executing command on localhost:xxxxx COMMIT; -- Function lands on worker2 and issues COPY ... INSERT on the same node into the shard_900029 BEGIN; -- This will pass SELECT insert_select_data(21); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call insert_select_data --------------------------------------------------------------------- (1 row) END; -- Function lands on worker2 and issues COPY ... INSERT on the worker1 into the shard_900028 BEGIN; INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (30); -- This will fail SELECT insert_select_data(22); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: cannot execute a distributed query from a query on a shard DETAIL: Executing a distributed query in a function call that may be pushed to a remote node can lead to incorrect results. HINT: Avoid nesting of distributed queries or use alter user current_user set citus.allow_nested_distributed_execution to on to allow it with possible incorrectness. CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.test_forcepushdown SELECT(a+1)" PL/pgSQL function forcepushdown_schema.insert_select_data(integer) line XX at SQL statement while executing command on localhost:xxxxx END; -- Functions lands on worker1 and issues COPY ... INSERT on the worker2 into the shard_900021 -- This will pass as there is no surrounding transaction SELECT insert_select_data(20); DEBUG: pushing down the function call insert_select_data --------------------------------------------------------------------- (1 row) -- (21+1) and (20+1) should appear SELECT * FROM forcepushdown_schema.test_forcepushdown ORDER BY 1; intcol | data --------------------------------------------------------------------- 1 | default 2 | default 3 | default 21 | default 22 | default (5 rows) CREATE FUNCTION insert_select_data_nonlocal(a integer) RETURNS void LANGUAGE plpgsql AS $fn$ BEGIN INSERT INTO forcepushdown_schema.test_forcepushdown(intcol) SELECT intcol FROM forcepushdown_schema.test_forcepushdown_noncolocate; END; $fn$; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'insert_select_data_nonlocal(int)', 'a', colocate_with := 'test_forcepushdown', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) INSERT INTO forcepushdown_schema.test_forcepushdown_noncolocate VALUES (30); INSERT INTO forcepushdown_schema.test_forcepushdown_noncolocate VALUES (31); INSERT INTO forcepushdown_schema.test_forcepushdown_noncolocate VALUES (32); BEGIN; INSERT INTO forcepushdown_schema.test_forcepushdown VALUES (40); -- This will fail SELECT insert_select_data_nonlocal(41); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: cannot execute a distributed query from a query on a shard DETAIL: Executing a distributed query in a function call that may be pushed to a remote node can lead to incorrect results. HINT: Avoid nesting of distributed queries or use alter user current_user set citus.allow_nested_distributed_execution to on to allow it with possible incorrectness. CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.test_forcepushdown(intcol) SELECT intcol FROM forcepushdown_schema.test_forcepushdown_noncolocate" PL/pgSQL function forcepushdown_schema.insert_select_data_nonlocal(integer) line XX at SQL statement while executing command on localhost:xxxxx COMMIT; -- Above 3 rows (30, 31, 32) should appear now SELECT insert_select_data_nonlocal(40); DEBUG: pushing down the function call insert_select_data_nonlocal --------------------------------------------------------------------- (1 row) SELECT * FROM forcepushdown_schema.test_forcepushdown ORDER BY 1; intcol | data --------------------------------------------------------------------- 1 | default 2 | default 3 | default 21 | default 22 | default 30 | default 31 | default 32 | default (8 rows) CREATE TABLE test_forcepushdown_char(data char(50) PRIMARY KEY); DEBUG: CREATE TABLE / PRIMARY KEY will create implicit index "test_forcepushdown_char_pkey" for table "test_forcepushdown_char" SELECT create_distributed_table('test_forcepushdown_char', 'data', colocate_with := 'none'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE TABLE test_forcepushdown_varchar(data varchar PRIMARY KEY); DEBUG: CREATE TABLE / PRIMARY KEY will create implicit index "test_forcepushdown_varchar_pkey" for table "test_forcepushdown_varchar" SELECT create_distributed_table('test_forcepushdown_varchar', 'data', colocate_with := 'none'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE TABLE test_forcepushdown_text(data text PRIMARY KEY); DEBUG: CREATE TABLE / PRIMARY KEY will create implicit index "test_forcepushdown_text_pkey" for table "test_forcepushdown_text" SELECT create_distributed_table('test_forcepushdown_text', 'data', colocate_with := 'none'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE FUNCTION insert_data_char(a char(50)) RETURNS void LANGUAGE plpgsql AS $fn$ BEGIN INSERT INTO forcepushdown_schema.test_forcepushdown_char VALUES (a); END; $fn$; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'insert_data_char(char)', 'a', colocate_with := 'test_forcepushdown_char', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) CREATE FUNCTION insert_data_varchar(a varchar) RETURNS void LANGUAGE plpgsql AS $fn$ BEGIN INSERT INTO forcepushdown_schema.test_forcepushdown_varchar VALUES (a); END; $fn$; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'insert_data_varchar(varchar)', 'a', colocate_with := 'test_forcepushdown_varchar', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) CREATE FUNCTION insert_data_text(a text) RETURNS void LANGUAGE plpgsql AS $fn$ BEGIN INSERT INTO forcepushdown_schema.test_forcepushdown_text VALUES (a); END; $fn$; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'insert_data_text(text)', 'a', colocate_with := 'test_forcepushdown_text', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) SELECT insert_data_varchar('VARCHAR'); DEBUG: pushing down the function call insert_data_varchar --------------------------------------------------------------------- (1 row) BEGIN; SELECT insert_data_varchar('VARCHAR2'); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call insert_data_varchar --------------------------------------------------------------------- (1 row) COMMIT; SELECT insert_data_text('TEXT'); DEBUG: pushing down the function call insert_data_text --------------------------------------------------------------------- (1 row) BEGIN; SELECT insert_data_text('TEXT2'); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call insert_data_text --------------------------------------------------------------------- (1 row) COMMIT; -- Char is failing as the datatype is represented differently in the -- PL/PgSQL and the exec engine. SELECT insert_data_char('CHAR'); DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.test_forcepushdown_char VALUES (a)" PL/pgSQL function forcepushdown_schema.insert_data_char(character) line XX at SQL statement while executing command on localhost:xxxxx BEGIN; SELECT insert_data_char('CHAR'); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.test_forcepushdown_char VALUES (a)" PL/pgSQL function forcepushdown_schema.insert_data_char(character) line XX at SQL statement while executing command on localhost:xxxxx COMMIT; SELECT * FROM test_forcepushdown_char ORDER BY 1; data --------------------------------------------------------------------- (0 rows) SELECT * FROM test_forcepushdown_varchar ORDER BY 1; data --------------------------------------------------------------------- VARCHAR VARCHAR2 (2 rows) SELECT * FROM test_forcepushdown_text ORDER BY 1; data --------------------------------------------------------------------- TEXT TEXT2 (2 rows) -- Test sub query CREATE TABLE test_subquery(data int, result int); SELECT create_distributed_table('test_subquery', 'data', colocate_with := 'none'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE TABLE test_non_colocated(id int); SELECT create_distributed_table('test_non_colocated', 'id', colocate_with := 'none'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE FUNCTION select_data(a integer) RETURNS void LANGUAGE plpgsql AS $fn$ DECLARE var INT; BEGIN SELECT result INTO var FROM forcepushdown_schema.test_subquery WHERE data = (SELECT data FROM forcepushdown_schema.test_subquery WHERE data = a); RAISE NOTICE 'Result: %', var; END; $fn$; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'select_data(int)', 'a', colocate_with := 'test_subquery', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) CREATE FUNCTION select_data_noncolocate(a integer) RETURNS void LANGUAGE plpgsql AS $fn$ DECLARE var INT; BEGIN -- Key is the same but colocation ID is different SELECT data INTO var FROM forcepushdown_schema.test_subquery WHERE data = (SELECT id FROM forcepushdown_schema.test_non_colocated WHERE id = a); RAISE NOTICE 'Result: %', var; END; $fn$; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'select_data_noncolocate(int)', 'a', colocate_with := 'test_subquery', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) CREATE FUNCTION insert_select_data_cte1(a integer) RETURNS void LANGUAGE plpgsql AS $fn$ DECLARE var INT; BEGIN WITH ins AS (INSERT INTO forcepushdown_schema.test_subquery VALUES (a) RETURNING data) SELECT ins.data INTO var FROM ins; RAISE NOTICE 'Result: %', var; END; $fn$; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'insert_select_data_cte1(int)', 'a', colocate_with := 'test_subquery', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) CREATE FUNCTION insert_select_data_cte2(a integer) RETURNS void LANGUAGE plpgsql AS $fn$ DECLARE var INT; BEGIN WITH ins AS (INSERT INTO forcepushdown_schema.test_subquery VALUES (a) RETURNING data) SELECT ins.data INTO var FROM forcepushdown_schema.test_subquery, ins WHERE forcepushdown_schema.test_subquery.data = a; RAISE NOTICE 'Result: %', var; END; $fn$; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'insert_select_data_cte2(int)', 'a', colocate_with := 'test_subquery', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) CREATE FUNCTION insert_data_cte_nondist(a integer) RETURNS void LANGUAGE plpgsql AS $fn$ DECLARE var INT; BEGIN -- Inserting a non-distribution argument (a+1) WITH ins AS (INSERT INTO forcepushdown_schema.test_subquery VALUES (a+1) RETURNING data) SELECT ins.data INTO var FROM forcepushdown_schema.test_subquery, ins WHERE forcepushdown_schema.test_subquery.data = a; RAISE NOTICE 'Result: %', var; END; $fn$; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'insert_data_cte_nondist(int)', 'a', colocate_with := 'test_subquery', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) INSERT INTO forcepushdown_schema.test_subquery VALUES(100, -1); -- This should pass SELECT select_data(100); DEBUG: pushing down the function call NOTICE: Result: -1 DETAIL: from localhost:xxxxx select_data --------------------------------------------------------------------- (1 row) BEGIN; SELECT select_data(100); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: cannot execute a distributed query from a query on a shard DETAIL: Executing a distributed query in a function call that may be pushed to a remote node can lead to incorrect results. HINT: Avoid nesting of distributed queries or use alter user current_user set citus.allow_nested_distributed_execution to on to allow it with possible incorrectness. CONTEXT: SQL statement "SELECT result FROM forcepushdown_schema.test_subquery WHERE data = (SELECT data FROM forcepushdown_schema.test_subquery WHERE data = a)" PL/pgSQL function forcepushdown_schema.select_data(integer) line XX at SQL statement while executing command on localhost:xxxxx END; -- This should fail SELECT select_data_noncolocate(100); DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "SELECT data FROM forcepushdown_schema.test_subquery WHERE data = (SELECT id FROM forcepushdown_schema.test_non_colocated WHERE id = a)" PL/pgSQL function forcepushdown_schema.select_data_noncolocate(integer) line XX at SQL statement while executing command on localhost:xxxxx BEGIN; SELECT select_data_noncolocate(100); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "SELECT data FROM forcepushdown_schema.test_subquery WHERE data = (SELECT id FROM forcepushdown_schema.test_non_colocated WHERE id = a)" PL/pgSQL function forcepushdown_schema.select_data_noncolocate(integer) line XX at SQL statement while executing command on localhost:xxxxx END; -- This should pass SELECT insert_select_data_cte1(200); DEBUG: pushing down the function call NOTICE: Result: 200 DETAIL: from localhost:xxxxx insert_select_data_cte1 --------------------------------------------------------------------- (1 row) BEGIN; SELECT insert_select_data_cte1(200); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call NOTICE: Result: 200 DETAIL: from localhost:xxxxx insert_select_data_cte1 --------------------------------------------------------------------- (1 row) COMMIT; -- This should pass SELECT insert_select_data_cte2(300); DEBUG: pushing down the function call NOTICE: Result: DETAIL: from localhost:xxxxx insert_select_data_cte2 --------------------------------------------------------------------- (1 row) BEGIN; SELECT insert_select_data_cte2(300); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call NOTICE: Result: 300 DETAIL: from localhost:xxxxx insert_select_data_cte2 --------------------------------------------------------------------- (1 row) COMMIT; -- This should fail SELECT insert_data_cte_nondist(400); DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "WITH ins AS (INSERT INTO forcepushdown_schema.test_subquery VALUES (a+1) RETURNING data) SELECT ins.data FROM forcepushdown_schema.test_subquery, ins WHERE forcepushdown_schema.test_subquery.data = a" PL/pgSQL function forcepushdown_schema.insert_data_cte_nondist(integer) line XX at SQL statement while executing command on localhost:xxxxx BEGIN; SELECT insert_data_cte_nondist(400); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "WITH ins AS (INSERT INTO forcepushdown_schema.test_subquery VALUES (a+1) RETURNING data) SELECT ins.data FROM forcepushdown_schema.test_subquery, ins WHERE forcepushdown_schema.test_subquery.data = a" PL/pgSQL function forcepushdown_schema.insert_data_cte_nondist(integer) line XX at SQL statement while executing command on localhost:xxxxx COMMIT; -- Rows 100, 200, 300 should be seen SELECT * FROM forcepushdown_schema.test_subquery ORDER BY 1; data | result --------------------------------------------------------------------- 100 | -1 200 | 200 | 300 | 300 | (5 rows) -- Query with targetList greater than 1 -- Function from FROM clause is delegated outside of a BEGIN SELECT 1,2,3 FROM select_data(100); DEBUG: pushing down the function call NOTICE: Result: -1 DETAIL: from localhost:xxxxx ?column? | ?column? | ?column? --------------------------------------------------------------------- 1 | 2 | 3 (1 row) BEGIN; -- Function from FROM clause is delegated SELECT 1,2,3 FROM select_data(100); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: cannot execute a distributed query from a query on a shard DETAIL: Executing a distributed query in a function call that may be pushed to a remote node can lead to incorrect results. HINT: Avoid nesting of distributed queries or use alter user current_user set citus.allow_nested_distributed_execution to on to allow it with possible incorrectness. CONTEXT: SQL statement "SELECT result FROM forcepushdown_schema.test_subquery WHERE data = (SELECT data FROM forcepushdown_schema.test_subquery WHERE data = a)" PL/pgSQL function forcepushdown_schema.select_data(integer) line XX at SQL statement while executing command on localhost:xxxxx END; -- Test prepared statements CREATE TABLE table_test_prepare(i int, j bigint); SELECT create_distributed_table('table_test_prepare', 'i', colocate_with := 'none'); create_distributed_table --------------------------------------------------------------------- (1 row) DROP FUNCTION test_prepare(int, int); ERROR: function test_prepare(integer, integer) does not exist CREATE OR REPLACE FUNCTION test_prepare(x int, y int) RETURNS bigint AS $$ DECLARE BEGIN INSERT INTO forcepushdown_schema.table_test_prepare VALUES (x, y); INSERT INTO forcepushdown_schema.table_test_prepare VALUES (y, x); RETURN x + y; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function('test_prepare(int,int)','x',force_delegation :=true, colocate_with := 'table_test_prepare'); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) DROP FUNCTION outer_test_prepare(int, int); ERROR: function outer_test_prepare(integer, integer) does not exist CREATE OR REPLACE FUNCTION outer_test_prepare(x int, y int) RETURNS void AS $$ DECLARE v int; BEGIN PERFORM FROM test_prepare(x, y); PERFORM 1, 1 + a FROM test_prepare(x + 1, y + 1) a; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands -- First 5 get delegated and succeeds BEGIN; SELECT outer_test_prepare(1,1); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM outer_test_prepare --------------------------------------------------------------------- (1 row) SELECT outer_test_prepare(1,1); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM outer_test_prepare --------------------------------------------------------------------- (1 row) SELECT outer_test_prepare(1,1); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM outer_test_prepare --------------------------------------------------------------------- (1 row) SELECT outer_test_prepare(1,1); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM outer_test_prepare --------------------------------------------------------------------- (1 row) SELECT outer_test_prepare(1,1); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM outer_test_prepare --------------------------------------------------------------------- (1 row) -- All the above gets delegated and should see 5 * 4 rows SELECT COUNT(*) FROM table_test_prepare; count --------------------------------------------------------------------- 20 (1 row) -- 6th execution will be generic plan and should get delegated SELECT outer_test_prepare(1,1); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM outer_test_prepare --------------------------------------------------------------------- (1 row) SELECT outer_test_prepare(1,1); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT 1, 1 + a FROM test_prepare(x + 1, y + 1) a" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM outer_test_prepare --------------------------------------------------------------------- (1 row) END; -- Fails as expected SELECT outer_test_prepare(1,2); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.table_test_prepare VALUES (y, x)" PL/pgSQL function forcepushdown_schema.test_prepare(integer,integer) line XX at SQL statement while executing command on localhost:xxxxx SQL statement "SELECT FROM test_prepare(x, y)" PL/pgSQL function outer_test_prepare(integer,integer) line XX at PERFORM SELECT COUNT(*) FROM table_test_prepare; count --------------------------------------------------------------------- 28 (1 row) CREATE TABLE test_perform(i int); SELECT create_distributed_table('test_perform', 'i', colocate_with := 'none'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE OR REPLACE FUNCTION test(x int) RETURNS int AS $$ DECLARE BEGIN RAISE NOTICE 'INPUT %', x; RETURN x; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function('test(int)', 'x', colocate_with := 'test_perform', force_delegation := true); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) DO $$ BEGIN PERFORM test(3); END; $$ LANGUAGE plpgsql; DEBUG: Skipping pushdown of function from a PL/PgSQL simple expression CONTEXT: SQL statement "SELECT test(3)" PL/pgSQL function inline_code_block line XX at PERFORM NOTICE: INPUT 3 CONTEXT: PL/pgSQL function test(integer) line XX at RAISE SQL statement "SELECT test(3)" PL/pgSQL function inline_code_block line XX at PERFORM CREATE TABLE testnested_table (x int, y int); SELECT create_distributed_table('testnested_table','x'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE OR REPLACE FUNCTION inner_fn(x int) RETURNS void AS $$ DECLARE BEGIN INSERT INTO forcepushdown_schema.testnested_table VALUES (x,x); END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands -- Non-force function calling force-delegation function CREATE OR REPLACE FUNCTION outer_local_fn() RETURNS void AS $$ DECLARE BEGIN PERFORM 1 FROM inner_fn(1); INSERT INTO forcepushdown_schema.testnested_table VALUES (2,3); PERFORM 1 FROM inner_fn(4); INSERT INTO forcepushdown_schema.testnested_table VALUES (5,6); END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function('inner_fn(int)','x', colocate_with:='testnested_table', force_delegation := true); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) SELECT outer_local_fn(); DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT 1 FROM inner_fn(1)" PL/pgSQL function outer_local_fn() line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT 1 FROM inner_fn(1)" PL/pgSQL function outer_local_fn() line XX at PERFORM DEBUG: pushing down function call in a multi-statement transaction CONTEXT: SQL statement "SELECT 1 FROM inner_fn(4)" PL/pgSQL function outer_local_fn() line XX at PERFORM DEBUG: pushing down the function call CONTEXT: SQL statement "SELECT 1 FROM inner_fn(4)" PL/pgSQL function outer_local_fn() line XX at PERFORM outer_local_fn --------------------------------------------------------------------- (1 row) -- Rows from 1-6 should appear SELECT * FROM testnested_table ORDER BY 1; x | y --------------------------------------------------------------------- 1 | 1 2 | 3 4 | 4 5 | 6 (4 rows) BEGIN; SELECT outer_local_fn(); outer_local_fn --------------------------------------------------------------------- (1 row) END; SELECT * FROM testnested_table ORDER BY 1; x | y --------------------------------------------------------------------- 1 | 1 1 | 1 2 | 3 2 | 3 4 | 4 4 | 4 5 | 6 5 | 6 (8 rows) DROP FUNCTION inner_fn(int); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands DROP FUNCTION outer_local_fn(); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands TRUNCATE TABLE testnested_table; CREATE OR REPLACE FUNCTION inner_fn(x int) RETURNS void AS $$ DECLARE BEGIN INSERT INTO forcepushdown_schema.testnested_table VALUES (x,x); END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands -- Force-delegation function calling non-force function CREATE OR REPLACE FUNCTION outer_fn(y int, z int) RETURNS void AS $$ DECLARE BEGIN PERFORM 1 FROM forcepushdown_schema.inner_fn(y); INSERT INTO forcepushdown_schema.testnested_table VALUES (y,y); PERFORM 1 FROM forcepushdown_schema.inner_fn(z); INSERT INTO forcepushdown_schema.testnested_table VALUES (z,z); END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function('inner_fn(int)','x', colocate_with:='testnested_table', force_delegation := false); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function('outer_fn(int, int)','y', colocate_with:='testnested_table', force_delegation := true); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) SELECT outer_fn(1, 2); DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.testnested_table VALUES (x,x)" PL/pgSQL function forcepushdown_schema.inner_fn(integer) line XX at SQL statement SQL statement "SELECT 1 FROM forcepushdown_schema.inner_fn(z)" PL/pgSQL function forcepushdown_schema.outer_fn(integer,integer) line XX at PERFORM while executing command on localhost:xxxxx BEGIN; SELECT outer_fn(1, 2); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.testnested_table VALUES (x,x)" PL/pgSQL function forcepushdown_schema.inner_fn(integer) line XX at SQL statement SQL statement "SELECT 1 FROM forcepushdown_schema.inner_fn(z)" PL/pgSQL function forcepushdown_schema.outer_fn(integer,integer) line XX at PERFORM while executing command on localhost:xxxxx END; -- No rows SELECT * FROM testnested_table ORDER BY 1; x | y --------------------------------------------------------------------- (0 rows) -- Force-delegation function calling force-delegation function CREATE OR REPLACE FUNCTION force_push_inner(y int) RETURNS void AS $$ DECLARE BEGIN INSERT INTO forcepushdown_schema.testnested_table VALUES (y,y); END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands CREATE OR REPLACE FUNCTION force_push_outer(x int) RETURNS void AS $$ DECLARE BEGIN INSERT INTO forcepushdown_schema.testnested_table VALUES (x,x); PERFORM forcepushdown_schema.force_push_inner(x+1) LIMIT 1; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'force_push_outer(int)', 'x', colocate_with := 'testnested_table', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'force_push_inner(int)', 'y', colocate_with := 'testnested_table', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) -- Keys 7,8,9,14 fall on one node and 15 on a different node -- Function gets delegated to node with shard-key = 7 and inner function -- will not be delegated but inserts shard-key = 8 locally SELECT force_push_outer(7); DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.testnested_table VALUES (y,y)" PL/pgSQL function forcepushdown_schema.force_push_inner(integer) line XX at SQL statement SQL statement "SELECT forcepushdown_schema.force_push_inner(x+1) LIMIT 1" PL/pgSQL function forcepushdown_schema.force_push_outer(integer) line XX at PERFORM while executing command on localhost:xxxxx BEGIN; -- Function gets delegated to node with shard-key = 8 and inner function -- will not be delegated but inserts shard-key = 9 locally SELECT force_push_outer(8); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.testnested_table VALUES (y,y)" PL/pgSQL function forcepushdown_schema.force_push_inner(integer) line XX at SQL statement SQL statement "SELECT forcepushdown_schema.force_push_inner(x+1) LIMIT 1" PL/pgSQL function forcepushdown_schema.force_push_outer(integer) line XX at PERFORM while executing command on localhost:xxxxx END; BEGIN; -- Function gets delegated to node with shard-key = 14 and inner function -- will not be delegated but fails to insert shard-key = 15 remotely SELECT force_push_outer(14); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.testnested_table VALUES (y,y)" PL/pgSQL function forcepushdown_schema.force_push_inner(integer) line XX at SQL statement SQL statement "SELECT forcepushdown_schema.force_push_inner(x+1) LIMIT 1" PL/pgSQL function forcepushdown_schema.force_push_outer(integer) line XX at PERFORM while executing command on localhost:xxxxx END; SELECT * FROM testnested_table ORDER BY 1; x | y --------------------------------------------------------------------- (0 rows) -- -- Function-1() --> function-2() --> function-3() -- CREATE OR REPLACE FUNCTION force_push_1(x int) RETURNS void AS $$ DECLARE BEGIN INSERT INTO forcepushdown_schema.testnested_table VALUES (x,x); PERFORM forcepushdown_schema.force_push_2(x+1) LIMIT 1; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands CREATE OR REPLACE FUNCTION force_push_2(y int) RETURNS void AS $$ DECLARE BEGIN INSERT INTO forcepushdown_schema.testnested_table VALUES (y,y); PERFORM forcepushdown_schema.force_push_3(y+1) LIMIT 1; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands CREATE OR REPLACE FUNCTION force_push_3(z int) RETURNS void AS $$ DECLARE BEGIN INSERT INTO forcepushdown_schema.testnested_table VALUES (z,z); END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'force_push_1(int)', 'x', colocate_with := 'testnested_table', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'force_push_2(int)', 'y', colocate_with := 'testnested_table', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'force_push_3(int)', 'z', colocate_with := 'testnested_table', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) TRUNCATE TABLE testnested_table; BEGIN; -- All local inserts SELECT force_push_1(7); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.testnested_table VALUES (y,y)" PL/pgSQL function forcepushdown_schema.force_push_2(integer) line XX at SQL statement SQL statement "SELECT forcepushdown_schema.force_push_2(x+1) LIMIT 1" PL/pgSQL function forcepushdown_schema.force_push_1(integer) line XX at PERFORM while executing command on localhost:xxxxx END; BEGIN; -- Local(shard-keys 13, 15) + remote insert (shard-key 14) SELECT force_push_1(13); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.testnested_table VALUES (y,y)" PL/pgSQL function forcepushdown_schema.force_push_2(integer) line XX at SQL statement SQL statement "SELECT forcepushdown_schema.force_push_2(x+1) LIMIT 1" PL/pgSQL function forcepushdown_schema.force_push_1(integer) line XX at PERFORM while executing command on localhost:xxxxx END; SELECT * FROM testnested_table ORDER BY 1; x | y --------------------------------------------------------------------- (0 rows) TRUNCATE TABLE testnested_table; CREATE OR REPLACE FUNCTION force_push_inner(y int) RETURNS void AS $$ DECLARE BEGIN INSERT INTO forcepushdown_schema.testnested_table VALUES (y,y); END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands CREATE OR REPLACE FUNCTION force_push_outer(x int) RETURNS void AS $$ DECLARE BEGIN PERFORM FROM forcepushdown_schema.force_push_inner(x); INSERT INTO forcepushdown_schema.testnested_table VALUES (x+1,x+1); END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands SELECT create_distributed_function( 'force_push_inner(int)', 'y', colocate_with := 'testnested_table', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'force_push_outer(int)', 'x', colocate_with := 'testnested_table', force_delegation := true ); DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands create_distributed_function --------------------------------------------------------------------- (1 row) BEGIN; SELECT force_push_outer(7); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call ERROR: queries must filter by the distribution argument in the same colocation group when using the forced function pushdown HINT: consider disabling forced delegation through create_distributed_table(..., force_delegation := false) CONTEXT: SQL statement "INSERT INTO forcepushdown_schema.testnested_table VALUES (x+1,x+1)" PL/pgSQL function forcepushdown_schema.force_push_outer(integer) line XX at SQL statement while executing command on localhost:xxxxx END; TABLE testnested_table ORDER BY 1; x | y --------------------------------------------------------------------- (0 rows) CREATE OR REPLACE FUNCTION force_push_inner(y int) RETURNS void AS $$ DECLARE BEGIN RAISE NOTICE '%', y; END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands CREATE OR REPLACE FUNCTION force_push_outer(x int) RETURNS void AS $$ DECLARE BEGIN PERFORM FROM forcepushdown_schema.force_push_inner(x+1); INSERT INTO forcepushdown_schema.testnested_table VALUES (x,x); END; $$ LANGUAGE plpgsql; DEBUG: switching to sequential query execution mode DETAIL: A command for a distributed function is run. To make sure subsequent commands see the function correctly we need to make sure to use only one connection for all future commands BEGIN; SELECT force_push_outer(9); DEBUG: pushing down function call in a multi-statement transaction DEBUG: pushing down the function call NOTICE: 10 DETAIL: from localhost:xxxxx force_push_outer --------------------------------------------------------------------- (1 row) END; TABLE testnested_table ORDER BY 1; x | y --------------------------------------------------------------------- 9 | 9 (1 row) RESET client_min_messages; SET citus.log_remote_commands TO off; DROP SCHEMA forcepushdown_schema CASCADE; NOTICE: drop cascades to 46 other objects DETAIL: drop cascades to table test_forcepushdown drop cascades to table test_forcepushdown_noncolocate drop cascades to function insert_data(integer) drop cascades to function insert_data_non_distarg(integer) drop cascades to function update_data_nonlocal(integer) drop cascades to function insert_data_noncolocation(integer) drop cascades to table test_nested drop cascades to function inner_force_delegation_function(integer) drop cascades to function func_calls_forcepush_func() drop cascades to function get_val() drop cascades to function func_calls_forcepush_func_infrom() drop cascades to function func_calls_forcepush_func_intarget() drop cascades to function test_recursive(integer) drop cascades to function test_non_constant(integer,bigint) drop cascades to table emp drop cascades to table emp_audit drop cascades to function inner_emp(text) drop cascades to function outer_emp() drop cascades to function insert_select_data(integer) drop cascades to function insert_select_data_nonlocal(integer) drop cascades to table test_forcepushdown_char drop cascades to table test_forcepushdown_varchar drop cascades to table test_forcepushdown_text drop cascades to function insert_data_char(character) drop cascades to function insert_data_varchar(character varying) drop cascades to function insert_data_text(text) drop cascades to table test_subquery drop cascades to table test_non_colocated drop cascades to function select_data(integer) drop cascades to function select_data_noncolocate(integer) drop cascades to function insert_select_data_cte1(integer) drop cascades to function insert_select_data_cte2(integer) drop cascades to function insert_data_cte_nondist(integer) drop cascades to table table_test_prepare drop cascades to function test_prepare(integer,integer) drop cascades to function outer_test_prepare(integer,integer) drop cascades to table test_perform drop cascades to function test(integer) drop cascades to table testnested_table drop cascades to function inner_fn(integer) drop cascades to function outer_fn(integer,integer) drop cascades to function force_push_inner(integer) drop cascades to function force_push_outer(integer) drop cascades to function force_push_1(integer) drop cascades to function force_push_2(integer) drop cascades to function force_push_3(integer)