|
| 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 | +} |
0 commit comments