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

241 {
242  TriggerData *trigdata = (TriggerData *) fcinfo->context;
243  Trigger *trigger; /* to get trigger name */
244  int nargs; /* # of args specified in CREATE TRIGGER */
245  char **args; /* arguments: as described above */
246  char **args_temp;
247  int nrefs; /* number of references (== # of plans) */
248  char action; /* 'R'estrict | 'S'etnull | 'C'ascade */
249  int nkeys; /* # of key columns */
250  Datum *kvals; /* key values */
251  char *relname; /* referencing relation name */
252  Relation rel; /* triggered relation */
253  HeapTuple trigtuple = NULL; /* tuple to being changed */
254  HeapTuple newtuple = NULL; /* tuple to return */
255  TupleDesc tupdesc; /* tuple description */
256  EPlan *plan; /* prepared plan(s) */
257  Oid *argtypes = NULL; /* key types to prepare execution plan */
258  bool isnull; /* to know is some column NULL or not */
259  bool isequal = true; /* are keys in both tuples equal (in UPDATE) */
260  char ident[2 * NAMEDATALEN]; /* to identify myself */
261  int is_update = 0;
262  int ret;
263  int i,
264  r;
265 
266 #ifdef DEBUG_QUERY
267  elog(DEBUG4, "check_foreign_key: Enter Function");
268 #endif
269 
270  /*
271  * Some checks first...
272  */
273 
274  /* Called by trigger manager ? */
275  if (!CALLED_AS_TRIGGER(fcinfo))
276  /* internal error */
277  elog(ERROR, "check_foreign_key: not fired by trigger manager");
278 
279  /* Should be called for ROW trigger */
280  if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
281  /* internal error */
282  elog(ERROR, "check_foreign_key: must be fired for row");
283 
284  /* Not should be called for INSERT */
285  if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
286  /* internal error */
287  elog(ERROR, "check_foreign_key: cannot process INSERT events");
288 
289  /* Have to check tg_trigtuple - tuple being deleted */
290  trigtuple = trigdata->tg_trigtuple;
291 
292  /*
293  * But if this is UPDATE then we have to return tg_newtuple. Also, if key
294  * in tg_newtuple is the same as in tg_trigtuple then nothing to do.
295  */
296  is_update = 0;
297  if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
298  {
299  newtuple = trigdata->tg_newtuple;
300  is_update = 1;
301  }
302  trigger = trigdata->tg_trigger;
303  nargs = trigger->tgnargs;
304  args = trigger->tgargs;
305 
306  if (nargs < 5) /* nrefs, action, key, Relation, key - at
307  * least */
308  /* internal error */
309  elog(ERROR, "check_foreign_key: too short %d (< 5) list of arguments", nargs);
310 
311  nrefs = pg_strtoint32(args[0]);
312  if (nrefs < 1)
313  /* internal error */
314  elog(ERROR, "check_foreign_key: %d (< 1) number of references specified", nrefs);
315  action = tolower((unsigned char) *(args[1]));
316  if (action != 'r' && action != 'c' && action != 's')
317  /* internal error */
318  elog(ERROR, "check_foreign_key: invalid action %s", args[1]);
319  nargs -= 2;
320  args += 2;
321  nkeys = (nargs - nrefs) / (nrefs + 1);
322  if (nkeys <= 0 || nargs != (nrefs + nkeys * (nrefs + 1)))
323  /* internal error */
324  elog(ERROR, "check_foreign_key: invalid number of arguments %d for %d references",
325  nargs + 2, nrefs);
326 
327  rel = trigdata->tg_relation;
328  tupdesc = rel->rd_att;
329 
330  /* Connect to SPI manager */
331  if ((ret = SPI_connect()) < 0)
332  /* internal error */
333  elog(ERROR, "check_foreign_key: SPI_connect returned %d", ret);
334 
335  /*
336  * We use SPI plan preparation feature, so allocate space to place key
337  * values.
338  */
339  kvals = (Datum *) palloc(nkeys * sizeof(Datum));
340 
341  /*
342  * Construct ident string as TriggerName $ TriggeredRelationId and try to
343  * find prepared execution plan(s).
344  */
345  snprintf(ident, sizeof(ident), "%s$%u", trigger->tgname, rel->rd_id);
347 
348  /* if there is no plan(s) then allocate argtypes for preparation */
349  if (plan->nplans <= 0)
350  argtypes = (Oid *) palloc(nkeys * sizeof(Oid));
351 
352  /*
353  * else - check that we have exactly nrefs plan(s) ready
354  */
355  else if (plan->nplans != nrefs)
356  /* internal error */
357  elog(ERROR, "%s: check_foreign_key: # of plans changed in meantime",
358  trigger->tgname);
359 
360  /* For each column in key ... */
361  for (i = 0; i < nkeys; i++)
362  {
363  /* get index of column in tuple */
364  int fnumber = SPI_fnumber(tupdesc, args[i]);
365 
366  /* Bad guys may give us un-existing column in CREATE TRIGGER */
367  if (fnumber <= 0)
368  ereport(ERROR,
369  (errcode(ERRCODE_UNDEFINED_COLUMN),
370  errmsg("there is no attribute \"%s\" in relation \"%s\"",
371  args[i], SPI_getrelname(rel))));
372 
373  /* Well, get binary (in internal format) value of column */
374  kvals[i] = SPI_getbinval(trigtuple, tupdesc, fnumber, &isnull);
375 
376  /*
377  * If it's NULL then nothing to do! DON'T FORGET call SPI_finish ()!
378  * DON'T FORGET return tuple! Executor inserts tuple you're returning!
379  * If you return NULL then nothing will be inserted!
380  */
381  if (isnull)
382  {
383  SPI_finish();
384  return PointerGetDatum((newtuple == NULL) ? trigtuple : newtuple);
385  }
386 
387  /*
388  * If UPDATE then get column value from new tuple being inserted and
389  * compare is this the same as old one. For the moment we use string
390  * presentation of values...
391  */
392  if (newtuple != NULL)
393  {
394  char *oldval = SPI_getvalue(trigtuple, tupdesc, fnumber);
395  char *newval;
396 
397  /* this shouldn't happen! SPI_ERROR_NOOUTFUNC ? */
398  if (oldval == NULL)
399  /* internal error */
400  elog(ERROR, "check_foreign_key: SPI_getvalue returned %s", SPI_result_code_string(SPI_result));
401  newval = SPI_getvalue(newtuple, tupdesc, fnumber);
402  if (newval == NULL || strcmp(oldval, newval) != 0)
403  isequal = false;
404  }
405 
406  if (plan->nplans <= 0) /* Get typeId of column */
407  argtypes[i] = SPI_gettypeid(tupdesc, fnumber);
408  }
409  args_temp = args;
410  nargs -= nkeys;
411  args += nkeys;
412 
413  /*
414  * If we have to prepare plans ...
415  */
416  if (plan->nplans <= 0)
417  {
418  SPIPlanPtr pplan;
419  char sql[8192];
420  char **args2 = args;
421 
423  nrefs * sizeof(SPIPlanPtr));
424 
425  for (r = 0; r < nrefs; r++)
426  {
427  relname = args2[0];
428 
429  /*---------
430  * For 'R'estrict action we construct SELECT query:
431  *
432  * SELECT 1
433  * FROM _referencing_relation_
434  * WHERE Fkey1 = $1 [AND Fkey2 = $2 [...]]
435  *
436  * to check is tuple referenced or not.
437  *---------
438  */
439  if (action == 'r')
440 
441  snprintf(sql, sizeof(sql), "select 1 from %s where ", relname);
442 
443  /*---------
444  * For 'C'ascade action we construct DELETE query
445  *
446  * DELETE
447  * FROM _referencing_relation_
448  * WHERE Fkey1 = $1 [AND Fkey2 = $2 [...]]
449  *
450  * to delete all referencing tuples.
451  *---------
452  */
453 
454  /*
455  * Max : Cascade with UPDATE query i create update query that
456  * updates new key values in referenced tables
457  */
458 
459 
460  else if (action == 'c')
461  {
462  if (is_update == 1)
463  {
464  int fn;
465  char *nv;
466  int k;
467 
468  snprintf(sql, sizeof(sql), "update %s set ", relname);
469  for (k = 1; k <= nkeys; k++)
470  {
471  int is_char_type = 0;
472  char *type;
473 
474  fn = SPI_fnumber(tupdesc, args_temp[k - 1]);
475  Assert(fn > 0); /* already checked above */
476  nv = SPI_getvalue(newtuple, tupdesc, fn);
477  type = SPI_gettype(tupdesc, fn);
478 
479  if (strcmp(type, "text") == 0 ||
480  strcmp(type, "varchar") == 0 ||
481  strcmp(type, "char") == 0 ||
482  strcmp(type, "bpchar") == 0 ||
483  strcmp(type, "date") == 0 ||
484  strcmp(type, "timestamp") == 0)
485  is_char_type = 1;
486 #ifdef DEBUG_QUERY
487  elog(DEBUG4, "check_foreign_key Debug value %s type %s %d",
488  nv, type, is_char_type);
489 #endif
490 
491  /*
492  * is_char_type =1 i set ' ' for define a new value
493  */
494  snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql),
495  " %s = %s%s%s %s ",
496  args2[k], (is_char_type > 0) ? "'" : "",
497  nv, (is_char_type > 0) ? "'" : "", (k < nkeys) ? ", " : "");
498  }
499  strcat(sql, " where ");
500  }
501  else
502  /* DELETE */
503  snprintf(sql, sizeof(sql), "delete from %s where ", relname);
504  }
505 
506  /*
507  * For 'S'etnull action we construct UPDATE query - UPDATE
508  * _referencing_relation_ SET Fkey1 null [, Fkey2 null [...]]
509  * WHERE Fkey1 = $1 [AND Fkey2 = $2 [...]] - to set key columns in
510  * all referencing tuples to NULL.
511  */
512  else if (action == 's')
513  {
514  snprintf(sql, sizeof(sql), "update %s set ", relname);
515  for (i = 1; i <= nkeys; i++)
516  {
517  snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql),
518  "%s = null%s",
519  args2[i], (i < nkeys) ? ", " : "");
520  }
521  strcat(sql, " where ");
522  }
523 
524  /* Construct WHERE qual */
525  for (i = 1; i <= nkeys; i++)
526  {
527  snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s = $%d %s",
528  args2[i], i, (i < nkeys) ? "and " : "");
529  }
530 
531  /* Prepare plan for query */
532  pplan = SPI_prepare(sql, nkeys, argtypes);
533  if (pplan == NULL)
534  /* internal error */
535  elog(ERROR, "check_foreign_key: SPI_prepare returned %s", SPI_result_code_string(SPI_result));
536 
537  /*
538  * Remember that SPI_prepare places plan in current memory context
539  * - so, we have to save plan in Top memory context for later use.
540  */
541  if (SPI_keepplan(pplan))
542  /* internal error */
543  elog(ERROR, "check_foreign_key: SPI_keepplan failed");
544 
545  plan->splan[r] = pplan;
546 
547  args2 += nkeys + 1; /* to the next relation */
548  }
549  plan->nplans = nrefs;
550 #ifdef DEBUG_QUERY
551  elog(DEBUG4, "check_foreign_key Debug Query is : %s ", sql);
552 #endif
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  snprintf(ident, sizeof(ident), "%s$%u", trigger->tgname, rel->rd_id);
579  ret = SPI_execp(plan->splan[r], kvals, NULL, tcount);
580  /* we have no NULLs - so we pass ^^^^ here */
581 
582  if (ret < 0)
583  ereport(ERROR,
584  (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
585  errmsg("SPI_execp returned %d", ret)));
586 
587  /* If action is 'R'estrict ... */
588  if (action == 'r')
589  {
590  /* If there is tuple returned by SELECT then ... */
591  if (SPI_processed > 0)
592  ereport(ERROR,
593  (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
594  errmsg("\"%s\": tuple is referenced in \"%s\"",
595  trigger->tgname, relname)));
596  }
597  else
598  {
599 #ifdef REFINT_VERBOSE
600  elog(NOTICE, "%s: " UINT64_FORMAT " tuple(s) of %s are %s",
601  trigger->tgname, SPI_processed, relname,
602  (action == 'c') ? "deleted" : "set to null");
603 #endif
604  }
605  args += nkeys + 1; /* to the next relation */
606  }
607 
608  SPI_finish();
609 
610  return PointerGetDatum((newtuple == NULL) ? trigtuple : newtuple);
611 }
#define Assert(condition)
Definition: c.h:858
#define UINT64_FORMAT
Definition: c.h:549
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#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:73
MemoryContext TopMemoryContext
Definition: mcxt.c:149
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1180
void * palloc(Size size)
Definition: mcxt.c:1316
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:162
#define snprintf
Definition: port.h:238
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
unsigned int Oid
Definition: postgres_ext.h:31
static EPlan * FPlans
Definition: refint.c:27
static EPlan * find_plan(char *ident, EPlan **eplan, int *nplans)
Definition: refint.c:614
static int nFPlans
Definition: refint.c:28
char * SPI_getrelname(Relation rel)
Definition: spi.c:1323
int SPI_fnumber(TupleDesc tupdesc, const char *fname)
Definition: spi.c:1172
uint64 SPI_processed
Definition: spi.c:44
Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber)
Definition: spi.c:1305
int SPI_connect(void)
Definition: spi.c:94
int SPI_result
Definition: spi.c:46
const char * SPI_result_code_string(int code)
Definition: spi.c:1969
int SPI_finish(void)
Definition: spi.c:182
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:857
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:973
int SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount)
Definition: spi.c:701
char * SPI_gettype(TupleDesc tupdesc, int fnumber)
Definition: spi.c:1265
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition: spi.c:1217
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1249
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  if ((ret = SPI_connect()) < 0)
112  /* internal error */
113  elog(ERROR, "check_primary_key: SPI_connect returned %d", ret);
114 
115  /*
116  * We use SPI plan preparation feature, so allocate space to place key
117  * values.
118  */
119  kvals = (Datum *) palloc(nkeys * sizeof(Datum));
120 
121  /*
122  * Construct ident string as TriggerName $ TriggeredRelationId and try to
123  * find prepared execution plan.
124  */
125  snprintf(ident, sizeof(ident), "%s$%u", trigger->tgname, rel->rd_id);
127 
128  /* if there is no plan then allocate argtypes for preparation */
129  if (plan->nplans <= 0)
130  argtypes = (Oid *) palloc(nkeys * sizeof(Oid));
131 
132  /* For each column in key ... */
133  for (i = 0; i < nkeys; i++)
134  {
135  /* get index of column in tuple */
136  int fnumber = SPI_fnumber(tupdesc, args[i]);
137 
138  /* Bad guys may give us un-existing column in CREATE TRIGGER */
139  if (fnumber <= 0)
140  ereport(ERROR,
141  (errcode(ERRCODE_UNDEFINED_COLUMN),
142  errmsg("there is no attribute \"%s\" in relation \"%s\"",
143  args[i], SPI_getrelname(rel))));
144 
145  /* Well, get binary (in internal format) value of column */
146  kvals[i] = SPI_getbinval(tuple, tupdesc, fnumber, &isnull);
147 
148  /*
149  * If it's NULL then nothing to do! DON'T FORGET call SPI_finish ()!
150  * DON'T FORGET return tuple! Executor inserts tuple you're returning!
151  * If you return NULL then nothing will be inserted!
152  */
153  if (isnull)
154  {
155  SPI_finish();
156  return PointerGetDatum(tuple);
157  }
158 
159  if (plan->nplans <= 0) /* Get typeId of column */
160  argtypes[i] = SPI_gettypeid(tupdesc, fnumber);
161  }
162 
163  /*
164  * If we have to prepare plan ...
165  */
166  if (plan->nplans <= 0)
167  {
168  SPIPlanPtr pplan;
169  char sql[8192];
170 
171  /*
172  * Construct query: SELECT 1 FROM _referenced_relation_ WHERE Pkey1 =
173  * $1 [AND Pkey2 = $2 [...]]
174  */
175  snprintf(sql, sizeof(sql), "select 1 from %s where ", relname);
176  for (i = 0; i < nkeys; i++)
177  {
178  snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s = $%d %s",
179  args[i + nkeys + 1], i + 1, (i < nkeys - 1) ? "and " : "");
180  }
181 
182  /* Prepare plan for query */
183  pplan = SPI_prepare(sql, nkeys, argtypes);
184  if (pplan == NULL)
185  /* internal error */
186  elog(ERROR, "check_primary_key: SPI_prepare returned %s", SPI_result_code_string(SPI_result));
187 
188  /*
189  * Remember that SPI_prepare places plan in current memory context -
190  * so, we have to save plan in TopMemoryContext for later use.
191  */
192  if (SPI_keepplan(pplan))
193  /* internal error */
194  elog(ERROR, "check_primary_key: SPI_keepplan failed");
196  sizeof(SPIPlanPtr));
197  *(plan->splan) = pplan;
198  plan->nplans = 1;
199  }
200 
201  /*
202  * Ok, execute prepared plan.
203  */
204  ret = SPI_execp(*(plan->splan), kvals, NULL, 1);
205  /* we have no NULLs - so we pass ^^^^ here */
206 
207  if (ret < 0)
208  /* internal error */
209  elog(ERROR, "check_primary_key: SPI_execp returned %d", ret);
210 
211  /*
212  * If there are no tuples returned by SELECT then ...
213  */
214  if (SPI_processed == 0)
215  ereport(ERROR,
216  (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
217  errmsg("tuple references non-existent key"),
218  errdetail("Trigger \"%s\" found tuple referencing non-existent key in \"%s\".", trigger->tgname, relname)));
219 
220  SPI_finish();
221 
222  return PointerGetDatum(tuple);
223 }
int errdetail(const char *fmt,...)
Definition: elog.c:1205
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
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 614 of file refint.c.

615 {
616  EPlan *newp;
617  int i;
618  MemoryContext oldcontext;
619 
620  /*
621  * All allocations done for the plans need to happen in a session-safe
622  * context.
623  */
625 
626  if (*nplans > 0)
627  {
628  for (i = 0; i < *nplans; i++)
629  {
630  if (strcmp((*eplan)[i].ident, ident) == 0)
631  break;
632  }
633  if (i != *nplans)
634  {
635  MemoryContextSwitchTo(oldcontext);
636  return (*eplan + i);
637  }
638  *eplan = (EPlan *) repalloc(*eplan, (i + 1) * sizeof(EPlan));
639  newp = *eplan + i;
640  }
641  else
642  {
643  newp = *eplan = (EPlan *) palloc(sizeof(EPlan));
644  (*nplans) = i = 0;
645  }
646 
647  newp->ident = pstrdup(ident);
648  newp->nplans = 0;
649  newp->splan = NULL;
650  (*nplans)++;
651 
652  MemoryContextSwitchTo(oldcontext);
653  return newp;
654 }
char * pstrdup(const char *in)
Definition: mcxt.c:1695
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1540
MemoryContextSwitchTo(old_ctx)
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().