Go to the documentation of this file.00001
00002
00003
00004 #include "postgres.h"
00005
00006 #include "catalog/pg_type.h"
00007 #include "commands/sequence.h"
00008 #include "commands/trigger.h"
00009 #include "executor/spi.h"
00010 #include "utils/builtins.h"
00011 #include "utils/rel.h"
00012
00013 PG_MODULE_MAGIC;
00014
00015 extern Datum autoinc(PG_FUNCTION_ARGS);
00016
00017 PG_FUNCTION_INFO_V1(autoinc);
00018
00019 Datum
00020 autoinc(PG_FUNCTION_ARGS)
00021 {
00022 TriggerData *trigdata = (TriggerData *) fcinfo->context;
00023 Trigger *trigger;
00024 int nargs;
00025 int *chattrs;
00026 int chnattrs = 0;
00027 Datum *newvals;
00028 char **args;
00029 char *relname;
00030 Relation rel;
00031 HeapTuple rettuple = NULL;
00032 TupleDesc tupdesc;
00033 bool isnull;
00034 int i;
00035
00036 if (!CALLED_AS_TRIGGER(fcinfo))
00037
00038 elog(ERROR, "not fired by trigger manager");
00039 if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
00040
00041 elog(ERROR, "must be fired for row");
00042 if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
00043
00044 elog(ERROR, "must be fired before event");
00045
00046 if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
00047 rettuple = trigdata->tg_trigtuple;
00048 else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
00049 rettuple = trigdata->tg_newtuple;
00050 else
00051
00052 elog(ERROR, "cannot process DELETE events");
00053
00054 rel = trigdata->tg_relation;
00055 relname = SPI_getrelname(rel);
00056
00057 trigger = trigdata->tg_trigger;
00058
00059 nargs = trigger->tgnargs;
00060 if (nargs <= 0 || nargs % 2 != 0)
00061
00062 elog(ERROR, "autoinc (%s): even number gt 0 of arguments was expected", relname);
00063
00064 args = trigger->tgargs;
00065 tupdesc = rel->rd_att;
00066
00067 chattrs = (int *) palloc(nargs / 2 * sizeof(int));
00068 newvals = (Datum *) palloc(nargs / 2 * sizeof(Datum));
00069
00070 for (i = 0; i < nargs;)
00071 {
00072 int attnum = SPI_fnumber(tupdesc, args[i]);
00073 int32 val;
00074 Datum seqname;
00075
00076 if (attnum < 0)
00077 ereport(ERROR,
00078 (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
00079 errmsg("\"%s\" has no attribute \"%s\"",
00080 relname, args[i])));
00081
00082 if (SPI_gettypeid(tupdesc, attnum) != INT4OID)
00083 ereport(ERROR,
00084 (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
00085 errmsg("attribute \"%s\" of \"%s\" must be type INT4",
00086 args[i], relname)));
00087
00088 val = DatumGetInt32(SPI_getbinval(rettuple, tupdesc, attnum, &isnull));
00089
00090 if (!isnull && val != 0)
00091 {
00092 i += 2;
00093 continue;
00094 }
00095
00096 i++;
00097 chattrs[chnattrs] = attnum;
00098 seqname = CStringGetTextDatum(args[i]);
00099 newvals[chnattrs] = DirectFunctionCall1(nextval, seqname);
00100
00101 newvals[chnattrs] = Int32GetDatum((int32) DatumGetInt64(newvals[chnattrs]));
00102 if (DatumGetInt32(newvals[chnattrs]) == 0)
00103 {
00104 newvals[chnattrs] = DirectFunctionCall1(nextval, seqname);
00105 newvals[chnattrs] = Int32GetDatum((int32) DatumGetInt64(newvals[chnattrs]));
00106 }
00107 pfree(DatumGetTextP(seqname));
00108 chnattrs++;
00109 i++;
00110 }
00111
00112 if (chnattrs > 0)
00113 {
00114 rettuple = SPI_modifytuple(rel, rettuple, chnattrs, chattrs, newvals, NULL);
00115 if (rettuple == NULL)
00116
00117 elog(ERROR, "autoinc (%s): %d returned by SPI_modifytuple",
00118 relname, SPI_result);
00119 }
00120
00121 pfree(relname);
00122 pfree(chattrs);
00123 pfree(newvals);
00124
00125 return PointerGetDatum(rettuple);
00126 }