summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Kreen2009-11-24 15:16:41 +0000
committerMarko Kreen2009-11-24 15:16:41 +0000
commit2cd1e444a8ca3417ef0d5ca1d5141cde4122f01c (patch)
treea7bbdaa9292b04668a9c0e169bd073d380258eff
parentd31e3e4059934f0a6001d4cb3f0bf014fedfee38 (diff)
sql/pgq: make pgq.logutriga() ignore UPDATE when only ignored fields change
previously it behaved differently from sqltriga, as it did not need to analyze which field change. but it's better if it acts like sqltriga when field ignoring is used.
-rw-r--r--sql/pgq/expected/logutriga.out18
-rw-r--r--sql/pgq/sql/logutriga.sql12
-rw-r--r--sql/pgq/triggers/logutriga.c117
3 files changed, 139 insertions, 8 deletions
diff --git a/sql/pgq/expected/logutriga.out b/sql/pgq/expected/logutriga.out
index 62262718..74245e11 100644
--- a/sql/pgq/expected/logutriga.out
+++ b/sql/pgq/expected/logutriga.out
@@ -20,6 +20,24 @@ 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, $6, $7)"
+-- test ignore
+drop trigger utest on udata;
+truncate udata;
+create trigger utest after insert or update or delete on udata
+for each row execute procedure pgq.logutriga('udata_que', 'ignore=bin');
+insert into udata values (1, 'txt', 'bin');
+NOTICE: insert_event(udata_que, I:id, id=1&txt=txt, public.udata)
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
+update udata set txt = 'txt';
+NOTICE: insert_event(udata_que, U:id, id=1&txt=txt, public.udata)
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
+update udata set txt = 'txt2', bin = 'bin2';
+NOTICE: insert_event(udata_que, U:id, id=1&txt=txt2, public.udata)
+CONTEXT: SQL statement "select pgq.insert_event($1, $2, $3, $4, $5, $6, $7)"
+update udata set bin = 'bin3';
+delete from udata;
+NOTICE: insert_event(udata_que, D:id, id=1&txt=txt2, public.udata)
+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
diff --git a/sql/pgq/sql/logutriga.sql b/sql/pgq/sql/logutriga.sql
index ce5e42c6..38b61dc7 100644
--- a/sql/pgq/sql/logutriga.sql
+++ b/sql/pgq/sql/logutriga.sql
@@ -19,6 +19,18 @@ for each row execute procedure pgq.logutriga('udata_que');
insert into udata (txt) values ('text1');
insert into udata (bin) values (E'bi\tn\\000bin');
+-- test ignore
+drop trigger utest on udata;
+truncate udata;
+create trigger utest after insert or update or delete on udata
+for each row execute procedure pgq.logutriga('udata_que', 'ignore=bin');
+
+insert into udata values (1, 'txt', 'bin');
+update udata set txt = 'txt';
+update udata set txt = 'txt2', bin = 'bin2';
+update udata set bin = 'bin3';
+delete from udata;
+
-- test missing pkey
create table nopkey2 (dat text);
create trigger nopkey_triga2 after insert or update or delete on nopkey2
diff --git a/sql/pgq/triggers/logutriga.c b/sql/pgq/triggers/logutriga.c
index 59a0cf04..b3d4cf50 100644
--- a/sql/pgq/triggers/logutriga.c
+++ b/sql/pgq/triggers/logutriga.c
@@ -19,7 +19,10 @@
#include <postgres.h>
#include <executor/spi.h>
#include <commands/trigger.h>
+#include <catalog/pg_operator.h>
#include <lib/stringinfo.h>
+#include <utils/typcache.h>
+
#include "common.h"
#include "stringutil.h"
@@ -27,6 +30,102 @@
PG_FUNCTION_INFO_V1(pgq_logutriga);
Datum pgq_logutriga(PG_FUNCTION_ARGS);
+/* need to ignore UPDATE where only ignored columns change */
+static int is_interesting_change(PgqTriggerEvent *ev, TriggerData *tg)
+{
+ HeapTuple old_row = tg->tg_trigtuple;
+ HeapTuple new_row = tg->tg_newtuple;
+ TupleDesc tupdesc = tg->tg_relation->rd_att;
+ Datum old_value;
+ Datum new_value;
+ bool old_isnull;
+ bool new_isnull;
+
+ int i, attkind_idx = -1;
+ int ignore_count = 0;
+
+ /* only UPDATE may need to be ignored */
+ if (!TRIGGER_FIRED_BY_UPDATE(tg->tg_event))
+ return 1;
+
+ /* if no columns are ignored, all events are interesting */
+ if (ev->ignore_list == NULL)
+ return 1;
+
+ for (i = 0; i < tupdesc->natts; i++) {
+ /*
+ * Ignore dropped columns
+ */
+ if (tupdesc->attrs[i]->attisdropped)
+ continue;
+ attkind_idx++;
+
+ old_value = SPI_getbinval(old_row, tupdesc, i + 1, &old_isnull);
+ new_value = SPI_getbinval(new_row, tupdesc, i + 1, &new_isnull);
+
+ /*
+ * If old and new value are NULL, the column is unchanged
+ */
+ if (old_isnull && new_isnull)
+ continue;
+
+ /*
+ * If both are NOT NULL, we need to compare the values and skip
+ * setting the column if equal
+ */
+ if (!old_isnull && !new_isnull) {
+ Oid opr_oid;
+ FmgrInfo *opr_finfo_p;
+
+ /*
+ * Lookup the equal operators function call info using the
+ * typecache if available
+ */
+ TypeCacheEntry *type_cache;
+
+ type_cache = lookup_type_cache(SPI_gettypeid(tupdesc, i + 1),
+ TYPECACHE_EQ_OPR | TYPECACHE_EQ_OPR_FINFO);
+ opr_oid = type_cache->eq_opr;
+ if (opr_oid == ARRAY_EQ_OP)
+ opr_oid = InvalidOid;
+ else
+ opr_finfo_p = &(type_cache->eq_opr_finfo);
+
+ /*
+ * If we have an equal operator, use that to do binary
+ * comparision. Else get the string representation of both
+ * attributes and do string comparision.
+ */
+ if (OidIsValid(opr_oid)) {
+ if (DatumGetBool(FunctionCall2(opr_finfo_p, old_value, new_value)))
+ continue;
+ } else {
+ char *old_strval = SPI_getvalue(old_row, tupdesc, i + 1);
+ char *new_strval = SPI_getvalue(new_row, tupdesc, i + 1);
+
+ if (strcmp(old_strval, new_strval) == 0)
+ continue;
+ }
+ }
+
+ if (pgqtriga_skip_col(ev, tg, i, attkind_idx)) {
+ /* this change should be ignored */
+ ignore_count++;
+ continue;
+ }
+
+ /* a non-ignored column has changed */
+ return 1;
+ }
+
+ /* skip if only ignored column had changed */
+ if (ignore_count)
+ return 0;
+
+ /* do show NOP updates */
+ return 1;
+}
+
void pgq_urlenc_row(PgqTriggerEvent *ev, TriggerData *tg, HeapTuple row, StringInfo buf)
{
TupleDesc tupdesc = tg->tg_relation->rd_att;
@@ -107,15 +206,17 @@ Datum pgq_logutriga(PG_FUNCTION_ARGS)
appendStringInfoString(ev.ev_type, ev.pkey_list);
appendStringInfoString(ev.ev_extra1, ev.info->table_name);
- /*
- * create type, data
- */
- pgq_urlenc_row(&ev, tg, row, ev.ev_data);
+ if (is_interesting_change(&ev, tg)) {
+ /*
+ * create type, data
+ */
+ pgq_urlenc_row(&ev, tg, row, ev.ev_data);
- /*
- * Construct the parameter array and insert the log row.
- */
- pgq_insert_tg_event(&ev, tg);
+ /*
+ * Construct the parameter array and insert the log row.
+ */
+ pgq_insert_tg_event(&ev, tg);
+ }
if (SPI_finish() < 0)
elog(ERROR, "SPI_finish failed");