PostgreSQL Source Code git master
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

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

 PG_MODULE_MAGIC
 
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 238 of file refint.c.

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

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

611{
612 EPlan *newp;
613 int i;
614 MemoryContext oldcontext;
615
616 /*
617 * All allocations done for the plans need to happen in a session-safe
618 * context.
619 */
621
622 if (*nplans > 0)
623 {
624 for (i = 0; i < *nplans; i++)
625 {
626 if (strcmp((*eplan)[i].ident, ident) == 0)
627 break;
628 }
629 if (i != *nplans)
630 {
631 MemoryContextSwitchTo(oldcontext);
632 return (*eplan + i);
633 }
634 *eplan = (EPlan *) repalloc(*eplan, (i + 1) * sizeof(EPlan));
635 newp = *eplan + i;
636 }
637 else
638 {
639 newp = *eplan = (EPlan *) palloc(sizeof(EPlan));
640 (*nplans) = i = 0;
641 }
642
643 newp->ident = pstrdup(ident);
644 newp->nplans = 0;
645 newp->splan = NULL;
646 (*nplans)++;
647
648 MemoryContextSwitchTo(oldcontext);
649 return newp;
650}
char * pstrdup(const char *in)
Definition: mcxt.c:1696
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
SPIPlanPtr * splan
Definition: refint.c:24
int nplans
Definition: refint.c:23
char * ident
Definition: refint.c:22

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  )

Variable Documentation

◆ FPlans

EPlan* FPlans = NULL
static

Definition at line 27 of file refint.c.

Referenced by check_foreign_key().

◆ nFPlans

int nFPlans = 0
static

Definition at line 28 of file refint.c.

Referenced by check_foreign_key().

◆ nPPlans

int nPPlans = 0
static

Definition at line 30 of file refint.c.

Referenced by check_primary_key().

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 18 of file refint.c.

◆ PPlans

EPlan* PPlans = NULL
static

Definition at line 29 of file refint.c.

Referenced by check_primary_key().