1-- 2-- Tests for procedures / CALL syntax 3-- 4CREATE PROCEDURE test_proc1() 5LANGUAGE plpgsql 6AS $$ 7BEGIN 8 NULL; 9END; 10$$; 11CALL test_proc1(); 12-- error: can't return non-NULL 13CREATE PROCEDURE test_proc2() 14LANGUAGE plpgsql 15AS $$ 16BEGIN 17 RETURN 5; 18END; 19$$; 20ERROR: RETURN cannot have a parameter in a procedure 21LINE 5: RETURN 5; 22 ^ 23CREATE TABLE test1 (a int); 24CREATE PROCEDURE test_proc3(x int) 25LANGUAGE plpgsql 26AS $$ 27BEGIN 28 INSERT INTO test1 VALUES (x); 29END; 30$$; 31CALL test_proc3(55); 32SELECT * FROM test1; 33 a 34---- 35 55 36(1 row) 37 38-- nested CALL 39TRUNCATE TABLE test1; 40CREATE PROCEDURE test_proc4(y int) 41LANGUAGE plpgsql 42AS $$ 43BEGIN 44 CALL test_proc3(y); 45 CALL test_proc3($1); 46END; 47$$; 48CALL test_proc4(66); 49SELECT * FROM test1; 50 a 51---- 52 66 53 66 54(2 rows) 55 56CALL test_proc4(66); 57SELECT * FROM test1; 58 a 59---- 60 66 61 66 62 66 63 66 64(4 rows) 65 66-- output arguments 67CREATE PROCEDURE test_proc5(INOUT a text) 68LANGUAGE plpgsql 69AS $$ 70BEGIN 71 a := a || '+' || a; 72END; 73$$; 74CALL test_proc5('abc'); 75 a 76--------- 77 abc+abc 78(1 row) 79 80CREATE PROCEDURE test_proc6(a int, INOUT b int, INOUT c int) 81LANGUAGE plpgsql 82AS $$ 83BEGIN 84 b := b * a; 85 c := c * a; 86END; 87$$; 88CALL test_proc6(2, 3, 4); 89 b | c 90---+--- 91 6 | 8 92(1 row) 93 94DO 95LANGUAGE plpgsql 96$$ 97DECLARE 98 x int := 3; 99 y int := 4; 100BEGIN 101 CALL test_proc6(2, x, y); 102 RAISE INFO 'x = %, y = %', x, y; 103END; 104$$; 105INFO: x = 6, y = 8 106DO 107LANGUAGE plpgsql 108$$ 109DECLARE 110 x int := 3; 111 y int := 4; 112BEGIN 113 CALL test_proc6(2, x + 1, y); -- error 114 RAISE INFO 'x = %, y = %', x, y; 115END; 116$$; 117ERROR: procedure parameter "b" is an output parameter but corresponding argument is not writable 118CONTEXT: PL/pgSQL function inline_code_block line 6 at CALL 119DO 120LANGUAGE plpgsql 121$$ 122DECLARE 123 x int := 3; 124 y int := 4; 125BEGIN 126 FOR i IN 1..5 LOOP 127 CALL test_proc6(i, x, y); 128 RAISE INFO 'x = %, y = %', x, y; 129 END LOOP; 130END; 131$$; 132INFO: x = 3, y = 4 133INFO: x = 6, y = 8 134INFO: x = 18, y = 24 135INFO: x = 72, y = 96 136INFO: x = 360, y = 480 137-- recursive with output arguments 138CREATE PROCEDURE test_proc7(x int, INOUT a int, INOUT b numeric) 139LANGUAGE plpgsql 140AS $$ 141BEGIN 142IF x > 1 THEN 143 a := x / 10; 144 b := x / 2; 145 CALL test_proc7(b::int, a, b); 146END IF; 147END; 148$$; 149CALL test_proc7(100, -1, -1); 150 a | b 151---+--- 152 0 | 1 153(1 row) 154 155-- inner COMMIT with output arguments 156CREATE PROCEDURE test_proc7c(x int, INOUT a int, INOUT b numeric) 157LANGUAGE plpgsql 158AS $$ 159BEGIN 160 a := x / 10; 161 b := x / 2; 162 COMMIT; 163END; 164$$; 165CREATE PROCEDURE test_proc7cc(_x int) 166LANGUAGE plpgsql 167AS $$ 168DECLARE _a int; _b numeric; 169BEGIN 170 CALL test_proc7c(_x, _a, _b); 171 RAISE NOTICE '_x: %,_a: %, _b: %', _x, _a, _b; 172END 173$$; 174CALL test_proc7cc(10); 175NOTICE: _x: 10,_a: 1, _b: 5 176-- named parameters and defaults 177CREATE PROCEDURE test_proc8a(INOUT a int, INOUT b int) 178LANGUAGE plpgsql 179AS $$ 180BEGIN 181 RAISE NOTICE 'a: %, b: %', a, b; 182 a := a * 10; 183 b := b + 10; 184END; 185$$; 186CALL test_proc8a(10, 20); 187NOTICE: a: 10, b: 20 188 a | b 189-----+---- 190 100 | 30 191(1 row) 192 193CALL test_proc8a(b => 20, a => 10); 194NOTICE: a: 10, b: 20 195 a | b 196-----+---- 197 100 | 30 198(1 row) 199 200DO $$ 201DECLARE _a int; _b int; 202BEGIN 203 _a := 10; _b := 30; 204 CALL test_proc8a(_a, _b); 205 RAISE NOTICE '_a: %, _b: %', _a, _b; 206 CALL test_proc8a(b => _b, a => _a); 207 RAISE NOTICE '_a: %, _b: %', _a, _b; 208END 209$$; 210NOTICE: a: 10, b: 30 211NOTICE: _a: 100, _b: 40 212NOTICE: a: 100, b: 40 213NOTICE: _a: 1000, _b: 50 214CREATE PROCEDURE test_proc8b(INOUT a int, INOUT b int, INOUT c int) 215LANGUAGE plpgsql 216AS $$ 217BEGIN 218 RAISE NOTICE 'a: %, b: %, c: %', a, b, c; 219 a := a * 10; 220 b := b + 10; 221 c := c * -10; 222END; 223$$; 224DO $$ 225DECLARE _a int; _b int; _c int; 226BEGIN 227 _a := 10; _b := 30; _c := 50; 228 CALL test_proc8b(_a, _b, _c); 229 RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c; 230 CALL test_proc8b(_a, c => _c, b => _b); 231 RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c; 232END 233$$; 234NOTICE: a: 10, b: 30, c: 50 235NOTICE: _a: 100, _b: 40, _c: -500 236NOTICE: a: 100, b: 40, c: -500 237NOTICE: _a: 1000, _b: 50, _c: 5000 238CREATE PROCEDURE test_proc8c(INOUT a int, INOUT b int, INOUT c int DEFAULT 11) 239LANGUAGE plpgsql 240AS $$ 241BEGIN 242 RAISE NOTICE 'a: %, b: %, c: %', a, b, c; 243 a := a * 10; 244 b := b + 10; 245 c := c * -10; 246END; 247$$; 248DO $$ 249DECLARE _a int; _b int; _c int; 250BEGIN 251 _a := 10; _b := 30; _c := 50; 252 CALL test_proc8c(_a, _b, _c); 253 RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c; 254 _a := 10; _b := 30; _c := 50; 255 CALL test_proc8c(_a, c => _c, b => _b); 256 RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c; 257 _a := 10; _b := 30; _c := 50; 258 CALL test_proc8c(c => _c, b => _b, a => _a); 259 RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c; 260END 261$$; 262NOTICE: a: 10, b: 30, c: 50 263NOTICE: _a: 100, _b: 40, _c: -500 264NOTICE: a: 10, b: 30, c: 50 265NOTICE: _a: 100, _b: 40, _c: -500 266NOTICE: a: 10, b: 30, c: 50 267NOTICE: _a: 100, _b: 40, _c: -500 268DO $$ 269DECLARE _a int; _b int; _c int; 270BEGIN 271 _a := 10; _b := 30; _c := 50; 272 CALL test_proc8c(_a, _b); -- fail, no output argument for c 273 RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c; 274END 275$$; 276ERROR: procedure parameter "c" is an output parameter but corresponding argument is not writable 277CONTEXT: PL/pgSQL function inline_code_block line 5 at CALL 278DO $$ 279DECLARE _a int; _b int; _c int; 280BEGIN 281 _a := 10; _b := 30; _c := 50; 282 CALL test_proc8c(_a, b => _b); -- fail, no output argument for c 283 RAISE NOTICE '_a: %, _b: %, _c: %', _a, _b, _c; 284END 285$$; 286ERROR: procedure parameter "c" is an output parameter but corresponding argument is not writable 287CONTEXT: PL/pgSQL function inline_code_block line 5 at CALL 288-- transition variable assignment 289TRUNCATE test1; 290CREATE FUNCTION triggerfunc1() RETURNS trigger 291LANGUAGE plpgsql 292AS $$ 293DECLARE 294 z int := 0; 295BEGIN 296 CALL test_proc6(2, NEW.a, NEW.a); 297 RETURN NEW; 298END; 299$$; 300CREATE TRIGGER t1 BEFORE INSERT ON test1 EXECUTE PROCEDURE triggerfunc1(); 301INSERT INTO test1 VALUES (1), (2), (3); 302UPDATE test1 SET a = 22 WHERE a = 2; 303SELECT * FROM test1 ORDER BY a; 304 a 305---- 306 1 307 3 308 22 309(3 rows) 310 311DROP PROCEDURE test_proc1; 312DROP PROCEDURE test_proc3; 313DROP PROCEDURE test_proc4; 314DROP TABLE test1; 315-- more checks for named-parameter handling 316CREATE PROCEDURE p1(v_cnt int, v_Text inout text = NULL) 317AS $$ 318BEGIN 319 v_Text := 'v_cnt = ' || v_cnt; 320END 321$$ LANGUAGE plpgsql; 322DO $$ 323DECLARE 324 v_Text text; 325 v_cnt integer := 42; 326BEGIN 327 CALL p1(v_cnt := v_cnt); -- error, must supply something for v_Text 328 RAISE NOTICE '%', v_Text; 329END; 330$$; 331ERROR: procedure parameter "v_text" is an output parameter but corresponding argument is not writable 332CONTEXT: PL/pgSQL function inline_code_block line 6 at CALL 333DO $$ 334DECLARE 335 v_Text text; 336 v_cnt integer := 42; 337BEGIN 338 CALL p1(v_cnt := v_cnt, v_Text := v_Text); 339 RAISE NOTICE '%', v_Text; 340END; 341$$; 342NOTICE: v_cnt = 42 343DO $$ 344DECLARE 345 v_Text text; 346BEGIN 347 CALL p1(10, v_Text := v_Text); 348 RAISE NOTICE '%', v_Text; 349END; 350$$; 351NOTICE: v_cnt = 10 352DO $$ 353DECLARE 354 v_Text text; 355 v_cnt integer; 356BEGIN 357 CALL p1(v_Text := v_Text, v_cnt := v_cnt); 358 RAISE NOTICE '%', v_Text; 359END; 360$$; 361NOTICE: <NULL> 362