Hi.

I've a PostgreSQL 9.0 server and I'm using heritage on some tables, for
this reason I have to simulate foreign keys through triggers like this:

*CREATE OR REPLACE FUNCTION othertable_before_update_trigger()
RETURNS trigger AS
$BODY$
DECLARE
  sql   VARCHAR;
  rows  SMALLINT;
BEGIN
  IF (NEW.parenttable_id IS DISTINCT FROM OLD.parenttable_id) THEN
    sql  := 'SELECT id '
         || 'FROM parentTable '
         || 'WHERE id = ' || NEW.parenttable_id || ';';
     BEGIN
        EXECUTE sql;
        GET DIAGNOSTICS rows = ROW_COUNT;

     EXCEPTION
        WHEN OTHERS THEN
           RAISE EXCEPTION 'Error when I try find in parentTable the
id %. SQL: %. ERROR: %',
                            NEW.parenttable_id,sql,SQLERRM;
     END;

     IF rows = 0 THEN
        RAISE EXCEPTION 'Not found a row in parentTable with id %.
SQL: %.',NEW.parenttable_id,sql;
     END IF;
  END IF;
  RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;*


But due to performance I try to create a equivalent trigger in C code:

*#include "postgres.h"
#include "executor/spi.h"       /* this is what you need to work with SPI */
#include "commands/trigger.h"   /* ... and triggers */

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
extern Datum othertable_before_update_trigger(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(othertable_before_update_trigger);

Datum
 othertable_before_update_trigger(PG_FUNCTION_ARGS) {

   TriggerData *trigdata = (TriggerData *) fcinfo->context;
   TupleDesc   tupdesc;
   HeapTuple   rettuple;
   bool        isnull;
   int         ret, i;

   /* make sure it's called as a trigger at all */
   if (!CALLED_AS_TRIGGER(fcinfo))
     elog(ERROR, "othertable_before_update_trigger: not called by
trigger manager");

   /* tuple to return to executor */
   if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
     rettuple = trigdata->tg_newtuple;
   else
     rettuple = trigdata->tg_trigtuple;

   tupdesc = trigdata->tg_relation->rd_att;

   /* connect to SPI manager */
   if ((ret = SPI_connect()) < 0)
     elog(ERROR, "othertable_before_update_trigger (fired %s):
SPI_connect returned %d", "before", ret);

   [A]

   [B]

   return PointerGetDatum(rettuple);
 }*


I need fill the code in:

   1.

   *[A]*: get the previous and new values for *parenttable_id*. With:

   *int32 att = DatumGetInt32(heap_getattr(rettuple, 1, tupdesc, &isnull));*

   or

   *int32 att = DatumGetInt32(SPI_getbinval(rettuple, tupdesc, 1, &isnull));
   *

I can get only the old value of *parenttable_id* but not the new value.
Even if I try to use the column name instead of their number with:

*GetAttributeByName (rettuple->t_data, "parenttable_id", &isnull);*

Getting error: *record type has not been registered*

   1. *[B]*: execute the query *SELECT id FROM parentTable WHERE id =
   NEW.parenttable_id*

I found the function *SPI_execute_with_args*, but I haven't found examples
of this for my case.

Thanks in advance.

Reply via email to