diff --git a/src/test/regress/expected/distributed_functions.out b/src/test/regress/expected/distributed_functions.out index 7fb8166a3..7d6e63a63 100644 --- a/src/test/regress/expected/distributed_functions.out +++ b/src/test/regress/expected/distributed_functions.out @@ -344,6 +344,8 @@ SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,maca (1 row) ALTER FUNCTION eq(macaddr,macaddr) SET "citus.setting;'" TO 'hello '' world'; +ERROR: invalid configuration parameter name "citus.setting;'" +DETAIL: Custom parameter names must be two or more simple identifiers separated by dots. SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); verify_function_is_same_on_workers --------------------------------------------------------------------- @@ -351,6 +353,8 @@ SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,maca (1 row) ALTER FUNCTION eq(macaddr,macaddr) RESET "citus.setting;'"; +ERROR: invalid configuration parameter name "citus.setting;'" +DETAIL: Custom parameter names must be two or more simple identifiers separated by dots. SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); verify_function_is_same_on_workers --------------------------------------------------------------------- @@ -542,7 +546,8 @@ SELECT * FROM run_command_on_workers('SELECT function_tests2.sum2(id) FROM (sele -- postgres doesn't accept parameter names in the regprocedure input SELECT create_distributed_function('eq_with_param_names(val1 macaddr, macaddr)', 'val1'); -ERROR: invalid type name "val1 macaddr" +ERROR: syntax error at or near "macaddr" +CONTEXT: invalid type name "val1 macaddr" -- invalid distribution_arg_name SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', distribution_arg_name:='test'); ERROR: cannot distribute the function "eq_with_param_names" since the distribution argument is not valid diff --git a/src/test/regress/expected/distributed_functions_0.out b/src/test/regress/expected/distributed_functions_0.out new file mode 100644 index 000000000..7fb8166a3 --- /dev/null +++ b/src/test/regress/expected/distributed_functions_0.out @@ -0,0 +1,885 @@ +SET citus.next_shard_id TO 20020000; +CREATE USER functionuser; +NOTICE: not propagating CREATE ROLE/USER commands to worker nodes +HINT: Connect to worker nodes directly to manually create all necessary users and roles. +SELECT run_command_on_workers($$CREATE USER functionuser;$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"CREATE ROLE") + (localhost,57638,t,"CREATE ROLE") +(2 rows) + +CREATE SCHEMA function_tests AUTHORIZATION functionuser; +CREATE SCHEMA function_tests2 AUTHORIZATION functionuser; +SET search_path TO function_tests; +SET citus.shard_count TO 4; +-- test notice +CREATE TABLE notices ( + id int primary key, + message text +); +SELECT create_distributed_table('notices', 'id'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO notices VALUES (1, 'hello world'); +CREATE FUNCTION notice(text) +RETURNS void +LANGUAGE plpgsql AS $$ +BEGIN + RAISE NOTICE '%', $1; +END; +$$; +SELECT create_distributed_function('notice(text)'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT notice(message) FROM notices WHERE id = 1; +NOTICE: hello world +DETAIL: from localhost:xxxxx + notice +--------------------------------------------------------------------- + +(1 row) + +-- should not see a NOTICE if worker_min_messages is WARNING +SET citus.worker_min_messages TO WARNING; +SELECT notice(message) FROM notices WHERE id = 1; + notice +--------------------------------------------------------------------- + +(1 row) + +RESET citus.worker_min_messages; +-- Create and distribute a simple function +CREATE FUNCTION eq(macaddr, macaddr) RETURNS bool + AS 'select $1 = $2;' + LANGUAGE SQL + IMMUTABLE + RETURNS NULL ON NULL INPUT; +CREATE FUNCTION eq8(macaddr8, macaddr8) RETURNS bool + AS 'select $1 = $2;' + LANGUAGE SQL + IMMUTABLE + RETURNS NULL ON NULL INPUT; +-- $function$ is what postgres escapes functions with when deparsing +-- make sure $function$ doesn't cause invalid syntax +CREATE FUNCTION add_text(text, text) RETURNS text + AS 'select $function$test$function$ || $1::int || $2::int;' + LANGUAGE SQL + IMMUTABLE + RETURNS NULL ON NULL INPUT; +CREATE FUNCTION add_polygons(polygon, polygon) RETURNS int + AS 'select 1' + LANGUAGE SQL + IMMUTABLE + RETURNS NULL ON NULL INPUT; +-- Test some combination of functions without ddl propagation +-- This will prevent the workers from having those types created. They are +-- created just-in-time on function distribution +SET citus.enable_ddl_propagation TO off; +CREATE TYPE dup_result AS (f1 macaddr, f2 text); +CREATE FUNCTION dup(macaddr) RETURNS dup_result + AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$ + LANGUAGE SQL; +CREATE FUNCTION increment(int2) RETURNS int + AS $$ SELECT $1 + 1$$ + LANGUAGE SQL; +CREATE FUNCTION eq_with_param_names(val1 macaddr, val2 macaddr) RETURNS bool + AS 'select $1 = $2;' + LANGUAGE SQL + IMMUTABLE + RETURNS NULL ON NULL INPUT; +CREATE FUNCTION add_without_param_names(integer, integer) RETURNS integer + AS 'select $1 + $2;' + LANGUAGE SQL + IMMUTABLE + RETURNS NULL ON NULL INPUT; +CREATE FUNCTION "eq_mi'xed_param_names"(macaddr, "va'l1" macaddr) RETURNS bool + AS 'select $1 = $2;' + LANGUAGE SQL + IMMUTABLE + RETURNS NULL ON NULL INPUT; +-- Include aggregate function case +CREATE FUNCTION agg_sfunc(state int, item int) +RETURNS int IMMUTABLE LANGUAGE plpgsql AS $$ +begin + return state + item; +end; +$$; +CREATE FUNCTION agg_invfunc(state int, item int) +RETURNS int IMMUTABLE LANGUAGE plpgsql AS $$ +begin + return state - item; +end; +$$; +CREATE FUNCTION agg_finalfunc(state int, extra int) +RETURNS int IMMUTABLE LANGUAGE plpgsql AS $$ +begin + return state * 2; +end; +$$; +CREATE AGGREGATE sum2(int) ( + sfunc = agg_sfunc, + stype = int, + sspace = 8, + finalfunc = agg_finalfunc, + finalfunc_extra, + initcond = '5', + msfunc = agg_sfunc, + mstype = int, + msspace = 12, + minvfunc = agg_invfunc, + mfinalfunc = agg_finalfunc, + mfinalfunc_extra, + minitcond = '1', + sortop = ">" +); +-- Test VARIADIC, example taken from postgres test suite +CREATE AGGREGATE my_rank(VARIADIC "any" ORDER BY VARIADIC "any") ( + stype = internal, + sfunc = ordered_set_transition_multi, + finalfunc = rank_final, + finalfunc_extra, + hypothetical +); +-- Test deparsing multiple parameters with names +CREATE FUNCTION agg_names_sfunc(state dup_result, x dup_result, yz dup_result) +RETURNS dup_result IMMUTABLE STRICT LANGUAGE sql AS $$ + select x.f1 | yz.f1, x.f2 || yz.f2; +$$; +CREATE FUNCTION agg_names_finalfunc(x dup_result) +RETURNS int IMMUTABLE STRICT LANGUAGE plpgsql AS $$ +begin + return x.f1; +end; +$$; +CREATE AGGREGATE agg_names(x dup_result, yz dup_result) ( + stype = dup_result, + sfunc = agg_names_sfunc, + finalfunc = agg_names_finalfunc, + finalfunc_modify = shareable +); +-- make sure to propagate ddl propagation after we have setup our functions, this will +-- allow alter statements to be propagated and keep the functions in sync across machines +SET citus.enable_ddl_propagation TO on; +-- use an unusual type to force a new colocation group +CREATE TABLE statement_table(id int2); +SET citus.shard_replication_factor TO 2; +SELECT create_distributed_table('statement_table','id'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +-- create a table uses streaming-based replication (can be synced) +CREATE TABLE streaming_table(id macaddr); +SET citus.shard_replication_factor TO 1; +SELECT create_distributed_table('streaming_table','id'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +-- make sure that none of the active and primary nodes hasmetadata +-- at the start of the test +select bool_or(hasmetadata) from pg_dist_node WHERE isactive AND noderole = 'primary'; + bool_or +--------------------------------------------------------------------- + f +(1 row) + +-- if not paremeters are supplied, we'd see that function doesn't have +-- distribution_argument_index and colocationid +SELECT create_distributed_function('"eq_mi''xed_param_names"(macaddr, macaddr)'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT distribution_argument_index is NULL, colocationid is NULL from citus.pg_dist_object +WHERE objid = 'eq_mi''xed_param_names(macaddr, macaddr)'::regprocedure; + ?column? | ?column? +--------------------------------------------------------------------- + t | t +(1 row) + +-- also show that we can use the function +SELECT * FROM run_command_on_workers($$SELECT function_tests."eq_mi'xed_param_names"('0123456789ab','ba9876543210');$$) ORDER BY 1,2; + nodename | nodeport | success | result +--------------------------------------------------------------------- + localhost | 57637 | t | f + localhost | 57638 | t | f +(2 rows) + +-- make sure that none of the active and primary nodes hasmetadata +-- since the function doesn't have a parameter +select bool_or(hasmetadata) from pg_dist_node WHERE isactive AND noderole = 'primary'; + bool_or +--------------------------------------------------------------------- + f +(1 row) + +-- try to co-locate with a table that uses statement-based replication +SELECT create_distributed_function('increment(int2)', '$1'); +ERROR: cannot distribute the function "increment" since there is no table to colocate with +HINT: Provide a distributed table via "colocate_with" option to create_distributed_function() +SELECT create_distributed_function('increment(int2)', '$1', colocate_with := 'statement_table'); +ERROR: cannot colocate function "increment" and table "statement_table" +DETAIL: Citus currently only supports colocating function with distributed tables that are created using streaming replication model. +HINT: When distributing tables make sure that citus.shard_replication_factor = 1 +BEGIN; +DROP TABLE statement_table; +SELECT create_distributed_function('increment(int2)', '$1'); +ERROR: cannot distribute the function "increment" since there is no table to colocate with +HINT: Provide a distributed table via "colocate_with" option to create_distributed_function() +END; +-- try to co-locate with a table that uses streaming replication +SELECT create_distributed_function('dup(macaddr)', '$1', colocate_with := 'streaming_table'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT * FROM run_command_on_workers($$SELECT function_tests.dup('0123456789ab');$$) ORDER BY 1,2; + nodename | nodeport | success | result +--------------------------------------------------------------------- + localhost | 57637 | t | (01:23:45:67:89:ab,"01:23:45:67:89:ab is text") + localhost | 57638 | t | (01:23:45:67:89:ab,"01:23:45:67:89:ab is text") +(2 rows) + +SELECT create_distributed_function('eq(macaddr,macaddr)', '$1', colocate_with := 'streaming_table'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT * FROM run_command_on_workers($$SELECT function_tests.eq('012345689ab','0123456789ab');$$) ORDER BY 1,2; + nodename | nodeport | success | result +--------------------------------------------------------------------- + localhost | 57637 | t | f + localhost | 57638 | t | f +(2 rows) + +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +-- distribute aggregate +SELECT create_distributed_function('sum2(int)'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT create_distributed_function('my_rank("any")'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT create_distributed_function('agg_names(dup_result,dup_result)'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +-- testing alter statements for a distributed function +-- ROWS 5, untested because; +-- ERROR: ROWS is not applicable when function does not return a set +ALTER FUNCTION eq(macaddr,macaddr) CALLED ON NULL INPUT IMMUTABLE SECURITY INVOKER PARALLEL UNSAFE LEAKPROOF COST 5; +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +ALTER FUNCTION eq(macaddr,macaddr) RETURNS NULL ON NULL INPUT STABLE SECURITY DEFINER PARALLEL RESTRICTED; +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +ALTER FUNCTION eq(macaddr,macaddr) STRICT VOLATILE PARALLEL SAFE; +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +-- Test SET/RESET for alter function +ALTER FUNCTION eq(macaddr,macaddr) SET client_min_messages TO warning; +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +ALTER FUNCTION eq(macaddr,macaddr) SET client_min_messages TO error; +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +ALTER ROUTINE eq(macaddr,macaddr) SET client_min_messages TO debug; +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +ALTER FUNCTION eq(macaddr,macaddr) RESET client_min_messages; +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +ALTER FUNCTION eq(macaddr,macaddr) SET "citus.setting;'" TO 'hello '' world'; +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +ALTER FUNCTION eq(macaddr,macaddr) RESET "citus.setting;'"; +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +ALTER FUNCTION eq(macaddr,macaddr) SET search_path TO 'sch'';ma', public; +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +ALTER FUNCTION eq(macaddr,macaddr) RESET search_path; +-- SET ... FROM CURRENT is not supported, verify the query fails with a descriptive error irregardless of where in the action list the statement occurs +ALTER FUNCTION eq(macaddr,macaddr) SET client_min_messages FROM CURRENT; +ERROR: unsupported ALTER FUNCTION ... SET ... FROM CURRENT for a distributed function +HINT: SET FROM CURRENT is not supported for distributed functions, instead use the SET ... TO ... syntax with a constant value. +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +ALTER FUNCTION eq(macaddr,macaddr) RETURNS NULL ON NULL INPUT SET client_min_messages FROM CURRENT; +ERROR: unsupported ALTER FUNCTION ... SET ... FROM CURRENT for a distributed function +HINT: SET FROM CURRENT is not supported for distributed functions, instead use the SET ... TO ... syntax with a constant value. +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +ALTER FUNCTION eq(macaddr,macaddr) SET client_min_messages FROM CURRENT SECURITY DEFINER; +ERROR: unsupported ALTER FUNCTION ... SET ... FROM CURRENT for a distributed function +HINT: SET FROM CURRENT is not supported for distributed functions, instead use the SET ... TO ... syntax with a constant value. +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +-- rename function and make sure the new name can be used on the workers while the old name can't +ALTER FUNCTION eq(macaddr,macaddr) RENAME TO eq2; +SELECT public.verify_function_is_same_on_workers('function_tests.eq2(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +SELECT * FROM run_command_on_workers($$SELECT function_tests.eq('012346789ab','012345689ab');$$) ORDER BY 1,2; + nodename | nodeport | success | result +--------------------------------------------------------------------- + localhost | 57637 | f | ERROR: function function_tests.eq(unknown, unknown) does not exist + localhost | 57638 | f | ERROR: function function_tests.eq(unknown, unknown) does not exist +(2 rows) + +SELECT * FROM run_command_on_workers($$SELECT function_tests.eq2('012345689ab','012345689ab');$$) ORDER BY 1,2; + nodename | nodeport | success | result +--------------------------------------------------------------------- + localhost | 57637 | t | t + localhost | 57638 | t | t +(2 rows) + +ALTER ROUTINE eq2(macaddr,macaddr) RENAME TO eq; +ALTER AGGREGATE sum2(int) RENAME TO sum27; +SELECT * FROM run_command_on_workers($$SELECT 1 from pg_proc where proname = 'sum27';$$) ORDER BY 1,2; + nodename | nodeport | success | result +--------------------------------------------------------------------- + localhost | 57637 | t | 1 + localhost | 57638 | t | 1 +(2 rows) + +ALTER AGGREGATE sum27(int) RENAME TO sum2; +-- change the owner of the function and verify the owner has been changed on the workers +ALTER FUNCTION eq(macaddr,macaddr) OWNER TO functionuser; +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +ALTER AGGREGATE sum2(int) OWNER TO functionuser; +ALTER ROUTINE my_rank("any") OWNER TO functionuser; +ALTER AGGREGATE my_rank("any") OWNER TO functionuser; +SELECT run_command_on_workers($$ +SELECT array_agg(row(usename, nspname, proname) order by proname) +FROM pg_proc +JOIN pg_user ON (usesysid = proowner) +JOIN pg_namespace ON (pg_namespace.oid = pronamespace and nspname = 'function_tests') +WHERE proname IN ('eq', 'sum2', 'my_rank'); +$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"{""(functionuser,function_tests,eq)"",""(functionuser,function_tests,my_rank)"",""(functionuser,function_tests,sum2)""}") + (localhost,57638,t,"{""(functionuser,function_tests,eq)"",""(functionuser,function_tests,my_rank)"",""(functionuser,function_tests,sum2)""}") +(2 rows) + +-- change the schema of the function and verify the old schema doesn't exist anymore while +-- the new schema has the function. +ALTER FUNCTION eq(macaddr,macaddr) SET SCHEMA function_tests2; +SELECT public.verify_function_is_same_on_workers('function_tests2.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +SELECT * FROM run_command_on_workers($$SELECT function_tests.eq('0123456789ab','ba9876543210');$$) ORDER BY 1,2; + nodename | nodeport | success | result +--------------------------------------------------------------------- + localhost | 57637 | f | ERROR: function function_tests.eq(unknown, unknown) does not exist + localhost | 57638 | f | ERROR: function function_tests.eq(unknown, unknown) does not exist +(2 rows) + +SELECT * FROM run_command_on_workers($$SELECT function_tests2.eq('012345689ab','ba9876543210');$$) ORDER BY 1,2; + nodename | nodeport | success | result +--------------------------------------------------------------------- + localhost | 57637 | t | f + localhost | 57638 | t | f +(2 rows) + +ALTER ROUTINE function_tests2.eq(macaddr,macaddr) SET SCHEMA function_tests; +ALTER AGGREGATE sum2(int) SET SCHEMA function_tests2; +-- when a function is distributed and we create or replace the function we need to propagate the statement to the worker to keep it in sync with the coordinator +CREATE OR REPLACE FUNCTION eq(macaddr, macaddr) RETURNS bool +AS 'select $1 <> $2;' -- I know, this is not an add, but the output will tell us if the update succeeded + LANGUAGE SQL + IMMUTABLE + RETURNS NULL ON NULL INPUT; +SELECT public.verify_function_is_same_on_workers('function_tests.eq(macaddr,macaddr)'); + verify_function_is_same_on_workers +--------------------------------------------------------------------- + t +(1 row) + +SELECT * FROM run_command_on_workers($$SELECT function_tests.eq('012345689ab','012345689ab');$$) ORDER BY 1,2; + nodename | nodeport | success | result +--------------------------------------------------------------------- + localhost | 57637 | t | f + localhost | 57638 | t | f +(2 rows) + +-- distributed functions should not be allowed to depend on an extension, also functions +-- that depend on an extension should not be allowed to be distributed. +ALTER FUNCTION eq(macaddr,macaddr) DEPENDS ON EXTENSION citus; +ERROR: distrtibuted functions are not allowed to depend on an extension +DETAIL: Function "function_tests.eq(pg_catalog.macaddr,pg_catalog.macaddr)" is already distributed. Functions from extensions are expected to be created on the workers by the extension they depend on. +SELECT create_distributed_function('pg_catalog.citus_drop_trigger()'); +ERROR: unable to create a distributed function from functions owned by an extension +DETAIL: Function "pg_catalog.citus_drop_trigger()" has a dependency on extension "citus". Functions depending on an extension cannot be distributed. Create the function by creating the extension on the workers. +DROP FUNCTION eq(macaddr,macaddr); +-- call should fail as function should have been dropped +SELECT * FROM run_command_on_workers($$SELECT function_tests.eq('0123456789ab','ba9876543210');$$) ORDER BY 1,2; + nodename | nodeport | success | result +--------------------------------------------------------------------- + localhost | 57637 | f | ERROR: function function_tests.eq(unknown, unknown) does not exist + localhost | 57638 | f | ERROR: function function_tests.eq(unknown, unknown) does not exist +(2 rows) + +-- Test DROP for ROUTINE +CREATE OR REPLACE FUNCTION eq(macaddr, macaddr) RETURNS bool +AS 'select $1 = $2;' + LANGUAGE SQL + IMMUTABLE + RETURNS NULL ON NULL INPUT; +select create_distributed_function('eq(macaddr,macaddr)'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +DROP ROUTINE eq(macaddr, macaddr); +-- call should fail as function should have been dropped +SELECT * FROM run_command_on_workers($$SELECT function_tests.eq('0123456789ab','ba9876543210');$$) ORDER BY 1,2; + nodename | nodeport | success | result +--------------------------------------------------------------------- + localhost | 57637 | f | ERROR: function function_tests.eq(unknown, unknown) does not exist + localhost | 57638 | f | ERROR: function function_tests.eq(unknown, unknown) does not exist +(2 rows) + +DROP AGGREGATE function_tests2.sum2(int); +-- call should fail as aggregate should have been dropped +SELECT * FROM run_command_on_workers('SELECT function_tests2.sum2(id) FROM (select 1 id, 2) subq;') ORDER BY 1,2; + nodename | nodeport | success | result +--------------------------------------------------------------------- + localhost | 57637 | f | ERROR: function function_tests2.sum2(integer) does not exist + localhost | 57638 | f | ERROR: function function_tests2.sum2(integer) does not exist +(2 rows) + +-- postgres doesn't accept parameter names in the regprocedure input +SELECT create_distributed_function('eq_with_param_names(val1 macaddr, macaddr)', 'val1'); +ERROR: invalid type name "val1 macaddr" +-- invalid distribution_arg_name +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', distribution_arg_name:='test'); +ERROR: cannot distribute the function "eq_with_param_names" since the distribution argument is not valid +HINT: Either provide a valid function argument name or a valid "$paramIndex" to create_distributed_function() +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', distribution_arg_name:='int'); +ERROR: cannot distribute the function "eq_with_param_names" since the distribution argument is not valid +HINT: Either provide a valid function argument name or a valid "$paramIndex" to create_distributed_function() +-- invalid distribution_arg_index +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', '$0'); +ERROR: cannot distribute the function "eq_with_param_names" since the distribution argument is not valid +HINT: Either provide a valid function argument name or a valid "$paramIndex" to create_distributed_function() +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', '$-1'); +ERROR: cannot distribute the function "eq_with_param_names" since the distribution argument is not valid +HINT: Either provide a valid function argument name or a valid "$paramIndex" to create_distributed_function() +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', '$-10'); +ERROR: cannot distribute the function "eq_with_param_names" since the distribution argument is not valid +HINT: Either provide a valid function argument name or a valid "$paramIndex" to create_distributed_function() +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', '$3'); +ERROR: cannot distribute the function "eq_with_param_names" since the distribution argument is not valid +HINT: Either provide a valid function argument name or a valid "$paramIndex" to create_distributed_function() +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', '$1a'); +ERROR: invalid input syntax for integer: "1a" +-- non existing column name +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', 'aaa'); +ERROR: cannot distribute the function "eq_with_param_names" since the distribution argument is not valid +HINT: Either provide a valid function argument name or a valid "$paramIndex" to create_distributed_function() +-- NULL function +SELECT create_distributed_function(NULL); +ERROR: the first parameter for create_distributed_function() should be a single a valid function or procedure name followed by a list of parameters in parantheses +HINT: skip the parameters with OUT argtype as they are not part of the signature in PostgreSQL +-- NULL colocate_with +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', '$1', NULL); +ERROR: colocate_with parameter should not be NULL +HINT: To use the default value, set colocate_with option to "default" +-- empty string distribution_arg_index +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', ''); +ERROR: cannot distribute the function "eq_with_param_names" since the distribution argument is not valid +HINT: Either provide a valid function argument name or a valid "$paramIndex" to create_distributed_function() +-- The first distributed function syncs the metadata to nodes +-- and metadata syncing is not supported within transaction blocks +BEGIN; + SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', distribution_arg_name:='val1'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +ROLLBACK; +-- make sure that none of the nodes have the function because we've rollbacked +SELECT run_command_on_workers($$SELECT count(*) FROM pg_proc WHERE proname='eq_with_param_names';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,0) + (localhost,57638,t,0) +(2 rows) + +-- make sure that none of the active and primary nodes hasmetadata +select bool_or(hasmetadata) from pg_dist_node WHERE isactive AND noderole = 'primary'; + bool_or +--------------------------------------------------------------------- + t +(1 row) + +-- valid distribution with distribution_arg_name +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', distribution_arg_name:='val1'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +-- make sure that the primary nodes are now metadata synced +select bool_and(hasmetadata) from pg_dist_node WHERE isactive AND noderole = 'primary'; + bool_and +--------------------------------------------------------------------- + t +(1 row) + +-- make sure that both of the nodes have the function because we've succeeded +SELECT run_command_on_workers($$SELECT count(*) FROM pg_proc WHERE proname='eq_with_param_names';$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,1) + (localhost,57638,t,1) +(2 rows) + +-- valid distribution with distribution_arg_name -- case insensitive +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', distribution_arg_name:='VaL1'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +-- valid distribution with distribution_arg_index +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)','$1'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +-- a function cannot be colocated with a table that is not "streaming" replicated +SET citus.shard_replication_factor TO 2; +CREATE TABLE replicated_table_func_test (a macaddr); +SELECT create_distributed_table('replicated_table_func_test', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', '$1', colocate_with:='replicated_table_func_test'); +ERROR: cannot colocate function "eq_with_param_names" and table "replicated_table_func_test" +DETAIL: Citus currently only supports colocating function with distributed tables that are created using streaming replication model. +HINT: When distributing tables make sure that citus.shard_replication_factor = 1 +SELECT public.wait_until_metadata_sync(30000); + wait_until_metadata_sync +--------------------------------------------------------------------- + +(1 row) + +-- a function can be colocated with a different distribution argument type +-- as long as there is a coercion path +SET citus.shard_replication_factor TO 1; +CREATE TABLE replicated_table_func_test_2 (a macaddr8); +SELECT create_distributed_table('replicated_table_func_test_2', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', 'val1', colocate_with:='replicated_table_func_test_2'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +-- colocate_with cannot be used without distribution key +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', colocate_with:='replicated_table_func_test_2'); +ERROR: cannot distribute the function "eq_with_param_names" since the distribution argument is not valid +HINT: To provide "colocate_with" option with a distributed table, the distribution argument parameter should also be provided +-- a function cannot be colocated with a local table +CREATE TABLE replicated_table_func_test_3 (a macaddr8); +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', 'val1', colocate_with:='replicated_table_func_test_3'); +ERROR: relation replicated_table_func_test_3 is not distributed +-- finally, colocate the function with a distributed table +SET citus.shard_replication_factor TO 1; +CREATE TABLE replicated_table_func_test_4 (a macaddr); +SELECT create_distributed_table('replicated_table_func_test_4', 'a'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', '$1', colocate_with:='replicated_table_func_test_4'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +-- show that the colocationIds are the same +SELECT pg_dist_partition.colocationid = objects.colocationid as table_and_function_colocated +FROM pg_dist_partition, citus.pg_dist_object as objects +WHERE pg_dist_partition.logicalrelid = 'replicated_table_func_test_4'::regclass AND + objects.objid = 'eq_with_param_names(macaddr, macaddr)'::regprocedure; + table_and_function_colocated +--------------------------------------------------------------------- + t +(1 row) + +-- now, redistributed with the default colocation option, we should still see that the same colocation +-- group preserved, because we're using the default shard creation settings +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', 'val1'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT pg_dist_partition.colocationid = objects.colocationid as table_and_function_colocated +FROM pg_dist_partition, citus.pg_dist_object as objects +WHERE pg_dist_partition.logicalrelid = 'replicated_table_func_test_4'::regclass AND + objects.objid = 'eq_with_param_names(macaddr, macaddr)'::regprocedure; + table_and_function_colocated +--------------------------------------------------------------------- + t +(1 row) + +-- a function cannot be colocated with a reference table when a distribution column is provided +SELECT create_reference_table('replicated_table_func_test_3'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', 'val1', colocate_with:='replicated_table_func_test_3'); +ERROR: cannot colocate function "eq_with_param_names" and table "replicated_table_func_test_3" because distribution arguments are not supported when colocating with reference tables. +-- a function can be colocated with a reference table when the distribution argument is omitted +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', colocate_with:='replicated_table_func_test_3'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +-- function with a macaddr8 dist. arg can be colocated with macaddr +-- column of a distributed table. In general, if there is a coercion +-- path, we rely on postgres for implicit coersions, and users for explicit coersions +-- to coerce the values +SELECT create_distributed_function('eq8(macaddr8, macaddr8)', '$1', colocate_with:='replicated_table_func_test_4'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT pg_dist_partition.colocationid = objects.colocationid as table_and_function_colocated +FROM pg_dist_partition, citus.pg_dist_object as objects +WHERE pg_dist_partition.logicalrelid = 'replicated_table_func_test_4'::regclass AND + objects.objid = 'eq8(macaddr8, macaddr8)'::regprocedure; + table_and_function_colocated +--------------------------------------------------------------------- + t +(1 row) + +SELECT create_distributed_function('add_text(text, text)', '$1', colocate_with:='replicated_table_func_test_4'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT pg_dist_partition.colocationid = objects.colocationid as table_and_function_colocated +FROM pg_dist_partition, citus.pg_dist_object as objects +WHERE pg_dist_partition.logicalrelid = 'replicated_table_func_test_4'::regclass AND + objects.objid = 'add_text(text, text)'::regprocedure; + table_and_function_colocated +--------------------------------------------------------------------- + t +(1 row) + +-- cannot distribute function because there is no +-- coercion path from polygon to int +SELECT create_distributed_function('add_polygons(polygon,polygon)', '$1', colocate_with:='replicated_table_func_test_4'); +ERROR: cannot colocate function "replicated_table_func_test_4" and table "add_polygons" because distribution column types don't match and there is no coercion path +-- without the colocate_with, the function errors out since there is no +-- default colocation group +SET citus.shard_count TO 55; +SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', 'val1'); +ERROR: cannot distribute the function "eq_with_param_names" since there is no table to colocate with +HINT: Provide a distributed table via "colocate_with" option to create_distributed_function() +-- sync metadata to workers for consistent results when clearing objects +SELECT public.wait_until_metadata_sync(30000); + wait_until_metadata_sync +--------------------------------------------------------------------- + +(1 row) + +SET citus.shard_replication_factor TO 1; +SET citus.shard_count TO 4; +CREATE TABLE test (id int, name text); +SELECT create_distributed_table('test','id'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +INSERT INTO test VALUES (3,'three'); +CREATE OR REPLACE FUNCTION increment(int) +RETURNS NUMERIC AS $$ +DECLARE ret_val NUMERIC; +BEGIN + SELECT max(id)::numeric+1 INTO ret_val FROM test WHERE id = $1; + RETURN ret_val; +END; +$$ LANGUAGE plpgsql; +SELECT create_distributed_function('increment(int)', '$1', colocate_with := 'test'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +-- call a distributed function inside a pl/pgsql function +CREATE OR REPLACE FUNCTION test_func_calls_dist_func() +RETURNS NUMERIC AS $$ +DECLARE incremented_val NUMERIC; +BEGIN + SELECT INTO incremented_val increment(1); + RETURN incremented_val; +END; +$$ LANGUAGE plpgsql; +SELECT test_func_calls_dist_func(); + test_func_calls_dist_func +--------------------------------------------------------------------- + +(1 row) + +SELECT test_func_calls_dist_func(); + test_func_calls_dist_func +--------------------------------------------------------------------- + +(1 row) + +-- test an INSERT..SELECT via the coordinator just because it is kind of funky +INSERT INTO test SELECT increment(3); +SELECT * FROM test ORDER BY id; + id | name +--------------------------------------------------------------------- + 3 | three + 4 | +(2 rows) + +DROP TABLE test; +SET client_min_messages TO error; -- suppress cascading objects dropping +DROP SCHEMA function_tests CASCADE; +DROP SCHEMA function_tests2 CASCADE; +-- clear objects +SELECT stop_metadata_sync_to_node(nodename,nodeport) FROM pg_dist_node WHERE isactive AND noderole = 'primary'; + stop_metadata_sync_to_node +--------------------------------------------------------------------- + + +(2 rows) + +-- This is hacky, but we should clean-up the resources as below +\c - - - :worker_1_port +UPDATE pg_dist_local_group SET groupid = 0; +TRUNCATE pg_dist_node; +SET client_min_messages TO error; -- suppress cascading objects dropping +DROP SCHEMA function_tests CASCADE; +DROP SCHEMA function_tests2 CASCADE; +SET search_path TO function_tests, function_tests2; +\c - - - :worker_2_port +UPDATE pg_dist_local_group SET groupid = 0; +TRUNCATE pg_dist_node; +SET client_min_messages TO error; -- suppress cascading objects dropping +DROP SCHEMA function_tests CASCADE; +DROP SCHEMA function_tests2 CASCADE; +\c - - - :master_port +DROP USER functionuser; +SELECT run_command_on_workers($$DROP USER functionuser$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"DROP ROLE") + (localhost,57638,t,"DROP ROLE") +(2 rows) + diff --git a/src/test/regress/expected/multi_deparse_function.out b/src/test/regress/expected/multi_deparse_function.out index 7a7d775c8..c33be0aa7 100644 --- a/src/test/regress/expected/multi_deparse_function.out +++ b/src/test/regress/expected/multi_deparse_function.out @@ -70,7 +70,7 @@ SELECT create_distributed_function('add(int,int)'); SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add CALLED ON NULL INPUT $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) CALLED ON NULL INPUT; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) CALLED ON NULL INPUT; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -83,7 +83,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add RETURNS NULL ON NULL INPUT $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) STRICT; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) STRICT; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -94,7 +94,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add STRICT $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) STRICT; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) STRICT; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -105,7 +105,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add IMMUTABLE $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) IMMUTABLE; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) IMMUTABLE; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -116,7 +116,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add STABLE $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) STABLE; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) STABLE; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -127,7 +127,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add VOLATILE $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) VOLATILE; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) VOLATILE; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -138,7 +138,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add LEAKPROOF $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) LEAKPROOF; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) LEAKPROOF; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -149,7 +149,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add NOT LEAKPROOF $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) NOT LEAKPROOF; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) NOT LEAKPROOF; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -162,7 +162,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add EXTERNAL SECURITY INVOKER $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SECURITY INVOKER; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SECURITY INVOKER; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -173,7 +173,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add SECURITY INVOKER $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SECURITY INVOKER; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SECURITY INVOKER; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -184,7 +184,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add EXTERNAL SECURITY DEFINER $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SECURITY DEFINER; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SECURITY DEFINER; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -195,7 +195,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add SECURITY DEFINER $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SECURITY DEFINER; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SECURITY DEFINER; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -206,7 +206,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add PARALLEL UNSAFE $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) PARALLEL UNSAFE; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) PARALLEL UNSAFE; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -217,7 +217,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add PARALLEL RESTRICTED $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) PARALLEL RESTRICTED; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) PARALLEL RESTRICTED; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -228,7 +228,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add PARALLEL SAFE $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) PARALLEL SAFE; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) PARALLEL SAFE; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -240,7 +240,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add COST 1234 $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) COST 1234.000000; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) COST 1234.000000; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -251,7 +251,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add COST 1234.5 $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) COST 1234.500000; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) COST 1234.500000; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -262,7 +262,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add SET log_min_messages = ERROR $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET log_min_messages = 'error'; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SET log_min_messages = 'error'; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -273,7 +273,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add SET log_min_messages TO DEFAULT $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET log_min_messages TO DEFAULT; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SET log_min_messages TO DEFAULT; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -284,7 +284,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add SET log_min_messages FROM CURRENT $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET log_min_messages FROM CURRENT; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SET log_min_messages FROM CURRENT; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -295,7 +295,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add(int, int) SET TIME ZONE INTERVAL '-08:00' HOUR TO MINUTE; $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET TIME ZONE INTERVAL '@ 8 hours ago'; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SET TIME ZONE INTERVAL '@ 8 hours ago'; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -306,7 +306,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add(int, int) SET TIME ZONE '-7'; $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET timezone = '-7'; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SET timezone = '-7'; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -317,34 +317,34 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add(int, int) SET "citus.setting;'" TO 'hello '' world'; $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET "citus.setting;'" = 'hello '' world'; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SET "citus.setting;'" = 'hello '' world'; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE - deparse_and_run_on_workers + deparse_and_run_on_workers --------------------------------------------------------------------- - (localhost,57637,t,"ALTER FUNCTION") - (localhost,57638,t,"ALTER FUNCTION") + (localhost,57637,f,"ERROR: invalid configuration parameter name ""citus.setting;'""") + (localhost,57638,f,"ERROR: invalid configuration parameter name ""citus.setting;'""") (2 rows) SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add(int, int) SET "citus.setting;'" TO -3.2; $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET "citus.setting;'" = -3.2; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SET "citus.setting;'" = -3.2; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE - deparse_and_run_on_workers + deparse_and_run_on_workers --------------------------------------------------------------------- - (localhost,57637,t,"ALTER FUNCTION") - (localhost,57638,t,"ALTER FUNCTION") + (localhost,57637,f,"ERROR: invalid configuration parameter name ""citus.setting;'""") + (localhost,57638,f,"ERROR: invalid configuration parameter name ""citus.setting;'""") (2 rows) SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add(int, int) SET "citus.setting;'" TO -32; $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET "citus.setting;'" = -32; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SET "citus.setting;'" = -32; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE - deparse_and_run_on_workers + deparse_and_run_on_workers --------------------------------------------------------------------- - (localhost,57637,t,"ALTER FUNCTION") - (localhost,57638,t,"ALTER FUNCTION") + (localhost,57637,f,"ERROR: invalid configuration parameter name ""citus.setting;'""") + (localhost,57638,f,"ERROR: invalid configuration parameter name ""citus.setting;'""") (2 rows) -- This raises an error about only accepting one item, @@ -352,7 +352,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add(int, int) SET "citus.setting;'" TO 'hello '' world', 'second '' item'; $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET "citus.setting;'" = 'hello '' world', 'second '' item'; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SET "citus.setting;'" = 'hello '' world', 'second '' item'; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -363,7 +363,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add RESET log_min_messages $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) RESET log_min_messages; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) RESET log_min_messages; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -374,7 +374,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add RESET ALL $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) RESET ALL; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) RESET ALL; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -386,7 +386,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add RENAME TO summation $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) RENAME TO summation; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) RENAME TO summation; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -401,7 +401,7 @@ ALTER FUNCTION add RENAME TO summation; SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION summation RENAME TO add $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.summation(integer, integer) RENAME TO add; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.summation(integer,integer) RENAME TO add; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -424,7 +424,7 @@ SELECT run_command_on_workers('CREATE ROLE function_role'); SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add OWNER TO function_role $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) OWNER TO function_role; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) OWNER TO function_role; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -435,7 +435,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add OWNER TO missing_role $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) OWNER TO missing_role; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) OWNER TO missing_role; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -447,7 +447,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add SET SCHEMA public $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET SCHEMA public; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) SET SCHEMA public; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -460,7 +460,7 @@ ALTER FUNCTION add SET SCHEMA public; SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION public.add SET SCHEMA function_tests $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION public.add(integer, integer) SET SCHEMA function_tests; +INFO: Propagating deparsed query: ALTER FUNCTION public.add(integer,integer) SET SCHEMA function_tests; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -472,7 +472,7 @@ ALTER FUNCTION public.add SET SCHEMA function_tests; SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add DEPENDS ON EXTENSION citus $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) DEPENDS ON EXTENSION citus; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) DEPENDS ON EXTENSION citus; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -484,7 +484,7 @@ CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION pg_catalog.get_shard_id_for_distribution_column(table_name regclass, distribution_value "any") PARALLEL SAFE; $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION pg_catalog.get_shard_id_for_distribution_column(pg_catalog.regclass, pg_catalog."any") PARALLEL SAFE; +INFO: Propagating deparsed query: ALTER FUNCTION pg_catalog.get_shard_id_for_distribution_column(pg_catalog.regclass,pg_catalog."any") PARALLEL SAFE; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- @@ -498,14 +498,14 @@ DROP FUNCTION add(int,int); $cmd$); deparse_test --------------------------------------------------------------------- - DROP FUNCTION function_tests.add(integer, integer); + DROP FUNCTION function_tests.add(integer,integer); (1 row) -- have multiple actions in a single query SELECT deparse_and_run_on_workers($cmd$ ALTER FUNCTION add volatile leakproof SECURITY DEFINER PARALLEL unsafe; $cmd$); -INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) VOLATILE LEAKPROOF SECURITY DEFINER PARALLEL UNSAFE; +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer,integer) VOLATILE LEAKPROOF SECURITY DEFINER PARALLEL UNSAFE; CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE deparse_and_run_on_workers --------------------------------------------------------------------- diff --git a/src/test/regress/expected/multi_deparse_function_0.out b/src/test/regress/expected/multi_deparse_function_0.out new file mode 100644 index 000000000..7a7d775c8 --- /dev/null +++ b/src/test/regress/expected/multi_deparse_function_0.out @@ -0,0 +1,776 @@ +-- +-- Regression tests for deparsing ALTER/DROP FUNCTION Queries +-- +-- This test implements all the possible queries as of Postgres 11 +-- in the order they are listed in the docs +-- +-- ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] +-- action [ ... ] [ RESTRICT ] +-- ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] +-- RENAME TO new_name +-- ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] +-- OWNER TO { new_owner | CURRENT_USER | SESSION_USER } +-- ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] +-- SET SCHEMA new_schema +-- ALTER FUNCTION name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] +-- DEPENDS ON EXTENSION extension_name +-- +-- where action is one of: +-- +-- CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT +-- IMMUTABLE | STABLE | VOLATILE | [ NOT ] LEAKPROOF +-- [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER +-- PARALLEL { UNSAFE | RESTRICTED | SAFE } +-- COST execution_cost +-- ROWS result_rows +-- SET configuration_parameter { TO | = } { value | DEFAULT } +-- SET configuration_parameter FROM CURRENT +-- RESET configuration_parameter +-- RESET ALL +-- +-- DROP FUNCTION [ IF EXISTS ] name [ ( [ [ argmode ] [ argname ] argtype [, ...] ] ) ] [, ...] +-- [ CASCADE | RESTRICT ] +SET citus.next_shard_id TO 20020000; +SET citus.enable_ddl_propagation TO off; +CREATE SCHEMA function_tests; +SET search_path TO function_tests; +SET citus.shard_count TO 4; +SET client_min_messages TO INFO; +CREATE FUNCTION deparse_test(text) + RETURNS text + AS 'citus' + LANGUAGE C STRICT; +CREATE OR REPLACE FUNCTION deparse_and_run_on_workers(IN query text, + OUT nodename text, + OUT nodeport int, + OUT success bool, + OUT result text) + RETURNS SETOF record + LANGUAGE PLPGSQL AS $fnc$ + DECLARE + deparsed_query character varying(255); + BEGIN + deparsed_query := ( SELECT deparse_test($1) ); + RAISE INFO 'Propagating deparsed query: %', deparsed_query; + RETURN QUERY SELECT * FROM run_command_on_workers(deparsed_query); + END; + $fnc$; +-- Create a simple function and distribute it +CREATE FUNCTION add(integer, integer) RETURNS integer + AS 'select $1 + $2;' + LANGUAGE SQL + IMMUTABLE + RETURNS NULL ON NULL INPUT; +SELECT create_distributed_function('add(int,int)'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add CALLED ON NULL INPUT +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) CALLED ON NULL INPUT; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- RETURNS NULL ON NULL INPUT and STRICT are synonyms and can be used interchangeably +-- RETURNS NULL ON NULL INPUT is actually stored as STRICT in the query parse tree +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add RETURNS NULL ON NULL INPUT +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) STRICT; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add STRICT +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) STRICT; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add IMMUTABLE +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) IMMUTABLE; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add STABLE +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) STABLE; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add VOLATILE +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) VOLATILE; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add LEAKPROOF +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) LEAKPROOF; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add NOT LEAKPROOF +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) NOT LEAKPROOF; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- EXTERNAL keyword is ignored by Postgres Parser. It is allowed only for SQL conformance +-- The following queries will not have the EXTERNAL keyword after deparsing +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add EXTERNAL SECURITY INVOKER +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SECURITY INVOKER; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add SECURITY INVOKER +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SECURITY INVOKER; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add EXTERNAL SECURITY DEFINER +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SECURITY DEFINER; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add SECURITY DEFINER +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SECURITY DEFINER; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add PARALLEL UNSAFE +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) PARALLEL UNSAFE; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add PARALLEL RESTRICTED +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) PARALLEL RESTRICTED; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add PARALLEL SAFE +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) PARALLEL SAFE; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- The COST arguments should always be numeric +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add COST 1234 +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) COST 1234.000000; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add COST 1234.5 +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) COST 1234.500000; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add SET log_min_messages = ERROR +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET log_min_messages = 'error'; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add SET log_min_messages TO DEFAULT +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET log_min_messages TO DEFAULT; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add SET log_min_messages FROM CURRENT +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET log_min_messages FROM CURRENT; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add(int, int) SET TIME ZONE INTERVAL '-08:00' HOUR TO MINUTE; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET TIME ZONE INTERVAL '@ 8 hours ago'; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add(int, int) SET TIME ZONE '-7'; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET timezone = '-7'; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add(int, int) SET "citus.setting;'" TO 'hello '' world'; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET "citus.setting;'" = 'hello '' world'; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add(int, int) SET "citus.setting;'" TO -3.2; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET "citus.setting;'" = -3.2; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add(int, int) SET "citus.setting;'" TO -32; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET "citus.setting;'" = -32; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- This raises an error about only accepting one item, +-- that's okay, we're just testing that we don't produce bad syntax. +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add(int, int) SET "citus.setting;'" TO 'hello '' world', 'second '' item'; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET "citus.setting;'" = 'hello '' world', 'second '' item'; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,f,"ERROR: SET citus.setting;' takes only one argument") + (localhost,57638,f,"ERROR: SET citus.setting;' takes only one argument") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add RESET log_min_messages +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) RESET log_min_messages; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add RESET ALL +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) RESET ALL; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- Rename the function in the workers +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add RENAME TO summation +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) RENAME TO summation; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- Rename the function inb the coordinator as well. +-- This is needed so the next query is parsed on the coordinator +ALTER FUNCTION add RENAME TO summation; +-- Rename it back to the original so that the next tests can pass +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION summation RENAME TO add +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.summation(integer, integer) RENAME TO add; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- Rename the function back to the original name in the coordinator +ALTER FUNCTION summation RENAME TO add; +CREATE ROLE function_role; +NOTICE: not propagating CREATE ROLE/USER commands to worker nodes +HINT: Connect to worker nodes directly to manually create all necessary users and roles. +SELECT run_command_on_workers('CREATE ROLE function_role'); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"CREATE ROLE") + (localhost,57638,t,"CREATE ROLE") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add OWNER TO function_role +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) OWNER TO function_role; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add OWNER TO missing_role +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) OWNER TO missing_role; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,f,"ERROR: role ""missing_role"" does not exist") + (localhost,57638,f,"ERROR: role ""missing_role"" does not exist") +(2 rows) + +-- SET the schema in workers as well as the coordinator so that it remains in the same schema +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add SET SCHEMA public +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) SET SCHEMA public; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +ALTER FUNCTION add SET SCHEMA public; +-- Revert the schema back +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION public.add SET SCHEMA function_tests +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION public.add(integer, integer) SET SCHEMA function_tests; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +ALTER FUNCTION public.add SET SCHEMA function_tests; +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add DEPENDS ON EXTENSION citus +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) DEPENDS ON EXTENSION citus; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- make sure "any" type is correctly deparsed +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION pg_catalog.get_shard_id_for_distribution_column(table_name regclass, distribution_value "any") PARALLEL SAFE; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION pg_catalog.get_shard_id_for_distribution_column(pg_catalog.regclass, pg_catalog."any") PARALLEL SAFE; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- Do not run valid drop queries in the workers +SELECT deparse_test($cmd$ +DROP FUNCTION add(int,int); +$cmd$); + deparse_test +--------------------------------------------------------------------- + DROP FUNCTION function_tests.add(integer, integer); +(1 row) + +-- have multiple actions in a single query +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION add volatile leakproof SECURITY DEFINER PARALLEL unsafe; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.add(integer, integer) VOLATILE LEAKPROOF SECURITY DEFINER PARALLEL UNSAFE; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- Check that an invalid function name is still parsed correctly +-- Test that it fails when run without IF EXISTS clause +SELECT deparse_and_run_on_workers($cmd$ +DROP FUNCTION missing_function(int, text); +$cmd$); +INFO: Propagating deparsed query: DROP FUNCTION missing_function(pg_catalog.int4,text); +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,f,"ERROR: function missing_function(integer, text) does not exist") + (localhost,57638,f,"ERROR: function missing_function(integer, text) does not exist") +(2 rows) + +-- Check that an invalid function name is still parsed correctly +-- Test that it is successful when run with IF EXISTS clause +SELECT deparse_and_run_on_workers($cmd$ +DROP FUNCTION IF EXISTS missing_function(int, text); +$cmd$); +INFO: Propagating deparsed query: DROP FUNCTION IF EXISTS missing_function(pg_catalog.int4,text); +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"DROP FUNCTION") + (localhost,57638,t,"DROP FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +DROP FUNCTION IF EXISTS missing_schema.missing_function(int,float); +$cmd$); +INFO: Propagating deparsed query: DROP FUNCTION IF EXISTS missing_schema.missing_function(pg_catalog.int4,pg_catalog.float8); +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"DROP FUNCTION") + (localhost,57638,t,"DROP FUNCTION") +(2 rows) + +SELECT deparse_and_run_on_workers($cmd$ +DROP FUNCTION IF EXISTS missing_func_without_args; +$cmd$); +INFO: Propagating deparsed query: DROP FUNCTION IF EXISTS missing_func_without_args; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"DROP FUNCTION") + (localhost,57638,t,"DROP FUNCTION") +(2 rows) + +-- create schema with weird names +CREATE SCHEMA "CiTuS.TeeN"; +CREATE SCHEMA "CiTUS.TEEN2"; +SELECT run_command_on_workers($$ + CREATE SCHEMA IF NOT EXISTS "CiTuS.TeeN"; + CREATE SCHEMA IF NOT EXISTS "CiTUS.TEEN2"; +$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"CREATE SCHEMA") + (localhost,57638,t,"CREATE SCHEMA") +(2 rows) + +-- create table with weird names +CREATE FUNCTION "CiTuS.TeeN"."TeeNFunCT10N.1!?!"() RETURNS TEXT + AS $$ SELECT 'test function without params' $$ + LANGUAGE SQL; +CREATE FUNCTION "CiTuS.TeeN"."TeeNFunCT10N.1!?!"(text) RETURNS TEXT + AS $$ SELECT 'Overloaded function called with param: ' || $1 $$ + LANGUAGE SQL; +SELECT create_distributed_function('"CiTuS.TeeN"."TeeNFunCT10N.1!?!"()'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT create_distributed_function('"CiTuS.TeeN"."TeeNFunCT10N.1!?!"(text)'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION "CiTuS.TeeN"."TeeNFunCT10N.1!?!"() SET SCHEMA "CiTUS.TEEN2" +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION "CiTuS.TeeN"."TeeNFunCT10N.1!?!"() SET SCHEMA "CiTUS.TEEN2"; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- drop 2 functions at the same time +SELECT deparse_and_run_on_workers($cmd$ +DROP FUNCTION "CiTUS.TEEN2"."TeeNFunCT10N.1!?!"(),"CiTuS.TeeN"."TeeNFunCT10N.1!?!"(text); +$cmd$); +INFO: Propagating deparsed query: DROP FUNCTION "CiTUS.TEEN2"."TeeNFunCT10N.1!?!"(), "CiTuS.TeeN"."TeeNFunCT10N.1!?!"(pg_catalog.text); +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"DROP FUNCTION") + (localhost,57638,t,"DROP FUNCTION") +(2 rows) + +-- a function with a default parameter +CREATE FUNCTION func_default_param(param INT DEFAULT 0) RETURNS TEXT + AS $$ SELECT 'supplied param is : ' || param; $$ + LANGUAGE SQL; +SELECT create_distributed_function('func_default_param(INT)'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION func_default_param RENAME TO func_with_default_param; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.func_default_param(integer) RENAME TO func_with_default_param; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- a function with IN and OUT parameters +CREATE FUNCTION func_out_param(IN param INT, OUT result TEXT) + AS $$ SELECT 'supplied param is : ' || param; $$ + LANGUAGE SQL; +SELECT create_distributed_function('func_out_param(INT)'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION func_out_param RENAME TO func_in_and_out_param; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.func_out_param(integer) RENAME TO func_in_and_out_param; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- a function with INOUT parameter +CREATE FUNCTION square(INOUT a NUMERIC) +AS $$ +BEGIN + a := a * a; +END; $$ +LANGUAGE plpgsql; +SELECT create_distributed_function('square(NUMERIC)'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION square SET search_path TO DEFAULT; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.square(numeric) SET search_path TO DEFAULT; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- a function with variadic input. +CREATE FUNCTION sum_avg( + VARIADIC list NUMERIC[], + OUT total NUMERIC, + OUT average NUMERIC) +AS $$ +BEGIN + SELECT INTO total SUM(list[i]) + FROM generate_subscripts(list, 1) g(i); + + SELECT INTO average AVG(list[i]) + FROM generate_subscripts(list, 1) g(i); +END; $$ +LANGUAGE plpgsql; +SELECT create_distributed_function('sum_avg(NUMERIC[])'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION sum_avg COST 10000; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.sum_avg(numeric[]) COST 10000.000000; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- a function with a custom type IN parameter +CREATE TYPE intpair AS (x int, y int); +CREATE FUNCTION func_custom_param(IN param intpair, OUT total INT) + AS $$ SELECT param.x + param.y $$ + LANGUAGE SQL; +SELECT create_distributed_function('func_custom_param(intpair)'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION func_custom_param RENAME TO func_with_custom_param; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.func_custom_param(function_tests.intpair) RENAME TO func_with_custom_param; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- a function that returns TABLE +CREATE FUNCTION func_returns_table(IN count INT) + RETURNS TABLE (x INT, y INT) + AS $$ SELECT i,i FROM generate_series(1,count) i $$ + LANGUAGE SQL; +SELECT create_distributed_function('func_returns_table(INT)'); + create_distributed_function +--------------------------------------------------------------------- + +(1 row) + +SELECT deparse_and_run_on_workers($cmd$ +ALTER FUNCTION func_returns_table ROWS 100; +$cmd$); +INFO: Propagating deparsed query: ALTER FUNCTION function_tests.func_returns_table(integer) ROWS 100.000000; +CONTEXT: PL/pgSQL function deparse_and_run_on_workers(text) line XX at RAISE + deparse_and_run_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"ALTER FUNCTION") + (localhost,57638,t,"ALTER FUNCTION") +(2 rows) + +-- clear objects +SET client_min_messages TO WARNING; -- suppress cascading objects dropping +DROP SCHEMA "CiTuS.TeeN" CASCADE; +DROP SCHEMA "CiTUS.TEEN2" CASCADE; +DROP SCHEMA function_tests CASCADE; +SELECT run_command_on_workers($$ + DROP SCHEMA "CiTuS.TeeN" CASCADE; + DROP SCHEMA "CiTUS.TEEN2" CASCADE; + DROP SCHEMA function_tests CASCADE; +$$); + run_command_on_workers +--------------------------------------------------------------------- + (localhost,57637,t,"DROP SCHEMA") + (localhost,57638,t,"DROP SCHEMA") +(2 rows) + +DROP ROLE function_role;