2 * contrib/spi/autoinc.c
6 #include "catalog/pg_type.h"
7 #include "commands/sequence.h"
8 #include "commands/trigger.h"
9 #include "executor/spi.h"
10 #include "utils/builtins.h"
14 extern Datum autoinc(PG_FUNCTION_ARGS);
16 PG_FUNCTION_INFO_V1(autoinc);
19 autoinc(PG_FUNCTION_ARGS)
21 TriggerData *trigdata = (TriggerData *) fcinfo->context;
22 Trigger *trigger; /* to get trigger name */
23 int nargs; /* # of arguments */
24 int *chattrs; /* attnums of attributes to change */
25 int chnattrs = 0; /* # of above */
26 Datum *newvals; /* vals of above */
27 char **args; /* arguments */
28 char *relname; /* triggered relation name */
29 Relation rel; /* triggered relation */
30 HeapTuple rettuple = NULL;
31 TupleDesc tupdesc; /* tuple description */
35 if (!CALLED_AS_TRIGGER(fcinfo))
37 elog(ERROR, "not fired by trigger manager");
38 if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
40 elog(ERROR, "cannot process STATEMENT events");
41 if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
43 elog(ERROR, "must be fired before event");
45 if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
46 rettuple = trigdata->tg_trigtuple;
47 else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
48 rettuple = trigdata->tg_newtuple;
51 elog(ERROR, "cannot process DELETE events");
53 rel = trigdata->tg_relation;
54 relname = SPI_getrelname(rel);
56 trigger = trigdata->tg_trigger;
58 nargs = trigger->tgnargs;
59 if (nargs <= 0 || nargs % 2 != 0)
61 elog(ERROR, "autoinc (%s): even number gt 0 of arguments was expected", relname);
63 args = trigger->tgargs;
64 tupdesc = rel->rd_att;
66 chattrs = (int *) palloc(nargs / 2 * sizeof(int));
67 newvals = (Datum *) palloc(nargs / 2 * sizeof(Datum));
69 for (i = 0; i < nargs;)
71 int attnum = SPI_fnumber(tupdesc, args[i]);
77 (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
78 errmsg("\"%s\" has no attribute \"%s\"",
81 if (SPI_gettypeid(tupdesc, attnum) != INT4OID)
83 (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
84 errmsg("attribute \"%s\" of \"%s\" must be type INT4",
87 val = DatumGetInt32(SPI_getbinval(rettuple, tupdesc, attnum, &isnull));
89 if (!isnull && val != 0)
96 chattrs[chnattrs] = attnum;
97 seqname = CStringGetTextDatum(args[i]);
98 newvals[chnattrs] = DirectFunctionCall1(nextval, seqname);
99 /* nextval now returns int64; coerce down to int32 */
100 newvals[chnattrs] = Int32GetDatum((int32) DatumGetInt64(newvals[chnattrs]));
101 if (DatumGetInt32(newvals[chnattrs]) == 0)
103 newvals[chnattrs] = DirectFunctionCall1(nextval, seqname);
104 newvals[chnattrs] = Int32GetDatum((int32) DatumGetInt64(newvals[chnattrs]));
106 pfree(DatumGetTextP(seqname));
113 rettuple = SPI_modifytuple(rel, rettuple, chnattrs, chattrs, newvals, NULL);
114 if (rettuple == NULL)
116 elog(ERROR, "autoinc (%s): %d returned by SPI_modifytuple",
117 relname, SPI_result);
124 return PointerGetDatum(rettuple);