Эквивалентный триггер plpgsql в C - PullRequest
2 голосов
/ 02 февраля 2012

У меня есть сервер PostgreSQL 9.0, и я использую наследие для некоторых таблиц, поэтому мне приходится моделировать внешние ключи с помощью триггеров, подобных этому:

CREATE OR REPLACE FUNCTION othertable_before_update_trigger()
RETURNS trigger AS
$BODY$
DECLARE
  sql   VARCHAR;
  rows  SMALLINT;
BEGIN
  IF (NEW.parenttable_id IS DISTINCT FROM OLD.parenttable_id) THEN
    sql  := 'SELECT id '
         || 'FROM parentTable '
         || 'WHERE id = ' || NEW.parenttable_id || ';';
     BEGIN
        EXECUTE sql;
        GET DIAGNOSTICS rows = ROW_COUNT;

     EXCEPTION
        WHEN OTHERS THEN
           RAISE EXCEPTION 'Error when I try find in parentTable the id %. SQL: %. ERROR: %',
                            NEW.parenttable_id,sql,SQLERRM;
     END;

     IF rows = 0 THEN
        RAISE EXCEPTION 'Not found a row in parentTable with id %. SQL: %.',NEW.parenttable_id,sql;
     END IF;
  END IF;
  RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;

Но из-за производительности я пытаюсьсоздать эквивалентный триггер в коде C:

#include "postgres.h"
#include "executor/spi.h"       /* this is what you need to work with SPI */
#include "commands/trigger.h"   /* ... and triggers */

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
extern Datum othertable_before_update_trigger(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(othertable_before_update_trigger);

Datum
 othertable_before_update_trigger(PG_FUNCTION_ARGS) {

   TriggerData *trigdata = (TriggerData *) fcinfo->context;
   TupleDesc   tupdesc;
   HeapTuple   rettuple;
   bool        isnull;
   int         ret, i;

   /* make sure it's called as a trigger at all */
   if (!CALLED_AS_TRIGGER(fcinfo))
     elog(ERROR, "othertable_before_update_trigger: not called by trigger manager");

   /* tuple to return to executor */
   if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
     rettuple = trigdata->tg_newtuple;
   else
     rettuple = trigdata->tg_trigtuple;

   tupdesc = trigdata->tg_relation->rd_att;

   /* connect to SPI manager */
   if ((ret = SPI_connect()) < 0)
     elog(ERROR, "othertable_before_update_trigger (fired %s): SPI_connect returned %d", "before", ret);

   [A]

   [B]

   return PointerGetDatum(rettuple);
 }

Мне нужно заполнить код:

  1. [A] : получить предыдущий иновые значения для parenttable_id .С помощью:

    int32 att = DatumGetInt32 (heap_getattr (rettuple, 1, tupdesc, & isnull));

    или

    int32 att = DatumGetInt32 (SPI_getbinval (rettuple, tupdes), tupdes, & isnull));

Я могу получить только старое значение parenttable_id , но не новое значение.Даже если я попытаюсь использовать имя столбца вместо номера с:

GetAttributeByName (rettuple->t_data, "parenttable_id", &isnull);

Ошибка получения: тип записи не зарегистрирован

  1. [B] : выполнить запрос SELECT id FROM parentTable WHERE id = NEW.parenttable_id

Я нашел функцию SPI_execute_with_args , но яне нашел примеров этого для моего случая.

Заранее спасибо.

1 Ответ

1 голос
/ 25 марта 2013

Это не кажется мне триггером, который выиграет от перехода на C. Вы можете воспользоваться большим кэшированием планов в pl / pgsql, и это, скорее всего, поможет больше, чем переход на C ускорит процесс.вверх.Кроме того, здесь есть два красных флажка с высокой производительностью, которые мне кажутся заслуживающими исправления.

Во-первых, блоки EXCEPTION имеют значительные затраты производительности.Все, что вы делаете здесь, сообщает об исключении в более дружественных выражениях.Вы бы лучше просто удалили его, если производительность является проблемой.

Вторым является ваш EXECUTE, что означает, что план запроса никогда не будет кэшироваться.Вы действительно должны изменить это на прямой запрос.

Когда вы комбинируете это с возможностью триггера на языке C, вызывающего сбои или, что еще хуже, в серверной части, я думаю, вы приложите много усилий дляпереписать триггер с меньшим приростом производительности, чем вы могли бы переписать в pl / pgsql.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...