PostgreSQL Source Code  git master
plsample.c File Reference
#include "postgres.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/event_trigger.h"
#include "commands/trigger.h"
#include "executor/spi.h"
#include "funcapi.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Include dependency graph for plsample.c:

Go to the source code of this file.

Functions

 PG_FUNCTION_INFO_V1 (plsample_call_handler)
 
static Datum plsample_func_handler (PG_FUNCTION_ARGS)
 
static HeapTuple plsample_trigger_handler (PG_FUNCTION_ARGS)
 
Datum plsample_call_handler (PG_FUNCTION_ARGS)
 

Variables

 PG_MODULE_MAGIC
 

Function Documentation

◆ PG_FUNCTION_INFO_V1()

PG_FUNCTION_INFO_V1 ( plsample_call_handler  )

◆ plsample_call_handler()

Datum plsample_call_handler ( PG_FUNCTION_ARGS  )

Definition at line 39 of file plsample.c.

40 {
41  Datum retval = (Datum) 0;
42 
43  /*
44  * Many languages will require cleanup that happens even in the event of
45  * an error. That can happen in the PG_FINALLY block. If none is needed,
46  * this PG_TRY construct can be omitted.
47  */
48  PG_TRY();
49  {
50  /*
51  * Determine if called as function or trigger and call appropriate
52  * subhandler.
53  */
54  if (CALLED_AS_TRIGGER(fcinfo))
55  {
56  /*
57  * This function has been called as a trigger function, where
58  * (TriggerData *) fcinfo->context includes the information of the
59  * context.
60  */
61  retval = PointerGetDatum(plsample_trigger_handler(fcinfo));
62  }
63  else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
64  {
65  /*
66  * This function is called as an event trigger function, where
67  * (EventTriggerData *) fcinfo->context includes the information
68  * of the context.
69  *
70  * TODO: provide an example handler.
71  */
72  }
73  else
74  {
75  /* Regular function handler */
76  retval = plsample_func_handler(fcinfo);
77  }
78  }
79  PG_FINALLY();
80  {
81  }
82  PG_END_TRY();
83 
84  return retval;
85 }
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define PG_FINALLY(...)
Definition: elog.h:387
#define CALLED_AS_EVENT_TRIGGER(fcinfo)
Definition: event_trigger.h:43
static Datum plsample_func_handler(PG_FUNCTION_ARGS)
Definition: plsample.c:93
static HeapTuple plsample_trigger_handler(PG_FUNCTION_ARGS)
Definition: plsample.c:205
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
#define CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:26

References CALLED_AS_EVENT_TRIGGER, CALLED_AS_TRIGGER, PG_END_TRY, PG_FINALLY, PG_TRY, plsample_func_handler(), plsample_trigger_handler(), and PointerGetDatum().

◆ plsample_func_handler()

static Datum plsample_func_handler ( PG_FUNCTION_ARGS  )
static

Definition at line 93 of file plsample.c.

94 {
95  HeapTuple pl_tuple;
96  Datum ret;
97  char *source;
98  bool isnull;
99  FmgrInfo *arg_out_func;
100  Form_pg_type type_struct;
101  HeapTuple type_tuple;
102  Form_pg_proc pl_struct;
103  volatile MemoryContext proc_cxt = NULL;
104  Oid *argtypes;
105  char **argnames;
106  char *argmodes;
107  char *proname;
108  Form_pg_type pg_type_entry;
109  Oid result_typioparam;
110  Oid prorettype;
111  FmgrInfo result_in_func;
112  int numargs;
113 
114  /* Fetch the function's pg_proc entry. */
115  pl_tuple = SearchSysCache1(PROCOID,
116  ObjectIdGetDatum(fcinfo->flinfo->fn_oid));
117  if (!HeapTupleIsValid(pl_tuple))
118  elog(ERROR, "cache lookup failed for function %u",
119  fcinfo->flinfo->fn_oid);
120 
121  /*
122  * Extract and print the source text of the function. This can be used as
123  * a base for the function validation and execution.
124  */
125  pl_struct = (Form_pg_proc) GETSTRUCT(pl_tuple);
126  proname = pstrdup(NameStr(pl_struct->proname));
127  ret = SysCacheGetAttr(PROCOID, pl_tuple, Anum_pg_proc_prosrc, &isnull);
128  if (isnull)
129  elog(ERROR, "could not find source text of function \"%s\"",
130  proname);
132  ereport(NOTICE,
133  (errmsg("source text of function \"%s\": %s",
134  proname, source)));
135 
136  /*
137  * Allocate a context that will hold all the Postgres data for the
138  * procedure.
139  */
141  "PL/Sample function",
143 
144  arg_out_func = (FmgrInfo *) palloc0(fcinfo->nargs * sizeof(FmgrInfo));
145  numargs = get_func_arg_info(pl_tuple, &argtypes, &argnames, &argmodes);
146 
147  /*
148  * Iterate through all of the function arguments, printing each input
149  * value.
150  */
151  for (int i = 0; i < numargs; i++)
152  {
153  Oid argtype = pl_struct->proargtypes.values[i];
154  char *value;
155 
156  type_tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(argtype));
157  if (!HeapTupleIsValid(type_tuple))
158  elog(ERROR, "cache lookup failed for type %u", argtype);
159 
160  type_struct = (Form_pg_type) GETSTRUCT(type_tuple);
161  fmgr_info_cxt(type_struct->typoutput, &(arg_out_func[i]), proc_cxt);
162  ReleaseSysCache(type_tuple);
163 
164  value = OutputFunctionCall(&arg_out_func[i], fcinfo->args[i].value);
165  ereport(NOTICE,
166  (errmsg("argument: %d; name: %s; value: %s",
167  i, argnames[i], value)));
168  }
169 
170  /* Type of the result */
171  prorettype = pl_struct->prorettype;
172  ReleaseSysCache(pl_tuple);
173 
174  /*
175  * Get the required information for input conversion of the return value.
176  *
177  * If the function uses VOID as result, it is better to return NULL.
178  * Anyway, let's be honest. This is just a template, so there is not much
179  * we can do here. This returns NULL except if the result type is text,
180  * where the result is the source text of the function.
181  */
182  if (prorettype != TEXTOID)
183  PG_RETURN_NULL();
184 
185  type_tuple = SearchSysCache1(TYPEOID,
186  ObjectIdGetDatum(prorettype));
187  if (!HeapTupleIsValid(type_tuple))
188  elog(ERROR, "cache lookup failed for type %u", prorettype);
189  pg_type_entry = (Form_pg_type) GETSTRUCT(type_tuple);
190  result_typioparam = getTypeIOParam(type_tuple);
191 
192  fmgr_info_cxt(pg_type_entry->typinput, &result_in_func, proc_cxt);
193  ReleaseSysCache(type_tuple);
194 
195  ret = InputFunctionCall(&result_in_func, source, result_typioparam, -1);
196  PG_RETURN_DATUM(ret);
197 }
#define NameStr(name)
Definition: c.h:746
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:149
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition: fmgr.c:1530
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition: fmgr.c:1683
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
int get_func_arg_info(HeapTuple procTup, Oid **p_argtypes, char ***p_argnames, char **p_argmodes)
Definition: funcapi.c:1379
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
static struct @155 value
int i
Definition: isn.c:73
Oid getTypeIOParam(HeapTuple typeTuple)
Definition: lsyscache.c:2303
char * pstrdup(const char *in)
Definition: mcxt.c:1695
MemoryContext TopMemoryContext
Definition: mcxt.c:149
void * palloc0(Size size)
Definition: mcxt.c:1346
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136
NameData proname
Definition: pg_proc.h:35
static rewind_source * source
Definition: pg_rewind.c:89
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
static char * DatumGetCString(Datum X)
Definition: postgres.h:335
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
unsigned int Oid
Definition: postgres_ext.h:31
Definition: fmgr.h:57
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:479
Datum textout(PG_FUNCTION_ARGS)
Definition: varlena.c:590

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, DatumGetCString(), DirectFunctionCall1, elog, ereport, errmsg(), ERROR, fmgr_info_cxt(), get_func_arg_info(), GETSTRUCT, getTypeIOParam(), HeapTupleIsValid, i, InputFunctionCall(), NameStr, NOTICE, ObjectIdGetDatum(), OutputFunctionCall(), palloc0(), PG_RETURN_DATUM, PG_RETURN_NULL, proname, pstrdup(), ReleaseSysCache(), SearchSysCache1(), source, SysCacheGetAttr(), textout(), TopMemoryContext, and value.

Referenced by plsample_call_handler().

◆ plsample_trigger_handler()

static HeapTuple plsample_trigger_handler ( PG_FUNCTION_ARGS  )
static

Definition at line 205 of file plsample.c.

206 {
207  TriggerData *trigdata = (TriggerData *) fcinfo->context;
208  char *string;
209  volatile HeapTuple rettup;
210  HeapTuple pl_tuple;
211  Datum ret;
212  char *source;
213  bool isnull;
214  Form_pg_proc pl_struct;
215  char *proname;
217 
218  /* Make sure this is being called from a trigger. */
219  if (!CALLED_AS_TRIGGER(fcinfo))
220  elog(ERROR, "not called by trigger manager");
221 
222  /* Connect to the SPI manager */
223  if (SPI_connect() != SPI_OK_CONNECT)
224  elog(ERROR, "could not connect to SPI manager");
225 
226  rc = SPI_register_trigger_data(trigdata);
227  Assert(rc >= 0);
228 
229  /* Fetch the function's pg_proc entry. */
230  pl_tuple = SearchSysCache1(PROCOID,
231  ObjectIdGetDatum(fcinfo->flinfo->fn_oid));
232  if (!HeapTupleIsValid(pl_tuple))
233  elog(ERROR, "cache lookup failed for function %u",
234  fcinfo->flinfo->fn_oid);
235 
236  /*
237  * Code Retrieval
238  *
239  * Extract and print the source text of the function. This can be used as
240  * a base for the function validation and execution.
241  */
242  pl_struct = (Form_pg_proc) GETSTRUCT(pl_tuple);
243  proname = pstrdup(NameStr(pl_struct->proname));
244  ret = SysCacheGetAttr(PROCOID, pl_tuple, Anum_pg_proc_prosrc, &isnull);
245  if (isnull)
246  elog(ERROR, "could not find source text of function \"%s\"",
247  proname);
249  ereport(NOTICE,
250  (errmsg("source text of function \"%s\": %s",
251  proname, source)));
252 
253  /*
254  * We're done with the pg_proc tuple, so release it. (Note that the
255  * "proname" and "source" strings are now standalone copies.)
256  */
257  ReleaseSysCache(pl_tuple);
258 
259  /*
260  * Code Augmentation
261  *
262  * The source text may be augmented here, such as by wrapping it as the
263  * body of a function in the target language, prefixing a parameter list
264  * with names like TD_name, TD_relid, TD_table_name, TD_table_schema,
265  * TD_event, TD_when, TD_level, TD_NEW, TD_OLD, and args, using whatever
266  * types in the target language are convenient. The augmented text can be
267  * cached in a longer-lived memory context, or, if the target language
268  * uses a compilation step, that can be done here, caching the result of
269  * the compilation.
270  */
271 
272  /*
273  * Code Execution
274  *
275  * Here the function (the possibly-augmented source text, or the result of
276  * compilation if the target language uses such a step) should be
277  * executed, after binding values from the TriggerData struct to the
278  * appropriate parameters.
279  *
280  * In this example we just print a lot of info via ereport.
281  */
282 
283  PG_TRY();
284  {
285  ereport(NOTICE,
286  (errmsg("trigger name: %s", trigdata->tg_trigger->tgname)));
287  string = SPI_getrelname(trigdata->tg_relation);
288  ereport(NOTICE, (errmsg("trigger relation: %s", string)));
289 
290  string = SPI_getnspname(trigdata->tg_relation);
291  ereport(NOTICE, (errmsg("trigger relation schema: %s", string)));
292 
293  /* Example handling of different trigger aspects. */
294 
295  if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
296  {
297  ereport(NOTICE, (errmsg("triggered by INSERT")));
298  rettup = trigdata->tg_trigtuple;
299  }
300  else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
301  {
302  ereport(NOTICE, (errmsg("triggered by DELETE")));
303  rettup = trigdata->tg_trigtuple;
304  }
305  else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
306  {
307  ereport(NOTICE, (errmsg("triggered by UPDATE")));
308  rettup = trigdata->tg_trigtuple;
309  }
310  else if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event))
311  {
312  ereport(NOTICE, (errmsg("triggered by TRUNCATE")));
313  rettup = trigdata->tg_trigtuple;
314  }
315  else
316  elog(ERROR, "unrecognized event: %u", trigdata->tg_event);
317 
318  if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
319  ereport(NOTICE, (errmsg("triggered BEFORE")));
320  else if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
321  ereport(NOTICE, (errmsg("triggered AFTER")));
322  else if (TRIGGER_FIRED_INSTEAD(trigdata->tg_event))
323  ereport(NOTICE, (errmsg("triggered INSTEAD OF")));
324  else
325  elog(ERROR, "unrecognized when: %u", trigdata->tg_event);
326 
327  if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
328  ereport(NOTICE, (errmsg("triggered per row")));
329  else if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
330  ereport(NOTICE, (errmsg("triggered per statement")));
331  else
332  elog(ERROR, "unrecognized level: %u", trigdata->tg_event);
333 
334  /*
335  * Iterate through all of the trigger arguments, printing each input
336  * value.
337  */
338  for (int i = 0; i < trigdata->tg_trigger->tgnargs; i++)
339  ereport(NOTICE,
340  (errmsg("trigger arg[%i]: %s", i,
341  trigdata->tg_trigger->tgargs[i])));
342  }
343  PG_CATCH();
344  {
345  /* Error cleanup code would go here */
346  PG_RE_THROW();
347  }
348  PG_END_TRY();
349 
350  if (SPI_finish() != SPI_OK_FINISH)
351  elog(ERROR, "SPI_finish() failed");
352 
353  return rettup;
354 }
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:182
#define Assert(condition)
Definition: c.h:858
#define PG_RE_THROW()
Definition: elog.h:411
#define PG_CATCH(...)
Definition: elog.h:380
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
char * SPI_getrelname(Relation rel)
Definition: spi.c:1323
int SPI_connect(void)
Definition: spi.c:94
int SPI_finish(void)
Definition: spi.c:182
int SPI_register_trigger_data(TriggerData *tdata)
Definition: spi.c:3344
char * SPI_getnspname(Relation rel)
Definition: spi.c:1329
#define SPI_OK_CONNECT
Definition: spi.h:82
#define SPI_OK_FINISH
Definition: spi.h:83
Relation tg_relation
Definition: trigger.h:35
TriggerEvent tg_event
Definition: trigger.h:34
Trigger * tg_trigger
Definition: trigger.h:38
HeapTuple tg_trigtuple
Definition: trigger.h:36
char * tgname
Definition: reltrigger.h:27
int16 tgnargs
Definition: reltrigger.h:38
char ** tgargs
Definition: reltrigger.h:41
#define TRIGGER_FIRED_FOR_STATEMENT(event)
Definition: trigger.h:125
#define TRIGGER_FIRED_BY_DELETE(event)
Definition: trigger.h:113
#define TRIGGER_FIRED_BEFORE(event)
Definition: trigger.h:128
#define TRIGGER_FIRED_FOR_ROW(event)
Definition: trigger.h:122
#define TRIGGER_FIRED_AFTER(event)
Definition: trigger.h:131
#define TRIGGER_FIRED_BY_TRUNCATE(event)
Definition: trigger.h:119
#define TRIGGER_FIRED_BY_INSERT(event)
Definition: trigger.h:110
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition: trigger.h:116
#define TRIGGER_FIRED_INSTEAD(event)
Definition: trigger.h:134

References Assert, CALLED_AS_TRIGGER, DatumGetCString(), DirectFunctionCall1, elog, ereport, errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, i, if(), NameStr, NOTICE, ObjectIdGetDatum(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PG_USED_FOR_ASSERTS_ONLY, proname, pstrdup(), ReleaseSysCache(), SearchSysCache1(), source, SPI_connect(), SPI_finish(), SPI_getnspname(), SPI_getrelname(), SPI_OK_CONNECT, SPI_OK_FINISH, SPI_register_trigger_data(), SysCacheGetAttr(), textout(), TriggerData::tg_event, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, Trigger::tgargs, Trigger::tgname, Trigger::tgnargs, TRIGGER_FIRED_AFTER, TRIGGER_FIRED_BEFORE, TRIGGER_FIRED_BY_DELETE, TRIGGER_FIRED_BY_INSERT, TRIGGER_FIRED_BY_TRUNCATE, TRIGGER_FIRED_BY_UPDATE, TRIGGER_FIRED_FOR_ROW, TRIGGER_FIRED_FOR_STATEMENT, and TRIGGER_FIRED_INSTEAD.

Referenced by plsample_call_handler().

Variable Documentation

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 28 of file plsample.c.