Line data Source code
1 : /*
2 : * contrib/spi/insert_username.c
3 : *
4 : * insert user name in response to a trigger
5 : * usage: insert_username (column_name)
6 : */
7 : #include "postgres.h"
8 :
9 : #include "access/htup_details.h"
10 : #include "catalog/pg_type.h"
11 : #include "commands/trigger.h"
12 : #include "executor/spi.h"
13 : #include "miscadmin.h"
14 : #include "utils/builtins.h"
15 : #include "utils/rel.h"
16 :
17 0 : PG_MODULE_MAGIC_EXT(
18 : .name = "insert_username",
19 : .version = PG_VERSION
20 : );
21 :
22 0 : PG_FUNCTION_INFO_V1(insert_username);
23 :
24 : Datum
25 0 : insert_username(PG_FUNCTION_ARGS)
26 : {
27 0 : TriggerData *trigdata = (TriggerData *) fcinfo->context;
28 0 : Trigger *trigger; /* to get trigger name */
29 0 : int nargs; /* # of arguments */
30 0 : Datum newval; /* new value of column */
31 0 : bool newnull; /* null flag */
32 0 : char **args; /* arguments */
33 0 : char *relname; /* triggered relation name */
34 0 : Relation rel; /* triggered relation */
35 0 : HeapTuple rettuple = NULL;
36 0 : TupleDesc tupdesc; /* tuple description */
37 0 : int attnum;
38 :
39 : /* sanity checks from autoinc.c */
40 0 : if (!CALLED_AS_TRIGGER(fcinfo))
41 : /* internal error */
42 0 : elog(ERROR, "insert_username: not fired by trigger manager");
43 0 : if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
44 : /* internal error */
45 0 : elog(ERROR, "insert_username: must be fired for row");
46 0 : if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
47 : /* internal error */
48 0 : elog(ERROR, "insert_username: must be fired before event");
49 :
50 0 : if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
51 0 : rettuple = trigdata->tg_trigtuple;
52 0 : else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
53 0 : rettuple = trigdata->tg_newtuple;
54 : else
55 : /* internal error */
56 0 : elog(ERROR, "insert_username: cannot process DELETE events");
57 :
58 0 : rel = trigdata->tg_relation;
59 0 : relname = SPI_getrelname(rel);
60 :
61 0 : trigger = trigdata->tg_trigger;
62 :
63 0 : nargs = trigger->tgnargs;
64 0 : if (nargs != 1)
65 : /* internal error */
66 0 : elog(ERROR, "insert_username (%s): one argument was expected", relname);
67 :
68 0 : args = trigger->tgargs;
69 0 : tupdesc = rel->rd_att;
70 :
71 0 : attnum = SPI_fnumber(tupdesc, args[0]);
72 :
73 0 : if (attnum <= 0)
74 0 : ereport(ERROR,
75 : (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
76 : errmsg("\"%s\" has no attribute \"%s\"", relname, args[0])));
77 :
78 0 : if (SPI_gettypeid(tupdesc, attnum) != TEXTOID)
79 0 : ereport(ERROR,
80 : (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
81 : errmsg("attribute \"%s\" of \"%s\" must be type TEXT",
82 : args[0], relname)));
83 :
84 : /* create fields containing name */
85 0 : newval = CStringGetTextDatum(GetUserNameFromId(GetUserId(), false));
86 0 : newnull = false;
87 :
88 : /* construct new tuple */
89 0 : rettuple = heap_modify_tuple_by_cols(rettuple, tupdesc,
90 : 1, &attnum, &newval, &newnull);
91 :
92 0 : pfree(relname);
93 :
94 0 : return PointerGetDatum(rettuple);
95 0 : }
|