5
It is a function to be called from a trigger for the purpose of updating
6
a modification datetime stamp in a record when that record is UPDATEd.
9
This is 95%+ based on autoinc.c, which I used as a starting point as I do
10
not really know what I am doing. I also had help from
11
Jan Wieck <jwieck@debis.com> who told me about the timestamp_in("now") function.
12
OH, me, I'm Terry Mackintosh <terry@terrym.com>
15
#include "executor/spi.h" /* this is what you need to work with SPI */
16
#include "commands/trigger.h" /* -"- and triggers */
18
extern Datum moddatetime(PG_FUNCTION_ARGS);
20
PG_FUNCTION_INFO_V1(moddatetime);
23
moddatetime(PG_FUNCTION_ARGS)
25
TriggerData *trigdata = (TriggerData *) fcinfo->context;
26
Trigger *trigger; /* to get trigger name */
27
int nargs; /* # of arguments */
28
int attnum; /* positional number of field to change */
29
Datum newdt; /* The current datetime. */
30
char **args; /* arguments */
31
char *relname; /* triggered relation name */
32
Relation rel; /* triggered relation */
33
HeapTuple rettuple = NULL;
34
TupleDesc tupdesc; /* tuple description */
36
if (!CALLED_AS_TRIGGER(fcinfo))
38
elog(ERROR, "moddatetime: not fired by trigger manager");
40
if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
42
elog(ERROR, "moddatetime: can't process STATEMENT events");
44
if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
46
elog(ERROR, "moddatetime: must be fired before event");
48
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
50
elog(ERROR, "moddatetime: must be fired before event");
51
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
52
rettuple = trigdata->tg_newtuple;
55
elog(ERROR, "moddatetime: can't process DELETE events");
57
rel = trigdata->tg_relation;
58
relname = SPI_getrelname(rel);
60
trigger = trigdata->tg_trigger;
62
nargs = trigger->tgnargs;
66
elog(ERROR, "moddatetime (%s): A single argument was expected", relname);
68
args = trigger->tgargs;
69
/* must be the field layout? */
70
tupdesc = rel->rd_att;
72
/* Get the current datetime. */
73
newdt = DirectFunctionCall3(timestamp_in,
74
CStringGetDatum("now"),
75
ObjectIdGetDatum(InvalidOid),
79
* This gets the position in the tuple of the field we want. args[0]
80
* being the name of the field to update, as passed in from the
83
attnum = SPI_fnumber(tupdesc, args[0]);
86
* This is were we check to see if the field we are supposed to update
87
* even exits. The above function must return -1 if name not found?
91
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
92
errmsg("\"%s\" has no attribute \"%s\"",
96
* OK, this is where we make sure the timestamp field that we are
97
* modifying is really a timestamp field. Hay, error checking, what a
100
if (SPI_gettypeid(tupdesc, attnum) != TIMESTAMPOID)
102
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
103
errmsg("attribute \"%s\" of \"%s\" must be type TIMESTAMP",
106
/* 1 is the number of items in the arrays attnum and newdt.
107
attnum is the positional number of the field to be updated.
108
newdt is the new datetime stamp.
109
NOTE that attnum and newdt are not arrays, but then a 1 ellement array
110
is not an array any more then they are. Thus, they can be considered a
113
rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newdt, NULL);
115
if (rettuple == NULL)
117
elog(ERROR, "moddatetime (%s): %d returned by SPI_modifytuple",
118
relname, SPI_result);
123
return PointerGetDatum(rettuple);