-- 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;
$$;
