SPI problem - Mailing list pgsql-interfaces

From Alastair Bell" Turner
Subject SPI problem
Date
Msg-id 12482.209.212.106.190.1088002081.squirrel@mail.tangent.co.za
Whole thread Raw
Responses Re: SPI problem  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-interfaces
I'm trying to build a c trigger with the Server Programming Interface and
not having a lot of joy.

The code is based mainly on the example code on the documentation site.

If it return trigdata->tg_trigtuple with PointerGetDatum it seems to work.
Trying to return TempTuple with PointerGetDatum gives me no error at
execution but I get an error the next time I try to select from the table
which I have to DROP DATABASE to get rid of which leads me to believe that
it returns bad data. If I try to return trigdata->tg_trigtuple or
TempTuple using TupleGetDatum it fails at insert time with 'server closed
the connection unexpectedly ...'.

I can't see how my code doesn't match the prototypes, hopefully it's a
dumb error that someone can point out to me quickly ... :)

+  //Trigger to add hashes to rows on insert
+
+  #include "postgres.h"
+  #include "funcapi.h"
+  #include "executor/spi.h"
+  #include "commands/trigger.h"
+  #include <openssl/sha.h>
+
+  extern Datum hashtrigger(PG_FUNCTION_ARGS);
+
+  //Field number of versioning data
+  #define VERSIONFIELD 5
+  #define WHOLEHASHFIELD 36
+  #define ETLHASHFIELD 37
+
+  PG_FUNCTION_INFO_V1(hashtrigger);
+
+  Datum hashtrigger(PG_FUNCTION_ARGS) {
+   TriggerData *trigdata = (TriggerData *) fcinfo->context;
+   HeapTuple TempTuple;
+   TupleTableSlot *TupleSlot;
+   TupleDesc TupleDescription;
+   int Looper;
+
+   int Oops = SPI_connect();
+
+   static char *hexdigits = "0123456789abcdef";
+   static int HashColumns[] = {6, 7};
+   static int ColumnsAlteredVersioning[] = {1, 5, 6, 7};
+   //Suggested change here - insert checks for if this is null and only
do the first operation of it is
+   static int ColumnsAlteredETL[] = {1, 3, 5, 6, 7};
+
+   // make sure it's called as a trigger at all
+   if (!CALLED_AS_TRIGGER(fcinfo))
+    elog(ERROR, "hashtrigger: not called by trigger manager");
+
+   //palloc memory for hashes
+   char **hashes = (char **) palloc(4 * sizeof(char *));
+   //The hashes will be put into the 20 arrays, and then expanded into th
40s into hex
+   hashes[0] = (char *) palloc(20 * sizeof(char));
+   hashes[1] = (char *) palloc(40 * sizeof(char));
+   hashes[2] = (char *) palloc(40 * sizeof(char));
+
+   //Palloc array values for nulling out unused fields in tuple
+   Datum *NewColumnValues = (Datum *) palloc(sizeof(ColumnsAlteredETL) /
sizeof(int) * sizeof(Datum));
+
+   //Since I cant get the nulls parameter of SPI_modifytuple to work it
appears we're going to have to overwrite all the entries we want null
+   for (Looper = 0; Looper < (sizeof(ColumnsAlteredETL) / sizeof(int));
Looper++) {
+    NewColumnValues[Looper] = PointerGetDatum("");
+   }
+
+   //Use SPI_modifytuple to null out versioning field
+   TempTuple = SPI_modifytuple(trigdata->tg_relation,
trigdata->tg_trigtuple, sizeof(ColumnsAlteredVersioning) / sizeof(int),
ColumnsAlteredVersioning, NewColumnValues, NULL);
+
+   //Determine hash of TempTuple->t_len bytes at pointer
TempTuple->t_data and store the first element of allocated array
+   SHA1((const unsigned char *) TempTuple->t_data, TempTuple->t_len,
hashes[0]);
+   for (Looper = 0; Looper < 20; Looper++) {
+    //Spread hash out into hex coded form
+    hashes[1][Looper * 2] = hexdigits[(hashes[0][Looper] >> 4) & 0x0f];
+    hashes[1][(Looper * 2) + 1] = hexdigits[hashes[0][Looper] & 0x0f];
+   }
+
+   //Display hash for debug
+   elog (INFO, "hashtrigger returns %s for versionless hash of row",
hashes[1]);
+
+   //Use SPI_modifytuple to null out non etl fields
+   TempTuple = SPI_modifytuple(trigdata->tg_relation,
trigdata->tg_trigtuple, sizeof(ColumnsAlteredETL) / sizeof(int),
ColumnsAlteredETL, NewColumnValues, NULL);
+
+   //Determine hash of TempTuple->t_len bytes at pointer
TempTuple->t_data and store the first element of allocated array
+   SHA1((const unsigned char *) TempTuple->t_data, TempTuple->t_len,
hashes[0]);
+   for (Looper = 0; Looper < 20; Looper++) {
+    //Spread hash out into hex coded form
+    hashes[2][Looper * 2] = hexdigits[(hashes[0][Looper] >> 4) & 0x0f];
+    hashes[2][(Looper * 2) + 1] = hexdigits[hashes[0][Looper] & 0x0f];
+   }
+
+   //Display hash for debug
+   elog (INFO, "hashtrigger returns %s for material hash of row",
hashes[2]);
+
+   //Use SPI_modifytuple to write hash into fields on record into result
tuple
+  // NewColumnValues[0] = PointerGetDatum(hashes[1]);
+  // NewColumnValues[1] = PointerGetDatum(hashes[2]);
+
+   TempTuple = SPI_modifytuple(trigdata->tg_relation,
trigdata->tg_trigtuple, 2, HashColumns, NewColumnValues, NULL);
+
+   //Free allocated memory
+
+   //Return result tuple
+   TupleSlot = TupleDescGetSlot(trigdata->tg_relation->rd_att);
+  // return TupleGetDatum(TupleDestination, TempTuple);
+   return TupleGetDatum(TupleSlot, trigdata->tg_trigtuple);
+  // return PointerGetDatum(trigdata->tg_trigtuple);
+  }

Thank you very much

Alastair "Bell" Turner


pgsql-interfaces by date:

Previous
From: "Darko Prenosil"
Date:
Subject: Re: : query using kylix (delphi)
Next
From: "Darko Prenosil"
Date:
Subject: Re: SPI problem