88 *
99 * Copyright (c) 2000-2009, PostgreSQL Global Development Group
1010 *
11- * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.208 2009/04/08 22:29:30 tgl Exp $
11+ * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.209 2009/04/21 15:49:06 momjian Exp $
1212 */
1313#include "postgres_fe.h"
1414
@@ -183,15 +183,43 @@ describeTablespaces(const char *pattern, bool verbose)
183183
184184
185185/* \df
186- * Takes an optional regexp to select particular functions
186+ * Takes an optional regexp to select particular functions.
187+ *
188+ * As with \d, you can specify the kinds of functions you want:
189+ *
190+ * a for aggregates
191+ * n for normal
192+ * t for trigger
193+ * w for window
194+ *
195+ * and you can mix and match these in any order.
187196 */
188197bool
189- describeFunctions (const char * pattern ,bool verbose ,bool showSystem )
198+ describeFunctions (const char * functypes , const char * pattern ,bool verbose ,bool showSystem )
190199{
200+ bool showAggregate = strchr (functypes ,'a' )!= NULL ;
201+ bool showNormal = strchr (functypes ,'n' )!= NULL ;
202+ bool showTrigger = strchr (functypes ,'t' )!= NULL ;
203+ bool showWindow = strchr (functypes ,'w' )!= NULL ;
204+
191205PQExpBufferData buf ;
192206PGresult * res ;
193207printQueryOpt myopt = pset .popt ;
194208
209+ if (showWindow && pset .sversion < 80400 )
210+ {
211+ fprintf (stderr ,_ ("\\df does not take a \"w\" decorator in %d.%d.\n" ),
212+ pset .sversion /10000 , (pset .sversion /100 ) %100 );
213+ return true;
214+ }
215+
216+ if (!showAggregate && !showNormal && !showTrigger && !showWindow )
217+ {
218+ showAggregate = showNormal = showTrigger = true;
219+ if (pset .sversion >=80400 )
220+ showWindow = true;
221+ }
222+
195223initPQExpBuffer (& buf );
196224
197225printfPQExpBuffer (& buf ,
@@ -203,9 +231,21 @@ describeFunctions(const char *pattern, bool verbose, bool showSystem)
203231if (pset .sversion >=80400 )
204232appendPQExpBuffer (& buf ,
205233" pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
206- " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\"" ,
234+ " pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
235+ " CASE\n"
236+ " WHEN p.proisagg THEN '%s'\n"
237+ " WHEN p.proiswindow THEN '%s'\n"
238+ " WHEN pg_catalog.pg_get_function_result(p.oid) = 'trigger' THEN '%s'\n"
239+ " ELSE '%s'\n"
240+ "END as \"%s\"" ,
207241gettext_noop ("Result data type" ),
208- gettext_noop ("Argument data types" ));
242+ gettext_noop ("Argument data types" ),
243+ /* translator: "agg" is short for "aggregate" */
244+ gettext_noop ("agg" ),
245+ gettext_noop ("window" ),
246+ gettext_noop ("trigger" ),
247+ gettext_noop ("normal" ),
248+ gettext_noop ("Type" ));
209249else if (pset .sversion >=80100 )
210250appendPQExpBuffer (& buf ,
211251" CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
@@ -238,16 +278,36 @@ describeFunctions(const char *pattern, bool verbose, bool showSystem)
238278" FROM\n"
239279" pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)\n"
240280" ), ', ')\n"
281+ " END AS \"%s\",\n"
282+ " CASE\n"
283+ " WHEN p.proisagg THEN '%s'\n"
284+ " WHEN 'trigger' = pg_catalog.format_type(p.prorettype, NULL) THEN '%s'\n"
285+ " ELSE '%s'\n"
241286" END AS \"%s\"" ,
242287gettext_noop ("Result data type" ),
243- gettext_noop ("Argument data types" ));
288+ gettext_noop ("Argument data types" ),
289+ /* translator: "agg" is short for "aggregate" */
290+ gettext_noop ("agg" ),
291+ gettext_noop ("trigger" ),
292+ gettext_noop ("normal" ),
293+ gettext_noop ("Type" ));
244294else
245295appendPQExpBuffer (& buf ,
246296" CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||\n"
247297" pg_catalog.format_type(p.prorettype, NULL) as \"%s\",\n"
248- " pg_catalog.oidvectortypes(p.proargtypes) as \"%s\"" ,
298+ " pg_catalog.oidvectortypes(p.proargtypes) as \"%s\",\n"
299+ " CASE\n"
300+ " WHEN p.proisagg THEN '%s'\n"
301+ " WHEN 'trigger' = pg_catalog.format_type(p.prorettype, NULL) THEN '%s'\n"
302+ " ELSE '%s'\n"
303+ " END AS \"%s\"" ,
249304gettext_noop ("Result data type" ),
250- gettext_noop ("Argument data types" ));
305+ gettext_noop ("Argument data types" ),
306+ /* translator: "agg" is short for "aggregate" */
307+ gettext_noop ("agg" ),
308+ gettext_noop ("trigger" ),
309+ gettext_noop ("normal" ),
310+ gettext_noop ("Type" ));
251311
252312if (verbose )
253313appendPQExpBuffer (& buf ,
@@ -274,16 +334,63 @@ describeFunctions(const char *pattern, bool verbose, bool showSystem)
274334appendPQExpBuffer (& buf ,
275335" LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang\n" );
276336
277- appendPQExpBuffer (& buf ,"WHERE NOT p.proisagg\n" );
337+ processSQLNamePattern (pset .db ,& buf ,pattern , false, true,
338+ "n.nspname" ,"p.proname" ,NULL ,
339+ "pg_catalog.pg_function_is_visible(p.oid)" );
340+
341+ if (showNormal && showAggregate && showTrigger && showWindow )
342+ /* Do nothing */ ;
343+ else if (showNormal )
344+ {
345+ if (!showWindow && pset .sversion >=80400 )
346+ appendPQExpBuffer (& buf ," AND NOT p.proiswindow\n" );
347+ if (!showAggregate )
348+ appendPQExpBuffer (& buf ," AND NOT p.proisagg\n" );
349+ if (!showTrigger )
350+ {
351+ if (pset .sversion >=80400 )
352+ appendPQExpBuffer (& buf ,
353+ " AND pg_catalog.pg_get_function_result(p.oid) <> 'trigger'\n" );
354+ else
355+ appendPQExpBuffer (& buf ,
356+ " AND pg_catalog.format_type(p.prorettype, NULL) <> 'trigger'\n" );
357+ }
358+ }
359+ else
360+ {
361+ bool needs_or = false;
362+
363+ appendPQExpBuffer (& buf ," AND (\n " );
364+ if (showAggregate )
365+ {
366+ appendPQExpBuffer (& buf ,"p.proisagg\n" );
367+ needs_or = true;
368+ }
369+ if (showTrigger )
370+ {
371+ if (needs_or )
372+ appendPQExpBuffer (& buf ," OR " );
373+ if (pset .sversion >=80400 )
374+ appendPQExpBuffer (& buf ,
375+ "pg_catalog.pg_get_function_result(p.oid) = 'trigger'\n" );
376+ else
377+ appendPQExpBuffer (& buf ,
378+ "'trigger' <> pg_catalog.format_type(p.prorettype, NULL)\n" );
379+ needs_or = true;
380+ }
381+ if (showWindow )
382+ {
383+ if (needs_or )
384+ appendPQExpBuffer (& buf ," OR " );
385+ appendPQExpBuffer (& buf ,"p.proiswindow\n" );
386+ }
387+ appendPQExpBuffer (& buf ," )\n" );
388+ }
278389
279390if (!showSystem && !pattern )
280391appendPQExpBuffer (& buf ," AND n.nspname <> 'pg_catalog'\n"
281392" AND n.nspname <> 'information_schema'\n" );
282393
283- processSQLNamePattern (pset .db ,& buf ,pattern , true, false,
284- "n.nspname" ,"p.proname" ,NULL ,
285- "pg_catalog.pg_function_is_visible(p.oid)" );
286-
287394appendPQExpBuffer (& buf ,"ORDER BY 1, 2, 4;" );
288395
289396res = PSQLexec (buf .data , false);