]> granicus.if.org Git - postgresql/commitdiff
Implement information_schema.parameters.parameter_default column
authorPeter Eisentraut <peter_e@gmx.net>
Wed, 27 Nov 2013 04:18:58 +0000 (23:18 -0500)
committerPeter Eisentraut <peter_e@gmx.net>
Wed, 27 Nov 2013 04:21:35 +0000 (23:21 -0500)
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>
doc/src/sgml/information_schema.sgml
src/backend/catalog/information_schema.sql
src/backend/utils/adt/ruleutils.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/test/regress/expected/create_function_3.out
src/test/regress/sql/create_function_3.sql

index 22e17bb5e6917dbeaaf3931454905a1ddb7b2c20..22f43c8a5bf27c1dbc89a47507e9b6349821cb9e 100644 (file)
@@ -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>
index c5f7a8b21008b422b9ec47a0dbe9389dfb6a6bdd..fd706e3479ebd0cc7908da7636df7b8b60ff3d32 100644 (file)
@@ -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
index 29a1027a1006998e66f3d7d4f901d5ac9bffc03d..348f620f2a4fa6d30faa5e862f8abe1470d942bc 100644 (file)
@@ -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
index c783b2628174bdd459f739061a68d1ae3e52203b..759395a24b942be8480456b0bf85f37f6025d847 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201311211
+#define CATALOG_VERSION_NO     201311261
 
 #endif
index 6da4a50efe4a9bb74f962d2276b13dfdb930f7b9..0117500a8a6de1d5803649e13138dc0a6bb4d54f 100644 (file)
@@ -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");
index f25a9de8d317f3157ce057afd047365337510a36..1bfd145da502d3661c262eb964eced52bbe8ff4c 100644 (file)
@@ -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);
index e7952322dc2ac59c19b6a198a8ca386dee0873a8..486ae7adf7131974ea0bab8259f5da4ca3f90bb1 100644 (file)
@@ -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;
index e2dd9a35a02f7845c524da378aca61611c85cdce..54b25e62dd7eb82c147167e1e82cd7ffd215677e 100644 (file)
@@ -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;