PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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/builtins.h"
25#include "utils/fmgrprotos.h"
26#include "utils/lsyscache.h"
27#include "utils/syscache.h"
28
30
32
35
36/*
37 * Handle function, procedure, and trigger calls.
38 */
41{
42 Datum retval = (Datum) 0;
43
44 /*
45 * Many languages will require cleanup that happens even in the event of
46 * an error. That can happen in the PG_FINALLY block. If none is needed,
47 * this PG_TRY construct can be omitted.
48 */
49 PG_TRY();
50 {
51 /*
52 * Determine if called as function or trigger and call appropriate
53 * subhandler.
54 */
55 if (CALLED_AS_TRIGGER(fcinfo))
56 {
57 /*
58 * This function has been called as a trigger function, where
59 * (TriggerData *) fcinfo->context includes the information of the
60 * context.
61 */
63 }
64 else if (CALLED_AS_EVENT_TRIGGER(fcinfo))
65 {
66 /*
67 * This function is called as an event trigger function, where
68 * (EventTriggerData *) fcinfo->context includes the information
69 * of the context.
70 *
71 * TODO: provide an example handler.
72 */
73 }
74 else
75 {
76 /* Regular function handler */
77 retval = plsample_func_handler(fcinfo);
78 }
79 }
80 PG_FINALLY();
81 {
82 }
83 PG_END_TRY();
84
85 return retval;
86}
87
88/*
89 * plsample_func_handler
90 *
91 * Function called by the call handler for function execution.
92 */
93static Datum
95{
97 Datum ret;
98 char *source;
99 bool isnull;
100 FmgrInfo *arg_out_func;
104 volatile MemoryContext proc_cxt = NULL;
105 Oid *argtypes;
106 char **argnames;
107 char *argmodes;
108 char *proname;
110 Oid result_typioparam;
111 Oid prorettype;
112 FmgrInfo result_in_func;
113 int numargs;
114
115 /* Fetch the function's pg_proc entry. */
117 ObjectIdGetDatum(fcinfo->flinfo->fn_oid));
119 elog(ERROR, "cache lookup failed for function %u",
120 fcinfo->flinfo->fn_oid);
121
122 /*
123 * Extract and print the source text of the function. This can be used as
124 * a base for the function validation and execution.
125 */
127 proname = pstrdup(NameStr(pl_struct->proname));
129 if (isnull)
130 elog(ERROR, "could not find source text of function \"%s\"",
131 proname);
134 (errmsg("source text of function \"%s\": %s",
135 proname, source)));
136
137 /*
138 * Allocate a context that will hold all the Postgres data for the
139 * procedure.
140 */
142 "PL/Sample function",
144
145 arg_out_func = (FmgrInfo *) palloc0(fcinfo->nargs * sizeof(FmgrInfo));
146 numargs = get_func_arg_info(pl_tuple, &argtypes, &argnames, &argmodes);
147
148 /*
149 * Iterate through all of the function arguments, printing each input
150 * value.
151 */
152 for (int i = 0; i < numargs; i++)
153 {
154 Oid argtype = pl_struct->proargtypes.values[i];
155 char *value;
156
159 elog(ERROR, "cache lookup failed for type %u", argtype);
160
162 fmgr_info_cxt(type_struct->typoutput, &(arg_out_func[i]), proc_cxt);
164
165 value = OutputFunctionCall(&arg_out_func[i], fcinfo->args[i].value);
167 (errmsg("argument: %d; name: %s; value: %s",
168 i, argnames[i], value)));
169 }
170
171 /* Type of the result */
172 prorettype = pl_struct->prorettype;
174
175 /*
176 * Get the required information for input conversion of the return value.
177 *
178 * If the function uses VOID as result, it is better to return NULL.
179 * Anyway, let's be honest. This is just a template, so there is not much
180 * we can do here. This returns NULL except if the result type is text,
181 * where the result is the source text of the function.
182 */
183 if (prorettype != TEXTOID)
185
187 ObjectIdGetDatum(prorettype));
189 elog(ERROR, "cache lookup failed for type %u", prorettype);
191 result_typioparam = getTypeIOParam(type_tuple);
192
193 fmgr_info_cxt(pg_type_entry->typinput, &result_in_func, proc_cxt);
195
196 ret = InputFunctionCall(&result_in_func, source, result_typioparam, -1);
197 PG_RETURN_DATUM(ret);
198}
199
200/*
201 * plsample_trigger_handler
202 *
203 * Function called by the call handler for trigger execution.
204 */
205static HeapTuple
207{
208 TriggerData *trigdata = (TriggerData *) fcinfo->context;
209 char *string;
210 volatile HeapTuple rettup;
212 Datum ret;
213 char *source;
214 bool isnull;
216 char *proname;
218
219 /* Make sure this is being called from a trigger. */
220 if (!CALLED_AS_TRIGGER(fcinfo))
221 elog(ERROR, "not called by trigger manager");
222
223 /* Connect to the SPI manager */
224 SPI_connect();
225
226 rc = SPI_register_trigger_data(trigdata);
227 Assert(rc >= 0);
228
229 /* Fetch the function's pg_proc entry. */
231 ObjectIdGetDatum(fcinfo->flinfo->fn_oid));
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 */
243 proname = pstrdup(NameStr(pl_struct->proname));
245 if (isnull)
246 elog(ERROR, "could not find source text of function \"%s\"",
247 proname);
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 */
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 {
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++)
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 TextDatumGetCString(d)
Definition builtins.h:99
#define NameStr(name)
Definition c.h:835
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:249
#define Assert(condition)
Definition c.h:943
#define PG_RE_THROW()
Definition elog.h:407
#define PG_TRY(...)
Definition elog.h:374
#define PG_END_TRY(...)
Definition elog.h:399
#define ERROR
Definition elog.h:40
#define PG_CATCH(...)
Definition elog.h:384
#define elog(elevel,...)
Definition elog.h:228
#define NOTICE
Definition elog.h:36
#define PG_FINALLY(...)
Definition elog.h:391
#define ereport(elevel,...)
Definition elog.h:152
#define CALLED_AS_EVENT_TRIGGER(fcinfo)
Datum InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
Definition fmgr.c:1532
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition fmgr.c:139
char * OutputFunctionCall(FmgrInfo *flinfo, Datum val)
Definition fmgr.c:1684
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
#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:1382
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
static struct @177 value
int i
Definition isn.c:77
Oid getTypeIOParam(HeapTuple typeTuple)
Definition lsyscache.c:2496
char * pstrdup(const char *in)
Definition mcxt.c:1781
void * palloc0(Size size)
Definition mcxt.c:1417
MemoryContext TopMemoryContext
Definition mcxt.c:166
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition memutils.h:170
static char * errmsg
END_CATALOG_STRUCT typedef FormData_pg_proc * Form_pg_proc
Definition pg_proc.h:140
NameData proname
Definition pg_proc.h:37
static rewind_source * source
Definition pg_rewind.c:89
END_CATALOG_STRUCT typedef FormData_pg_type * Form_pg_type
Definition pg_type.h:265
PG_MODULE_MAGIC
Definition plsample.c:29
static Datum plsample_func_handler(PG_FUNCTION_ARGS)
Definition plsample.c:94
Datum plsample_call_handler(PG_FUNCTION_ARGS)
Definition plsample.c:40
static HeapTuple plsample_trigger_handler(PG_FUNCTION_ARGS)
Definition plsample.c:206
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
#define PointerGetDatum(X)
Definition postgres.h:354
unsigned int Oid
static int fb(int x)
char string[11]
int SPI_connect(void)
Definition spi.c:95
int SPI_finish(void)
Definition spi.c:183
int SPI_register_trigger_data(TriggerData *tdata)
Definition spi.c:3364
char * SPI_getnspname(Relation rel)
Definition spi.c:1333
char * SPI_getrelname(Relation rel)
Definition spi.c:1327
#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
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596
#define TRIGGER_FIRED_FOR_STATEMENT(event)
Definition trigger.h:127
#define TRIGGER_FIRED_BY_DELETE(event)
Definition trigger.h:115
#define TRIGGER_FIRED_BEFORE(event)
Definition trigger.h:130
#define CALLED_AS_TRIGGER(fcinfo)
Definition trigger.h:26
#define TRIGGER_FIRED_FOR_ROW(event)
Definition trigger.h:124
#define TRIGGER_FIRED_AFTER(event)
Definition trigger.h:133
#define TRIGGER_FIRED_BY_TRUNCATE(event)
Definition trigger.h:121
#define TRIGGER_FIRED_BY_INSERT(event)
Definition trigger.h:112
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition trigger.h:118
#define TRIGGER_FIRED_INSTEAD(event)
Definition trigger.h:136