diff options
author | Marko Kreen | 2009-11-24 15:16:41 +0000 |
---|---|---|
committer | Marko Kreen | 2009-11-24 15:16:41 +0000 |
commit | 2cd1e444a8ca3417ef0d5ca1d5141cde4122f01c (patch) | |
tree | a7bbdaa9292b04668a9c0e169bd073d380258eff | |
parent | d31e3e4059934f0a6001d4cb3f0bf014fedfee38 (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.out | 18 | ||||
-rw-r--r-- | sql/pgq/sql/logutriga.sql | 12 | ||||
-rw-r--r-- | sql/pgq/triggers/logutriga.c | 117 |
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"); |