~ubuntu-branches/ubuntu/hardy/postgresql-8.4/hardy-backports

« back to all changes in this revision

Viewing changes to contrib/spi/moddatetime.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
moddatetime.c
 
3
 
 
4
$PostgreSQL$
 
5
 
 
6
What is this?
 
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.
 
9
 
 
10
Credits
 
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>
 
15
*/
 
16
#include "postgres.h"
 
17
 
 
18
#include "catalog/pg_type.h"
 
19
#include "executor/spi.h"
 
20
#include "commands/trigger.h"
 
21
 
 
22
PG_MODULE_MAGIC;
 
23
 
 
24
extern Datum moddatetime(PG_FUNCTION_ARGS);
 
25
 
 
26
PG_FUNCTION_INFO_V1(moddatetime);
 
27
 
 
28
Datum
 
29
moddatetime(PG_FUNCTION_ARGS)
 
30
{
 
31
        TriggerData *trigdata = (TriggerData *) fcinfo->context;
 
32
        Trigger    *trigger;            /* to get trigger name */
 
33
        int                     nargs;                  /* # of arguments */
 
34
        int                     attnum;                 /* positional number of field to change */
 
35
        Datum           newdt;                  /* The current datetime. */
 
36
        char      **args;                       /* arguments */
 
37
        char       *relname;            /* triggered relation name */
 
38
        Relation        rel;                    /* triggered relation */
 
39
        HeapTuple       rettuple = NULL;
 
40
        TupleDesc       tupdesc;                /* tuple description */
 
41
 
 
42
        if (!CALLED_AS_TRIGGER(fcinfo))
 
43
                /* internal error */
 
44
                elog(ERROR, "moddatetime: not fired by trigger manager");
 
45
 
 
46
        if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
 
47
                /* internal error */
 
48
                elog(ERROR, "moddatetime: cannot process STATEMENT events");
 
49
 
 
50
        if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
 
51
                /* internal error */
 
52
                elog(ERROR, "moddatetime: must be fired before event");
 
53
 
 
54
        if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
 
55
                /* internal error */
 
56
                elog(ERROR, "moddatetime: must be fired before event");
 
57
        else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
 
58
                rettuple = trigdata->tg_newtuple;
 
59
        else
 
60
                /* internal error */
 
61
                elog(ERROR, "moddatetime: cannot process DELETE events");
 
62
 
 
63
        rel = trigdata->tg_relation;
 
64
        relname = SPI_getrelname(rel);
 
65
 
 
66
        trigger = trigdata->tg_trigger;
 
67
 
 
68
        nargs = trigger->tgnargs;
 
69
 
 
70
        if (nargs != 1)
 
71
                /* internal error */
 
72
                elog(ERROR, "moddatetime (%s): A single argument was expected", relname);
 
73
 
 
74
        args = trigger->tgargs;
 
75
        /* must be the field layout? */
 
76
        tupdesc = rel->rd_att;
 
77
 
 
78
        /* Get the current datetime. */
 
79
        newdt = DirectFunctionCall3(timestamp_in,
 
80
                                                                CStringGetDatum("now"),
 
81
                                                                ObjectIdGetDatum(InvalidOid),
 
82
                                                                Int32GetDatum(-1));
 
83
 
 
84
        /*
 
85
         * This gets the position in the tuple of the field we want. args[0] being
 
86
         * the name of the field to update, as passed in from the trigger.
 
87
         */
 
88
        attnum = SPI_fnumber(tupdesc, args[0]);
 
89
 
 
90
        /*
 
91
         * This is were we check to see if the field we are supposed to update
 
92
         * even exits.  The above function must return -1 if name not found?
 
93
         */
 
94
        if (attnum < 0)
 
95
                ereport(ERROR,
 
96
                                (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
 
97
                                 errmsg("\"%s\" has no attribute \"%s\"",
 
98
                                                relname, args[0])));
 
99
 
 
100
        /*
 
101
         * OK, this is where we make sure the timestamp field that we are
 
102
         * modifying is really a timestamp field. Hay, error checking, what a
 
103
         * novel idea !-)
 
104
         */
 
105
        if (SPI_gettypeid(tupdesc, attnum) != TIMESTAMPOID)
 
106
                ereport(ERROR,
 
107
                                (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
 
108
                                 errmsg("attribute \"%s\" of \"%s\" must be type TIMESTAMP",
 
109
                                                args[0], relname)));
 
110
 
 
111
/* 1 is the number of items in the arrays attnum and newdt.
 
112
        attnum is the positional number of the field to be updated.
 
113
        newdt is the new datetime stamp.
 
114
        NOTE that attnum and newdt are not arrays, but then a 1 ellement array
 
115
        is not an array any more then they are.  Thus, they can be considered a
 
116
        one element array.
 
117
*/
 
118
        rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newdt, NULL);
 
119
 
 
120
        if (rettuple == NULL)
 
121
                /* internal error */
 
122
                elog(ERROR, "moddatetime (%s): %d returned by SPI_modifytuple",
 
123
                         relname, SPI_result);
 
124
 
 
125
/* Clean up */
 
126
        pfree(relname);
 
127
 
 
128
        return PointerGetDatum(rettuple);
 
129
}