trigger functions and access to datatypes

From: Brook Milligan <brook(at)trillium(dot)NMSU(dot)Edu>
To: hackers(at)postgreSQL(dot)org
Subject: trigger functions and access to datatypes
Date: 1999-06-14 21:32:11
Message-ID: 199906142132.PAA20191@trillium.nmsu.edu
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: 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'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;
}

Browse pgsql-hackers by date

  From Date Subject
Next Message Bruce Momjian 1999-06-14 21:53:25 Re: [PORTS] Patch for m68k architecture (fwd)
Previous Message Tom Lane 1999-06-14 20:57:53 Re: [HACKERS] Docs done?