subtest types

statement ok
CREATE PROCEDURE p(IN param1 INT, OUT param2 INT) AS $$ BEGIN SELECT param1 INTO param2; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42883 procedure p\(\) does not exist
CALL p();

statement error pgcode 42883 procedure p\(int\) does not exist
CALL p(1);

statement error pgcode 42883 procedure p\(int, string\) does not exist
CALL p(1, NULL::TEXT);

statement error pgcode 42883 procedure p\(int, int, int\) does not exist
CALL p(1, 2, 3);

statement ok
CREATE PROCEDURE p(IN param1 FLOAT, OUT param2 FLOAT) AS $$ BEGIN SELECT param1 INTO param2; END; $$ LANGUAGE PLpgSQL;

query I colnames
CALL p(1, 2);
----
param2
1

query R colnames
CALL p(1.1, 2.2);
----
param2
1.1

statement error pgcode 42723 function "p" already exists with same argument types
CREATE PROCEDURE p(OUT param1 INT, IN param2 INT) AS $$ BEGIN SELECT param2 INTO param1; END; $$ LANGUAGE PLpgSQL;

statement ok
CREATE OR REPLACE PROCEDURE p(OUT param2 INT, IN param1 INT) AS $$ BEGIN SELECT param1 INTO param2; END; $$ LANGUAGE PLpgSQL;

query I colnames
CALL p(1, 2);
----
param2
2

statement error pgcode 42723 function "p" already exists with same argument types
CREATE PROCEDURE p(OUT param1 INT, IN param2 INT, OUT param3 INT) AS $$
BEGIN
  SELECT 1 INTO param1;
  SELECT param2 INTO param3;
END; $$ LANGUAGE PLpgSQL;

statement ok
CREATE PROCEDURE p(OUT param1 INT, IN param2 INT, IN param3 INT) AS $$ BEGIN SELECT param2 + param3 INTO param1; END; $$ LANGUAGE PLpgSQL;

query I colnames
CALL p(1, 2, 3);
----
param1
5

statement error pgcode 42723 function "p" already exists with same argument types
CREATE PROCEDURE p(INOUT param1 INT, IN param2 INT) AS $$ BEGIN SELECT param1 + param2 INTO param1; END; $$ LANGUAGE PLpgSQL;

statement ok
CREATE PROCEDURE p(OUT param1 INT, OUT param2 INT, OUT param3 INT) AS $$
BEGIN
  SELECT 1 INTO param1;
  SELECT 2 INTO param2;
  SELECT 3 INTO param3;
END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42725 procedure p\(int, int, int\) is not unique
CALL p(1, 2, 3);

statement error pgcode 42725 procedure name "p" is not unique
DROP PROCEDURE p;

# For DROP PROCEDURE (and DROP ROUTINE if/when we implement it), if all
# parameters have unspecified ("default") parameter class, then Postgres applies
# two resolution approaches: Postgres-specific (the main) way of matching based
# on input parameters and SQL-compliant way of matching based on all parameters.
# See https://github.com/postgres/postgres/commit/e56bce5d43789cce95d099554ae9593ada92b3b7
# for more context.

statement error pgcode 42725 procedure name "p" is not unique
DROP PROCEDURE p(INT, INT, INT);

statement error pgcode 42725 procedure name "p" is not unique
DROP PROCEDURE p(INT, INT);

statement ok
DROP PROCEDURE p(OUT INT, INT, INT)

query III colnames
CALL p(-1, -2, -3);
----
param1  param2  param3
1       2       3

statement ok
CREATE PROCEDURE p(OUT param1 INT, IN param2 INT, IN param3 INT) AS $$ BEGIN SELECT param2 + param3 INTO param1; END; $$ LANGUAGE PLpgSQL;

statement ok
DROP PROCEDURE p(OUT INT, INT, INT);

statement error pgcode 42725 procedure name "p" is not unique
DROP PROCEDURE p;

# Postgres here drops the overload with 3 OUT parameters.
statement ok
DROP PROCEDURE p(INT, INT, INT);

statement error pgcode 42883 procedure p\(\) does not exist
DROP PROCEDURE p(OUT INT, OUT INT, OUT INT);

statement ok
DROP PROCEDURE p(OUT INT, IN INT);

statement error pgcode 42883 procedure p\(\) does not exist
DROP PROCEDURE p();

statement ok
DROP PROCEDURE p;

statement ok
CREATE PROCEDURE p(OUT param INT) AS $$ BEGIN SELECT 1 INTO param; END $$ LANGUAGE PLpgSQL;

statement error pgcode 42883 procedure p\(\) does not exist
CALL p();

query I colnames
CALL p(NULL);
----
param
1

# Argument expressions for OUT parameters shouldn't be evaluated.
query I colnames
CALL p(1 // 0);
----
param
1

statement ok
DROP PROCEDURE p;

statement ok
CREATE PROCEDURE p(IN INT, INOUT a INT) AS $$ BEGIN END $$ LANGUAGE PLpgSQL;

# Argument expressions for IN and INOUT parameters are evaluated.
statement error pgcode 22012 division by zero
CALL p(1 // 0, 1)

statement error pgcode 22012 division by zero
CALL p(1, 1 // 0)

statement ok
DROP PROCEDURE p;

statement ok
CREATE PROCEDURE p(IN param1 INT, INOUT param2 INT, OUT param3 INT) AS $$
BEGIN
  SELECT 1 INTO param1;
  SELECT 2 INTO param2;
  SELECT 3 INTO param3;
END $$ LANGUAGE PLpgSQL;

query II colnames
CALL p(-1, -2, NULL);
----
param2  param3
2       3

statement ok
DROP PROCEDURE p;

statement ok
CREATE PROCEDURE p(INOUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 1, 2, 3; END $$ LANGUAGE PLpgSQL;

statement ok
DROP PROCEDURE p;

statement ok
CREATE PROCEDURE p(INOUT param INT) AS $$ BEGIN SELECT 'hello'; END $$ LANGUAGE PLpgSQL;

statement ok
DROP PROCEDURE p;

statement ok
CREATE PROCEDURE p(OUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 1 INTO param1; END $$ LANGUAGE PLpgSQL;

statement ok
DROP PROCEDURE p(OUT INT);

statement ok
CREATE PROCEDURE p(OUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 1 INTO param2; END $$ LANGUAGE PLpgSQL;

statement error pgcode 42883 pq: procedure p\(int\) does not exist
DROP PROCEDURE p(INT);

statement ok
DROP PROCEDURE p;

statement ok
CREATE PROCEDURE p(OUT param INT) AS $$ BEGIN SELECT 1 INTO param; END $$ LANGUAGE PLpgSQL;

statement ok
DROP PROCEDURE p(OUT INT, OUT text, OUT INT);

statement error pgcode 42804 RETURN cannot have a parameter in function with OUT parameters
CREATE PROCEDURE p(OUT INT) AS $$ BEGIN RETURN NULL; END $$ LANGUAGE PLpgSQL;

statement error pgcode 42804 RETURN cannot have a parameter in function with OUT parameters
CREATE PROCEDURE p(OUT INT, OUT INT) AS $$ BEGIN RETURN NULL; END $$ LANGUAGE PLpgSQL;

statement error pgcode 42804 RETURN cannot have a parameter in function with OUT parameters
CREATE PROCEDURE p(INOUT a INT) AS $$ BEGIN RETURN NULL; END $$ LANGUAGE PLpgSQL;

statement ok
CREATE PROCEDURE p(INOUT param1 INT, OUT param2 INT) AS $$
BEGIN
  param2 := 2;
  RAISE NOTICE '%', param2;
END
$$ LANGUAGE PLpgSQL;

query II colnames
CALL p(3, NULL);
----
param1  param2
3       2

query II noticetrace
CALL p(3, NULL);
----
NOTICE: 2

statement ok
DROP PROCEDURE p;

statement ok
CREATE PROCEDURE p(INOUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 3 INTO param1; END $$ LANGUAGE PLpgSQL;

query II colnames
CALL p(1, NULL);
----
param1  param2
3       NULL

statement ok
CREATE OR REPLACE PROCEDURE p(INOUT param1 INT, OUT param2 INT) AS $$
BEGIN
  RAISE NOTICE '% %', param1, param2;
  param1 = 3;
  RAISE NOTICE '% %', param1, param2;
  SELECT 4 INTO param2;
  RAISE NOTICE '% %', param1, param2;
END
$$ LANGUAGE PLpgSQL;

query II colnames
CALL p(1, NULL);
----
param1  param2
3       4

query II noticetrace
CALL p(1, NULL);
----
NOTICE: 1 <NULL>
NOTICE: 3 <NULL>
NOTICE: 3 4

statement ok
DROP PROCEDURE p;

statement ok
CREATE PROCEDURE p(INOUT param1 INT, OUT param2 INT) AS $$
BEGIN
  param1 := 1;
  SELECT 2 INTO param2;
END
$$ LANGUAGE PLpgSQL;

query II colnames
CALL p(3, NULL);
----
param1  param2
1       2

statement ok
DROP PROCEDURE p;

# Verify that overload resolution works correctly when dropping procedures (OUT
# arguments are ignored).
statement ok
CREATE PROCEDURE p(OUT param INT) AS $$ BEGIN SELECT 1 INTO param; END $$ LANGUAGE PLpgSQL;

statement ok
DROP PROCEDURE p;

statement ok
CREATE PROCEDURE p(OUT param INT) AS $$ BEGIN SELECT 1 INTO param; END $$ LANGUAGE PLpgSQL;

statement ok
DROP PROCEDURE p(OUT INT);

statement ok
CREATE PROCEDURE p(OUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 1 INTO param1; END $$ LANGUAGE PLpgSQL;

statement ok
DROP PROCEDURE p(OUT INT);

# TODO(119502): uncomment this and call the procedure when $i notation is
# supported.
# statement ok
# CREATE PROCEDURE p(OUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 1 INTO $2; END $$ LANGUAGE PLpgSQL;

statement ok
CREATE PROCEDURE p(OUT param1 INT, OUT param2 INT) AS $$ BEGIN SELECT 1 INTO param2; END $$ LANGUAGE PLpgSQL;

statement error pgcode 42883 pq: procedure p\(int\) does not exist
DROP PROCEDURE p(INT);

statement ok
DROP PROCEDURE p;

statement ok
CREATE PROCEDURE p(OUT param INT) AS $$ BEGIN SELECT 1 INTO param; END $$ LANGUAGE PLpgSQL;

statement ok
DROP PROCEDURE p(OUT INT, OUT text, OUT INT);

subtest end

subtest show_create

statement ok
CREATE PROCEDURE p_param_types(IN p1 INT, INOUT p2 INT, IN OUT p3 INT, OUT p4 INT) AS $$
BEGIN
  SELECT p2, p3, p1;
END
$$ LANGUAGE PLpgSQL;

query T
SELECT create_statement FROM [SHOW CREATE PROCEDURE p_param_types];
----
CREATE PROCEDURE public.p_param_types(IN p1 INT8, INOUT p2 INT8, INOUT p3 INT8, OUT p4 INT8)
  LANGUAGE plpgsql
  SECURITY INVOKER
  AS $$
  BEGIN
  SELECT p2, p3, p1;
  END;
$$

statement ok
DROP PROCEDURE p_param_types;

statement ok
CREATE PROCEDURE p_param_types(OUT param INT) AS $$
BEGIN
  SELECT 1;
END
$$ LANGUAGE PLpgSQL;

query T
SELECT create_statement FROM [SHOW CREATE PROCEDURE p_param_types];
----
CREATE PROCEDURE public.p_param_types(OUT param INT8)
  LANGUAGE plpgsql
  SECURITY INVOKER
  AS $$
  BEGIN
  SELECT 1;
  END;
$$

statement ok
DROP PROCEDURE p_param_types;

subtest end

subtest parameter_names

# Unlike for SQL procedures, sharing of parameter names is not allowed across
# different "parameter namespaces" (IN vs OUT).

statement error pgcode 42P13 pq: parameter name "a" used more than once
CREATE PROCEDURE p_same_name(IN a INT, IN a INT) AS $$ BEGIN RETURN a + a; END $$ LANGUAGE PLpgSQL;

statement error pgcode 42P13 pq: parameter name "a" used more than once
CREATE PROCEDURE p_same_name(IN a INT, INOUT a INT) AS $$ BEGIN RETURN a + a; END $$ LANGUAGE PLpgSQL;

statement error pgcode 42P13 pq: parameter name "a" used more than once
CREATE PROCEDURE p_same_name(OUT a INT, INOUT a INT) AS $$ BEGIN RETURN a + a; END $$ LANGUAGE PLpgSQL;

statement error pgcode 42P13 pq: parameter name "a" used more than once
CREATE PROCEDURE p_same_name(IN a INT, OUT a INT) AS $$ BEGIN RETURN a; END $$ LANGUAGE PLpgSQL;

statement ok
CREATE PROCEDURE p_names(IN param_in INT, OUT param_out INT) AS $$ BEGIN SELECT param_in INTO param_out; END $$ LANGUAGE PLpgSQL;

query I colnames
CALL p_names(1, NULL);
----
param_out
1

statement error pgcode 42601 RETURN cannot have a parameter in a procedure
CREATE PROCEDURE p_in_int(IN param INT) AS $$ BEGIN RETURN param; END; $$ LANGUAGE PLpgSQL;

statement ok
CREATE PROCEDURE p_in_int(IN param INT) AS $$ BEGIN END; $$ LANGUAGE PLpgSQL;

# Unlike for functions, changing OUT parameter name is not ok.
statement ok
CREATE PROCEDURE p_out_int(OUT param INT) AS $$ BEGIN param = 2; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42P13 cannot change return type of existing function
CREATE OR REPLACE PROCEDURE p_out_int(OUT param_new INT) AS $$ BEGIN param_new = 2; END; $$ LANGUAGE PLpgSQL;

# Changing IN or INOUT parameter name is not allowed.
statement error pgcode 42P13 pq: cannot change name of input parameter "param"
CREATE OR REPLACE PROCEDURE p_in_int(IN param_new INT) AS $$ BEGIN END; $$ LANGUAGE PLpgSQL;

statement ok
CREATE PROCEDURE p_inout_int(INOUT param INT) AS $$ BEGIN param = 2; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42P13 pq: cannot change return type of existing function
CREATE OR REPLACE PROCEDURE p_inout_int(INOUT param_new INT) AS $$ BEGIN param_new = 2; END; $$ LANGUAGE PLpgSQL;

subtest end

subtest changing_parameters

statement ok
CREATE PROCEDURE p_int(IN param INT) AS $$ BEGIN END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42P13 pq: cannot change whether a procedure has output parameters
CREATE OR REPLACE PROCEDURE p_int(INOUT param INT) AS $$ BEGIN param = 2; END; $$ LANGUAGE PLpgSQL;

# Note that in postgres this returns an error with the same code but with
# "cannot change whether a procedure has output parameters" as the message.
statement error pgcode 42P13 pq: parameter name "param" used more than once
CREATE OR REPLACE PROCEDURE p_int(IN param INT, OUT param INT) AS $$ BEGIN param = 2; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42P13 pq: cannot change whether a procedure has output parameters
CREATE OR REPLACE PROCEDURE p_int(IN param INT, OUT param_out INT) AS $$ BEGIN param = 2; END; $$ LANGUAGE PLpgSQL;

subtest end

subtest default_parameter_names

# Parameter names are optional. Each unnamed OUT parameter with ordinal 'i'
# (among all OUT parameters) gets the default name that is "column" || i.

statement ok
CREATE PROCEDURE p_default_names(OUT INT, OUT param2 INT, IN INT, OUT INT) AS $$ BEGIN param2 = 2; END; $$ LANGUAGE PLpgSQL;

query III colnames
CALL p_default_names(NULL, NULL, 3, NULL);
----
column1  param2  column3
NULL     2       NULL

# However, attempting to access the parameter by the default names is invalid.
statement error pgcode 42601 pq: \"column1\" is not a known variable
CREATE OR REPLACE PROCEDURE p_default_names(OUT INT, OUT param2 INT, IN INT, OUT INT) AS $$ BEGIN SELECT 1 INTO column1; END; $$ LANGUAGE PLpgSQL;

# Introducing the OUT parameter name is disallowed because it'd change the
# return type.
statement error pgcode 42P13 cannot change return type of existing function
CREATE OR REPLACE PROCEDURE p_default_names(OUT INT, OUT param2 INT, IN INT, OUT param3 INT) AS $$ BEGIN param2 = 2; END; $$ LANGUAGE PLpgSQL;

# Introducing the name that matches the default OUT parameter name is allowed.
statement ok
CREATE OR REPLACE PROCEDURE p_default_names(OUT INT, OUT param2 INT, IN INT, OUT column3 INT) AS $$ BEGIN SELECT 3 INTO column3; END; $$ LANGUAGE PLpgSQL;

query T
SELECT create_statement FROM [SHOW CREATE PROCEDURE p_default_names];
----
CREATE PROCEDURE public.p_default_names(OUT INT8, OUT param2 INT8, IN INT8, OUT column3 INT8)
  LANGUAGE plpgsql
  SECURITY INVOKER
  AS $$
  BEGIN
  SELECT 3 INTO column3;
  END;
$$

query III colnames
CALL p_default_names(NULL, NULL, 3, NULL);
----
column1  param2  column3
NULL     NULL    3

# Then we can omit the default OUT parameter name again (but still cannot use it
# in the body).
statement error pgcode 42601 pq: \"column3\" is not a known variable
CREATE OR REPLACE PROCEDURE p_default_names(OUT INT, OUT param2 INT, IN INT, OUT INT) AS $$ BEGIN SELECT 3 INTO column3; END; $$ LANGUAGE PLpgSQL;

statement ok
CREATE OR REPLACE PROCEDURE p_default_names(OUT INT, OUT param2 INT, IN INT, OUT INT) AS $$ BEGIN param2 = 2; END; $$ LANGUAGE PLpgSQL;

query T
SELECT create_statement FROM [SHOW CREATE PROCEDURE p_default_names];
----
CREATE PROCEDURE public.p_default_names(OUT INT8, OUT param2 INT8, IN INT8, OUT INT8)
  LANGUAGE plpgsql
  SECURITY INVOKER
  AS $$
  BEGIN
  param2 := 2;
  END;
$$

query III colnames
CALL p_default_names(NULL, NULL, 3, NULL);
----
column1  param2  column3
NULL     2       NULL

# Introducing the IN parameter name is ok.
statement ok
CREATE OR REPLACE PROCEDURE p_default_names(OUT INT, OUT param2 INT, IN in_param INT, OUT INT) AS $$ BEGIN SELECT in_param INTO param2; END; $$ LANGUAGE PLpgSQL;

query T
SELECT create_statement FROM [SHOW CREATE PROCEDURE p_default_names];
----
CREATE PROCEDURE public.p_default_names(OUT INT8, OUT param2 INT8, IN in_param INT8, OUT INT8)
  LANGUAGE plpgsql
  SECURITY INVOKER
  AS $$
  BEGIN
  SELECT in_param INTO param2;
  END;
$$

query III colnames
CALL p_default_names(NULL, NULL, 3, NULL);
----
column1  param2  column3
NULL     3       NULL

# But then the IN parameter name cannot be changed anymore.
statement error pgcode 42P13 cannot change name of input parameter "in_param"
CREATE OR REPLACE PROCEDURE p_default_names(OUT INT, OUT param2 INT, IN in_param_new INT, OUT INT) AS $$ BEGIN SELECT in_param_new INTO param2; END; $$ LANGUAGE PLpgSQL;

subtest end

statement ok
CREATE TYPE typ AS (a INT, b INT);

statement ok
CREATE PROCEDURE p_udt(OUT param typ) AS $$ BEGIN param := (1, 2); END $$ LANGUAGE PLpgSQL;

query T colnames
CALL p_udt(NULL);
----
param
(1,2)

statement error pgcode 2BP01 cannot drop type "typ" because other objects \(\[test.public.p_udt\]\) still depend on it
DROP TYPE typ;

statement ok
DROP PROCEDURE p_udt;

statement ok
CREATE TYPE greeting AS ENUM('hello', 'hi', 'yo');
CREATE PROCEDURE p_enum(OUT greeting greeting) AS $$ BEGIN greeting := 'hi'::greeting; END; $$ LANGUAGE PLpgSQL;

query T colnames
CALL p_enum(NULL)
----
greeting
hi

statement error pgcode 2BP01 cannot drop type "greeting" because other objects \(\[test.public.p_enum\]\) still depend on it
DROP TYPE greeting;

statement ok
DROP PROCEDURE p_enum;

subtest default_exprs

statement error pgcode 22P02 could not parse "a" as type int
CREATE PROCEDURE my_sum(OUT o INT, a INT, b INT DEFAULT 2, c INT DEFAULT 'a') AS $$ BEGIN SELECT a + b + c INTO o; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42P13 input parameters after one with a default value must also have defaults
CREATE PROCEDURE my_sum(OUT o INT, a INT, b INT DEFAULT 2, c INT) AS $$ BEGIN SELECT a + b + c INTO o; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42P13 input parameters after one with a default value must also have defaults
CREATE PROCEDURE my_sum(OUT o INT, a INT, b INT DEFAULT 2, INOUT c INT) AS $$ BEGIN SELECT a + b + c INTO o; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42P13 only input parameters can have default values
CREATE PROCEDURE my_sum(OUT o INT, a INT, b INT DEFAULT 2, OUT c INT = 3) AS $$ BEGIN SELECT a + b INTO c; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42703 column "b" does not exist
CREATE PROCEDURE my_sum(OUT o INT, a INT, b INT, c INT = b + 1) AS $$ BEGIN SELECT a + b + c INTO o; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42703 column "b" does not exist
CREATE PROCEDURE my_sum(OUT o INT, a INT, b INT = 2, c INT = b + 1) AS $$ BEGIN SELECT a + b + c INTO o; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42703 column "d" does not exist
CREATE PROCEDURE my_sum(OUT o INT, a INT, b INT = 2, c INT = d + 1) AS $$ BEGIN SELECT a + b + c INTO o; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42804 argument of DEFAULT must be type int, not type bool
CREATE PROCEDURE my_sum(OUT o INT, a INT, b INT DEFAULT true) AS $$ BEGIN SELECT a + b INTO o; END; $$ LANGUAGE PLpgSQL;

statement ok
CREATE PROCEDURE my_sum(OUT o INT, a INT, b INT, c INT) AS $$ BEGIN SELECT a + b + c INTO o; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42P13 input parameters after one with a default value must also have defaults
CREATE OR REPLACE PROCEDURE my_sum(OUT o INT, a INT = 1, b INT, c INT = 3) AS $$ BEGIN SELECT a + b + c INTO o; END; $$ LANGUAGE PLpgSQL;

# Adding a default expression to a parameter is ok.
statement ok
CREATE OR REPLACE PROCEDURE my_sum(OUT o INT, a INT, b INT DEFAULT 2, c INT = 3) AS $$ BEGIN SELECT a + b + c INTO o; END; $$ LANGUAGE PLpgSQL;

# But removing an existing default expression is not ok.
statement error pgcode 42P13 cannot remove parameter defaults from existing function
CREATE OR REPLACE PROCEDURE my_sum(OUT o INT, a INT, b INT, c INT = 3) AS $$ BEGIN SELECT a + b + c INTO o; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 22P02 could not parse "a" as type int
CREATE OR REPLACE PROCEDURE my_sum(OUT o INT, a INT = 'a', b INT DEFAULT 2, c INT = 3) AS $$ BEGIN SELECT a + b + c INTO o; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 0A000 subqueries are not allowed in DEFAULT expressions
CREATE OR REPLACE PROCEDURE my_sum(a INT, b INT DEFAULT (SELECT 1)) AS $$ BEGIN SELECT a + b; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 0A000 subqueries are not allowed in DEFAULT expressions
CREATE OR REPLACE PROCEDURE my_sum(a INT, b INT DEFAULT 1 + (SELECT 2 FROM (VALUES (NULL)))) AS $$ BEGIN SELECT a + b; END; $$ LANGUAGE PLpgSQL;

query I
CALL my_sum(NULL, 1);
----
6

query I
CALL my_sum(NULL, 1, 1);
----
5

query I
CALL my_sum(NULL, 1, 1, 1);
----
3

statement error pgcode 42883 procedure my_sum\(unknown\) does not exist
CALL my_sum(NULL);

statement error pgcode 42883 procedure my_sum\(unknown, int, int, int, int\) does not exist
CALL my_sum(NULL, 1, 1, 1, 1);

# Same as above, but the default value needs to be coerced from numeric to int
# (becoming 4).
statement ok
CREATE OR REPLACE PROCEDURE my_sum(OUT o INT, a INT, b INT DEFAULT 2, c INT = 3.5) AS $$ BEGIN SELECT a + b + c INTO o; END; $$ LANGUAGE PLpgSQL;

query I
CALL my_sum(NULL, 1);
----
7

query I
CALL my_sum(NULL, 1, 1);
----
6

# Add another overload that creates ambiguity for some number of input
# arguments.
statement ok
CREATE PROCEDURE my_sum(OUT o INT, a INT) AS $$ BEGIN SELECT a INTO o; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 42725 procedure my_sum\(unknown, int\) is not unique
CALL my_sum(NULL, 1);

statement ok
DROP PROCEDURE my_sum(INT);

statement ok
DROP PROCEDURE my_sum;

statement ok
CREATE PROCEDURE my_sum(OUT sum INT, INOUT a INT, INOUT b INT = 3) AS $$ BEGIN SELECT a + b INTO sum; END; $$ LANGUAGE PLpgSQL;

query III
CALL my_sum(NULL, 1);
----
4  1  3

query III
CALL my_sum(NULL, 1, 1);
----
2  1  1

statement ok
DROP PROCEDURE my_sum;

statement error pgcode 0A000 unnamed INOUT parameters are not yet supported
CREATE PROCEDURE my_sum(OUT a_plus_one INT, INOUT a INT, INOUT INT = 3) AS $$ BEGIN SELECT a + 1 INTO a_plus_one; END; $$ LANGUAGE PLpgSQL;

statement ok
CREATE PROCEDURE my_sum(OUT a_plus_one INT, INOUT a INT, INOUT b INT = 3) AS $$ BEGIN SELECT a + 1 INTO a_plus_one; END; $$ LANGUAGE PLpgSQL;

query III
CALL my_sum(NULL, 1);
----
2  1  3

query III
CALL my_sum(NULL, 1, 1);
----
2  1  1

statement ok
DROP PROCEDURE my_sum;

# Test for a narrowing type coercion.
statement ok
CREATE PROCEDURE f(OUT o CHAR, x CHAR DEFAULT 'foo') AS $$ BEGIN SELECT x INTO o; END; $$ LANGUAGE PLpgSQL;

# Note that postgres doesn't actually truncate the value and returns 'foo' here
# (this difference is tracked by #115385).
query T
CALL f(NULL);
----
f

statement ok
DROP PROCEDURE f;

# Test case when DEFAULT expression uses a UDF.

statement ok
CREATE FUNCTION f1(a INT, b INT = 2) RETURNS INT AS $$ BEGIN RETURN a + b; END; $$ LANGUAGE PLpgSQL;

statement ok
CREATE PROCEDURE p2(OUT o INT, a INT, b INT = f1(1)) AS $$ BEGIN SELECT a + b INTO o; END; $$ LANGUAGE PLpgSQL;

query I
CALL p2(NULL, 1);
----
4

query I
CALL p2(NULL, 1, 1);
----
2

statement ok
CREATE OR REPLACE FUNCTION f1(a INT, b INT = 2) RETURNS INT AS $$ BEGIN RETURN a * b; END; $$ LANGUAGE PLpgSQL;

query I
CALL p2(NULL, 1);
----
3

query I
CALL p2(NULL, 1, 1);
----
2

statement error pgcode 2BP01 cannot drop function "f1" because other objects \(\[test.public.p2\]\) still depend on it
DROP FUNCTION f1;

statement ok
DROP PROCEDURE p2;

statement ok
DROP FUNCTION f1;

# Test that dropping UDTs or enum members used in the DEFAULT expression is not
# allowed.

statement ok
CREATE PROCEDURE p(p1 typ DEFAULT (1, 2), p2 greeting = 'yo') AS $$ BEGIN NULL; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 2BP01 cannot drop type "typ" because other objects \(\[test.public.p\]\) still depend on it
DROP TYPE typ;

statement error pgcode 2BP01 could not remove enum value "yo" as it is being used in a routine "p"
ALTER TYPE greeting DROP VALUE 'yo';

# Dropping enum value not used in the DEFAULT expression should be ok.
statement ok
ALTER TYPE greeting DROP VALUE 'hello';

# Using a different enum value in the DEFAULT expression should allow us to drop
# the original enum value.
statement ok
CREATE OR REPLACE PROCEDURE p(p1 typ DEFAULT (1, 2), p2 greeting = 'hi') AS $$ BEGIN NULL; END; $$ LANGUAGE PLpgSQL;

statement ok
ALTER TYPE greeting DROP VALUE 'yo';

statement error pgcode 2BP01 could not remove enum value "hi" as it is being used in a routine "p"
ALTER TYPE greeting DROP VALUE 'hi';

statement ok
DROP PROCEDURE p;

# Test having sequences in the DEFAULT expression.

statement ok
CREATE SEQUENCE seq;

statement ok
CREATE PROCEDURE p(OUT o INT, a INT = nextval('seq')) AS $$ BEGIN SELECT a INTO o; END; $$ LANGUAGE PLpgSQL;

query I
CALL p(NULL);
----
1

query I
CALL p(NULL, 1);
----
1

query I
CALL p(NULL);
----
2

statement error pgcode 2BP01 cannot drop sequence seq because other objects depend on it
DROP SEQUENCE seq;

statement ok
CREATE OR REPLACE PROCEDURE p(OUT o INT, a INT = 3) AS $$ BEGIN o := a; END; $$ LANGUAGE PLpgSQL;

# DEFAULT expression no longer uses the sequence.
statement ok
DROP SEQUENCE seq;

statement ok
DROP PROCEDURE p;

# Try doing the same when the sequence is added in the replacement.

statement ok
CREATE SEQUENCE seq;

statement ok
CREATE OR REPLACE PROCEDURE p(OUT o INT, a INT = 3) AS $$ BEGIN o := a; END; $$ LANGUAGE PLpgSQL;

statement ok
CREATE OR REPLACE PROCEDURE p(OUT o INT, a INT = nextval('seq')) AS $$ BEGIN SELECT a INTO o; END; $$ LANGUAGE PLpgSQL;

statement error pgcode 2BP01 cannot drop sequence seq because other objects depend on it
DROP SEQUENCE seq;

statement ok
DROP PROCEDURE p;

statement ok
DROP SEQUENCE seq;

# Regression test for invalid assertion when using the default argument for
# INOUT parameter when invoking the procedure (#122263).
statement ok
CREATE PROCEDURE p(INOUT a int DEFAULT 11) AS $$
BEGIN
  RAISE NOTICE 'a: %', a;
  a := a * 10;
END;
$$ LANGUAGE PLpgSQL;

statement error pgcode 42601 procedure parameter "a" is an output parameter but corresponding argument is not writable
CREATE PROCEDURE foo() AS $$
DECLARE _a int;
BEGIN
  _a := 10;
  CALL p();  -- fail, no output argument for a
  RAISE NOTICE '_a: %', _a;
END
$$ LANGUAGE PLpgSQL;

statement ok
DROP PROCEDURE p;

subtest end
