PostgreSQL триггеры и исключения - PullRequest
0 голосов
/ 19 ноября 2009

Я пытаюсь заставить работать мой первый триггер и функцию, но как правильно генерировать исключения и возвращать данные?

PostgreSQL 8.4.1

CREATE TABLE "SHIFTS" (
    id integer NOT NULL, -- SERIAL
    added timestamp without time zone DEFAULT now() NOT NULL,
    starts timestamp without time zone NOT NULL,
    ends timestamp without time zone NOT NULL,
    employee_id integer,
    modified timestamp without time zone,
    status integer DEFAULT 1 NOT NULL,
    billid integer,
    CONSTRAINT "SHIFTS_check" CHECK ((starts < ends))
);


-- Check if given shift time overlaps with existing data
CREATE OR REPLACE FUNCTION 
  shift_overlaps (integer, timestamp, timestamp)
RETURNS 
  boolean AS $$
DECLARE
  _employeeid ALIAS FOR $1;
  _start      ALIAS FOR $2;
  _end        ALIAS FOR $3;
BEGIN
  SELECT 
    COUNT(id) AS c
  FROM 
    "SHIFTS" 
  WHERE 
    employee_id = _employeeid AND 
    status = 1 AND
    (
      (starts BETWEEN _start AND _end)
      OR 
      (ends BETWEEN _start AND _end)
    )
  ;

  -- Return boolean
  RETURN (c > 0);
END;
$$
LANGUAGE 
  plpgsql
;


CREATE OR REPLACE FUNCTION
  check_shift()
RETURNS trigger AS '
BEGIN

  -- Bill ID is set, do not allow update
  IF tg_op = "UPDATE" THEN
    IF old.billid IS NOT NULL THEN
      RAISE EXCEPTION "Shift is locked"
    END IF;
  END IF;

  -- Check for overlap
  IF tg_op = "INSERT" THEN
    IF new.employee_id IS NOT NULL THEN
      IF shift_overlaps(new.employee_id, new.starts, new.ends) THEN
        RAISE EXCEPTION "Given time overlaps with shifts"
      END IF;
    END IF;
  END IF;

  -- Check for overlap
  IF tg_op = "UPDATE" THEN
    IF (new.employee_id IS NOT NULL) AND (new.status = 1) THEN
      IF shift_overlaps(new.employee_id, new.starts, new.ends) THEN
        RAISE EXCEPTION "Given time overlaps with shifts"
      END IF;
    END IF;
  END IF;

  RETURN new;
END
'
LANGUAGE
  plpgsql
;


-- Shift checker trigger
CREATE TRIGGER
  check_shifts
BEFORE
  INSERT OR UPDATE
ON 
  "SHIFTS"  
FOR EACH ROW EXECUTE PROCEDURE
  check_shift()
;

shift_overlaps ():

SQL error: ERROR: query has no destination for result data

check_shift ():

SQL error: ERROR: unrecognized exception condition "Shift is locked"

Ответы [ 3 ]

3 голосов
/ 19 ноября 2009

У вас есть ошибка здесь:

SELECT 
    COUNT(id) AS c
  FROM 
    "SHIFTS" 
  WHERE 
    employee_id = _employeeid AND 
    status = 1 AND
    (
      (starts BETWEEN _start AND _end)
      OR 
      (ends BETWEEN _start AND _end)
    )
  ;

Такой выбор в процедуре plpgsql должен быть SELECT INTO ... вот так:

DECLARE
 c INTEGER;
BEGIN
  SELECT 
    COUNT(id)
  INTO c
  FROM 
    "SHIFTS" 
  WHERE 
    employee_id = _employeeid AND 
    status = 1 AND
    (
      (starts BETWEEN _start AND _end)
      OR 
      (ends BETWEEN _start AND _end)
    )
  ;

  RETURN (c > 0);

END;

И здесь у вас должна быть точка с запятой в конце строки:

enter code here`RAISE EXCEPTION "Shift is locked";
0 голосов
/ 19 ноября 2009

Вы должны использовать SELECT INTO, чтобы получить значение, возвращаемое запросом

DECLARE
  [...]
  c boolean;
SELECT 
    COUNT(id) INTO c
  FROM 
    "SHIFTS" 
  WHERE 
  [...]
0 голосов
/ 19 ноября 2009

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

Если вы хотите что-то сделать внутри процедуры, вам нужен раздел ИСКЛЮЧЕНИЯ:

[<>] [ОБЪЯВИТЬ декларации] НАЧАТЬ заявления ИСКЛЮЧЕНИЕ КОГДА условие [ИЛИ условие ...] ТО handler_statements [КОГДА условие [ИЛИ условие ...] ТО handler_statements ...] END;

Но, как правило, я ожидаю, что вы справитесь с этим в коде вызова.

...