263 lines
5.3 KiB
PL/PgSQL
263 lines
5.3 KiB
PL/PgSQL
CALL nonexistent(); -- error
|
|
CALL random(); -- error
|
|
|
|
CREATE FUNCTION cp_testfunc1(a int) RETURNS int LANGUAGE SQL AS $$ SELECT a $$;
|
|
|
|
CREATE TABLE cp_test (a int, b text);
|
|
|
|
CREATE PROCEDURE ptest1(x text)
|
|
LANGUAGE SQL
|
|
AS $$
|
|
INSERT INTO cp_test VALUES (1, x);
|
|
$$;
|
|
|
|
\df ptest1
|
|
SELECT pg_get_functiondef('ptest1'::regproc);
|
|
|
|
-- show only normal functions
|
|
\dfn public.*test*1
|
|
|
|
-- show only procedures
|
|
\dfp public.*test*1
|
|
|
|
SELECT ptest1('x'); -- error
|
|
CALL ptest1('a'); -- ok
|
|
CALL ptest1('xy' || 'zzy'); -- ok, constant-folded arg
|
|
CALL ptest1(substring(random()::numeric(20,15)::text, 1, 1)); -- ok, volatile arg
|
|
|
|
SELECT * FROM cp_test ORDER BY b COLLATE "C";
|
|
|
|
|
|
-- SQL-standard body
|
|
CREATE PROCEDURE ptest1s(x text)
|
|
LANGUAGE SQL
|
|
BEGIN ATOMIC
|
|
INSERT INTO cp_test VALUES (1, x);
|
|
END;
|
|
|
|
\df ptest1s
|
|
SELECT pg_get_functiondef('ptest1s'::regproc);
|
|
|
|
CALL ptest1s('b');
|
|
|
|
SELECT * FROM cp_test ORDER BY b COLLATE "C";
|
|
|
|
-- utility functions currently not supported here
|
|
CREATE PROCEDURE ptestx()
|
|
LANGUAGE SQL
|
|
BEGIN ATOMIC
|
|
CREATE TABLE x (a int);
|
|
END;
|
|
|
|
|
|
CREATE PROCEDURE ptest2()
|
|
LANGUAGE SQL
|
|
AS $$
|
|
SELECT 5;
|
|
$$;
|
|
|
|
CALL ptest2();
|
|
|
|
|
|
-- nested CALL
|
|
TRUNCATE cp_test;
|
|
|
|
CREATE PROCEDURE ptest3(y text)
|
|
LANGUAGE SQL
|
|
AS $$
|
|
CALL ptest1(y);
|
|
CALL ptest1($1);
|
|
$$;
|
|
|
|
CALL ptest3('b');
|
|
|
|
SELECT * FROM cp_test;
|
|
|
|
|
|
-- output arguments
|
|
|
|
CREATE PROCEDURE ptest4a(INOUT a int, INOUT b int)
|
|
LANGUAGE SQL
|
|
AS $$
|
|
SELECT 1, 2;
|
|
$$;
|
|
|
|
CALL ptest4a(NULL, NULL);
|
|
|
|
CREATE PROCEDURE ptest4b(INOUT b int, INOUT a int)
|
|
LANGUAGE SQL
|
|
AS $$
|
|
CALL ptest4a(a, b); -- error, not supported
|
|
$$;
|
|
|
|
-- we used to get confused by a single output argument that is composite
|
|
CREATE PROCEDURE ptest4c(INOUT comp int8_tbl)
|
|
LANGUAGE SQL
|
|
AS $$
|
|
SELECT ROW(1, 2);
|
|
$$;
|
|
|
|
CALL ptest4c(NULL);
|
|
|
|
DROP PROCEDURE ptest4a, ptest4c;
|
|
|
|
|
|
-- named and default parameters
|
|
|
|
CREATE OR REPLACE PROCEDURE ptest5(a int, b text, c int default 100)
|
|
LANGUAGE SQL
|
|
AS $$
|
|
INSERT INTO cp_test VALUES(a, b);
|
|
INSERT INTO cp_test VALUES(c, b);
|
|
$$;
|
|
|
|
TRUNCATE cp_test;
|
|
|
|
CALL ptest5(10, 'Hello', 20);
|
|
CALL ptest5(10, 'Hello');
|
|
CALL ptest5(10, b => 'Hello');
|
|
CALL ptest5(b => 'Hello', a => 10);
|
|
|
|
SELECT * FROM cp_test;
|
|
|
|
|
|
-- polymorphic types
|
|
|
|
CREATE PROCEDURE ptest6(a int, b anyelement)
|
|
LANGUAGE SQL
|
|
AS $$
|
|
SELECT NULL::int;
|
|
$$;
|
|
|
|
CALL ptest6(1, 2);
|
|
|
|
|
|
-- collation assignment
|
|
|
|
CREATE PROCEDURE ptest7(a text, b text)
|
|
LANGUAGE SQL
|
|
AS $$
|
|
SELECT a = b;
|
|
$$;
|
|
|
|
CALL ptest7(least('a', 'b'), 'a');
|
|
|
|
|
|
-- empty body
|
|
CREATE PROCEDURE ptest8(x text)
|
|
BEGIN ATOMIC
|
|
END;
|
|
|
|
\df ptest8
|
|
SELECT pg_get_functiondef('ptest8'::regproc);
|
|
CALL ptest8('');
|
|
|
|
|
|
-- OUT parameters
|
|
|
|
CREATE PROCEDURE ptest9(OUT a int)
|
|
LANGUAGE SQL
|
|
AS $$
|
|
INSERT INTO cp_test VALUES (1, 'a');
|
|
SELECT 1;
|
|
$$;
|
|
|
|
-- standard way to do a call:
|
|
CALL ptest9(NULL);
|
|
-- you can write an expression, but it's not evaluated
|
|
CALL ptest9(1/0); -- no error
|
|
-- ... and it had better match the type of the parameter
|
|
CALL ptest9(1./0.); -- error
|
|
|
|
-- check named-parameter matching
|
|
CREATE PROCEDURE ptest10(OUT a int, IN b int, IN c int)
|
|
LANGUAGE SQL AS $$ SELECT b - c $$;
|
|
|
|
CALL ptest10(null, 7, 4);
|
|
CALL ptest10(a => null, b => 8, c => 2);
|
|
CALL ptest10(null, 7, c => 2);
|
|
CALL ptest10(null, c => 4, b => 11);
|
|
CALL ptest10(b => 8, c => 2, a => 0);
|
|
|
|
CREATE PROCEDURE ptest11(a OUT int, VARIADIC b int[]) LANGUAGE SQL
|
|
AS $$ SELECT b[1] + b[2] $$;
|
|
|
|
CALL ptest11(null, 11, 12, 13);
|
|
|
|
-- check resolution of ambiguous DROP commands
|
|
|
|
CREATE PROCEDURE ptest10(IN a int, IN b int, IN c int)
|
|
LANGUAGE SQL AS $$ SELECT a + b - c $$;
|
|
|
|
\df ptest10
|
|
|
|
drop procedure ptest10; -- fail
|
|
drop procedure ptest10(int, int, int); -- fail
|
|
begin;
|
|
drop procedure ptest10(out int, int, int);
|
|
\df ptest10
|
|
drop procedure ptest10(int, int, int); -- now this would work
|
|
rollback;
|
|
begin;
|
|
drop procedure ptest10(in int, int, int);
|
|
\df ptest10
|
|
drop procedure ptest10(int, int, int); -- now this would work
|
|
rollback;
|
|
|
|
-- various error cases
|
|
|
|
CALL version(); -- error: not a procedure
|
|
CALL sum(1); -- error: not a procedure
|
|
|
|
CREATE PROCEDURE ptestx() LANGUAGE SQL WINDOW AS $$ INSERT INTO cp_test VALUES (1, 'a') $$;
|
|
CREATE PROCEDURE ptestx() LANGUAGE SQL STRICT AS $$ INSERT INTO cp_test VALUES (1, 'a') $$;
|
|
CREATE PROCEDURE ptestx(a VARIADIC int[], b OUT int) LANGUAGE SQL
|
|
AS $$ SELECT a[1] $$;
|
|
CREATE PROCEDURE ptestx(a int DEFAULT 42, b OUT int) LANGUAGE SQL
|
|
AS $$ SELECT a $$;
|
|
|
|
ALTER PROCEDURE ptest1(text) STRICT;
|
|
ALTER FUNCTION ptest1(text) VOLATILE; -- error: not a function
|
|
ALTER PROCEDURE cp_testfunc1(int) VOLATILE; -- error: not a procedure
|
|
ALTER PROCEDURE nonexistent() VOLATILE;
|
|
|
|
DROP FUNCTION ptest1(text); -- error: not a function
|
|
DROP PROCEDURE cp_testfunc1(int); -- error: not a procedure
|
|
DROP PROCEDURE nonexistent();
|
|
|
|
|
|
-- privileges
|
|
|
|
CREATE USER regress_cp_user1;
|
|
GRANT INSERT ON cp_test TO regress_cp_user1;
|
|
REVOKE EXECUTE ON PROCEDURE ptest1(text) FROM PUBLIC;
|
|
SET ROLE regress_cp_user1;
|
|
CALL ptest1('a'); -- error
|
|
RESET ROLE;
|
|
GRANT EXECUTE ON PROCEDURE ptest1(text) TO regress_cp_user1;
|
|
SET ROLE regress_cp_user1;
|
|
CALL ptest1('a'); -- ok
|
|
RESET ROLE;
|
|
|
|
|
|
-- ROUTINE syntax
|
|
|
|
ALTER ROUTINE cp_testfunc1(int) RENAME TO cp_testfunc1a;
|
|
ALTER ROUTINE cp_testfunc1a RENAME TO cp_testfunc1;
|
|
|
|
ALTER ROUTINE ptest1(text) RENAME TO ptest1a;
|
|
ALTER ROUTINE ptest1a RENAME TO ptest1;
|
|
|
|
DROP ROUTINE cp_testfunc1(int);
|
|
|
|
|
|
-- cleanup
|
|
|
|
DROP PROCEDURE ptest1;
|
|
DROP PROCEDURE ptest1s;
|
|
DROP PROCEDURE ptest2;
|
|
|
|
DROP TABLE cp_test;
|
|
|
|
DROP USER regress_cp_user1;
|