2 * contrib/spi/autoinc.c
6 #include "access/htup_details.h"
7 #include "catalog/pg_type.h"
8 #include "commands/sequence.h"
9 #include "commands/trigger.h"
10 #include "executor/spi.h"
11 #include "utils/builtins.h"
12 #include "utils/rel.h"
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 bool *newnulls
; /* null flags for above */
28 char **args
; /* arguments */
29 char *relname
; /* triggered relation name */
30 Relation rel
; /* triggered relation */
31 HeapTuple rettuple
= NULL
;
32 TupleDesc tupdesc
; /* tuple description */
36 if (!CALLED_AS_TRIGGER(fcinfo
))
38 elog(ERROR
, "not fired by trigger manager");
39 if (!TRIGGER_FIRED_FOR_ROW(trigdata
->tg_event
))
41 elog(ERROR
, "must be fired for row");
42 if (!TRIGGER_FIRED_BEFORE(trigdata
->tg_event
))
44 elog(ERROR
, "must be fired before event");
46 if (TRIGGER_FIRED_BY_INSERT(trigdata
->tg_event
))
47 rettuple
= trigdata
->tg_trigtuple
;
48 else if (TRIGGER_FIRED_BY_UPDATE(trigdata
->tg_event
))
49 rettuple
= trigdata
->tg_newtuple
;
52 elog(ERROR
, "cannot process DELETE events");
54 rel
= trigdata
->tg_relation
;
55 relname
= SPI_getrelname(rel
);
57 trigger
= trigdata
->tg_trigger
;
59 nargs
= trigger
->tgnargs
;
60 if (nargs
<= 0 || nargs
% 2 != 0)
62 elog(ERROR
, "autoinc (%s): even number gt 0 of arguments was expected", relname
);
64 args
= trigger
->tgargs
;
65 tupdesc
= rel
->rd_att
;
67 chattrs
= (int *) palloc(nargs
/ 2 * sizeof(int));
68 newvals
= (Datum
*) palloc(nargs
/ 2 * sizeof(Datum
));
69 newnulls
= (bool *) palloc(nargs
/ 2 * sizeof(bool));
71 for (i
= 0; i
< nargs
;)
73 int attnum
= SPI_fnumber(tupdesc
, args
[i
]);
79 (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION
),
80 errmsg("\"%s\" has no attribute \"%s\"",
83 if (SPI_gettypeid(tupdesc
, attnum
) != INT4OID
)
85 (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION
),
86 errmsg("attribute \"%s\" of \"%s\" must be type INT4",
89 val
= DatumGetInt32(SPI_getbinval(rettuple
, tupdesc
, attnum
, &isnull
));
91 if (!isnull
&& val
!= 0)
98 chattrs
[chnattrs
] = attnum
;
99 seqname
= CStringGetTextDatum(args
[i
]);
100 newvals
[chnattrs
] = DirectFunctionCall1(nextval
, seqname
);
101 /* nextval now returns int64; coerce down to int32 */
102 newvals
[chnattrs
] = Int32GetDatum((int32
) DatumGetInt64(newvals
[chnattrs
]));
103 if (DatumGetInt32(newvals
[chnattrs
]) == 0)
105 newvals
[chnattrs
] = DirectFunctionCall1(nextval
, seqname
);
106 newvals
[chnattrs
] = Int32GetDatum((int32
) DatumGetInt64(newvals
[chnattrs
]));
108 newnulls
[chnattrs
] = false;
109 pfree(DatumGetTextPP(seqname
));
116 rettuple
= heap_modify_tuple_by_cols(rettuple
, tupdesc
,
126 return PointerGetDatum(rettuple
);