Re: SPI problem - Mailing list pgsql-interfaces

From Darko Prenosil
Subject Re: SPI problem
Date
Msg-id 002101c45e2c$2ce2ce90$0b89bfd5@darko
Whole thread Raw
In response to SPI problem  ("Alastair Bell" Turner "" <bell@tangent.co.za>)
List pgsql-interfaces
I had a stupid error today, because I did not call a SPI_finish on function
exit. I can't see it in Your code either. Too late for analyze code, my ayes
are closing...
Regards !

----- Original Message -----
From: "Alastair Bell Turner" <bell@tangent.co.za>
To: <pgsql-interfaces@postgresql.org>
Sent: Wednesday, June 23, 2004 4:48 PM
Subject: [INTERFACES] SPI problem


> 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
>
> ---------------------------(end of broadcast)---------------------------
> TIP 4: Don't 'kill -9' the postmaster
>



pgsql-interfaces by date:

Previous
From: "Alastair Bell" Turner ""
Date:
Subject: SPI problem
Next
From: Greg Markham
Date:
Subject: Embedded SQL timestamp Question (ECPG)