~ubuntu-branches/debian/sid/postgresql-9.3/sid

« back to all changes in this revision

Viewing changes to contrib/spi/moddatetime.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2013-05-08 05:39:52 UTC
  • Revision ID: package-import@ubuntu.com-20130508053952-1j7uilp7mjtrvq8q
Tags: upstream-9.3~beta1
ImportĀ upstreamĀ versionĀ 9.3~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
moddatetime.c
 
3
 
 
4
contrib/spi/moddatetime.c
 
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
#include "utils/rel.h"
 
22
#include "utils/timestamp.h"
 
23
 
 
24
PG_MODULE_MAGIC;
 
25
 
 
26
extern Datum moddatetime(PG_FUNCTION_ARGS);
 
27
 
 
28
PG_FUNCTION_INFO_V1(moddatetime);
 
29
 
 
30
Datum
 
31
moddatetime(PG_FUNCTION_ARGS)
 
32
{
 
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 */
 
44
 
 
45
        if (!CALLED_AS_TRIGGER(fcinfo))
 
46
                /* internal error */
 
47
                elog(ERROR, "moddatetime: not fired by trigger manager");
 
48
 
 
49
        if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
 
50
                /* internal error */
 
51
                elog(ERROR, "moddatetime: must be fired for row");
 
52
 
 
53
        if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
 
54
                /* internal error */
 
55
                elog(ERROR, "moddatetime: must be fired before event");
 
56
 
 
57
        if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
 
58
                /* internal error */
 
59
                elog(ERROR, "moddatetime: cannot process INSERT events");
 
60
        else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
 
61
                rettuple = trigdata->tg_newtuple;
 
62
        else
 
63
                /* internal error */
 
64
                elog(ERROR, "moddatetime: cannot process DELETE events");
 
65
 
 
66
        rel = trigdata->tg_relation;
 
67
        relname = SPI_getrelname(rel);
 
68
 
 
69
        trigger = trigdata->tg_trigger;
 
70
 
 
71
        nargs = trigger->tgnargs;
 
72
 
 
73
        if (nargs != 1)
 
74
                /* internal error */
 
75
                elog(ERROR, "moddatetime (%s): A single argument was expected", relname);
 
76
 
 
77
        args = trigger->tgargs;
 
78
        /* must be the field layout? */
 
79
        tupdesc = rel->rd_att;
 
80
 
 
81
        /*
 
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.
 
84
         */
 
85
        attnum = SPI_fnumber(tupdesc, args[0]);
 
86
 
 
87
        /*
 
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?
 
90
         */
 
91
        if (attnum < 0)
 
92
                ereport(ERROR,
 
93
                                (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
 
94
                                 errmsg("\"%s\" has no attribute \"%s\"",
 
95
                                                relname, args[0])));
 
96
 
 
97
        /*
 
98
         * Check the target field has an allowed type, and get the current
 
99
         * datetime as a value of that type.
 
100
         */
 
101
        atttypid = SPI_gettypeid(tupdesc, attnum);
 
102
        if (atttypid == TIMESTAMPOID)
 
103
                newdt = DirectFunctionCall3(timestamp_in,
 
104
                                                                        CStringGetDatum("now"),
 
105
                                                                        ObjectIdGetDatum(InvalidOid),
 
106
                                                                        Int32GetDatum(-1));
 
107
        else if (atttypid == TIMESTAMPTZOID)
 
108
                newdt = DirectFunctionCall3(timestamptz_in,
 
109
                                                                        CStringGetDatum("now"),
 
110
                                                                        ObjectIdGetDatum(InvalidOid),
 
111
                                                                        Int32GetDatum(-1));
 
112
        else
 
113
        {
 
114
                ereport(ERROR,
 
115
                                (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
 
116
                                 errmsg("attribute \"%s\" of \"%s\" must be type TIMESTAMP or TIMESTAMPTZ",
 
117
                                                args[0], relname)));
 
118
                newdt = (Datum) 0;              /* keep compiler quiet */
 
119
        }
 
120
 
 
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
 
126
        one element array.
 
127
*/
 
128
        rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newdt, NULL);
 
129
 
 
130
        if (rettuple == NULL)
 
131
                /* internal error */
 
132
                elog(ERROR, "moddatetime (%s): %d returned by SPI_modifytuple",
 
133
                         relname, SPI_result);
 
134
 
 
135
/* Clean up */
 
136
        pfree(relname);
 
137
 
 
138
        return PointerGetDatum(rettuple);
 
139
}