PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 245 of file refint.c.

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

References generate_unaccent_rules::action, generate_unaccent_rules::args, Assert(), CALLED_AS_TRIGGER, DEBUG4, elog, ereport, errcode(), errmsg(), ERROR, find_plan(), fn(), FPlans, i, ident, MemoryContextAlloc(), NAMEDATALEN, newval, nFPlans, NOTICE, palloc(), pg_strtoint32(), plan, PointerGetDatum(), RelationData::rd_att, relname, snprintf, SPI_connect(), SPI_execp(), SPI_finish(), SPI_fnumber(), SPI_getbinval(), SPI_getrelname(), SPI_gettype(), 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, type, 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)
146 (errcode(ERRCODE_UNDEFINED_COLUMN),
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 {
173 SPIPlanPtr pplan;
174 char sql[8192];
175
176 /*
177 * Construct query: SELECT 1 FROM _referenced_relation_ WHERE Pkey1 =
178 * $1 [AND Pkey2 = $2 [...]]
179 */
180 snprintf(sql, sizeof(sql), "select 1 from %s where ", relname);
181 for (i = 0; i < nkeys; i++)
182 {
183 snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s = $%d %s",
184 args[i + nkeys + 1], i + 1, (i < nkeys - 1) ? "and " : "");
185 }
186
187 /* Prepare plan for query */
188 pplan = SPI_prepare(sql, nkeys, argtypes);
189 if (pplan == NULL)
190 /* internal error */
191 elog(ERROR, "check_primary_key: SPI_prepare returned %s", SPI_result_code_string(SPI_result));
192
193 /*
194 * Remember that SPI_prepare places plan in current memory context -
195 * so, we have to save plan in TopMemoryContext for later use.
196 */
197 if (SPI_keepplan(pplan))
198 /* internal error */
199 elog(ERROR, "check_primary_key: SPI_keepplan failed");
201 sizeof(SPIPlanPtr));
202 *(plan->splan) = pplan;
203 plan->nplans = 1;
204 }
205
206 /*
207 * Ok, execute prepared plan.
208 */
209 ret = SPI_execp(*(plan->splan), kvals, NULL, 1);
210 /* we have no NULLs - so we pass ^^^^ here */
211
212 if (ret < 0)
213 /* internal error */
214 elog(ERROR, "check_primary_key: SPI_execp returned %d", ret);
215
216 /*
217 * If there are no tuples returned by SELECT then ...
218 */
219 if (SPI_processed == 0)
221 (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
222 errmsg("tuple references non-existent key"),
223 errdetail("Trigger \"%s\" found tuple referencing non-existent key in \"%s\".", trigger->tgname, relname)));
224
225 SPI_finish();
226
227 return PointerGetDatum(tuple);
228}
int errdetail(const char *fmt,...)
Definition: elog.c:1204
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
static int nPPlans
Definition: refint.c:33
static EPlan * PPlans
Definition: refint.c:32
#define TRIGGER_FIRED_BY_DELETE(event)
Definition: trigger.h:113

References generate_unaccent_rules::args, CALLED_AS_TRIGGER, DEBUG4, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, find_plan(), i, ident, if(), MemoryContextAlloc(), NAMEDATALEN, nPPlans, palloc(), plan, PointerGetDatum(), PPlans, RelationData::rd_att, 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 625 of file refint.c.

626{
627 EPlan *newp;
628 int i;
629 MemoryContext oldcontext;
630
631 /*
632 * All allocations done for the plans need to happen in a session-safe
633 * context.
634 */
636
637 if (*nplans > 0)
638 {
639 for (i = 0; i < *nplans; i++)
640 {
641 if (strcmp((*eplan)[i].ident, ident) == 0)
642 break;
643 }
644 if (i != *nplans)
645 {
646 MemoryContextSwitchTo(oldcontext);
647 return (*eplan + i);
648 }
649 *eplan = (EPlan *) repalloc(*eplan, (i + 1) * sizeof(EPlan));
650 newp = *eplan + i;
651 }
652 else
653 {
654 newp = *eplan = (EPlan *) palloc(sizeof(EPlan));
655 (*nplans) = i = 0;
656 }
657
658 newp->ident = pstrdup(ident);
659 newp->nplans = 0;
660 newp->splan = NULL;
661 (*nplans)++;
662
663 MemoryContextSwitchTo(oldcontext);
664 return newp;
665}
char * pstrdup(const char *in)
Definition: mcxt.c:2325
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:2170
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
SPIPlanPtr * splan
Definition: refint.c:27
int nplans
Definition: refint.c:26
char * ident
Definition: refint.c:25

References i, EPlan::ident, ident, MemoryContextSwitchTo(), EPlan::nplans, palloc(), pstrdup(), repalloc(), EPlan::splan, 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().