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;
}