1+ /*
2+ pg_get_functiondef_extend.c
3+ The implementation of pg_get_functiondef('function_name', 'function_name', ...)
4+ */
5+ #include "postgres.h"
6+ #include "fmgr.h"
7+ #include "utils/elog.h"
8+ #include "lib/stringinfo.h"
9+ #include "executor/spi.h"
10+ #include "utils/array.h"
11+ #include "catalog/pg_proc.h"
12+ #include "catalog/pg_type_d.h"
13+ #include "funcapi.h"
14+ #include "utils/builtins.h"
15+ #include "utils/catcache.h"
16+ #include "utils/lsyscache.h"
17+ #include "utils/syscache.h"
18+ #include "access/htup_details.h"
19+
20+ typedef struct FunctionInfoData * FunctionInfo ;
21+ struct FunctionInfoData
22+ {
23+ char * * function_name ; /* The user's input */
24+ int cursor ; /* The cursor of the function_name[] */
25+ int count_of_tuples ; /* How many tuples will return? */
26+ TupleDesc result_desc ; /* Describe the tuple */
27+ AttInMetadata * result_tuple_meta ; /* Describe the tuple's attribute */
28+ };
29+
30+ /*
31+ GetFuncDefByName
32+ Export the oid based on the function name, the use the oid get the definition
33+ */
34+ char * GetFuncDefByName (char * function_name );
35+ char * GetFuncDefByName (char * function_name )
36+ {
37+ CatCList * catlist = NULL ;
38+ StringInfoData result = {};
39+ initStringInfo (& result );
40+ catlist = SearchSysCacheList1 (PROCNAMEARGSNSP , CStringGetDatum (function_name ));
41+
42+ if (catlist -> n_members == 0 )
43+ {
44+ appendStringInfo (& result , "/* Not Found */" );
45+ }
46+ else
47+ {
48+ /* A function name may correspond to multiple different results */
49+ for (int i = 0 ; i < catlist -> n_members ; i ++ )
50+ {
51+ HeapTuple proctup = & catlist -> members [i ]-> tuple ;
52+ Form_pg_proc proc = (Form_pg_proc )GETSTRUCT (proctup );
53+ if (proc -> prokind == PROKIND_AGGREGATE )
54+ {
55+ appendStringInfo (& result , "/* Not support aggregate function, oid: %d */\n" , proc -> oid );
56+ continue ;
57+ }
58+ appendStringInfo (& result , "/* oid: %d */\n" , proc -> oid );
59+ appendStringInfo (& result , "%s" , text_to_cstring (DatumGetTextP (DirectFunctionCall1 (pg_get_functiondef , proc -> oid ))));
60+ }
61+ }
62+ ReleaseCatCacheList (catlist );
63+ return result .data ;
64+ }
65+
66+ PG_FUNCTION_INFO_V1 (pg_get_functiondef_extend );
67+
68+ Datum pg_get_functiondef_extend (PG_FUNCTION_ARGS )
69+ {
70+ FuncCallContext * funcctx = NULL ;
71+ FunctionInfo info = NULL ;
72+
73+ if (SRF_IS_FIRSTCALL ())
74+ {
75+ ArrayType * arguments_raw ;
76+ int count_of_arguments ;
77+ Datum * arguments ;
78+ MemoryContext old_context ;
79+
80+ funcctx = SRF_FIRSTCALL_INIT ();
81+ old_context = MemoryContextSwitchTo (funcctx -> multi_call_memory_ctx );
82+
83+ arguments_raw = PG_GETARG_ARRAYTYPE_P (0 );
84+ deconstruct_array_builtin ((ArrayType * )arguments_raw , TEXTOID , & arguments , NULL , & count_of_arguments );
85+
86+ info = (FunctionInfo )palloc0 (sizeof (struct FunctionInfoData ));
87+ funcctx -> user_fctx = info ;
88+
89+ info -> function_name = palloc0 (count_of_arguments * sizeof (char * ));
90+ for (int i = 0 ; i < count_of_arguments ; i ++ )
91+ {
92+ info -> function_name [i ] = text_to_cstring ((text * )arguments [i ]);
93+ }
94+
95+ info -> cursor = 0 ;
96+ info -> count_of_tuples = count_of_arguments ;
97+
98+ if (get_call_result_type (fcinfo , NULL , & info -> result_desc ) != TYPEFUNC_COMPOSITE )
99+ {
100+ ereport (ERROR , (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ), errmsg ("function returning record called in context that cannot accept type record" )));
101+ }
102+ info -> result_tuple_meta = TupleDescGetAttInMetadata (info -> result_desc );
103+ MemoryContextSwitchTo (old_context );
104+ }
105+
106+ funcctx = SRF_PERCALL_SETUP ();
107+ info = (FunctionInfo )(funcctx -> user_fctx );
108+
109+ if (info -> cursor == info -> count_of_tuples )
110+ {
111+ SRF_RETURN_DONE (funcctx );
112+ }
113+ else
114+ {
115+ HeapTuple tuple ;
116+ Datum tuple_return ;
117+ char * * values ;
118+ values = palloc0 (sizeof (char * ) * 2 );
119+ values [0 ] = pstrdup (info -> function_name [info -> cursor ]);
120+ values [1 ] = GetFuncDefByName (info -> function_name [info -> cursor ]);
121+ info -> cursor ++ ;
122+ tuple = BuildTupleFromCStrings (info -> result_tuple_meta , values );
123+ tuple_return = HeapTupleGetDatum (tuple );
124+ SRF_RETURN_NEXT (funcctx , tuple_return );
125+ }
126+ PG_RETURN_NULL ();
127+ }
0 commit comments