trigger functions and access to datatypes - Mailing list pgsql-hackers

From Brook Milligan
Subject trigger functions and access to datatypes
Date
Msg-id 199906142132.PAA20191@trillium.nmsu.edu
Whole thread Raw
List pgsql-hackers
I'm trying to write some trigger functions that fill in the values of
some fields with functions of other fields.  Everything is fine,
except that I am unsure how to create Datum representations of the new
fields.  Presumably I need to do something like the following:
Point f (int32 i, int32 j);int32 i, j;Point p;Datum d;p = f (i, j);            /* ??? - how to create/access Point? */d
=PointGetDatum (&p);        /* ??? - how to convert to Datum? */rettuple = SPI_modifytuple (rel, rettuple, 1, attnum,
&d,NULL);
 

But I don't know how to get at the internal representations I need.
In this case I need to create a Point data type.  I can use the
structure in geo_decls.h fine, but is that the "correct" procedure?
Once I have a Point structure created, how do I convert that to a
Datum (or Datum*) for an argument to SPI_modifytuple?

So that I haven't missed any details, I'm including the full version
of my trigger below.

Thanks for your help.

Cheers,
Brook

===========================================================================

/** plot_corners.c** trigger for keeping corners in sync with distances*/


#include "executor/spi.h"    /* this is what you need to work with SPI */
#include "commands/trigger.h"    /* and triggers */
#include "utils/geo_decls.h"    /* this is needed for Point type */

HeapTuple plot_corners (void);
            /* coordinants of corners */
typedef struct _corners
{ Point LL; Point LR; Point UL; Point UR;
} Corners;
            /* calculate corner positions */
static Corners calc_corners (int n_distances, const int32 * d);

#define N_DISTANCES 6
static char * distance_names [N_DISTANCES] = { "d12", "d13", "d14", "d23", "d24", "d34" };

#define N_CORNERS 4
static char * corner_names [N_CORNERS] = { "ll", "lr", "ul", "ur" };

HeapTuple plot_corners ()
{ Relation rel;            /* triggered relation */ char *relname;        /* triggered relation name */ TupleDesc
tupdesc;       /* tuple description */
 
 HeapTuple rettuple = NULL;    /* tuple to return */
 int d_attnum [N_DISTANCES];    /* distance attribute numbers */ int32 d [N_DISTANCES];    /* distances between corners
*/
 int c_attnum [N_CORNERS];    /* corner attribute numbers */ Corners corners;        /* coordinants of corners */ Datum
c[N_CORNERS];        /* coordinants of corners */
 
 bool isnull; int i;
 if (!CurrentTriggerData)   elog (ERROR, "plot_corners: triggers are not initialized");
 rel = CurrentTriggerData -> tg_relation; relname = SPI_getrelname (rel); tupdesc = rel -> rd_att;
 if (CurrentTriggerData -> tg_trigger -> tgnargs != 0)   elog (ERROR, "plot_corners (%s): no arguments were expected",
relname);
 if (!TRIGGER_FIRED_FOR_ROW (CurrentTriggerData -> tg_event))   elog (ERROR, "plot_corners (%s): must process ROW
events",relname); if (TRIGGER_FIRED_FOR_STATEMENT (CurrentTriggerData -> tg_event))   elog (ERROR, "plot_corners (%s):
can'tprocess STATEMENT events", relname);
 
 if (!TRIGGER_FIRED_BEFORE (CurrentTriggerData -> tg_event))   elog (ERROR, "plot_corners (%s): must be fired before
event",relname); if (TRIGGER_FIRED_AFTER (CurrentTriggerData -> tg_event))   elog (ERROR, "plot_corners (%s): can't be
firedafter event", relname);
 
 if (TRIGGER_FIRED_BY_INSERT (CurrentTriggerData -> tg_event))   rettuple = CurrentTriggerData -> tg_trigtuple; else if
(TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData -> tg_event))   rettuple = CurrentTriggerData -> tg_newtuple; else if
(TRIGGER_FIRED_BY_DELETE(CurrentTriggerData -> tg_event))   elog (ERROR, "plot_corners (%s): can't process DELETE
events",relname); else   elog (ERROR, "plot_corners (%s): unknown trigger event", relname);
 
 CurrentTriggerData = NULL;
 for (i = 0; i < N_DISTANCES; i++)   {     d_attnum [i] = SPI_fnumber (tupdesc, distance_names [i]);     if (d_attnum
[i]< 0)elog (ERROR, "plot_corners (%s): there is no attribute %s", relname, distance_names [i]);     if (SPI_gettypeid
(tupdesc,d_attnum [i]) != INT4OID)elog (ERROR, "plot_corners (%s): attribute %s must be of INT4 type",      relname,
distance_names[i]);     d [i] = DatumGetInt32 (SPI_getbinval (rettuple, tupdesc, d_attnum [i], &isnull));     if
(isnull)elog(ERROR, "plot_corners (%s): attribute %s must not be NULL",      relname, distance_names [i]);   }
 
 for (i = 0; i < N_CORNERS; i++)   {     c_attnum [i] = SPI_fnumber (tupdesc, corner_names [i]);     if (c_attnum [i] <
0)elog(ERROR, "plot_corners (%s): there is no attribute %s", relname, corner_names [i]);     if (SPI_gettypeid
(tupdesc,c_attnum [i]) != POINTOID)elog (ERROR, "plot_corners (%s): attribute %s must be of POINT type",      relname,
distance_names[i]);   }
 
 corners = calc_corners (N_DISTANCES, d);
 c [0] = PointGetDatum (&corners.LL); /* ??? - how to convert Point to Datum? */ c [1] = PointGetDatum (&corners.LR); c
[2]= PointGetDatum (&corners.UL); c [3] = PointGetDatum (&corners.UR);
 
 rettuple = SPI_modifytuple (rel, rettuple, N_CORNERS, c_attnum, c, NULL); if (rettuple == NULL)   elog (ERROR,
"plot_corners(%s): %d returned by SPI_modifytuple",  relname, SPI_result);
 
 pfree (relname);
 return (rettuple);
}
            /* calculate corner positions */
Corners calc_corners (int n_distances, const int32 * d)
{ Corners c;
 c.LL.x = 0;            /* ??? - how to initialize/access Point values? */ c.LL.y = 0;
 c.LR.x = 1; c.LR.y = 0;
 c.UL.x = 0; c.UL.y = 1;
 c.UR.x = 1; c.UR.y = 1;
 return c;
}



pgsql-hackers by date:

Previous
From: Massimo Dal Zotto
Date:
Subject: Re: [HACKERS] new patch
Next
From: Tom Lane
Date:
Subject: Re: [HACKERS] Docs done?