-- plx rejection tests: each CREATE FUNCTION must fail at CREATE time with a -- precise error and source line number. CREATE EXTENSION IF NOT EXISTS plx; SET client_min_messages = warning; -- plxruby: nested def CREATE FUNCTION e_rb_def() RETURNS int LANGUAGE plxruby AS $$ def helper 1 end return helper $$; -- plxruby: unresolvable local type CREATE FUNCTION e_rb_type() RETURNS int LANGUAGE plxruby AS $$ x = some_call() return x $$; -- plxruby: next outside a loop CREATE FUNCTION e_rb_next() RETURNS int LANGUAGE plxruby AS $$ next return 1 $$; -- plxruby: assignment with an empty right-hand side CREATE FUNCTION e_rb_emptyrhs() RETURNS int LANGUAGE plxruby AS $$ x =#:: int return 1 $$; -- plxphp: nested function definition CREATE FUNCTION e_php_fn() RETURNS int LANGUAGE plxphp AS $$ function helper() { return 1; } return 1; $$; -- plxphp: switch fall-through (non-terminated case body) CREATE FUNCTION e_php_fall(n int) RETURNS text LANGUAGE plxphp AS $$ switch ($n) { case 1: $x = "a"; case 2: return "b"; } return "c"; $$; -- plxjs: switch fall-through CREATE FUNCTION e_js_fall(n int) RETURNS text LANGUAGE plxjs AS $$ switch (n) { case 1: let x = "a"; default: return "b"; } $$; -- plxruby: ||= has no faithful lowering CREATE FUNCTION e_rb_orassign() RETURNS int LANGUAGE plxruby AS $$ x = 0 x ||= 5 return x $$; -- plxruby: emit outside a set-returning function CREATE FUNCTION e_rb_emit() RETURNS int LANGUAGE plxruby AS $$ emit return 1 $$; -- plxruby: bare raise outside a handler CREATE FUNCTION e_rb_reraise() RETURNS int LANGUAGE plxruby AS $$ raise $$; -- plxpython3: def is not supported CREATE FUNCTION e_py_def() RETURNS int LANGUAGE plxpython3 AS $$ def helper(): return 1 return helper() $$; -- plxpython3: class is not supported CREATE FUNCTION e_py_class() RETURNS int LANGUAGE plxpython3 AS $$ class C: pass return 1 $$; -- plxpython3: match/case is not supported CREATE FUNCTION e_py_match(n int) RETURNS int LANGUAGE plxpython3 AS $$ match n: case 1: return 1 return 0 $$; -- plxpython3: conditional expression a if c else b CREATE FUNCTION e_py_ternary(x int) RETURNS int LANGUAGE plxpython3 AS $$ return 1 if x > 0 else 2 $$; -- plxjs: nested function definition CREATE FUNCTION e_js_fn() RETURNS int LANGUAGE plxjs AS $$ function helper() { return 1; } return 1; $$; -- plxruby: << on a numeric variable is not a string append; rejected CREATE FUNCTION e_rb_numshift() RETURNS int LANGUAGE plxruby AS $$ x = 0 x << 2 return x $$; -- plxcobol: PERFORM VARYING truncated at UNTIL (must error cleanly, not crash) CREATE FUNCTION e_cob_varying() RETURNS int LANGUAGE plxcobol AS $$ PROCEDURE DIVISION. PERFORM VARYING WS-I FROM 1 BY 1 UNTIL $$; -- plxcobol: OCCURS without an element type (PIC/TYPE) is rejected CREATE FUNCTION e_cob_occurs() RETURNS int LANGUAGE plxcobol AS $$ WORKING-STORAGE SECTION. 01 WS-T OCCURS 5 TIMES. PROCEDURE DIVISION. GOBACK RETURNING 1. $$; -- plxcobol: data item with no PIC/TYPE/CONSTANT CREATE FUNCTION e_cob_notype() RETURNS int LANGUAGE plxcobol AS $$ WORKING-STORAGE SECTION. 01 WS-X. PROCEDURE DIVISION. GOBACK RETURNING 1. $$; -- plxcobol: out-of-line PERFORM of a paragraph is not supported CREATE FUNCTION e_cob_para() RETURNS int LANGUAGE plxcobol AS $$ PROCEDURE DIVISION. PERFORM SOME-PARAGRAPH GOBACK RETURNING 1. $$; -- plxcobol: EXIT without PERFORM CREATE FUNCTION e_cob_exit() RETURNS int LANGUAGE plxcobol AS $$ PROCEDURE DIVISION. EXIT GOBACK RETURNING 1. $$; -- plxcobol: missing END-IF scope terminator CREATE FUNCTION e_cob_endif() RETURNS int LANGUAGE plxcobol AS $$ PROCEDURE DIVISION. IF 1 = 1 MOVE 2 TO WS-X GOBACK RETURNING 1. $$; -- plxcobol: unterminated string literal CREATE FUNCTION e_cob_str() RETURNS void LANGUAGE plxcobol AS $$ PROCEDURE DIVISION. DISPLAY "unterminated $$; -- plxtsql: the @@ROWCOUNT global variable is not supported CREATE FUNCTION e_tq_rowcount() RETURNS int LANGUAGE plxtsql AS $$ DECLARE @n int; SET @n = @@ROWCOUNT; RETURN @n; $$; -- plxtsql: DECLARE of a TABLE variable is not supported CREATE FUNCTION e_tq_tablevar() RETURNS int LANGUAGE plxtsql AS $$ DECLARE @t TABLE (id int); RETURN 1; $$; -- plxtsql: transaction control is not allowed in a function CREATE FUNCTION e_tq_commit() RETURNS int LANGUAGE plxtsql AS $$ DECLARE @x int = 1; COMMIT; RETURN @x; $$; -- plxtsql: EXEC of a stored procedure (not dynamic SQL) is not supported CREATE FUNCTION e_tq_execproc() RETURNS int LANGUAGE plxtsql AS $$ EXEC some_procedure; RETURN 1; $$; -- plxgo: a := with a right-hand side whose type cannot be inferred CREATE FUNCTION e_go_infer(n int) RETURNS int LANGUAGE plxgo AS $$ x := somefunc(n) return x $$; -- plxgo: goto is not supported CREATE FUNCTION e_go_goto() RETURNS int LANGUAGE plxgo AS $$ goto done return 1 $$; -- plxgo: switch fallthrough is not supported CREATE FUNCTION e_go_fallthrough(n int) RETURNS int LANGUAGE plxgo AS $$ switch n { case 1: fallthrough case 2: return 2 } return 0 $$; -- plxgo: map/chan/struct types are not supported CREATE FUNCTION e_go_maptype() RETURNS int LANGUAGE plxgo AS $$ var m map[string]int return 1 $$; -- plxgo: a stray closing bracket at statement position (must error, not hang) CREATE FUNCTION e_go_stray() RETURNS int LANGUAGE plxgo AS $$ x)) return 1 $$; -- plxtsql: a dangling ELSE (must error, not hang) CREATE FUNCTION e_tq_else() RETURNS int LANGUAGE plxtsql AS $$ IF 1 = 1 PRINT 'a' ELSE PRINT 'b' ELSE PRINT 'c'; RETURN 1; $$; -- shared: too many intrinsic arguments (must error, not read past the arg array) CREATE FUNCTION e_js_manyargs() RETURNS int LANGUAGE plxjs AS $$ execute(`insert`, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17); return 1; $$; -- plxcobol: USAGE with no value (truncated; must error, not read past EOF) CREATE FUNCTION e_cob_usage() RETURNS int LANGUAGE plxcobol AS $$ WORKING-STORAGE SECTION. 01 WS-X USAGE $$; -- plxjs: a switch with only a default (plpgsql CASE needs at least one WHEN) CREATE FUNCTION e_js_defonly(n int) RETURNS int LANGUAGE plxjs AS $$ switch (n) { default: return 1; } $$; -- plxjs: a case after default (plpgsql requires ELSE last) CREATE FUNCTION e_js_deffirst(n int) RETURNS int LANGUAGE plxjs AS $$ switch (n) { default: return 0; case 1: return 1; } $$; -- plxphp: the ?: elvis operator (empty THEN branch) is not supported CREATE FUNCTION e_php_elvis(n int) RETURNS int LANGUAGE plxphp AS $$ return $n ?: 5; $$; -- plxgo: a const with no value CREATE FUNCTION e_go_constval() RETURNS int LANGUAGE plxgo AS $$ const x int return 1 $$; -- Deep-nesting DoS guards. These generate pathological source and must fail with -- a clean error (never crash the backend). The bodies are built dynamically to -- avoid hundreds of literal lines; each error is caught and re-raised as its bare -- message so the .out does not echo the whole generated source. -- plxpython3: indentation nested past the lexer's fixed indent-stack limit DO $outer$ DECLARE body text; BEGIN SELECT 'def f():' || E'\n' || string_agg(repeat(' ', g) || 'if True:', E'\n' ORDER BY g) || E'\n' || repeat(' ', 200) || 'return 1' INTO body FROM generate_series(1, 199) g; EXECUTE format('CREATE FUNCTION e_py_deepindent() RETURNS int LANGUAGE plxpython3 AS %L', body); RAISE WARNING 'unexpected: creation succeeded'; EXCEPTION WHEN OTHERS THEN RAISE WARNING '%', SQLERRM; END $outer$; -- plxjs: statements/expressions nested past the parser recursion guard DO $outer$ DECLARE body text; n int := 600; BEGIN body := repeat('if (true) {' || E'\n', n) || 'return 1;' || E'\n' || repeat('}' || E'\n', n); EXECUTE format('CREATE FUNCTION e_js_deeprec() RETURNS int LANGUAGE plxjs AS %L', body); RAISE WARNING 'unexpected: creation succeeded'; EXCEPTION WHEN OTHERS THEN RAISE WARNING '%', SQLERRM; END $outer$; -- non-decimal integer literal that overflows 64 bits: clean error, not invalid -- generated SQL (raw 0x.. is unparseable by plpgsql on PG13-15) CREATE FUNCTION e_js_hex_overflow() RETURNS numeric LANGUAGE plxjs AS $$ return 0xFFFFFFFFFFFFFFFFFF; $$;