4
contrib/spi/moddatetime.c
7
It is a function to be called from a trigger for the purpose of updating
8
a modification datetime stamp in a record when that record is UPDATEd.
11
This is 95%+ based on autoinc.c, which I used as a starting point as I do
12
not really know what I am doing. I also had help from
13
Jan Wieck <jwieck@debis.com> who told me about the timestamp_in("now") function.
14
OH, me, I'm Terry Mackintosh <terry@terrym.com>
18
#include "catalog/pg_type.h"
19
#include "executor/spi.h"
20
#include "commands/trigger.h"
21
#include "utils/rel.h"
22
#include "utils/timestamp.h"
26
extern Datum moddatetime(PG_FUNCTION_ARGS);
28
PG_FUNCTION_INFO_V1(moddatetime);
31
moddatetime(PG_FUNCTION_ARGS)
33
TriggerData *trigdata = (TriggerData *) fcinfo->context;
34
Trigger *trigger; /* to get trigger name */
35
int nargs; /* # of arguments */
36
int attnum; /* positional number of field to change */
37
Oid atttypid; /* type OID of field to change */
38
Datum newdt; /* The current datetime. */
39
char **args; /* arguments */
40
char *relname; /* triggered relation name */
41
Relation rel; /* triggered relation */
42
HeapTuple rettuple = NULL;
43
TupleDesc tupdesc; /* tuple description */
45
if (!CALLED_AS_TRIGGER(fcinfo))
47
elog(ERROR, "moddatetime: not fired by trigger manager");
49
if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
51
elog(ERROR, "moddatetime: must be fired for row");
53
if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
55
elog(ERROR, "moddatetime: must be fired before event");
57
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
59
elog(ERROR, "moddatetime: cannot process INSERT events");
60
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
61
rettuple = trigdata->tg_newtuple;
64
elog(ERROR, "moddatetime: cannot process DELETE events");
66
rel = trigdata->tg_relation;
67
relname = SPI_getrelname(rel);
69
trigger = trigdata->tg_trigger;
71
nargs = trigger->tgnargs;
75
elog(ERROR, "moddatetime (%s): A single argument was expected", relname);
77
args = trigger->tgargs;
78
/* must be the field layout? */
79
tupdesc = rel->rd_att;
82
* This gets the position in the tuple of the field we want. args[0] being
83
* the name of the field to update, as passed in from the trigger.
85
attnum = SPI_fnumber(tupdesc, args[0]);
88
* This is where we check to see if the field we are supposed to update
89
* even exists. The above function must return -1 if name not found?
93
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
94
errmsg("\"%s\" has no attribute \"%s\"",
98
* Check the target field has an allowed type, and get the current
99
* datetime as a value of that type.
101
atttypid = SPI_gettypeid(tupdesc, attnum);
102
if (atttypid == TIMESTAMPOID)
103
newdt = DirectFunctionCall3(timestamp_in,
104
CStringGetDatum("now"),
105
ObjectIdGetDatum(InvalidOid),
107
else if (atttypid == TIMESTAMPTZOID)
108
newdt = DirectFunctionCall3(timestamptz_in,
109
CStringGetDatum("now"),
110
ObjectIdGetDatum(InvalidOid),
115
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
116
errmsg("attribute \"%s\" of \"%s\" must be type TIMESTAMP or TIMESTAMPTZ",
118
newdt = (Datum) 0; /* keep compiler quiet */
121
/* 1 is the number of items in the arrays attnum and newdt.
122
attnum is the positional number of the field to be updated.
123
newdt is the new datetime stamp.
124
NOTE that attnum and newdt are not arrays, but then a 1 element array
125
is not an array any more then they are. Thus, they can be considered a
128
rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newdt, NULL);
130
if (rettuple == NULL)
132
elog(ERROR, "moddatetime (%s): %d returned by SPI_modifytuple",
133
relname, SPI_result);
138
return PointerGetDatum(rettuple);