Renamed the trigger.c to dupetrigger.c to enlarge the namespace for
authormj <mj>
Thu, 27 Sep 2001 19:29:17 +0000 (19:29 +0000)
committermj <mj>
Thu, 27 Sep 2001 19:29:17 +0000 (19:29 +0000)
additional triggers. Cleaned up Makefile and the other files.

dbscripts/dupetrigger/INSTALL
dbscripts/dupetrigger/Makefile
dbscripts/dupetrigger/README
dbscripts/dupetrigger/dupetrigger.c [new file with mode: 0755]
dbscripts/dupetrigger/postgresql.sript
dbscripts/dupetrigger/trigger.c [deleted file]

index 8571231..e7687f7 100755 (executable)
@@ -5,5 +5,3 @@ To install the trigger do the following:
 
 # psql -U postgres Mir < postgresql.script
 (This installs the the trigger binary and creates a new trigger.)
-
-# rm /tmp/trigger.so
index ad1c52c..6185ec2 100755 (executable)
@@ -2,18 +2,25 @@
 
 CC=gcc
 PGINC=/usr/include/postgresql
+CFLAGS=-I$(PGINC)
 
-trigger.so: trigger.o
-       $(CC) -shared -dynamic -o trigger.so trigger.o
-       cp trigger.so /tmp
-       chmod 755 /tmp/trigger.so
+# If changed, also change postgresql.script
+INSTALLDIR=../../../Mir/src
 
-trigger.o: trigger.c
-       $(CC) -I$(PGINC) -c trigger.c -o trigger.o
 
+install: dupetrigger.so
+       cp dupetrigger.so $(INSTALLDIR)
+       chmod 755 $(INSTALLDIR)/dupetrigger.so
+       #
+       # Now, change the path to dupetrigger.so in postgresql.script to the
+       # absolute path where dupetrigger.so is installed (this 
+       # is typically ../../../Mir/src)
+
+dupetrigger.so: dupetrigger.o
+       $(CC) -shared -dynamic -o dupetrigger.so dupetrigger.o
 
 clean:
-       rm -rf trigger.o trigger.so
+       rm -rf dupetrigger.o dupetrigger.so
 
 
 tidy: clean
index 5856177..a506867 100755 (executable)
@@ -8,9 +8,9 @@ this somehow. Because Indymedia databases will hopefully grow big very fast,
 we want to do this check as fast as possible. 
 
 So Mir simply issues the INSERT. By this INSERT statement, a trigger gets,
-well, triggered that calculate a CRC-32 checksum of the comment and searches
-for rows with the same checksum. If it finds the checksum, the INSERT gets
-aborted. If the checksum isn't found, it is appended to the row and the
-INSERT is executed.
+well, triggered that calculates a CRC-32 checksum of the comment and
+searches for rows with the same checksum. If it finds the checksum, the
+INSERT gets aborted. If the checksum isn't found, it is appended to the row
+and the INSERT is executed.
 
 The trigger works for INSERTs and UPDATEs.
diff --git a/dbscripts/dupetrigger/dupetrigger.c b/dbscripts/dupetrigger/dupetrigger.c
new file mode 100755 (executable)
index 0000000..66f61e1
--- /dev/null
@@ -0,0 +1,209 @@
+//
+//
+// This File contructs a PostgreSQL trigger.
+// The trigger is fired BEFORE an INSERT or UPDATE of an article
+// or comment. It first calculates a CRC32 checksum of the row to be
+// inserted or updated and checks whether there exists already another
+// row with the same checksum and the same content. In this case,
+// the trigger returns NULL and thus, aborts the SQL command.
+//
+// Author: Matthias Jordan <mjordan@code-fu.de>
+//
+
+
+#include "executor/spi.h"
+#include "commands/trigger.h"
+#include "string.h"
+
+extern Datum dupecheck(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(dupecheck);
+
+
+
+
+//
+//
+// CRC32 stuff
+//
+
+// crc32 table based on the following polynom
+#define CRC32_POLY 0x04c11db7     /* AUTODIN II, Ethernet, & FDDI */
+
+u_long crc32_table[256] = 
+       {0x0000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+       0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+       0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
+       0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+       0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
+       0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+       0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
+       0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+       0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
+       0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+       0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+       0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+       0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x54bf6a4,
+       0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+       0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
+       0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+       0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
+       0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+       0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
+       0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+       0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+       0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+       0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
+       0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+       0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
+       0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0xe56f0ff,
+       0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
+       0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+       0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
+       0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+       0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+       0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+       0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
+       0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+       0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
+       0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0xfdc1bec,
+       0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
+       0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+       0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
+       0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+       0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+       0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+       0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
+
+
+static u_long crc32(u_char *buf, unsigned len)
+{
+        u_char *p;
+        u_long  crc;
+
+        crc = 0xffffffff;       /* preload shift register, per CRC-32 spec */
+        for (p = buf; len > 0; ++p, --len)
+        {
+                crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *p];
+        }
+        return ~crc;            /* transmit complement, per CRC-32 spec */
+} /* crc32 */
+
+
+
+
+
+//
+//
+// Trigger stuff
+//
+
+
+
+
+Datum dupecheck(PG_FUNCTION_ARGS)
+{
+       TriggerData *trigdata = (TriggerData *) fcinfo->context;
+       TupleDesc       tupdesc;
+       HeapTuple       rettuple;
+       bool            isnull;
+       int                     ret = 0, i, fnumber;
+       long rowstrlen = 0,
+               crc;
+       int maxitems = 3,
+               num;
+       char *items[maxitems],
+               *rowstring,
+               *query;
+       
+
+       /* Make sure trigdata is pointing at what I expect */
+       if (!CALLED_AS_TRIGGER(fcinfo))
+               elog(ERROR, "dupecheck: not fired by trigger manager");
+       
+       /* tuple to return to Executor */
+       if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
+               rettuple = trigdata->tg_newtuple;
+       else
+               rettuple = trigdata->tg_trigtuple;
+       
+       if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
+               return PointerGetDatum(NULL);
+       
+       tupdesc = trigdata->tg_relation->rd_att;
+       
+       /* Connect to SPI manager */
+       if ((ret = SPI_connect()) < 0)
+       ret = SPI_connect();
+       elog(NOTICE, "dupecheck: SPI_connect returned %d", ret);
+
+       // Now we are connected to the database's SPI manager
+       // We will now construct a string of some important row values. 
+       // First, we determine how long the string will be to allocate memory
+       // To include an additional item, add another SPI_getvalue line and
+       // increase maxitems above by 1
+       
+       items[0] = SPI_getvalue(rettuple, tupdesc, SPI_fnumber(tupdesc, "creator"));
+       items[1] = SPI_getvalue(rettuple, tupdesc, SPI_fnumber(tupdesc, "title"));
+       items[2] = SPI_getvalue(rettuple, tupdesc, SPI_fnumber(tupdesc, "description"));
+
+       for (i=0; (i < maxitems); i++)
+       {
+               rowstrlen += strlen(items[i]);
+       }
+       rowstrlen++; // add space for 0-terminator
+       
+       rowstring = malloc(rowstrlen);
+       if (rowstring == NULL)
+       {
+               // Big problem.
+               return PointerGetDatum(NULL);
+       }
+
+       *rowstring = 0;
+       for (i=0; (i < maxitems); i++)
+       {
+               strcat(rowstring, items[i]);
+       }
+
+       // rowstring now contains the data of the maxitems important
+       // items of the table record. Now we calculate the CRC-32 checksum
+       // of the rowstring
+
+       crc = crc32(rowstring, rowstrlen - 1); 
+
+       // Now we allocate some space and construct the SQL query
+       query = malloc(47 + 11 + 2 + 1); // SELECT part + crc32 + "';" + 0-term
+       if (query == NULL)
+       {
+               // Big problem
+               return PointerGetDatum(NULL);
+       }
+       
+       sprintf(query, "SELECT count(*) FROM comment WHERE checksum='%ld';", crc);
+       ret = SPI_exec(query, 2);
+       num = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull);
+
+       if ((ret == SPI_OK_SELECT) && (num > 0))
+       {
+               elog(NOTICE, "dupecheck: UBD prevented (dupe dropped)");
+               return PointerGetDatum(NULL);
+       }
+       else
+       {
+               // The checksum wasn't found. So we modify the tuple to be 
+               // inserted and add the fresh checksum.
+               int attnum;
+               Datum value;
+               char nulls = 0;
+               
+               elog(NOTICE, "dupecheck: Adding checksum to INSERT");
+               attnum = SPI_fnumber(tupdesc, "checksum");
+               value = (Datum) crc;
+               rettuple = SPI_modifytuple(trigdata->tg_relation, rettuple, 1, &attnum, &value, &nulls);
+       }
+
+       SPI_finish();
+       return PointerGetDatum(rettuple);
+}
+    
index d1f43c4..28e9027 100755 (executable)
@@ -1,5 +1,6 @@
 \connect - postgres
 DROP FUNCTION dupecheck();
 DROP TRIGGER dupetrigger ON comment;
-CREATE FUNCTION dupecheck() RETURNS OPAQUE AS '/tmp/trigger.so' LANGUAGE 'C';
+CREATE FUNCTION dupecheck() RETURNS OPAQUE AS '/path/to/dupetrigger.so' LANGUAGE 'C';
 CREATE TRIGGER dupetrigger BEFORE INSERT OR UPDATE ON comment FOR EACH ROW EXECUTE PROCEDURE dupecheck();
+CREATE INDEX comment_checksum_index on comment (checksum);
diff --git a/dbscripts/dupetrigger/trigger.c b/dbscripts/dupetrigger/trigger.c
deleted file mode 100755 (executable)
index 66f61e1..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-//
-//
-// This File contructs a PostgreSQL trigger.
-// The trigger is fired BEFORE an INSERT or UPDATE of an article
-// or comment. It first calculates a CRC32 checksum of the row to be
-// inserted or updated and checks whether there exists already another
-// row with the same checksum and the same content. In this case,
-// the trigger returns NULL and thus, aborts the SQL command.
-//
-// Author: Matthias Jordan <mjordan@code-fu.de>
-//
-
-
-#include "executor/spi.h"
-#include "commands/trigger.h"
-#include "string.h"
-
-extern Datum dupecheck(PG_FUNCTION_ARGS);
-
-PG_FUNCTION_INFO_V1(dupecheck);
-
-
-
-
-//
-//
-// CRC32 stuff
-//
-
-// crc32 table based on the following polynom
-#define CRC32_POLY 0x04c11db7     /* AUTODIN II, Ethernet, & FDDI */
-
-u_long crc32_table[256] = 
-       {0x0000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
-       0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
-       0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
-       0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
-       0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
-       0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
-       0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
-       0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
-       0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
-       0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
-       0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
-       0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
-       0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x54bf6a4,
-       0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
-       0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
-       0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
-       0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
-       0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
-       0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
-       0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
-       0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
-       0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
-       0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
-       0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
-       0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
-       0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0xe56f0ff,
-       0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
-       0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
-       0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
-       0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
-       0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
-       0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
-       0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
-       0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
-       0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
-       0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0xfdc1bec,
-       0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
-       0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
-       0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
-       0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
-       0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
-       0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
-       0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
-
-
-static u_long crc32(u_char *buf, unsigned len)
-{
-        u_char *p;
-        u_long  crc;
-
-        crc = 0xffffffff;       /* preload shift register, per CRC-32 spec */
-        for (p = buf; len > 0; ++p, --len)
-        {
-                crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *p];
-        }
-        return ~crc;            /* transmit complement, per CRC-32 spec */
-} /* crc32 */
-
-
-
-
-
-//
-//
-// Trigger stuff
-//
-
-
-
-
-Datum dupecheck(PG_FUNCTION_ARGS)
-{
-       TriggerData *trigdata = (TriggerData *) fcinfo->context;
-       TupleDesc       tupdesc;
-       HeapTuple       rettuple;
-       bool            isnull;
-       int                     ret = 0, i, fnumber;
-       long rowstrlen = 0,
-               crc;
-       int maxitems = 3,
-               num;
-       char *items[maxitems],
-               *rowstring,
-               *query;
-       
-
-       /* Make sure trigdata is pointing at what I expect */
-       if (!CALLED_AS_TRIGGER(fcinfo))
-               elog(ERROR, "dupecheck: not fired by trigger manager");
-       
-       /* tuple to return to Executor */
-       if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
-               rettuple = trigdata->tg_newtuple;
-       else
-               rettuple = trigdata->tg_trigtuple;
-       
-       if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
-               return PointerGetDatum(NULL);
-       
-       tupdesc = trigdata->tg_relation->rd_att;
-       
-       /* Connect to SPI manager */
-       if ((ret = SPI_connect()) < 0)
-       ret = SPI_connect();
-       elog(NOTICE, "dupecheck: SPI_connect returned %d", ret);
-
-       // Now we are connected to the database's SPI manager
-       // We will now construct a string of some important row values. 
-       // First, we determine how long the string will be to allocate memory
-       // To include an additional item, add another SPI_getvalue line and
-       // increase maxitems above by 1
-       
-       items[0] = SPI_getvalue(rettuple, tupdesc, SPI_fnumber(tupdesc, "creator"));
-       items[1] = SPI_getvalue(rettuple, tupdesc, SPI_fnumber(tupdesc, "title"));
-       items[2] = SPI_getvalue(rettuple, tupdesc, SPI_fnumber(tupdesc, "description"));
-
-       for (i=0; (i < maxitems); i++)
-       {
-               rowstrlen += strlen(items[i]);
-       }
-       rowstrlen++; // add space for 0-terminator
-       
-       rowstring = malloc(rowstrlen);
-       if (rowstring == NULL)
-       {
-               // Big problem.
-               return PointerGetDatum(NULL);
-       }
-
-       *rowstring = 0;
-       for (i=0; (i < maxitems); i++)
-       {
-               strcat(rowstring, items[i]);
-       }
-
-       // rowstring now contains the data of the maxitems important
-       // items of the table record. Now we calculate the CRC-32 checksum
-       // of the rowstring
-
-       crc = crc32(rowstring, rowstrlen - 1); 
-
-       // Now we allocate some space and construct the SQL query
-       query = malloc(47 + 11 + 2 + 1); // SELECT part + crc32 + "';" + 0-term
-       if (query == NULL)
-       {
-               // Big problem
-               return PointerGetDatum(NULL);
-       }
-       
-       sprintf(query, "SELECT count(*) FROM comment WHERE checksum='%ld';", crc);
-       ret = SPI_exec(query, 2);
-       num = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull);
-
-       if ((ret == SPI_OK_SELECT) && (num > 0))
-       {
-               elog(NOTICE, "dupecheck: UBD prevented (dupe dropped)");
-               return PointerGetDatum(NULL);
-       }
-       else
-       {
-               // The checksum wasn't found. So we modify the tuple to be 
-               // inserted and add the fresh checksum.
-               int attnum;
-               Datum value;
-               char nulls = 0;
-               
-               elog(NOTICE, "dupecheck: Adding checksum to INSERT");
-               attnum = SPI_fnumber(tupdesc, "checksum");
-               value = (Datum) crc;
-               rettuple = SPI_modifytuple(trigdata->tg_relation, rettuple, 1, &attnum, &value, &nulls);
-       }
-
-       SPI_finish();
-       return PointerGetDatum(rettuple);
-}
-