2009-11-19 9 views
0

J'essaie de faire fonctionner mon premier déclencheur et ma première fonction, mais comment puis-je lancer des exceptions et renvoyer des données correctement?Déclencheurs et exceptions PostgreSQL

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" 

Répondre

3

Vous avez une erreur ici:

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) 
    ) 
    ; 

Une telle sélection dans une procédure de plpgsql doit être SELECT INTO ... comme ceci:

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; 

Et là, vous avez d'avoir le point-virgule à la fin de la ligne:

enter code here`RAISE EXCEPTION "Shift is locked"; 
0

Vous ne savez pas exactement ce que vous essayez de savoir. Vous gérez vos propres exceptions, alors c'est bien. Je m'attendrais à ce que toute manipulation d'erreur soit dans le code qui évoque cette méthode.

Si vous voulez faire quelque chose dans la procédure, vous avez besoin d'une section EXCEPTION:

[<>] [DECLARE déclarations] BEGIN déclarations QUAND EXCEPTION état [condition OU ...] PUIS handler_statements [WHEN condition [OR condition ...] ALORS handler_statements ...] END;

Mais généralement je m'attendrais à ce que vous le manipuliez dans le code appelant.

0

Vous devez utiliser SELECT INTO pour obtenir une valeur renvoyée par une requête

DECLARE 
    [...] 
    c boolean; 
SELECT 
    COUNT(id) INTO c 
    FROM 
    "SHIFTS" 
    WHERE 
    [...]