Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 14f9dde

Browse files
committed
New moddatetime contrib from Terry Mackintosh.
1 parent 0d5a08f commit 14f9dde

File tree

4 files changed

+140
-1
lines changed

4 files changed

+140
-1
lines changed

contrib/spi/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ CFLAGS+= -DREFINT_VERBOSE
1212
endif
1313

1414
TARGETS= refint$(DLSUFFIX) refint.sql timetravel$(DLSUFFIX) timetravel.sql \
15-
autoinc$(DLSUFFIX) autoinc.sql \
15+
autoinc$(DLSUFFIX) autoinc.sql moddatetime$(DLSUFFIX) moddatetime.sql \
1616
insert_username$(DLSUFFIX) insert_username.sql
1717

1818
CLEANFILES+= $(TARGETS)

contrib/spi/moddatetime.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
moddatetime.c
3+
4+
What is this?
5+
It is a function to be called from a trigger for the perpose of updating
6+
a modification datetime stamp in a record when that record is UPDATEd.
7+
8+
Credits
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 datetime_in("now") function.
12+
OH, me, I'm Terry Mackintosh <terry@terrym.com>
13+
*/
14+
15+
#include "executor/spi.h" /* this is what you need to work with SPI */
16+
#include "commands/trigger.h" /* -"- and triggers */
17+
18+
HeapTuple moddatetime(void);
19+
20+
HeapTuple moddatetime()
21+
{
22+
Trigger *trigger; /* to get trigger name */
23+
int nargs; /* # of arguments */
24+
int attnum; /* positional number of field to change */
25+
Datum newdt; /* The current datetime. */
26+
char **args; /* arguments */
27+
char *relname; /* triggered relation name */
28+
Relation rel; /* triggered relation */
29+
HeapTuple rettuple = NULL;
30+
TupleDesc tupdesc; /* tuple description */
31+
32+
if (!CurrentTriggerData)
33+
elog(ERROR, "moddatetime: triggers are not initialized.");
34+
35+
if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
36+
elog(ERROR, "moddatetime: can't process STATEMENT events.");
37+
38+
if (TRIGGER_FIRED_AFTER(CurrentTriggerData->tg_event))
39+
elog(ERROR, "moddatetime: must be fired before event.");
40+
41+
if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
42+
elog(ERROR, "moddatetime: must be fired before event.");
43+
else if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
44+
rettuple = CurrentTriggerData->tg_newtuple;
45+
else
46+
elog(ERROR, "moddatetime: can't process DELETE events.");
47+
48+
rel = CurrentTriggerData->tg_relation;
49+
relname = SPI_getrelname(rel);
50+
51+
trigger = CurrentTriggerData->tg_trigger;
52+
53+
nargs = trigger->tgnargs;
54+
55+
if (nargs != 1)
56+
elog(ERROR, "moddatetime (%s): A single argument was expected.", relname);
57+
58+
args = trigger->tgargs;
59+
/* must be the field layout? */
60+
tupdesc = rel->rd_att;
61+
62+
/* Why do this? */
63+
CurrentTriggerData = NULL;
64+
65+
/* Get the current datetime. */
66+
newdt = datetime_in("now");
67+
68+
/* This gets the position in the turple of the field we want.
69+
args[0] being the name of the field to update, as passed in
70+
from the trigger.
71+
*/
72+
attnum = SPI_fnumber(tupdesc, args[0]);
73+
74+
/* This is were we check to see if the feild we are suppost to update even
75+
exits. The above function must return -1 if name not found?
76+
*/
77+
if (attnum < 0)
78+
elog(ERROR, "moddatetime (%s): there is no attribute %s", relname,
79+
args[0]);
80+
81+
/* OK, this is where we make sure the datetime field that we are
82+
modifying is really a datetime field.
83+
Hay, error checking, what a novel idea !-)
84+
*/
85+
if (SPI_gettypeid(tupdesc, attnum) != DATETIMEOID )
86+
elog(ERROR, "moddatetime (%s): attribute %s must be of DATETIME type",
87+
relname, args[0]);
88+
89+
/* 1 is the number of items in the arrays attnum and newdt.
90+
attnum is the positional number of the field to be updated.
91+
newdt is the new datetime stamp.
92+
NOTE that attnum and newdt are not arrays, but then a 1 ellement array
93+
is not an array any more then they are. Thus, they can be considered a
94+
one element array.
95+
*/
96+
rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newdt, NULL);
97+
98+
if (rettuple == NULL)
99+
elog(ERROR, "moddatetime (%s): %d returned by SPI_modifytuple",
100+
relname, SPI_result);
101+
102+
/* Clean up */
103+
pfree(relname);
104+
105+
return (rettuple);
106+
}

contrib/spi/moddatetime.example

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
DROP TABLE mdt;
2+
3+
CREATE TABLE mdt (
4+
id int4,
5+
idesc text,
6+
moddate datetime DEFAULT datetime(CURRENT_TIMESTAMP) NOT NULL
7+
);
8+
9+
CREATE TRIGGER mdt_moddatetime
10+
BEFORE UPDATE ON mdt
11+
FOR EACH ROW
12+
EXECUTE PROCEDURE moddatetime (moddate);
13+
14+
INSERT INTO mdt VALUES (1, 'first');
15+
INSERT INTO mdt VALUES (2, 'second');
16+
INSERT INTO mdt VALUES (3, 'third');
17+
18+
SELECT * FROM mdt;
19+
20+
UPDATE mdt SET id = 4
21+
WHERE id = 1;
22+
UPDATE mdt SET id = 5
23+
WHERE id = 2;
24+
UPDATE mdt SET id = 6
25+
WHERE id = 3;
26+
27+
SELECT * FROM mdt;

contrib/spi/moddatetime.source

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
DROP FUNCTION moddatetime();
2+
3+
CREATE FUNCTION moddatetime()
4+
RETURNS opaque
5+
AS '_OBJWD_/moddatetime_DLSUFFIX_'
6+
LANGUAGE 'c';

0 commit comments

Comments
 (0)