trigger functions and access to datatypes
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't process 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 fired after 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;
}