for each row execute procedure pgq.logutriga('udata_que');
insert into udata (txt) values ('text1');
NOTICE: insert_event(udata_que, I:id, id=1&txt=text1&bin, public.udata)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
insert into udata (bin) values (E'bi\tn\\000bin');
NOTICE: insert_event(udata_que, I:id, id=2&txt&bin=bi%5c011n%5c000bin, public.udata)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
-- test missing pkey
create table nopkey2 (dat text);
create trigger nopkey_triga2 after insert or update or delete on nopkey2
for each row execute procedure pgq.logutriga('que3');
insert into nopkey2 values ('foo');
NOTICE: insert_event(que3, I:, dat=foo, public.nopkey2)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
update nopkey2 set dat = 'bat';
ERROR: Update/Delete on table without pkey
delete from nopkey2;
for each row execute procedure pgq.logutriga('que3');
insert into ucustom_pkey values ('foo', '2');
NOTICE: insert_event(que3, I:, dat1=foo&dat2=2&dat3, public.ucustom_pkey)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
update ucustom_pkey set dat3 = 'bat';
ERROR: Update/Delete on table without pkey
delete from ucustom_pkey;
ERROR: Update/Delete on table without pkey
+-- test custom fields
+create table custom_fields2 (
+ dat1 text not null primary key,
+ dat2 int2 not null,
+ dat3 text,
+ _pgq_ev_type text default 'my_type',
+ _pgq_ev_extra1 text default 'e1',
+ _pgq_ev_extra2 text default 'e2',
+ _pgq_ev_extra3 text default 'e3',
+ _pgq_ev_extra4 text default 'e4'
+);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "custom_fields2_pkey" for table "custom_fields2"
+create trigger customf2_triga after insert or update or delete on custom_fields2
+for each row execute procedure pgq.logutriga('que3');
+insert into custom_fields2 values ('foo', '2');
+NOTICE: insert_event(que3, my_type, dat1=foo&dat2=2&dat3, e1)
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
+update custom_fields2 set dat3 = 'bat';
+NOTICE: insert_event(que3, my_type, dat1=foo&dat2=2&dat3=bat, e1)
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
+delete from custom_fields2;
+NOTICE: insert_event(que3, my_type, dat1=foo&dat2=2&dat3=bat, e1)
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
-- simple test
insert into rtest values (1, 'value1');
NOTICE: insert_event(que, I, (id,dat) values ('1','value1'), public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
update rtest set dat = 'value2';
NOTICE: insert_event(que, U, dat='value2' where id='1', public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
delete from rtest;
NOTICE: insert_event(que, D, id='1', public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
-- test new fields
alter table rtest add column dat2 text;
insert into rtest values (1, 'value1');
NOTICE: insert_event(que, I, (id,dat,dat2) values ('1','value1',null), public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
update rtest set dat = 'value2';
NOTICE: insert_event(que, U, dat='value2' where id='1', public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
delete from rtest;
NOTICE: insert_event(que, D, id='1', public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
-- test field ignore
drop trigger rtest_triga on rtest;
create trigger rtest_triga after insert or update or delete on rtest
for each row execute procedure pgq.sqltriga('que2', 'ignore=dat2');
insert into rtest values (1, '666', 'newdat');
NOTICE: insert_event(que2, I, (id,dat) values ('1','666'), public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
update rtest set dat = 5, dat2 = 'newdat2';
NOTICE: insert_event(que2, U, dat='5' where id='1', public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
update rtest set dat = 6;
NOTICE: insert_event(que2, U, dat='6' where id='1', public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
delete from rtest;
NOTICE: insert_event(que2, D, id='1', public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
-- test hashed pkey
-- drop trigger rtest_triga on rtest;
-- create trigger rtest_triga after insert or update or delete on rtest
for each row execute procedure pgq.sqltriga('que3');
insert into rtest values (1, 0, 'non-null');
NOTICE: insert_event(que3, I, (id,dat,dat2) values ('1','0','non-null'), public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
insert into rtest values (2, 0, NULL);
NOTICE: insert_event(que3, I, (id,dat,dat2) values ('2','0',null), public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
update rtest set dat2 = 'non-null2' where id=1;
NOTICE: insert_event(que3, U, dat2='non-null2' where id='1', public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
update rtest set dat2 = NULL where id=1;
NOTICE: insert_event(que3, U, dat2=NULL where id='1', public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
update rtest set dat2 = 'new-nonnull' where id=2;
NOTICE: insert_event(que3, U, dat2='new-nonnull' where id='2', public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
delete from rtest where id=1;
NOTICE: insert_event(que3, D, id='1', public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
delete from rtest where id=2;
NOTICE: insert_event(que3, D, id='2', public.rtest)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
-- test missing pkey
create table nopkey (dat text);
create trigger nopkey_triga after insert or update or delete on nopkey
for each row execute procedure pgq.sqltriga('que3');
insert into nopkey values ('foo');
NOTICE: insert_event(que3, I, (dat) values ('foo'), public.nopkey)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
update nopkey set dat = 'bat';
ERROR: Update/Delete on table without pkey
delete from nopkey;
for each row execute procedure pgq.sqltriga('que3', 'pkey=dat1,dat2');
insert into custom_pkey values ('foo', '2');
NOTICE: insert_event(que3, I, (dat1,dat2,dat3) values ('foo','2',null), public.custom_pkey)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
update custom_pkey set dat3 = 'bat';
NOTICE: insert_event(que3, U, dat3='bat' where dat1='foo' and dat2='2', public.custom_pkey)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
delete from custom_pkey;
NOTICE: insert_event(que3, D, dat1='foo' and dat2='2', public.custom_pkey)
-CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, null, null)"
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
+-- test custom fields
+create table custom_fields (
+ dat1 text not null primary key,
+ dat2 int2 not null,
+ dat3 text,
+ _pgq_ev_type text default 'my_type',
+ _pgq_ev_extra1 text default 'e1',
+ _pgq_ev_extra2 text default 'e2',
+ _pgq_ev_extra3 text default 'e3',
+ _pgq_ev_extra4 text default 'e4'
+);
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "custom_fields_pkey" for table "custom_fields"
+create trigger customf_triga after insert or update or delete on custom_fields
+for each row execute procedure pgq.sqltriga('que3');
+insert into custom_fields values ('foo', '2');
+NOTICE: insert_event(que3, my_type, (dat1,dat2,dat3) values ('foo','2',null), e1)
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
+update custom_fields set dat3 = 'bat';
+NOTICE: insert_event(que3, my_type, dat3='bat' where dat1='foo', e1)
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
+delete from custom_fields;
+NOTICE: insert_event(que3, my_type, dat1='foo', e1)
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
PG_MODULE_MAGIC;
#endif
+/* memcmp is ok on NameData fields */
+#define is_magic_field(s) (memcmp(s, "_pgq_ev_", 8) == 0)
+
/*
* primary key info
*/
static const char pkey_sql[] =
"SELECT k.attnum, k.attname FROM pg_index i, pg_attribute k"
" WHERE i.indrelid = $1 AND k.attrelid = i.indexrelid"
- " AND i.indisprimary AND k.attnum > 0 AND NOT k.attisdropped" " ORDER BY k.attnum";
+ " AND i.indisprimary AND k.attnum > 0 AND NOT k.attisdropped"
+ " ORDER BY k.attnum";
static void *pkey_plan;
static void relcache_reset_cb(Datum arg, Oid relid);
*
* does not support NULL arguments.
*/
-void pgq_simple_insert(const char *queue_name, Datum ev_type, Datum ev_data, Datum ev_extra1, Datum ev_extra2)
+void pgq_simple_insert(const char *queue_name, Datum ev_type, Datum ev_data,
+ Datum ev_extra1, Datum ev_extra2, Datum ev_extra3, Datum ev_extra4)
{
- Datum values[5];
- char nulls[5];
+ Datum values[7];
+ char nulls[7];
static void *plan = NULL;
int res;
if (!plan) {
const char *sql;
- Oid types[5] = { TEXTOID, TEXTOID, TEXTOID, TEXTOID, TEXTOID };
+ Oid types[7] = { TEXTOID, TEXTOID, TEXTOID, TEXTOID, TEXTOID, TEXTOID, TEXTOID };
- sql = "select pgq.insert_event($1, $2, $3, $4, $5, null, null)";
- plan = SPI_saveplan(SPI_prepare(sql, 5, types));
+ sql = "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)";
+ plan = SPI_saveplan(SPI_prepare(sql, 7, types));
if (plan == NULL)
elog(ERROR, "logtriga: SPI_prepare() failed");
}
values[2] = ev_data;
values[3] = ev_extra1;
values[4] = ev_extra2;
+ values[5] = ev_extra3;
+ values[6] = ev_extra4;
nulls[0] = ' ';
- nulls[1] = ' ';
- nulls[2] = ' ';
- nulls[3] = ' ';
+ nulls[1] = ev_type ? ' ' : 'n';
+ nulls[2] = ev_data ? ' ' : 'n';
+ nulls[3] = ev_extra1 ? ' ' : 'n';
nulls[4] = ev_extra2 ? ' ' : 'n';
+ nulls[5] = ev_extra3 ? ' ' : 'n';
+ nulls[6] = ev_extra4 ? ' ' : 'n';
res = SPI_execute_plan(plan, values, nulls, false, 0);
if (res != SPI_OK_SELECT)
elog(ERROR, "call of pgq.insert_event failed");
}
-void pgq_insert_tg_event(PgqTriggerEvent *ev)
+static void fill_magic_columns(PgqTriggerEvent *ev, TriggerData *tg)
+{
+ int i;
+ char *col_name, *col_value;
+ StringInfo *dst = NULL;
+ TupleDesc tupdesc = tg->tg_relation->rd_att;
+ HeapTuple row;
+
+ if (TRIGGER_FIRED_BY_UPDATE(tg->tg_event))
+ row = tg->tg_newtuple;
+ else
+ row = tg->tg_trigtuple;
+
+ for (i = 0; i < tupdesc->natts; i++) {
+ /* Skip dropped columns */
+ if (tupdesc->attrs[i]->attisdropped)
+ continue;
+ col_name = NameStr(tupdesc->attrs[i]->attname);
+ if (!is_magic_field(col_name))
+ continue;
+ if (strcmp(col_name, "_pgq_ev_type") == 0)
+ dst = &ev->ev_type;
+ else if (strcmp(col_name, "_pgq_ev_data") == 0)
+ dst = &ev->ev_data;
+ else if (strcmp(col_name, "_pgq_ev_extra1") == 0)
+ dst = &ev->ev_extra1;
+ else if (strcmp(col_name, "_pgq_ev_extra2") == 0)
+ dst = &ev->ev_extra2;
+ else if (strcmp(col_name, "_pgq_ev_extra3") == 0)
+ dst = &ev->ev_extra3;
+ else if (strcmp(col_name, "_pgq_ev_extra4") == 0)
+ dst = &ev->ev_extra4;
+ else
+ elog(ERROR, "Unknown magic column: %s", col_name);
+
+ col_value = SPI_getvalue(row, tupdesc, i + 1);
+ if (col_value != NULL) {
+ *dst = pgq_init_varbuf();
+ appendStringInfoString(*dst, col_value);
+ } else {
+ *dst = NULL;
+ }
+ }
+}
+
+void pgq_insert_tg_event(PgqTriggerEvent *ev, TriggerData *tg)
{
+ if (ev->custom_fields)
+ fill_magic_columns(ev, tg);
+
pgq_simple_insert(ev->queue_name,
pgq_finish_varbuf(ev->ev_type),
pgq_finish_varbuf(ev->ev_data),
pgq_finish_varbuf(ev->ev_extra1),
- ev->ev_extra2 ? pgq_finish_varbuf(ev->ev_extra2) : (Datum)0);
+ pgq_finish_varbuf(ev->ev_extra2),
+ pgq_finish_varbuf(ev->ev_extra3),
+ pgq_finish_varbuf(ev->ev_extra4));
}
char *pgq_find_table_name(Relation rel)
TupleDesc tupdesc;
const char *name;
+ tupdesc = tg->tg_relation->rd_att;
+ if (tupdesc->attrs[i]->attisdropped)
+ return true;
+ name = NameStr(tupdesc->attrs[i]->attname);
+
+ if (is_magic_field(name)) {
+ ev->custom_fields = 1;
+ return true;
+ }
+
if (ev->attkind) {
if (attkind_idx >= ev->attkind_len)
return true;
return ev->attkind[attkind_idx] == 'i';
} else if (ev->ignore_list) {
- tupdesc = tg->tg_relation->rd_att;
- if (tupdesc->attrs[i]->attisdropped)
- return true;
- name = NameStr(tupdesc->attrs[i]->attname);
return pgq_strlist_contains(ev->ignore_list, name);
}
return false;
if (tupdesc->attrs[i]->attisdropped)
return false;
name = NameStr(tupdesc->attrs[i]->attname);
+ if (is_magic_field(name)) {
+ ev->custom_fields = 1;
+ return false;
+ }
return pgq_strlist_contains(ev->pkey_list, name);
}
return false;