mirror of https://github.com/postgres/postgres
parent
0d5a08f769
commit
14f9dde379
@ -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); |
||||
} |
||||
@ -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; |
||||
@ -0,0 +1,6 @@ |
||||
DROP FUNCTION moddatetime(); |
||||
|
||||
CREATE FUNCTION moddatetime() |
||||
RETURNS opaque |
||||
AS '_OBJWD_/moddatetime_DLSUFFIX_' |
||||
LANGUAGE 'c'; |
||||
Loading…
Reference in new issue