summaryrefslogtreecommitdiff
path: root/contrib/spi/autoinc.c
diff options
context:
space:
mode:
authorVadim B. Mikheev1997-10-02 18:01:57 +0000
committerVadim B. Mikheev1997-10-02 18:01:57 +0000
commitd75206fdf59d1c0f49137e6b5dd65ea942da35ff (patch)
treeac13a5b7b6921bcc4ba5607904c60d6f95c96807 /contrib/spi/autoinc.c
parentcd7c56eeeb83f6407d791186927667c4a415b204 (diff)
General function for SERIAL/IDENTITY/AUTOINCREMENT feature.
Handle INSERT event in timetravel().
Diffstat (limited to 'contrib/spi/autoinc.c')
-rw-r--r--contrib/spi/autoinc.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/contrib/spi/autoinc.c b/contrib/spi/autoinc.c
new file mode 100644
index 00000000000..2aceea60fa0
--- /dev/null
+++ b/contrib/spi/autoinc.c
@@ -0,0 +1,100 @@
+
+#include "executor/spi.h" /* this is what you need to work with SPI */
+#include "commands/trigger.h" /* -"- and triggers */
+
+HeapTuple autoinc(void);
+
+extern int4 nextval(struct varlena * seqin);
+
+HeapTuple
+autoinc()
+{
+ Trigger *trigger; /* to get trigger name */
+ int nargs; /* # of arguments */
+ int *chattrs; /* attnums of attributes to change */
+ int chnattrs = 0; /* # of above */
+ Datum *newvals; /* vals of above */
+ char **args; /* arguments */
+ char *relname; /* triggered relation name */
+ Relation rel; /* triggered relation */
+ HeapTuple rettuple = NULL;
+ TupleDesc tupdesc; /* tuple description */
+ bool isnull;
+ int i;
+
+ if (!CurrentTriggerData)
+ elog(WARN, "autoinc: triggers are not initialized");
+ if (TRIGGER_FIRED_FOR_STATEMENT(CurrentTriggerData->tg_event))
+ elog(WARN, "autoinc: can't process STATEMENT events");
+ if (TRIGGER_FIRED_AFTER(CurrentTriggerData->tg_event))
+ elog(WARN, "autoinc: must be fired before event");
+
+ if (TRIGGER_FIRED_BY_INSERT(CurrentTriggerData->tg_event))
+ rettuple = CurrentTriggerData->tg_trigtuple;
+ else if (TRIGGER_FIRED_BY_UPDATE(CurrentTriggerData->tg_event))
+ rettuple = CurrentTriggerData->tg_newtuple;
+ else
+ elog(WARN, "autoinc: can't process DELETE events");
+
+ rel = CurrentTriggerData->tg_relation;
+ relname = SPI_getrelname(rel);
+
+ trigger = CurrentTriggerData->tg_trigger;
+
+ nargs = trigger->tgnargs;
+ if (nargs <= 0 || nargs % 2 != 0)
+ elog(WARN, "autoinc (%s): even number gt 0 of arguments was expected", relname);
+
+ args = trigger->tgargs;
+ tupdesc = rel->rd_att;
+
+ CurrentTriggerData = NULL;
+
+ chattrs = (int *) palloc (nargs/2 * sizeof (int));
+ newvals = (Datum *) palloc (nargs/2 * sizeof (Datum));
+
+ for (i = 0; i < nargs; )
+ {
+ struct varlena *seqname;
+ int attnum = SPI_fnumber (tupdesc, args[i]);
+ int32 val;
+
+ if ( attnum < 0 )
+ elog(WARN, "autoinc (%s): there is no attribute %s", relname, args[i]);
+ if (SPI_gettypeid (tupdesc, attnum) != INT4OID)
+ elog(WARN, "autoinc (%s): attribute %s must be of INT4 type",
+ relname, args[i]);
+
+ val = DatumGetInt32 (SPI_getbinval (rettuple, tupdesc, attnum, &isnull));
+
+ if (!isnull && val != 0)
+ {
+ i += 2;
+ continue;
+ }
+
+ i++;
+ chattrs[chnattrs] = attnum;
+ seqname = textin (args[i]);
+ newvals[chnattrs] = Int32GetDatum (nextval (seqname));
+ if ( DatumGetInt32 (newvals[chnattrs]) == 0 )
+ newvals[chnattrs] = Int32GetDatum (nextval (seqname));
+ pfree (seqname);
+ chnattrs++;
+ i++;
+ }
+
+ if (chnattrs > 0)
+ {
+ rettuple = SPI_modifytuple (rel, rettuple, chnattrs, chattrs, newvals, NULL);
+ if ( rettuple == NULL )
+ elog (WARN, "autoinc (%s): %d returned by SPI_modifytuple",
+ relname, SPI_result);
+ }
+
+ pfree (relname);
+ pfree (chattrs);
+ pfree (newvals);
+
+ return (rettuple);
+}