PostgreSQL Source Code  git master
plsample.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * plsample.c
4  * Handler for the PL/Sample procedural language
5  *
6  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/test/modules/plsample/plsample.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #include "postgres.h"
17 
18 #include "catalog/pg_proc.h"
19 #include "catalog/pg_type.h"
20 #include "commands/event_trigger.h"
21 #include "commands/trigger.h"
22 #include "funcapi.h"
23 #include "utils/builtins.h"
24 #include "utils/lsyscache.h"
25 #include "utils/syscache.h"
26 
28 
30 
32 
33 /*
34  * Handle function, procedure, and trigger calls.
35  */
36 Datum
38 {
39  Datum retval = (Datum) 0;
40 
41  PG_TRY();
42  {
43  /*
44  * Determine if called as function or trigger and call appropriate
45  * subhandler.
46  */
47  if (CALLED_AS_TRIGGER(fcinfo))
48  {
49  /*
50  * This function has been called as a trigger function, where
51  * (TriggerData *) fcinfo->context includes the information of the
52  * context.
53  */
54  }
55  else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
56  {
57  /*
58  * This function is called as an event trigger function, where
59  * (EventTriggerData *) fcinfo->context includes the information
60  * of the context.
61  */
62  }
63  else
64  {
65  /* Regular function handler */
66  retval = plsample_func_handler(fcinfo);
67  }
68  }
69  PG_FINALLY();
70  {
71  }
72  PG_END_TRY();
73 
74  return retval;
75 }
76 
77 /*
78  * plsample_func_handler
79  *
80  * Function called by the call handler for function execution.
81  */
82 static Datum
84 {
85  HeapTuple pl_tuple;
86  Datum ret;
87  char *source;
88  bool isnull;
89  FmgrInfo *arg_out_func;
90  Form_pg_type type_struct;
91  HeapTuple type_tuple;
92  Form_pg_proc pl_struct;
93  volatile MemoryContext proc_cxt = NULL;
94  Oid *argtypes;
95  char **argnames;
96  char *argmodes;
97  char *proname;
98  Form_pg_type pg_type_entry;
99  Oid result_typioparam;
100  Oid prorettype;
101  FmgrInfo result_in_func;
102  int numargs;
103 
104  /* Fetch the source text of the function. */
105  pl_tuple = SearchSysCache(PROCOID,
106  ObjectIdGetDatum(fcinfo->flinfo->fn_oid), 0, 0, 0);
107  if (!HeapTupleIsValid(pl_tuple))
108  elog(ERROR, "cache lookup failed for function %u",
109  fcinfo->flinfo->fn_oid);
110 
111  /*
112  * Extract and print the source text of the function. This can be used as
113  * a base for the function validation and execution.
114  */
115  pl_struct = (Form_pg_proc) GETSTRUCT(pl_tuple);
116  proname = pstrdup(NameStr(pl_struct->proname));
117  ret = SysCacheGetAttr(PROCOID, pl_tuple, Anum_pg_proc_prosrc, &isnull);
118  if (isnull)
119  elog(ERROR, "could not find source text of function \"%s\"",
120  proname);
122  ereport(NOTICE,
123  (errmsg("source text of function \"%s\": %s",
124  proname, source)));
125 
126  /*
127  * Allocate a context that will hold all the Postgres data for the
128  * procedure.
129  */
131  "PL/Sample function",
133 
134  arg_out_func = (FmgrInfo *) palloc0(fcinfo->nargs * sizeof(FmgrInfo));
135  numargs = get_func_arg_info(pl_tuple, &argtypes, &argnames, &argmodes);
136 
137  /*
138  * Iterate through all of the function arguments, printing each input
139  * value.
140  */
141  for (int i = 0; i < numargs; i++)
142  {
143  Oid argtype = pl_struct->proargtypes.values[i];
144  char *value;
145 
146  type_tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(argtype));
147  if (!HeapTupleIsValid(type_tuple))
148  elog(ERROR, "cache lookup failed for type %u", argtype);
149 
150  type_struct = (Form_pg_type) GETSTRUCT(type_tuple);
151  fmgr_info_cxt(type_struct->typoutput, &(arg_out_func[i]), proc_cxt);
152  ReleaseSysCache(type_tuple);
153 
154  value = OutputFunctionCall(&arg_out_func[i], fcinfo->args[i].value);
155  ereport(NOTICE,
156  (errmsg("argument: %d; name: %s; value: %s",
157  i, argnames[i], value)));
158  }
159 
160  /* Type of the result */
161  prorettype = pl_struct->prorettype;
162  ReleaseSysCache(pl_tuple);
163 
164  /*
165  * Get the required information for input conversion of the return value.
166  *
167  * If the function uses VOID as result, it is better to return NULL.
168  * Anyway, let's be honest. This is just a template, so there is not much
169  * we can do here. This returns NULL except if the result type is text,
170  * where the result is the source text of the function.
171  */
172  if (prorettype != TEXTOID)
173  PG_RETURN_NULL();
174 
175  type_tuple = SearchSysCache1(TYPEOID,
176  ObjectIdGetDatum(prorettype));
177  if (!HeapTupleIsValid(type_tuple))
178  elog(ERROR, "cache lookup failed for type %u", prorettype);
179  pg_type_entry = (Form_pg_type) GETSTRUCT(type_tuple);
180  result_typioparam = getTypeIOParam(type_tuple);
181 
182  fmgr_info_cxt(pg_type_entry->typinput, &result_in_func, proc_cxt);
183  ReleaseSysCache(type_tuple);
184 
185  ret = InputFunctionCall(&result_in_func, source, result_typioparam, -1);
186  PG_RETURN_DATUM(ret);
187 }
HeapTuple SearchSysCache(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4)
Definition: syscache.c:1102
PG_MODULE_MAGIC
Definition: plsample.c:27
Definition: fmgr.h:56
#define CALLED_AS_EVENT_TRIGGER(fcinfo)
Definition: event_trigger.h:40
#define AllocSetContextCreate
Definition: memutils.h:170
NameData proname
Definition: pg_proc.h:35
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
char * pstrdup(const char *in)
Definition: mcxt.c:1187
Datum textout(PG_FUNCTION_ARGS)
Definition: varlena.c:569
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:1094
static Datum plsample_func_handler(PG_FUNCTION_ARGS)
Definition: plsample.c:83
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:626
unsigned int Oid
Definition: postgres_ext.h:31
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1577
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define DatumGetCString(X)
Definition: postgres.h:566
PG_FUNCTION_INFO_V1(plsample_call_handler)
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:136
MemoryContext TopMemoryContext
Definition: mcxt.c:44
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1115
#define PG_FINALLY()
Definition: elog.h:326
void * palloc0(Size size)
Definition: mcxt.c:981
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1163
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1376
Datum plsample_call_handler(PG_FUNCTION_ARGS)
Definition: plsample.c:37
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:133
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1533
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:155
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:25
static rewind_source * source
Definition: pg_rewind.c:79
FormData_pg_type * Form_pg_type
Definition: pg_type.h:255
int errmsg(const char *fmt,...)
Definition: elog.c:902
#define elog(elevel,...)
Definition: elog.h:228
int i
Oid getTypeIOParam(HeapTuple typeTuple)
Definition: lsyscache.c:2196
#define NameStr(name)
Definition: c.h:677
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_TRY()
Definition: elog.h:309
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_END_TRY()
Definition: elog.h:334