2017-11-30 14:46:13 +01:00
|
|
|
CALL nonexistent(); -- error
|
|
|
|
CALL random(); -- error
|
|
|
|
|
|
|
|
CREATE FUNCTION 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);
|
|
|
|
$$;
|
|
|
|
|
|
|
|
SELECT ptest1('x'); -- error
|
|
|
|
CALL ptest1('a'); -- ok
|
Avoid premature free of pass-by-reference CALL arguments.
Prematurely freeing the EState used to evaluate CALL arguments led, in some
cases, to passing dangling pointers to the procedure. This was masked in
trivial cases because the argument pointers would point to Const nodes in
the original expression tree, and in some other cases because the result
value would end up in the standalone ExprContext rather than in memory
belonging to the EState --- but that wasn't exactly high quality
programming either, because the standalone ExprContext was never
explicitly freed, breaking assorted API contracts.
In addition, using a separate EState for each argument was just silly.
So let's use just one EState, and one ExprContext, and make the latter
belong to the former rather than be standalone, and clean up the EState
(and hence the ExprContext) post-call.
While at it, improve the function's commentary a bit.
Discussion: https://postgr.es/m/29173.1518282748@sss.pgh.pa.us
2018-02-10 19:37:12 +01:00
|
|
|
CALL ptest1('xy' || 'zzy'); -- ok, constant-folded arg
|
|
|
|
CALL ptest1(substring(random()::text, 1, 1)); -- ok, volatile arg
|
2017-11-30 14:46:13 +01:00
|
|
|
|
|
|
|
\df ptest1
|
2018-02-13 16:34:04 +01:00
|
|
|
SELECT pg_get_functiondef('ptest1'::regproc);
|
2017-11-30 14:46:13 +01:00
|
|
|
|
Avoid premature free of pass-by-reference CALL arguments.
Prematurely freeing the EState used to evaluate CALL arguments led, in some
cases, to passing dangling pointers to the procedure. This was masked in
trivial cases because the argument pointers would point to Const nodes in
the original expression tree, and in some other cases because the result
value would end up in the standalone ExprContext rather than in memory
belonging to the EState --- but that wasn't exactly high quality
programming either, because the standalone ExprContext was never
explicitly freed, breaking assorted API contracts.
In addition, using a separate EState for each argument was just silly.
So let's use just one EState, and one ExprContext, and make the latter
belong to the former rather than be standalone, and clean up the EState
(and hence the ExprContext) post-call.
While at it, improve the function's commentary a bit.
Discussion: https://postgr.es/m/29173.1518282748@sss.pgh.pa.us
2018-02-10 19:37:12 +01:00
|
|
|
SELECT * FROM cp_test ORDER BY b COLLATE "C";
|
2017-11-30 14:46:13 +01:00
|
|
|
|
|
|
|
|
|
|
|
CREATE PROCEDURE ptest2()
|
|
|
|
LANGUAGE SQL
|
|
|
|
AS $$
|
|
|
|
SELECT 5;
|
|
|
|
$$;
|
|
|
|
|
|
|
|
CALL ptest2();
|
|
|
|
|
|
|
|
|
|
|
|
-- various error cases
|
|
|
|
|
2017-12-13 16:37:48 +01:00
|
|
|
CALL version(); -- error: not a procedure
|
|
|
|
CALL sum(1); -- error: not a procedure
|
|
|
|
|
2017-11-30 14:46:13 +01:00
|
|
|
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(OUT a int) LANGUAGE SQL AS $$ INSERT INTO cp_test VALUES (1, 'a') $$;
|
|
|
|
|
|
|
|
ALTER PROCEDURE ptest1(text) STRICT;
|
|
|
|
ALTER FUNCTION ptest1(text) VOLATILE; -- error: not a function
|
|
|
|
ALTER PROCEDURE testfunc1(int) VOLATILE; -- error: not a procedure
|
|
|
|
ALTER PROCEDURE nonexistent() VOLATILE;
|
|
|
|
|
|
|
|
DROP FUNCTION ptest1(text); -- error: not a function
|
|
|
|
DROP PROCEDURE testfunc1(int); -- error: not a procedure
|
|
|
|
DROP PROCEDURE nonexistent();
|
|
|
|
|
|
|
|
|
|
|
|
-- privileges
|
|
|
|
|
|
|
|
CREATE USER regress_user1;
|
|
|
|
GRANT INSERT ON cp_test TO regress_user1;
|
|
|
|
REVOKE EXECUTE ON PROCEDURE ptest1(text) FROM PUBLIC;
|
|
|
|
SET ROLE regress_user1;
|
|
|
|
CALL ptest1('a'); -- error
|
|
|
|
RESET ROLE;
|
|
|
|
GRANT EXECUTE ON PROCEDURE ptest1(text) TO regress_user1;
|
|
|
|
SET ROLE regress_user1;
|
|
|
|
CALL ptest1('a'); -- ok
|
|
|
|
RESET ROLE;
|
|
|
|
|
|
|
|
|
|
|
|
-- ROUTINE syntax
|
|
|
|
|
|
|
|
ALTER ROUTINE testfunc1(int) RENAME TO testfunc1a;
|
|
|
|
ALTER ROUTINE testfunc1a RENAME TO testfunc1;
|
|
|
|
|
|
|
|
ALTER ROUTINE ptest1(text) RENAME TO ptest1a;
|
|
|
|
ALTER ROUTINE ptest1a RENAME TO ptest1;
|
|
|
|
|
|
|
|
DROP ROUTINE testfunc1(int);
|
|
|
|
|
|
|
|
|
|
|
|
-- cleanup
|
|
|
|
|
|
|
|
DROP PROCEDURE ptest1;
|
|
|
|
DROP PROCEDURE ptest2;
|
|
|
|
|
|
|
|
DROP TABLE cp_test;
|
|
|
|
|
|
|
|
DROP USER regress_user1;
|