Thread

  1. trigger functions and access to datatypes

    Brook Milligan <brook@trillium.nmsu.edu> — 1999-06-14T21:32:11Z

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