summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Momjian1998-12-12 20:20:49 +0000
committerBruce Momjian1998-12-12 20:20:49 +0000
commit14f9dde3795fab85a907426265a6e0f793be1482 (patch)
treeac777c301ab34a711c4f2b8ce4432d44b13e2c10
parent0d5a08f7694f93e93eba9792ed38a0ee95ad73bb (diff)
New moddatetime contrib from Terry Mackintosh.
-rw-r--r--contrib/spi/Makefile2
-rw-r--r--contrib/spi/moddatetime.c106
-rw-r--r--contrib/spi/moddatetime.example27
-rw-r--r--contrib/spi/moddatetime.source6
4 files changed, 140 insertions, 1 deletions
diff --git a/contrib/spi/Makefile b/contrib/spi/Makefile
index 6bb634aa770..c9c9ff8d480 100644
--- a/contrib/spi/Makefile
+++ b/contrib/spi/Makefile
@@ -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
index 00000000000..a6ef3b27953
--- /dev/null
+++ b/contrib/spi/moddatetime.c
@@ -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 <[email protected]> who told me about the datetime_in("now") function.
+OH, me, I'm Terry Mackintosh <[email protected]>
+*/
+
+#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
index 00000000000..25a54e3a335
--- /dev/null
+++ b/contrib/spi/moddatetime.example
@@ -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
index 00000000000..26906a3f333
--- /dev/null
+++ b/contrib/spi/moddatetime.source
@@ -0,0 +1,6 @@
+DROP FUNCTION moddatetime();
+
+CREATE FUNCTION moddatetime()
+ RETURNS opaque
+ AS '_OBJWD_/moddatetime_DLSUFFIX_'
+ LANGUAGE 'c';