mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-03-07 19:47:50 +08:00
Implement information_schema.parameters.parameter_default column
Reviewed-by: Ali Dar <ali.munir.dar@gmail.com> Reviewed-by: Amit Khandekar <amit.khandekar@enterprisedb.com> Reviewed-by: Rodolfo Campero <rodolfo.campero@anachronics.com>
This commit is contained in:
parent
3803ff985c
commit
85ed91ee7d
@ -3323,6 +3323,15 @@ ORDER BY c.ordinal_position;
|
||||
in future versions.)
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>parameter_default</literal></entry>
|
||||
<entry><type>character_data</type></entry>
|
||||
<entry>
|
||||
The default expression of the parameter, or null if none or if the
|
||||
function is not owned by a currently enabled role.
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
@ -1133,10 +1133,15 @@ CREATE VIEW parameters AS
|
||||
CAST(null AS sql_identifier) AS scope_schema,
|
||||
CAST(null AS sql_identifier) AS scope_name,
|
||||
CAST(null AS cardinal_number) AS maximum_cardinality,
|
||||
CAST((ss.x).n AS sql_identifier) AS dtd_identifier
|
||||
CAST((ss.x).n AS sql_identifier) AS dtd_identifier,
|
||||
CAST(
|
||||
CASE WHEN pg_has_role(proowner, 'USAGE')
|
||||
THEN pg_get_function_arg_default(p_oid, (ss.x).n)
|
||||
ELSE NULL END
|
||||
AS character_data) AS parameter_default
|
||||
|
||||
FROM pg_type t, pg_namespace nt,
|
||||
(SELECT n.nspname AS n_nspname, p.proname, p.oid AS p_oid,
|
||||
(SELECT n.nspname AS n_nspname, p.proname, p.oid AS p_oid, p.proowner,
|
||||
p.proargnames, p.proargmodes,
|
||||
_pg_expandarray(coalesce(p.proallargtypes, p.proargtypes::oid[])) AS x
|
||||
FROM pg_namespace n, pg_proc p
|
||||
|
@ -2266,6 +2266,90 @@ print_function_arguments(StringInfo buf, HeapTuple proctup,
|
||||
return argsprinted;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_input_argument(int nth, const char *argmodes)
|
||||
{
|
||||
return (!argmodes
|
||||
|| argmodes[nth] == PROARGMODE_IN
|
||||
|| argmodes[nth] == PROARGMODE_INOUT
|
||||
|| argmodes[nth] == PROARGMODE_VARIADIC);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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, *not* proargtypes), starting with 1, because that's
|
||||
* how information_schema.sql uses it.
|
||||
*/
|
||||
Datum
|
||||
pg_get_function_arg_default(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid funcid = PG_GETARG_OID(0);
|
||||
int32 nth_arg = PG_GETARG_INT32(1);
|
||||
HeapTuple proctup;
|
||||
Form_pg_proc proc;
|
||||
int numargs;
|
||||
Oid *argtypes;
|
||||
char **argnames;
|
||||
char *argmodes;
|
||||
int i;
|
||||
List *argdefaults;
|
||||
Node *node;
|
||||
char *str;
|
||||
int nth_inputarg;
|
||||
Datum proargdefaults;
|
||||
bool isnull;
|
||||
int nth_default;
|
||||
|
||||
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
|
||||
if (!HeapTupleIsValid(proctup))
|
||||
elog(ERROR, "cache lookup failed for function %u", funcid);
|
||||
|
||||
numargs = get_func_arg_info(proctup, &argtypes, &argnames, &argmodes);
|
||||
if (nth_arg < 1 || nth_arg > numargs || !is_input_argument(nth_arg - 1, argmodes))
|
||||
{
|
||||
ReleaseSysCache(proctup);
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
nth_inputarg = 0;
|
||||
for (i = 0; i < nth_arg; i++)
|
||||
if (is_input_argument(i, argmodes))
|
||||
nth_inputarg++;
|
||||
|
||||
proargdefaults = SysCacheGetAttr(PROCOID, proctup,
|
||||
Anum_pg_proc_proargdefaults,
|
||||
&isnull);
|
||||
if (isnull)
|
||||
{
|
||||
ReleaseSysCache(proctup);
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
str = TextDatumGetCString(proargdefaults);
|
||||
argdefaults = (List *) stringToNode(str);
|
||||
Assert(IsA(argdefaults, List));
|
||||
pfree(str);
|
||||
|
||||
proc = (Form_pg_proc) GETSTRUCT(proctup);
|
||||
|
||||
/* Calculate index into proargdefaults: proargdefaults corresponds to the
|
||||
* last N input arguments, where N = pronargdefaults. */
|
||||
nth_default = nth_inputarg - 1 - (proc->pronargs - proc->pronargdefaults);
|
||||
|
||||
if (nth_default < 0 || nth_default >= list_length(argdefaults))
|
||||
{
|
||||
ReleaseSysCache(proctup);
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
node = list_nth(argdefaults, nth_default);
|
||||
str = deparse_expression(node, NIL, false, false);
|
||||
|
||||
ReleaseSysCache(proctup);
|
||||
|
||||
PG_RETURN_TEXT_P(string_to_text(str));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* deparse_expression - General utility for deparsing expressions
|
||||
|
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 201311211
|
||||
#define CATALOG_VERSION_NO 201311261
|
||||
|
||||
#endif
|
||||
|
@ -1973,6 +1973,8 @@ DATA(insert OID = 2232 ( pg_get_function_identity_arguments PGNSP PGUID 12 1
|
||||
DESCR("identity argument list of a function");
|
||||
DATA(insert OID = 2165 ( pg_get_function_result PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 25 "26" _null_ _null_ _null_ _null_ pg_get_function_result _null_ _null_ _null_ ));
|
||||
DESCR("result type of a function");
|
||||
DATA(insert OID = 3808 ( pg_get_function_arg_default PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 25 "26 23" _null_ _null_ _null_ _null_ pg_get_function_arg_default _null_ _null_ _null_ ));
|
||||
DESCR("function argument default");
|
||||
|
||||
DATA(insert OID = 1686 ( pg_get_keywords PGNSP PGUID 12 10 400 0 0 f f f f t t s 0 0 2249 "" "{25,18,25}" "{o,o,o}" "{word,catcode,catdesc}" _null_ pg_get_keywords _null_ _null_ _null_ ));
|
||||
DESCR("list of SQL keywords");
|
||||
|
@ -665,6 +665,7 @@ extern Datum pg_get_functiondef(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_get_function_arguments(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_get_function_identity_arguments(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_get_function_result(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_get_function_arg_default(PG_FUNCTION_ARGS);
|
||||
extern char *deparse_expression(Node *expr, List *dpcontext,
|
||||
bool forceprefix, bool showimplicit);
|
||||
extern List *deparse_context_for(const char *aliasname, Oid relid);
|
||||
|
@ -425,9 +425,37 @@ SELECT proname, proisstrict FROM pg_proc
|
||||
functext_f_4 | t
|
||||
(4 rows)
|
||||
|
||||
-- information_schema tests
|
||||
CREATE FUNCTION functest_IS_1(a int, b int default 1, c text default 'foo')
|
||||
RETURNS int
|
||||
LANGUAGE SQL
|
||||
AS 'SELECT $1 + $2';
|
||||
CREATE FUNCTION functest_IS_2(out a int, b int default 1)
|
||||
RETURNS int
|
||||
LANGUAGE SQL
|
||||
AS 'SELECT $1';
|
||||
CREATE FUNCTION functest_IS_3(a int default 1, out b int)
|
||||
RETURNS int
|
||||
LANGUAGE SQL
|
||||
AS 'SELECT $1';
|
||||
SELECT routine_name, ordinal_position, parameter_name, parameter_default
|
||||
FROM information_schema.parameters JOIN information_schema.routines USING (specific_schema, specific_name)
|
||||
WHERE routine_schema = 'temp_func_test' AND routine_name ~ '^functest_is_'
|
||||
ORDER BY 1, 2;
|
||||
routine_name | ordinal_position | parameter_name | parameter_default
|
||||
---------------+------------------+----------------+-------------------
|
||||
functest_is_1 | 1 | a |
|
||||
functest_is_1 | 2 | b | 1
|
||||
functest_is_1 | 3 | c | 'foo'::text
|
||||
functest_is_2 | 1 | a |
|
||||
functest_is_2 | 2 | b | 1
|
||||
functest_is_3 | 1 | a | 1
|
||||
functest_is_3 | 2 | b |
|
||||
(7 rows)
|
||||
|
||||
-- Cleanups
|
||||
DROP SCHEMA temp_func_test CASCADE;
|
||||
NOTICE: drop cascades to 16 other objects
|
||||
NOTICE: drop cascades to 19 other objects
|
||||
DETAIL: drop cascades to function functest_a_1(text,date)
|
||||
drop cascades to function functest_a_2(text[])
|
||||
drop cascades to function functest_a_3()
|
||||
@ -444,5 +472,8 @@ drop cascades to function functext_f_1(integer)
|
||||
drop cascades to function functext_f_2(integer)
|
||||
drop cascades to function functext_f_3(integer)
|
||||
drop cascades to function functext_f_4(integer)
|
||||
drop cascades to function functest_is_1(integer,integer,text)
|
||||
drop cascades to function functest_is_2(integer)
|
||||
drop cascades to function functest_is_3(integer)
|
||||
DROP USER regtest_unpriv_user;
|
||||
RESET search_path;
|
||||
|
@ -138,6 +138,30 @@ SELECT proname, proisstrict FROM pg_proc
|
||||
'functext_F_3'::regproc,
|
||||
'functext_F_4'::regproc) ORDER BY proname;
|
||||
|
||||
|
||||
-- information_schema tests
|
||||
|
||||
CREATE FUNCTION functest_IS_1(a int, b int default 1, c text default 'foo')
|
||||
RETURNS int
|
||||
LANGUAGE SQL
|
||||
AS 'SELECT $1 + $2';
|
||||
|
||||
CREATE FUNCTION functest_IS_2(out a int, b int default 1)
|
||||
RETURNS int
|
||||
LANGUAGE SQL
|
||||
AS 'SELECT $1';
|
||||
|
||||
CREATE FUNCTION functest_IS_3(a int default 1, out b int)
|
||||
RETURNS int
|
||||
LANGUAGE SQL
|
||||
AS 'SELECT $1';
|
||||
|
||||
SELECT routine_name, ordinal_position, parameter_name, parameter_default
|
||||
FROM information_schema.parameters JOIN information_schema.routines USING (specific_schema, specific_name)
|
||||
WHERE routine_schema = 'temp_func_test' AND routine_name ~ '^functest_is_'
|
||||
ORDER BY 1, 2;
|
||||
|
||||
|
||||
-- Cleanups
|
||||
DROP SCHEMA temp_func_test CASCADE;
|
||||
DROP USER regtest_unpriv_user;
|
||||
|
Loading…
Reference in New Issue
Block a user