Доступ к динамическому имени столбца типа строки в функции триггера

Это похоже на то, что вы хотите (я нашел его на http://huddledmasses.org/powershell-find-path/ )

Function Find-Path($Path, [switch]$All=$false, [Microsoft.PowerShell.Commands.TestPathType]$type="Any")
## You could  comment out the function stuff and use it as a script instead, with this line:
# param($Path, [switch]$All=$false, [Microsoft.PowerShell.Commands.TestPathType]$type="Any")
   if($(Test-Path $Path -Type $type)) {
      return $path
   } else {
      [string[]]$paths = @($pwd);
      $paths += "$pwd;$env:path".split(";")

      $paths = Join-Path $paths $(Split-Path $Path -leaf) | ? { Test-Path $_ -Type $type }
      if($paths.Length -gt 0) {
         if($All) {
            return $paths;
         } else {
            return $paths[0]
         }
      }
   }
   throw "Couldn't find a matching path of type $type"
}
Set-Alias find Find-Path

1
задан Erwin Brandstetter 20 March 2019 в 18:52
поделиться

2 ответа

Это должно сделать это:

CREATE OR REPLACE FUNCTION device_bid_modifiers_count_per()
  RETURNS TRIGGER AS
$func$
DECLARE
   devices_count int      := device_types_count();
   table_name    regclass := TG_ARGV[0];
   column_name   text     := TG_ARGV[1];
BEGIN
   LOCK TABLE device_types IN EXCLUSIVE MODE;
   EXECUTE format('LOCK TABLE %s IN EXCLUSIVE MODE', table_name);

   IF TG_OP = 'DELETE' THEN
      PERFORM validate_bid_modifiers_count(table_name
                                         , column_name
                                         , (row_to_json(OLD) ->> column_name)::bigint
                                         , devices_count);
   ELSE
      PERFORM validate_bid_modifiers_count(table_name
                                         , column_name
                                         , (row_to_json(NEW) ->> column_name)::bigint
                                         , devices_count);
   END IF;

   RETURN NEW;
END
$func$  LANGUAGE plpgsql;

Непосредственной причиной сообщения об ошибке была внешняя SELECT. Без цели вам нужно заменить ее на PERFORM в plpgsql. Но внутреннее PERFORM в строке запроса, переданной EXECUTE, тоже было неверным. PERFORM - это команда plpgsql, недопустимая в строке SQL, переданной в EXECUTE, которая ожидает код SQL. Вы должны использовать SELECT там. Наконец, OLD и NEW не видны внутри EXECUTE, и каждый из них вызовет свое собственное исключение, как у вас. Все проблемы устранены путем удаления EXECUTE.

Простой и быстрый способ получить значение динамического имени столбца из типов строк OLD и NEW: приведение к json, затем вы можете параметризовать имя ключа, как показано , Должно быть немного проще и быстрее, чем альтернатива с динамическим SQL - что также возможно, например:

  ...
  EXECUTE format('SELECT validate_bid_modifiers_count(table_name
                                                    , column_name
                                                    , ($1.%I)::bigint
                                                    , devices_count)', column_name)
  USING OLD;
  ...

Связанный:

В стороне: не уверен, зачем нужны тяжелые блокировки.

В сторону 2: рассмотрите возможность написания отдельной функции триггера для каждого триггера. Более шумный DDL, но проще и быстрее для выполнения.

0
ответ дан Erwin Brandstetter 20 March 2019 в 18:52
поделиться

Как я указывал в комментарии к ответу Эрвина Брандштеттера , изначально у меня было почти идентичное решение.

Но проблема была в том, что я получал ошибку

ERROR: record "new" has no field "column_name"
CONTEXT: SQL statement "SELECT validate_bid_modifiers_count(table_name, column_name, NEW.column_name, devices_count)"
PL/pgSQL function device_bid_modifiers_count_per() line 15 at PERFORM

Вот почему я подумал, что мне нужен способ динамической оценки вещей.

В настоящее время это работает со следующим, все еще уродливым, ищущим меня решением (уродливо, потому что мне не нравятся 2 IF утверждения, я хотел бы, чтобы оно было супер динамичным, но, возможно, я прошу слишком много): 117]

CREATE OR REPLACE FUNCTION device_bid_modifiers_count_per()
  RETURNS TRIGGER AS
$func$
  DECLARE
    row           RECORD;
    table_name    regclass := TG_ARGV[0];
    column_name   text := TG_ARGV[1];
    devices_count INTEGER;

  BEGIN
    LOCK TABLE device_types IN EXCLUSIVE MODE;
    EXECUTE format('LOCK TABLE %s IN EXCLUSIVE MODE', table_name);

    devices_count := device_types_count();

    IF TG_OP = 'DELETE' THEN
      row := OLD;
    ELSE
      row := NEW;
    END IF;

    IF column_name = 'campaign_id' THEN
      PERFORM validate_bid_modifiers_count(table_name, column_name, row.campaign_id, devices_count);
    ELSIF column_name = 'adgroup_id' THEN
      PERFORM validate_bid_modifiers_count(table_name, column_name, row.adgroup_id, devices_count);
    ELSE
      RAISE EXCEPTION 'invalid_column_name %', column_name;
    END IF;
    RETURN NEW;
  END;
$func$ LANGUAGE plpgsql;

Я открыт для более надежных решений.

По существу, второе условие kind'a почти не имеет цели иметь единственную функцию, и я мог бы разделить ее на две функции. Потому что цель состоит в том, чтобы определить несколько (2) триггеров, используя эту функцию (предоставив ей аргументы).

0
ответ дан Andrey Deineko 20 March 2019 в 18:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: