PostgreSQL Source Code git master
Loading...
Searching...
No Matches
refint.c File Reference
#include "postgres.h"
#include <ctype.h>
#include "commands/trigger.h"
#include "executor/spi.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for refint.c:

Go to the source code of this file.

Data Structures

struct  EPlan
 

Functions

 PG_MODULE_MAGIC_EXT (.name="refint",.version=PG_VERSION)
 
static EPlanfind_plan (char *ident, EPlan **eplan, int *nplans)
 
 PG_FUNCTION_INFO_V1 (check_primary_key)
 
Datum check_primary_key (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (check_foreign_key)
 
Datum check_foreign_key (PG_FUNCTION_ARGS)
 

Variables

static EPlanFPlans = NULL
 
static int nFPlans = 0
 
static EPlanPPlans = NULL
 
static int nPPlans = 0
 

Function Documentation

◆ check_foreign_key()

Datum check_foreign_key ( PG_FUNCTION_ARGS  )

Definition at line 250 of file refint.c.

251{
252 TriggerData *trigdata = (TriggerData *) fcinfo->context;
253 Trigger *trigger; /* to get trigger name */
254 int nargs; /* # of args specified in CREATE TRIGGER */
255 char **args; /* arguments: as described above */
256 char **args_temp;
257 int nrefs; /* number of references (== # of plans) */
258 char action; /* 'R'estrict | 'S'etnull | 'C'ascade */
259 int nkeys; /* # of key columns */
260 Datum *kvals; /* key values */
261 char *relname; /* referencing relation name */
262 Relation rel; /* triggered relation */
263 HeapTuple trigtuple = NULL; /* tuple to being changed */
264 HeapTuple newtuple = NULL; /* tuple to return */
265 TupleDesc tupdesc; /* tuple description */
266 EPlan *plan; /* prepared plan(s) */
267 Oid *argtypes = NULL; /* key types to prepare execution plan */
268 bool isnull; /* to know is some column NULL or not */
269 bool isequal = true; /* are keys in both tuples equal (in UPDATE) */
270 char ident[2 * NAMEDATALEN]; /* to identify myself */
271 int is_update = 0;
272 int ret;
273 int i,
274 r;
275
276#ifdef DEBUG_QUERY
277 elog(DEBUG4, "check_foreign_key: Enter Function");
278#endif
279
280 /*
281 * Some checks first...
282 */
283
284 /* Called by trigger manager ? */
285 if (!CALLED_AS_TRIGGER(fcinfo))
286 /* internal error */
287 elog(ERROR, "check_foreign_key: not fired by trigger manager");
288
289 /* Should be called for ROW trigger */
290 if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
291 /* internal error */
292 elog(ERROR, "check_foreign_key: must be fired for row");
293
294 /* Not should be called for INSERT */
295 if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
296 /* internal error */
297 elog(ERROR, "check_foreign_key: cannot process INSERT events");
298
299 if (!TRIGGER_FIRED_AFTER(trigdata->tg_event))
300 /* internal error */
301 elog(ERROR, "check_foreign_key: must be fired by AFTER trigger");
302
303 /* Have to check tg_trigtuple - tuple being deleted */
304 trigtuple = trigdata->tg_trigtuple;
305
306 /*
307 * But if this is UPDATE then we have to return tg_newtuple. Also, if key
308 * in tg_newtuple is the same as in tg_trigtuple then nothing to do.
309 */
310 is_update = 0;
311 if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
312 {
313 newtuple = trigdata->tg_newtuple;
314 is_update = 1;
315 }
316 trigger = trigdata->tg_trigger;
317 nargs = trigger->tgnargs;
318 args = trigger->tgargs;
319
320 if (nargs < 5) /* nrefs, action, key, Relation, key - at
321 * least */
322 /* internal error */
323 elog(ERROR, "check_foreign_key: too short %d (< 5) list of arguments", nargs);
324
325 nrefs = pg_strtoint32(args[0]);
326 if (nrefs < 1)
327 /* internal error */
328 elog(ERROR, "check_foreign_key: %d (< 1) number of references specified", nrefs);
329 action = pg_ascii_tolower((unsigned char) *(args[1]));
330 if (action != 'r' && action != 'c' && action != 's')
331 /* internal error */
332 elog(ERROR, "check_foreign_key: invalid action %s", args[1]);
333 nargs -= 2;
334 args += 2;
335 nkeys = (nargs - nrefs) / (nrefs + 1);
336 if (nkeys <= 0 || nargs != (nrefs + nkeys * (nrefs + 1)))
337 /* internal error */
338 elog(ERROR, "check_foreign_key: invalid number of arguments %d for %d references",
339 nargs + 2, nrefs);
340
341 rel = trigdata->tg_relation;
342 tupdesc = rel->rd_att;
343
344 /* Connect to SPI manager */
345 SPI_connect();
346
347 /*
348 * We use SPI plan preparation feature, so allocate space to place key
349 * values.
350 */
351 kvals = (Datum *) palloc(nkeys * sizeof(Datum));
352
353 /*
354 * Construct ident string as TriggerName $ TriggeredRelationId $
355 * OperationType and try to find prepared execution plan(s).
356 */
357 snprintf(ident, sizeof(ident), "%s$%u$%c", trigger->tgname, rel->rd_id, is_update ? 'U' : 'D');
359
360 /* if there is no plan(s) then allocate argtypes for preparation */
361 if (plan->nplans <= 0)
362 argtypes = (Oid *) palloc(nkeys * sizeof(Oid));
363
364 /*
365 * else - check that we have exactly nrefs plan(s) ready
366 */
367 else if (plan->nplans != nrefs)
368 /* internal error */
369 elog(ERROR, "%s: check_foreign_key: # of plans changed in meantime",
370 trigger->tgname);
371
372 /* For each column in key ... */
373 for (i = 0; i < nkeys; i++)
374 {
375 /* get index of column in tuple */
376 int fnumber = SPI_fnumber(tupdesc, args[i]);
377
378 /* Bad guys may give us un-existing column in CREATE TRIGGER */
379 if (fnumber <= 0)
382 errmsg("there is no attribute \"%s\" in relation \"%s\"",
383 args[i], SPI_getrelname(rel))));
384
385 /* Well, get binary (in internal format) value of column */
386 kvals[i] = SPI_getbinval(trigtuple, tupdesc, fnumber, &isnull);
387
388 /*
389 * If it's NULL then nothing to do! DON'T FORGET call SPI_finish ()!
390 * DON'T FORGET return tuple! Executor inserts tuple you're returning!
391 * If you return NULL then nothing will be inserted!
392 */
393 if (isnull)
394 {
395 SPI_finish();
396 return PointerGetDatum((newtuple == NULL) ? trigtuple : newtuple);
397 }
398
399 /*
400 * If UPDATE then get column value from new tuple being inserted and
401 * compare is this the same as old one. For the moment we use string
402 * presentation of values...
403 */
404 if (newtuple != NULL)
405 {
406 char *oldval = SPI_getvalue(trigtuple, tupdesc, fnumber);
407 char *newval;
408
409 /* this shouldn't happen! SPI_ERROR_NOOUTFUNC ? */
410 if (oldval == NULL)
411 /* internal error */
412 elog(ERROR, "check_foreign_key: SPI_getvalue returned %s", SPI_result_code_string(SPI_result));
413 newval = SPI_getvalue(newtuple, tupdesc, fnumber);
414 if (newval == NULL || strcmp(oldval, newval) != 0)
415 isequal = false;
416 }
417
418 if (plan->nplans <= 0) /* Get typeId of column */
419 argtypes[i] = SPI_gettypeid(tupdesc, fnumber);
420 }
421 args_temp = args;
422 nargs -= nkeys;
423 args += nkeys;
424
425 /*
426 * If we have to prepare plans ...
427 */
428 if (plan->nplans <= 0)
429 {
431 char **args2 = args;
432
434 nrefs * sizeof(SPIPlanPtr));
435
436 for (r = 0; r < nrefs; r++)
437 {
438 StringInfoData sql;
439
440 initStringInfo(&sql);
441
442 relname = args2[0];
443
444 /*---------
445 * For 'R'estrict action we construct SELECT query:
446 *
447 * SELECT 1
448 * FROM _referencing_relation_
449 * WHERE Fkey1 = $1 [AND Fkey2 = $2 [...]]
450 *
451 * to check is tuple referenced or not.
452 *---------
453 */
454 if (action == 'r')
455 appendStringInfo(&sql, "select 1 from %s where ", relname);
456
457 /*---------
458 * For 'C'ascade action we construct DELETE query
459 *
460 * DELETE
461 * FROM _referencing_relation_
462 * WHERE Fkey1 = $1 [AND Fkey2 = $2 [...]]
463 *
464 * to delete all referencing tuples.
465 *---------
466 */
467
468 /*
469 * Max : Cascade with UPDATE query i create update query that
470 * updates new key values in referenced tables
471 */
472
473
474 else if (action == 'c')
475 {
476 if (is_update == 1)
477 {
478 int fn;
479 char *nv;
480 int k;
481
482 appendStringInfo(&sql, "update %s set ", relname);
483 for (k = 1; k <= nkeys; k++)
484 {
485 fn = SPI_fnumber(tupdesc, args_temp[k - 1]);
486 Assert(fn > 0); /* already checked above */
487 nv = SPI_getvalue(newtuple, tupdesc, fn);
488
489 appendStringInfo(&sql, " %s = %s ",
490 args2[k],
491 nv ? quote_literal_cstr(nv) : "NULL");
492 if (k < nkeys)
493 appendStringInfoString(&sql, ", ");
494 }
495 appendStringInfoString(&sql, " where ");
496 }
497 else
498 /* DELETE */
499 appendStringInfo(&sql, "delete from %s where ", relname);
500 }
501
502 /*
503 * For 'S'etnull action we construct UPDATE query - UPDATE
504 * _referencing_relation_ SET Fkey1 null [, Fkey2 null [...]]
505 * WHERE Fkey1 = $1 [AND Fkey2 = $2 [...]] - to set key columns in
506 * all referencing tuples to NULL.
507 */
508 else if (action == 's')
509 {
510 appendStringInfo(&sql, "update %s set ", relname);
511 for (i = 1; i <= nkeys; i++)
512 {
513 appendStringInfo(&sql, "%s = null", args2[i]);
514 if (i < nkeys)
515 appendStringInfoString(&sql, ", ");
516 }
517 appendStringInfoString(&sql, " where ");
518 }
519
520 /* Construct WHERE qual */
521 for (i = 1; i <= nkeys; i++)
522 {
523 appendStringInfo(&sql, "%s = $%d ", args2[i], i);
524 if (i < nkeys)
525 appendStringInfoString(&sql, "and ");
526 }
527
528 /* Prepare plan for query */
529 pplan = SPI_prepare(sql.data, nkeys, argtypes);
530 if (pplan == NULL)
531 /* internal error */
532 elog(ERROR, "check_foreign_key: SPI_prepare returned %s", SPI_result_code_string(SPI_result));
533
534 /*
535 * Remember that SPI_prepare places plan in current memory context
536 * - so, we have to save plan in Top memory context for later use.
537 */
538 if (SPI_keepplan(pplan))
539 /* internal error */
540 elog(ERROR, "check_foreign_key: SPI_keepplan failed");
541
542 plan->splan[r] = pplan;
543
544 args2 += nkeys + 1; /* to the next relation */
545
546#ifdef DEBUG_QUERY
547 elog(DEBUG4, "check_foreign_key Debug Query is : %s ", sql.data);
548#endif
549
550 pfree(sql.data);
551 }
552 plan->nplans = nrefs;
553 }
554
555 /*
556 * If UPDATE and key is not changed ...
557 */
558 if (newtuple != NULL && isequal)
559 {
560 SPI_finish();
561 return PointerGetDatum(newtuple);
562 }
563
564 /*
565 * Ok, execute prepared plan(s).
566 */
567 for (r = 0; r < nrefs; r++)
568 {
569 /*
570 * For 'R'estrict we may to execute plan for one tuple only, for other
571 * actions - for all tuples.
572 */
573 int tcount = (action == 'r') ? 1 : 0;
574
575 relname = args[0];
576
577 ret = SPI_execp(plan->splan[r], kvals, NULL, tcount);
578 /* we have no NULLs - so we pass ^^^^ here */
579
580 if (ret < 0)
583 errmsg("SPI_execp returned %d", ret)));
584
585 /* If action is 'R'estrict ... */
586 if (action == 'r')
587 {
588 /* If there is tuple returned by SELECT then ... */
589 if (SPI_processed > 0)
592 errmsg("\"%s\": tuple is referenced in \"%s\"",
593 trigger->tgname, relname)));
594 }
595 else
596 {
597#ifdef REFINT_VERBOSE
598 const char *operation;
599
600 if (action == 'c')
601 operation = is_update ? "updated" : "deleted";
602 else
603 operation = "set to null";
604
605 elog(NOTICE, "%s: " UINT64_FORMAT " tuple(s) of %s are %s",
607#endif
608 }
609 args += nkeys + 1; /* to the next relation */
610 }
611
612 SPI_finish();
613
614 return PointerGetDatum((newtuple == NULL) ? trigtuple : newtuple);
615}
#define Assert(condition)
Definition c.h:943
#define UINT64_FORMAT
Definition c.h:635
static DataChecksumsWorkerOperation operation
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define NOTICE
Definition elog.h:36
#define ereport(elevel,...)
Definition elog.h:152
#define DEBUG4
Definition elog.h:28
#define newval
#define ident
int i
Definition isn.c:77
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1235
void pfree(void *pointer)
Definition mcxt.c:1619
MemoryContext TopMemoryContext
Definition mcxt.c:167
void * palloc(Size size)
Definition mcxt.c:1390
int32 pg_strtoint32(const char *s)
Definition numutils.c:382
static char * errmsg
NameData relname
Definition pg_class.h:40
#define NAMEDATALEN
#define plan(x)
Definition pg_regress.c:164
#define snprintf
Definition port.h:261
static unsigned char pg_ascii_tolower(unsigned char ch)
Definition port.h:189
uint64_t Datum
Definition postgres.h:70
#define PointerGetDatum(X)
Definition postgres.h:354
unsigned int Oid
static int fb(int x)
char * quote_literal_cstr(const char *rawstr)
Definition quote.c:101
static EPlan * FPlans
Definition refint.c:30
static EPlan * find_plan(char *ident, EPlan **eplan, int *nplans)
Definition refint.c:618
static int nFPlans
Definition refint.c:31
int SPI_fnumber(TupleDesc tupdesc, const char *fname)
Definition spi.c:1176
uint64 SPI_processed
Definition spi.c:45
Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber)
Definition spi.c:1309
const char * SPI_result_code_string(int code)
Definition spi.c:1973
int SPI_connect(void)
Definition spi.c:95
int SPI_result
Definition spi.c:47
int SPI_finish(void)
Definition spi.c:183
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition spi.c:861
int SPI_keepplan(SPIPlanPtr plan)
Definition spi.c:977
int SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount)
Definition spi.c:705
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition spi.c:1221
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition spi.c:1253
char * SPI_getrelname(Relation rel)
Definition spi.c:1327
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
Definition refint.c:24
TupleDesc rd_att
Definition rel.h:112
Oid rd_id
Definition rel.h:113
static void * fn(void *arg)
#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_INSERT(event)
Definition trigger.h:112
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition trigger.h:118

References appendStringInfo(), appendStringInfoString(), Assert, CALLED_AS_TRIGGER, StringInfoData::data, DEBUG4, elog, ereport, errcode(), errmsg, ERROR, fb(), find_plan(), fn(), FPlans, i, ident, initStringInfo(), MemoryContextAlloc(), NAMEDATALEN, newval, nFPlans, NOTICE, operation, palloc(), pfree(), pg_ascii_tolower(), pg_strtoint32(), plan, PointerGetDatum, quote_literal_cstr(), RelationData::rd_att, RelationData::rd_id, relname, snprintf, SPI_connect(), SPI_execp(), SPI_finish(), SPI_fnumber(), SPI_getbinval(), SPI_getrelname(), SPI_gettypeid(), SPI_getvalue(), SPI_keepplan(), SPI_prepare(), SPI_processed, SPI_result, SPI_result_code_string(), TriggerData::tg_event, TriggerData::tg_newtuple, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, Trigger::tgnargs, TopMemoryContext, TRIGGER_FIRED_AFTER, TRIGGER_FIRED_BY_INSERT, TRIGGER_FIRED_BY_UPDATE, TRIGGER_FIRED_FOR_ROW, and UINT64_FORMAT.

◆ check_primary_key()

Datum check_primary_key ( PG_FUNCTION_ARGS  )

Definition at line 50 of file refint.c.

51{
52 TriggerData *trigdata = (TriggerData *) fcinfo->context;
53 Trigger *trigger; /* to get trigger name */
54 int nargs; /* # of args specified in CREATE TRIGGER */
55 char **args; /* arguments: column names and table name */
56 int nkeys; /* # of key columns (= nargs / 2) */
57 Datum *kvals; /* key values */
58 char *relname; /* referenced relation name */
59 Relation rel; /* triggered relation */
60 HeapTuple tuple = NULL; /* tuple to return */
61 TupleDesc tupdesc; /* tuple description */
62 EPlan *plan; /* prepared plan */
63 Oid *argtypes = NULL; /* key types to prepare execution plan */
64 bool isnull; /* to know is some column NULL or not */
65 char ident[2 * NAMEDATALEN]; /* to identify myself */
66 int ret;
67 int i;
68
69#ifdef DEBUG_QUERY
70 elog(DEBUG4, "check_primary_key: Enter Function");
71#endif
72
73 /*
74 * Some checks first...
75 */
76
77 /* Called by trigger manager ? */
78 if (!CALLED_AS_TRIGGER(fcinfo))
79 /* internal error */
80 elog(ERROR, "check_primary_key: not fired by trigger manager");
81
82 /* Should be called for ROW trigger */
83 if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
84 /* internal error */
85 elog(ERROR, "check_primary_key: must be fired for row");
86
87 if (!TRIGGER_FIRED_AFTER(trigdata->tg_event))
88 /* internal error */
89 elog(ERROR, "check_primary_key: must be fired by AFTER trigger");
90
91 /* If INSERTion then must check Tuple to being inserted */
92 if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
93 tuple = trigdata->tg_trigtuple;
94
95 /* Not should be called for DELETE */
96 else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
97 /* internal error */
98 elog(ERROR, "check_primary_key: cannot process DELETE events");
99
100 /* If UPDATE, then must check new Tuple, not old one */
101 else
102 tuple = trigdata->tg_newtuple;
103
104 trigger = trigdata->tg_trigger;
105 nargs = trigger->tgnargs;
106 args = trigger->tgargs;
107
108 if (nargs % 2 != 1) /* odd number of arguments! */
109 /* internal error */
110 elog(ERROR, "check_primary_key: odd number of arguments should be specified");
111
112 nkeys = nargs / 2;
113 relname = args[nkeys];
114 rel = trigdata->tg_relation;
115 tupdesc = rel->rd_att;
116
117 /* Connect to SPI manager */
118 SPI_connect();
119
120 /*
121 * We use SPI plan preparation feature, so allocate space to place key
122 * values.
123 */
124 kvals = (Datum *) palloc(nkeys * sizeof(Datum));
125
126 /*
127 * Construct ident string as TriggerName $ TriggeredRelationId and try to
128 * find prepared execution plan.
129 */
130 snprintf(ident, sizeof(ident), "%s$%u", trigger->tgname, rel->rd_id);
132
133 /* if there is no plan then allocate argtypes for preparation */
134 if (plan->nplans <= 0)
135 argtypes = (Oid *) palloc(nkeys * sizeof(Oid));
136
137 /* For each column in key ... */
138 for (i = 0; i < nkeys; i++)
139 {
140 /* get index of column in tuple */
141 int fnumber = SPI_fnumber(tupdesc, args[i]);
142
143 /* Bad guys may give us un-existing column in CREATE TRIGGER */
144 if (fnumber <= 0)
147 errmsg("there is no attribute \"%s\" in relation \"%s\"",
148 args[i], SPI_getrelname(rel))));
149
150 /* Well, get binary (in internal format) value of column */
151 kvals[i] = SPI_getbinval(tuple, tupdesc, fnumber, &isnull);
152
153 /*
154 * If it's NULL then nothing to do! DON'T FORGET call SPI_finish ()!
155 * DON'T FORGET return tuple! Executor inserts tuple you're returning!
156 * If you return NULL then nothing will be inserted!
157 */
158 if (isnull)
159 {
160 SPI_finish();
161 return PointerGetDatum(tuple);
162 }
163
164 if (plan->nplans <= 0) /* Get typeId of column */
165 argtypes[i] = SPI_gettypeid(tupdesc, fnumber);
166 }
167
168 /*
169 * If we have to prepare plan ...
170 */
171 if (plan->nplans <= 0)
172 {
174 StringInfoData sql;
175
176 initStringInfo(&sql);
177
178 /*
179 * Construct query: SELECT 1 FROM _referenced_relation_ WHERE Pkey1 =
180 * $1 [AND Pkey2 = $2 [...]]
181 */
182 appendStringInfo(&sql, "select 1 from %s where ", relname);
183 for (i = 1; i <= nkeys; i++)
184 {
185 appendStringInfo(&sql, "%s = $%d ", args[i + nkeys], i);
186 if (i < nkeys)
187 appendStringInfoString(&sql, "and ");
188 }
189
190 /* Prepare plan for query */
191 pplan = SPI_prepare(sql.data, nkeys, argtypes);
192 if (pplan == NULL)
193 /* internal error */
194 elog(ERROR, "check_primary_key: SPI_prepare returned %s", SPI_result_code_string(SPI_result));
195
196 /*
197 * Remember that SPI_prepare places plan in current memory context -
198 * so, we have to save plan in TopMemoryContext for later use.
199 */
200 if (SPI_keepplan(pplan))
201 /* internal error */
202 elog(ERROR, "check_primary_key: SPI_keepplan failed");
204 sizeof(SPIPlanPtr));
205 *(plan->splan) = pplan;
206 plan->nplans = 1;
207
208 pfree(sql.data);
209 }
210
211 /*
212 * Ok, execute prepared plan.
213 */
214 ret = SPI_execp(*(plan->splan), kvals, NULL, 1);
215 /* we have no NULLs - so we pass ^^^^ here */
216
217 if (ret < 0)
218 /* internal error */
219 elog(ERROR, "check_primary_key: SPI_execp returned %d", ret);
220
221 /*
222 * If there are no tuples returned by SELECT then ...
223 */
224 if (SPI_processed == 0)
227 errmsg("tuple references non-existent key"),
228 errdetail("Trigger \"%s\" found tuple referencing non-existent key in \"%s\".", trigger->tgname, relname)));
229
230 SPI_finish();
231
232 return PointerGetDatum(tuple);
233}
int errdetail(const char *fmt,...) pg_attribute_printf(1
static int nPPlans
Definition refint.c:33
static EPlan * PPlans
Definition refint.c:32
#define TRIGGER_FIRED_BY_DELETE(event)
Definition trigger.h:115

References appendStringInfo(), appendStringInfoString(), CALLED_AS_TRIGGER, StringInfoData::data, DEBUG4, elog, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), find_plan(), i, ident, initStringInfo(), MemoryContextAlloc(), NAMEDATALEN, nPPlans, palloc(), pfree(), plan, PointerGetDatum, PPlans, RelationData::rd_att, RelationData::rd_id, relname, snprintf, SPI_connect(), SPI_execp(), SPI_finish(), SPI_fnumber(), SPI_getbinval(), SPI_getrelname(), SPI_gettypeid(), SPI_keepplan(), SPI_prepare(), SPI_processed, SPI_result, SPI_result_code_string(), TriggerData::tg_event, TriggerData::tg_newtuple, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, Trigger::tgnargs, TopMemoryContext, TRIGGER_FIRED_AFTER, TRIGGER_FIRED_BY_DELETE, TRIGGER_FIRED_BY_INSERT, and TRIGGER_FIRED_FOR_ROW.

◆ find_plan()

static EPlan * find_plan ( char ident,
EPlan **  eplan,
int nplans 
)
static

Definition at line 618 of file refint.c.

619{
620 EPlan *newp;
621 int i;
622 MemoryContext oldcontext;
623
624 /*
625 * All allocations done for the plans need to happen in a session-safe
626 * context.
627 */
629
630 if (*nplans > 0)
631 {
632 for (i = 0; i < *nplans; i++)
633 {
634 if (strcmp((*eplan)[i].ident, ident) == 0)
635 break;
636 }
637 if (i != *nplans)
638 {
639 MemoryContextSwitchTo(oldcontext);
640 return (*eplan + i);
641 }
642 *eplan = (EPlan *) repalloc(*eplan, (i + 1) * sizeof(EPlan));
643 newp = *eplan + i;
644 }
645 else
646 {
648 (*nplans) = i = 0;
649 }
650
651 newp->ident = pstrdup(ident);
652 newp->nplans = 0;
653 newp->splan = NULL;
654 (*nplans)++;
655
656 MemoryContextSwitchTo(oldcontext);
657 return newp;
658}
#define palloc_object(type)
Definition fe_memutils.h:89
char * pstrdup(const char *in)
Definition mcxt.c:1910
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1635
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138

References fb(), i, ident, MemoryContextSwitchTo(), palloc_object, pstrdup(), repalloc(), and TopMemoryContext.

Referenced by check_foreign_key(), and check_primary_key().

◆ PG_FUNCTION_INFO_V1() [1/2]

PG_FUNCTION_INFO_V1 ( check_foreign_key  )

◆ PG_FUNCTION_INFO_V1() [2/2]

PG_FUNCTION_INFO_V1 ( check_primary_key  )

◆ PG_MODULE_MAGIC_EXT()

PG_MODULE_MAGIC_EXT ( name = "refint",
version = PG_VERSION 
)

Variable Documentation

◆ FPlans

EPlan* FPlans = NULL
static

Definition at line 30 of file refint.c.

Referenced by check_foreign_key().

◆ nFPlans

int nFPlans = 0
static

Definition at line 31 of file refint.c.

Referenced by check_foreign_key().

◆ nPPlans

int nPPlans = 0
static

Definition at line 33 of file refint.c.

Referenced by check_primary_key().

◆ PPlans

EPlan* PPlans = NULL
static

Definition at line 32 of file refint.c.

Referenced by check_primary_key().