Skip to content

Commit 0867670

Browse files
committed
builtins: implement pg_get_function_arg_default
Release note (sql change): The pg_get_function_arg_default builtin function has been implemented. This also causes the information_schema.parameters(parameter_default) column to be populated correctly.
1 parent a7d85da commit 0867670

File tree

3 files changed

+128
-4
lines changed

3 files changed

+128
-4
lines changed

docs/generated/sql/functions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3615,7 +3615,7 @@ may increase either contention or retry errors, or both.</p>
36153615
</span></td><td>Stable</td></tr>
36163616
<tr><td><a name="pg_function_is_visible"></a><code>pg_function_is_visible(oid: oid) &rarr; <a href="bool.html">bool</a></code></td><td><span class="funcdesc"><p>Returns whether the function with the given OID belongs to one of the schemas on the search path.</p>
36173617
</span></td><td>Stable</td></tr>
3618-
<tr><td><a name="pg_get_function_arg_default"></a><code>pg_get_function_arg_default(func_oid: oid, arg_num: int4) &rarr; <a href="string.html">string</a></code></td><td><span class="funcdesc"><p>Get textual representation of a function argument’s default value. The second argument of this function is the argument number among all arguments (i.e. proallargtypes, <em>not</em> proargtypes), starting with 1, because that’s how information_schema.sql uses it. Currently, this always returns NULL, since CockroachDB does not support default values.</p>
3618+
<tr><td><a name="pg_get_function_arg_default"></a><code>pg_get_function_arg_default(func_oid: oid, arg_num: int4) &rarr; <a href="string.html">string</a></code></td><td><span class="funcdesc"><p>Get textual representation of a function argument’s default value. The second argument of this function is the argument number among all arguments (i.e. proallargtypes, <em>not</em> proargtypes), starting with 1, because that’s how information_schema.sql uses it.</p>
36193619
</span></td><td>Stable</td></tr>
36203620
<tr><td><a name="pg_get_function_arguments"></a><code>pg_get_function_arguments(func_oid: oid) &rarr; <a href="string.html">string</a></code></td><td><span class="funcdesc"><p>Returns the argument list (with defaults) necessary to identify a function, in the form it would need to appear in within CREATE FUNCTION.</p>
36213621
</span></td><td>Stable</td></tr>

pkg/sql/logictest/testdata/logic_test/information_schema

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3530,6 +3530,97 @@ specific_catalog specific_schema specific_name ordinal_position parameter_mo
35303530
test pg_catalog get_byte_854 1 IN NO NO NULL bytea NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL test pg_catalog bytea NULL NULL NULL NULL 1 NULL
35313531
test pg_catalog get_byte_854 2 IN NO NO NULL bigint NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL test pg_catalog int8 NULL NULL NULL NULL 2 NULL
35323532

3533+
# Test that default values are populated correctly.
3534+
statement ok
3535+
CREATE OR REPLACE FUNCTION f_default(
3536+
p_no_default INT,
3537+
p_int INT DEFAULT 0,
3538+
p_string STRING DEFAULT '0'
3539+
)
3540+
RETURNS varchar
3541+
LANGUAGE plpgsql
3542+
AS
3543+
$$
3544+
BEGIN
3545+
RETURN p_no_default::varchar || ':' || p_int::varchar || ':' || p_string;
3546+
END;
3547+
$$
3548+
3549+
query TT
3550+
SELECT p.parameter_name, p.parameter_default
3551+
FROM information_schema.routines AS r
3552+
JOIN information_schema.parameters AS p ON r.specific_name = p.specific_name
3553+
WHERE r.routine_name = 'f_default'
3554+
ORDER BY p.ordinal_position;
3555+
----
3556+
p_no_default NULL
3557+
p_int 0:::INT8
3558+
p_string '0':::STRING
3559+
3560+
# Test INOUT parameters with defaults.
3561+
statement ok
3562+
CREATE FUNCTION f_inout_default(
3563+
INOUT p_inout_no_default INT,
3564+
INOUT p_inout_with_default INT DEFAULT 42
3565+
) RETURNS RECORD AS $$ SELECT p_inout_no_default + 1, p_inout_with_default + 1; $$ LANGUAGE SQL;
3566+
3567+
query TT
3568+
SELECT p.parameter_name, p.parameter_default
3569+
FROM information_schema.routines AS r
3570+
JOIN information_schema.parameters AS p ON r.specific_name = p.specific_name
3571+
WHERE r.routine_name = 'f_inout_default'
3572+
ORDER BY p.ordinal_position;
3573+
----
3574+
p_inout_no_default NULL
3575+
p_inout_with_default 42:::INT8
3576+
3577+
# Test mixed parameter modes with defaults. Note that parameters with
3578+
# defaults must appear after all parameters without defaults.
3579+
statement ok
3580+
CREATE FUNCTION f_mixed_defaults(
3581+
p_in_no_default INT,
3582+
OUT p_out_param INT,
3583+
INOUT p_inout_no_default INT,
3584+
p_in_default INT DEFAULT 10,
3585+
INOUT p_inout_default INT DEFAULT 20
3586+
) RETURNS RECORD AS $$
3587+
SELECT p_in_no_default + p_in_default, p_inout_no_default + 1, p_inout_default + 1;
3588+
$$ LANGUAGE SQL;
3589+
3590+
query TT
3591+
SELECT p.parameter_name, p.parameter_default
3592+
FROM information_schema.routines AS r
3593+
JOIN information_schema.parameters AS p ON r.specific_name = p.specific_name
3594+
WHERE r.routine_name = 'f_mixed_defaults'
3595+
ORDER BY p.ordinal_position;
3596+
----
3597+
p_in_no_default NULL
3598+
p_out_param NULL
3599+
p_inout_no_default NULL
3600+
p_in_default 10:::INT8
3601+
p_inout_default 20:::INT8
3602+
3603+
# Test complex default expressions with different parameter modes.
3604+
statement ok
3605+
CREATE FUNCTION f_complex_defaults(
3606+
OUT p_out_result INT,
3607+
INOUT p_complex_default INT DEFAULT length('test'),
3608+
p_function_default INT DEFAULT length('hello')
3609+
) RETURNS RECORD AS $$
3610+
SELECT p_complex_default + p_function_default, p_complex_default;
3611+
$$ LANGUAGE SQL;
3612+
3613+
query TT
3614+
SELECT p.parameter_name, p.parameter_default
3615+
FROM information_schema.routines AS r
3616+
JOIN information_schema.parameters AS p ON r.specific_name = p.specific_name
3617+
WHERE r.routine_name = 'f_complex_defaults'
3618+
ORDER BY p.ordinal_position;
3619+
----
3620+
p_out_result NULL
3621+
p_complex_default length('test':::STRING)
3622+
p_function_default length('hello':::STRING)
3623+
35333624
skipif config local-mixed-25.2
35343625
query TTTTTTTT colnames,rowsort
35353626
SELECT * FROM system.information_schema.column_privileges WHERE table_name = 'eventlog'

pkg/sql/sem/builtins/pg_builtins.go

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -773,12 +773,45 @@ var pgBuiltins = map[string]builtinDefinition{
773773
tree.Overload{
774774
Types: tree.ParamTypes{{Name: "func_oid", Typ: types.Oid}, {Name: "arg_num", Typ: types.Int4}},
775775
ReturnType: tree.FixedReturnType(types.String),
776-
Body: "SELECT NULL",
776+
Body: `
777+
WITH defaults_parsed AS (
778+
SELECT
779+
proargdefaults,
780+
pronargs,
781+
proargmodes,
782+
array_upper(proargmodes, 1) AS total_args,
783+
CASE
784+
WHEN proargdefaults IS NULL THEN 0
785+
ELSE array_length(string_to_array(trim('()' FROM proargdefaults), '}, {'), 1)
786+
END AS num_defaults,
787+
trim('()' FROM proargdefaults) AS defaults_trimmed,
788+
-- Count input arguments up to position $2
789+
CASE
790+
WHEN proargmodes IS NULL THEN $2
791+
ELSE (
792+
SELECT count(*)
793+
FROM generate_series(1, $2) AS i
794+
WHERE proargmodes[i] IN ('i', 'b', 'v')
795+
)
796+
END AS nth_input_arg
797+
FROM pg_catalog.pg_proc
798+
WHERE oid = $1
799+
LIMIT 1
800+
)
801+
SELECT
802+
CASE
803+
WHEN proargdefaults IS NULL THEN NULL
804+
WHEN $2 < 1 OR $2 > COALESCE(total_args, pronargs) THEN NULL
805+
WHEN (proargmodes IS NOT NULL AND proargmodes[$2] NOT IN ('i', 'b', 'v')) THEN NULL
806+
WHEN nth_input_arg <= (pronargs - num_defaults) THEN NULL
807+
ELSE trim('{}' FROM split_part(defaults_trimmed, '}, {', nth_input_arg - (pronargs - num_defaults)))
808+
END
809+
FROM defaults_parsed
810+
`,
777811
Info: "Get textual representation of a function argument's default value. " +
778812
"The second argument of this function is the argument number among all " +
779813
"arguments (i.e. proallargtypes, *not* proargtypes), starting with 1, " +
780-
"because that's how information_schema.sql uses it. Currently, this " +
781-
"always returns NULL, since CockroachDB does not support default values.",
814+
"because that's how information_schema.sql uses it.",
782815
Volatility: volatility.Stable,
783816
CalledOnNullInput: true,
784817
Language: tree.RoutineLangSQL,

0 commit comments

Comments
 (0)