PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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-2024, 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"
21#include "commands/trigger.h"
22#include "executor/spi.h"
23#include "funcapi.h"
24#include "utils/fmgrprotos.h"
25#include "utils/lsyscache.h"
26#include "utils/syscache.h"
27
29
31
34
35/*
36 * Handle function, procedure, and trigger calls.
37 */
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 */
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}
86
87/*
88 * plsample_func_handler
89 *
90 * Function called by the call handler for function execution.
91 */
92static Datum
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);
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);
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)
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}
198
199/*
200 * plsample_trigger_handler
201 *
202 * Function called by the call handler for trigger execution.
203 */
204static HeapTuple
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 SPI_connect();
224
225 rc = SPI_register_trigger_data(trigdata);
226 Assert(rc >= 0);
227
228 /* Fetch the function's pg_proc entry. */
229 pl_tuple = SearchSysCache1(PROCOID,
230 ObjectIdGetDatum(fcinfo->flinfo->fn_oid));
231 if (!HeapTupleIsValid(pl_tuple))
232 elog(ERROR, "cache lookup failed for function %u",
233 fcinfo->flinfo->fn_oid);
234
235 /*
236 * Code Retrieval
237 *
238 * Extract and print the source text of the function. This can be used as
239 * a base for the function validation and execution.
240 */
241 pl_struct = (Form_pg_proc) GETSTRUCT(pl_tuple);
242 proname = pstrdup(NameStr(pl_struct->proname));
243 ret = SysCacheGetAttr(PROCOID, pl_tuple, Anum_pg_proc_prosrc, &isnull);
244 if (isnull)
245 elog(ERROR, "could not find source text of function \"%s\"",
246 proname);
249 (errmsg("source text of function \"%s\": %s",
250 proname, source)));
251
252 /*
253 * We're done with the pg_proc tuple, so release it. (Note that the
254 * "proname" and "source" strings are now standalone copies.)
255 */
256 ReleaseSysCache(pl_tuple);
257
258 /*
259 * Code Augmentation
260 *
261 * The source text may be augmented here, such as by wrapping it as the
262 * body of a function in the target language, prefixing a parameter list
263 * with names like TD_name, TD_relid, TD_table_name, TD_table_schema,
264 * TD_event, TD_when, TD_level, TD_NEW, TD_OLD, and args, using whatever
265 * types in the target language are convenient. The augmented text can be
266 * cached in a longer-lived memory context, or, if the target language
267 * uses a compilation step, that can be done here, caching the result of
268 * the compilation.
269 */
270
271 /*
272 * Code Execution
273 *
274 * Here the function (the possibly-augmented source text, or the result of
275 * compilation if the target language uses such a step) should be
276 * executed, after binding values from the TriggerData struct to the
277 * appropriate parameters.
278 *
279 * In this example we just print a lot of info via ereport.
280 */
281
282 PG_TRY();
283 {
285 (errmsg("trigger name: %s", trigdata->tg_trigger->tgname)));
286 string = SPI_getrelname(trigdata->tg_relation);
287 ereport(NOTICE, (errmsg("trigger relation: %s", string)));
288
289 string = SPI_getnspname(trigdata->tg_relation);
290 ereport(NOTICE, (errmsg("trigger relation schema: %s", string)));
291
292 /* Example handling of different trigger aspects. */
293
294 if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
295 {
296 ereport(NOTICE, (errmsg("triggered by INSERT")));
297 rettup = trigdata->tg_trigtuple;
298 }
299 else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
300 {
301 ereport(NOTICE, (errmsg("triggered by DELETE")));
302 rettup = trigdata->tg_trigtuple;
303 }
304 else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
305 {
306 ereport(NOTICE, (errmsg("triggered by UPDATE")));
307 rettup = trigdata->tg_trigtuple;
308 }
309 else if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event))
310 {
311 ereport(NOTICE, (errmsg("triggered by TRUNCATE")));
312 rettup = trigdata->tg_trigtuple;
313 }
314 else
315 elog(ERROR, "unrecognized event: %u", trigdata->tg_event);
316
317 if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
318 ereport(NOTICE, (errmsg("triggered BEFORE")));
319 else if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
320 ereport(NOTICE, (errmsg("triggered AFTER")));
321 else if (TRIGGER_FIRED_INSTEAD(trigdata->tg_event))
322 ereport(NOTICE, (errmsg("triggered INSTEAD OF")));
323 else
324 elog(ERROR, "unrecognized when: %u", trigdata->tg_event);
325
326 if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
327 ereport(NOTICE, (errmsg("triggered per row")));
328 else if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
329 ereport(NOTICE, (errmsg("triggered per statement")));
330 else
331 elog(ERROR, "unrecognized level: %u", trigdata->tg_event);
332
333 /*
334 * Iterate through all of the trigger arguments, printing each input
335 * value.
336 */
337 for (int i = 0; i < trigdata->tg_trigger->tgnargs; i++)
339 (errmsg("trigger arg[%i]: %s", i,
340 trigdata->tg_trigger->tgargs[i])));
341 }
342 PG_CATCH();
343 {
344 /* Error cleanup code would go here */
345 PG_RE_THROW();
346 }
347 PG_END_TRY();
348
349 if (SPI_finish() != SPI_OK_FINISH)
350 elog(ERROR, "SPI_finish() failed");
351
352 return rettup;
353}
#define NameStr(name)
Definition: c.h:700
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:201
#define Assert(condition)
Definition: c.h:812
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define PG_RE_THROW()
Definition: elog.h:412
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define ERROR
Definition: elog.h:39
#define PG_CATCH(...)
Definition: elog.h:381
#define elog(elevel,...)
Definition: elog.h:225
#define NOTICE
Definition: elog.h:35
#define PG_FINALLY(...)
Definition: elog.h:388
#define ereport(elevel,...)
Definition: elog.h:149
#define CALLED_AS_EVENT_TRIGGER(fcinfo)
Definition: event_trigger.h:49
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:641
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
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 @161 value
int i
Definition: isn.c:72
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
Oid getTypeIOParam(HeapTuple typeTuple)
Definition: lsyscache.c:2303
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext TopMemoryContext
Definition: mcxt.c:149
#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
PG_MODULE_MAGIC
Definition: plsample.c:28
static Datum plsample_func_handler(PG_FUNCTION_ARGS)
Definition: plsample.c:93
PG_FUNCTION_INFO_V1(plsample_call_handler)
Datum plsample_call_handler(PG_FUNCTION_ARGS)
Definition: plsample.c:39
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
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static char * DatumGetCString(Datum X)
Definition: postgres.h:335
unsigned int Oid
Definition: postgres_ext.h:31
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:3364
char * SPI_getnspname(Relation rel)
Definition: spi.c:1332
char * SPI_getrelname(Relation rel)
Definition: spi.c:1326
#define SPI_OK_FINISH
Definition: spi.h:83
Definition: fmgr.h:57
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
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
#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 CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:26
#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
Datum textout(PG_FUNCTION_ARGS)
Definition: varlena.c:590