PostgreSQL Source Code git master
Loading...
Searching...
No Matches
tcn.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "commands/async.h"
#include "commands/trigger.h"
#include "executor/spi.h"
#include "lib/stringinfo.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for tcn.c:

Go to the source code of this file.

Functions

 PG_MODULE_MAGIC_EXT (.name="tcn",.version=PG_VERSION)
 
static void strcpy_quoted (StringInfo r, const char *s, const char q)
 
 PG_FUNCTION_INFO_V1 (triggered_change_notification)
 
Datum triggered_change_notification (PG_FUNCTION_ARGS)
 

Function Documentation

◆ PG_FUNCTION_INFO_V1()

PG_FUNCTION_INFO_V1 ( triggered_change_notification  )

◆ PG_MODULE_MAGIC_EXT()

PG_MODULE_MAGIC_EXT ( name = "tcn",
version = PG_VERSION 
)

◆ strcpy_quoted()

static void strcpy_quoted ( StringInfo  r,
const char s,
const char  q 
)
static

Definition at line 36 of file tcn.c.

37{
39 while (*s)
40 {
41 if (*s == q)
44 s++;
45 }
47}
#define appendStringInfoCharMacro(str, ch)
Definition stringinfo.h:231

References appendStringInfoCharMacro.

Referenced by triggered_change_notification().

◆ triggered_change_notification()

Datum triggered_change_notification ( PG_FUNCTION_ARGS  )

Definition at line 59 of file tcn.c.

60{
61 TriggerData *trigdata = (TriggerData *) fcinfo->context;
63 int nargs;
65 Relation rel;
66 TupleDesc tupdesc;
67 char *channel;
68 char operation;
69 StringInfoData payload;
70 bool foundPK;
71
74
75 initStringInfo(&payload);
76 /* make sure it's called as a trigger */
77 if (!CALLED_AS_TRIGGER(fcinfo))
80 errmsg("triggered_change_notification: must be called as trigger")));
81
82 /* and that it's called after the change */
83 if (!TRIGGER_FIRED_AFTER(trigdata->tg_event))
86 errmsg("triggered_change_notification: must be called after the change")));
87
88 /* and that it's called for each row */
89 if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
92 errmsg("triggered_change_notification: must be called for each row")));
93
94 if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
95 operation = 'I';
96 else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
97 operation = 'U';
98 else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
99 operation = 'D';
100 else
101 {
102 elog(ERROR, "triggered_change_notification: trigger fired by unrecognized operation");
103 operation = 'X'; /* silence compiler warning */
104 }
105
106 trigger = trigdata->tg_trigger;
107 nargs = trigger->tgnargs;
108 if (nargs > 1)
111 errmsg("triggered_change_notification: must not be called with more than one parameter")));
112
113 if (nargs == 0)
114 channel = "tcn";
115 else
116 channel = trigger->tgargs[0];
117
118 /* get tuple data */
119 trigtuple = trigdata->tg_trigtuple;
120 rel = trigdata->tg_relation;
121 tupdesc = rel->rd_att;
122
123 foundPK = false;
124
125 /*
126 * Get the list of index OIDs for the table from the relcache, and look up
127 * each one in the pg_index syscache until we find one marked primary key
128 * (hopefully there isn't more than one such).
129 */
131
132 foreach(indexoidscan, indexoidlist)
133 {
134 Oid indexoid = lfirst_oid(indexoidscan);
137
139 if (!HeapTupleIsValid(indexTuple)) /* should not happen */
140 elog(ERROR, "cache lookup failed for index %u", indexoid);
142 /* we're only interested if it is the primary key and valid */
143 if (index->indisprimary && index->indisvalid)
144 {
145 int indnkeyatts = index->indnkeyatts;
146
147 if (indnkeyatts > 0)
148 {
149 int i;
150
151 foundPK = true;
152
153 strcpy_quoted(&payload, RelationGetRelationName(rel), '"');
154 appendStringInfoCharMacro(&payload, ',');
155 appendStringInfoCharMacro(&payload, operation);
156
157 for (i = 0; i < indnkeyatts; i++)
158 {
159 int colno = index->indkey.values[i];
160 Form_pg_attribute attr = TupleDescAttr(tupdesc, colno - 1);
161
162 appendStringInfoCharMacro(&payload, ',');
163 strcpy_quoted(&payload, NameStr(attr->attname), '"');
164 appendStringInfoCharMacro(&payload, '=');
165 strcpy_quoted(&payload, SPI_getvalue(trigtuple, tupdesc, colno), '\'');
166 }
167
168 Async_Notify(channel, payload.data);
169 }
171 break;
172 }
174 }
175
177
178 if (!foundPK)
181 errmsg("triggered_change_notification: must be called on a table with a primary key")));
182
183 return PointerGetDatum(NULL); /* after trigger; value doesn't matter */
184}
void Async_Notify(const char *channel, const char *payload)
Definition async.c:885
#define NameStr(name)
Definition c.h:765
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
int i
Definition isn.c:77
void list_free(List *list)
Definition list.c:1546
FormData_pg_attribute * Form_pg_attribute
FormData_pg_index * Form_pg_index
Definition pg_index.h:70
#define lfirst_oid(lc)
Definition pg_list.h:174
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
unsigned int Oid
static int fb(int x)
#define RelationGetRelationName(relation)
Definition rel.h:548
List * RelationGetIndexList(Relation relation)
Definition relcache.c:4831
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition spi.c:1220
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
Definition pg_list.h:54
TupleDesc rd_att
Definition rel.h:112
Definition type.h:96
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220
static void strcpy_quoted(StringInfo r, const char *s, const char q)
Definition tcn.c:36
#define TRIGGER_FIRED_BY_DELETE(event)
Definition trigger.h:115
#define CALLED_AS_TRIGGER(fcinfo)
Definition trigger.h:26
#define TRIGGER_FIRED_FOR_ROW(event)
Definition trigger.h:124
#define TRIGGER_FIRED_AFTER(event)
Definition trigger.h:133
#define TRIGGER_FIRED_BY_INSERT(event)
Definition trigger.h:112
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition trigger.h:118
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:160

References appendStringInfoCharMacro, Async_Notify(), CALLED_AS_TRIGGER, StringInfoData::data, elog, ereport, errcode(), errmsg(), ERROR, fb(), GETSTRUCT(), HeapTupleIsValid, i, initStringInfo(), lfirst_oid, list_free(), NameStr, ObjectIdGetDatum(), PointerGetDatum(), RelationData::rd_att, RelationGetIndexList(), RelationGetRelationName, ReleaseSysCache(), SearchSysCache1(), SPI_getvalue(), strcpy_quoted(), TriggerData::tg_event, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, Trigger::tgnargs, TRIGGER_FIRED_AFTER, TRIGGER_FIRED_BY_DELETE, TRIGGER_FIRED_BY_INSERT, TRIGGER_FIRED_BY_UPDATE, TRIGGER_FIRED_FOR_ROW, and TupleDescAttr().