aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/information_schema.sql9
-rw-r--r--src/backend/utils/adt/ruleutils.c84
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_proc.h2
-rw-r--r--src/include/utils/builtins.h1
-rw-r--r--src/test/regress/expected/create_function_3.out33
-rw-r--r--src/test/regress/sql/create_function_3.sql24
7 files changed, 151 insertions, 4 deletions
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index c5f7a8b2100..fd706e3479e 100644
--- a/src/backend/catalog/information_schema.sql
+++ b/src/backend/catalog/information_schema.sql
@@ -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
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 29a1027a100..348f620f2a4 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -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
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index c783b262817..759395a24b9 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201311211
+#define CATALOG_VERSION_NO 201311261
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 6da4a50efe4..0117500a8a6 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -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");
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index f25a9de8d31..1bfd145da50 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -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);
diff --git a/src/test/regress/expected/create_function_3.out b/src/test/regress/expected/create_function_3.out
index e7952322dc2..486ae7adf71 100644
--- a/src/test/regress/expected/create_function_3.out
+++ b/src/test/regress/expected/create_function_3.out
@@ -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;
diff --git a/src/test/regress/sql/create_function_3.sql b/src/test/regress/sql/create_function_3.sql
index e2dd9a35a02..54b25e62dd7 100644
--- a/src/test/regress/sql/create_function_3.sql
+++ b/src/test/regress/sql/create_function_3.sql
@@ -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;