OSDN Git Service

New moddatetime contrib from Terry Mackintosh.
authorBruce Momjian <bruce@momjian.us>
Sat, 12 Dec 1998 20:20:49 +0000 (20:20 +0000)
committerBruce Momjian <bruce@momjian.us>
Sat, 12 Dec 1998 20:20:49 +0000 (20:20 +0000)
contrib/spi/Makefile
contrib/spi/moddatetime.c [new file with mode: 0644]
contrib/spi/moddatetime.example [new file with mode: 0644]
contrib/spi/moddatetime.source [new file with mode: 0644]

index 6bb634a..c9c9ff8 100644 (file)
@@ -12,7 +12,7 @@ CFLAGS+= -DREFINT_VERBOSE
 endif
 
 TARGETS= refint$(DLSUFFIX) refint.sql timetravel$(DLSUFFIX) timetravel.sql \
-               autoinc$(DLSUFFIX) autoinc.sql \
+               autoinc$(DLSUFFIX) autoinc.sql moddatetime$(DLSUFFIX) moddatetime.sql \
                insert_username$(DLSUFFIX) insert_username.sql
 
 CLEANFILES+= $(TARGETS)
diff --git a/contrib/spi/moddatetime.c b/contrib/spi/moddatetime.c
new file mode 100644 (file)
index 0000000..a6ef3b2
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+moddatetime.c
+
+What is this?
+It is a function to be called from a trigger for the perpose of updating
+a modification datetime stamp in a record when that record is UPDATEd.
+
+Credits
+This is 95%+ based on autoinc.c, which I used as a starting point as I do
+not really know what I am doing.  I also had help from 
+Jan Wieck <jwieck@debis.com> who told me about the datetime_in("now") function.
+OH, me, I'm Terry Mackintosh <terry@terrym.com>
+*/
+
+#include "executor/spi.h"              /* this is what you need to work with SPI */
+#include "commands/trigger.h"  /* -"- and triggers */
+
+HeapTuple      moddatetime(void);
+
+HeapTuple moddatetime()
+{
+       Trigger         *trigger;               /* to get trigger name */
+       int                     nargs;                  /* # of arguments */
+       int                     attnum;                 /* positional number of field to change */
+       Datum                   newdt;                  /* The current datetime. */
+       char                    **args;                 /* arguments */
+       char                    *relname;               /* triggered relation name */
+       Relation                rel;                            /* triggered relation */
+       HeapTuple       rettuple = NULL;
+       TupleDesc       tupdesc;                        /* tuple description */
+
+       if (!CurrentTriggerData)
+               elog(ERROR, "moddatetime: triggers are not initialized.");
+
+       if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
+               elog(ERROR, "moddatetime: can't process STATEMENT events.");
+
+       if (TRIGGER_FIRED_AFTER(CurrentTriggerData->tg_event))
+               elog(ERROR, "moddatetime: must be fired before event.");
+
+       if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
+               elog(ERROR, "moddatetime: must be fired before event.");
+       else if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
+               rettuple = CurrentTriggerData->tg_newtuple;
+       else
+               elog(ERROR, "moddatetime: can't process DELETE events.");
+
+       rel = CurrentTriggerData->tg_relation;
+       relname = SPI_getrelname(rel);
+
+       trigger = CurrentTriggerData->tg_trigger;
+
+       nargs = trigger->tgnargs;
+
+       if (nargs != 1)
+               elog(ERROR, "moddatetime (%s): A single argument was expected.", relname);
+
+       args = trigger->tgargs;
+       /* must be the field layout? */
+       tupdesc = rel->rd_att;
+
+       /* Why do this? */
+       CurrentTriggerData = NULL;
+
+       /* Get the current datetime. */
+       newdt = datetime_in("now");
+
+       /* This gets the position in the turple of the field we want.
+               args[0] being the name of the field to update, as passed in
+               from the trigger.
+       */
+       attnum = SPI_fnumber(tupdesc, args[0]);
+
+       /* This is were we check to see if the feild we are suppost to update even
+               exits.  The above function must return -1 if name not found?
+       */
+       if (attnum < 0)
+               elog(ERROR, "moddatetime (%s): there is no attribute %s", relname,
+                       args[0]);
+                       
+       /* OK, this is where we make sure the datetime field that we are 
+               modifying is really a datetime field.
+               Hay, error checking, what a novel idea !-)
+       */
+       if (SPI_gettypeid(tupdesc, attnum) != DATETIMEOID )
+               elog(ERROR, "moddatetime (%s): attribute %s must be of DATETIME type",
+                        relname, args[0]);
+
+/* 1 is the number of items in the arrays attnum and newdt. 
+       attnum is the positional number of the field to be updated.
+       newdt is the new datetime stamp.
+       NOTE that attnum and newdt are not arrays, but then a 1 ellement array
+       is not an array any more then they are.  Thus, they can be considered a
+       one element array.
+*/
+       rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newdt, NULL);
+
+       if (rettuple == NULL)
+               elog(ERROR, "moddatetime (%s): %d returned by SPI_modifytuple",
+                        relname, SPI_result);
+
+/* Clean up */
+       pfree(relname);
+
+       return (rettuple);
+}
diff --git a/contrib/spi/moddatetime.example b/contrib/spi/moddatetime.example
new file mode 100644 (file)
index 0000000..25a54e3
--- /dev/null
@@ -0,0 +1,27 @@
+DROP TABLE mdt;
+
+CREATE TABLE mdt (
+       id              int4,
+       idesc           text,
+       moddate datetime DEFAULT datetime(CURRENT_TIMESTAMP) NOT NULL
+);
+
+CREATE TRIGGER mdt_moddatetime
+       BEFORE UPDATE ON mdt
+       FOR EACH ROW 
+       EXECUTE PROCEDURE moddatetime (moddate);
+
+INSERT INTO mdt VALUES (1, 'first');
+INSERT INTO mdt VALUES (2, 'second');
+INSERT INTO mdt VALUES (3, 'third');
+
+SELECT * FROM mdt;
+
+UPDATE mdt SET id = 4
+       WHERE id = 1;
+UPDATE mdt SET id = 5
+       WHERE id = 2;
+UPDATE mdt SET id = 6
+       WHERE id = 3;
+
+SELECT * FROM mdt;
diff --git a/contrib/spi/moddatetime.source b/contrib/spi/moddatetime.source
new file mode 100644 (file)
index 0000000..26906a3
--- /dev/null
@@ -0,0 +1,6 @@
+DROP FUNCTION moddatetime();
+
+CREATE FUNCTION moddatetime() 
+       RETURNS opaque 
+       AS '_OBJWD_/moddatetime_DLSUFFIX_'
+       LANGUAGE 'c';