Salta el contingut

4. Handlers

Amb SQL podem gestionar els errors generats per les ordres SQL. Si per exemple fem un SELECT a una taula que no existeix, ens dóna l'error 1146. Podem fer que si alguna vegada ocorre eixe error, que faça tal cosa. Per a aconseguir això cal definir un HANDLER.

Veiem primer un exemple i després explicarem la sintaxi.

Exemple: PE de prova per a saber si hi ha hagut error de clau duplicada

SQL
CREATE TABLE prova (codi int, primary key (codi));

DELIMITER //

CREATE PROCEDURE demo_handler()
BEGIN
    DECLARE CONTINUE HANDLER FOR
    SQLSTATE '23000'
    SET @err = 1;

    SET @x = 1;
    INSERT INTO prova VALUES (1);   -- Ok
    SET @x = 2;
    INSERT INTO prova VALUES (1);   -- Error (*)
    SET @x = 3;
END;
//

CALL demo_handler()//
SELECT @x//

Estem dient que si més endavant ocorre l'error 23000 (error per clau duplicada), que la variable @err tinga el valor 1 i que "CONTINUE" executant-se el tros de codi del bloc BEGIN-END.

Si executem això vorem que no ha aparegut cap error i, a més, el valor de @x és 3. Per què?

(*) L'error provocat no apareix ja que ha estat "agafat" pel handler que hem creat. A més, com que eixe handler estava definit com a CONTINUE, la rutina ha continuat executant-se.

Si en compte de CONTINUE, el handler haguera estat definit com EXIT, en executar el 2n INSERT hauria acabat el procediment. En eixe cas @x valdria 2.

4.1. Sintaxi del HANDLER

SQL
1
2
3
DECLARE tipus_handler HANDLER FOR
codi_error [, ...]
sentència;

On tenim:

  • sentència: pot ser una ordre SQL simple o composta (bloc BEGIN ... END).
  • tipus_handler: indica si continuen executant-se les següents instruccions a l'error o no:
    • CONTINUE: continuar la rutina.
    • EXIT: se n'ix del bloc BEGIN ... END on està.
  • codi_error: identificador de l'error (o llista d'errors) que es vol controlar.

Es pot posar de distintes formes:

  • codi_error_mysql
  • SQLSTATE codi_error_sqlstate
  • nom_error
  • SQLWARNING
  • NOT FOUND
  • SQLEXCEPTION

4.2. Codis d'error

4.2.1. codi_error_mysql

És un codi d'error numèric.

Exemple: 1022 -- Clau duplicada

Problema

Estos codis només són vàlids per a MySQL. Per tant, no és portable a altres SGBD.

4.2.2. SQLSTATE codi_error_sqlstate

És la paraula reservada SQLSTATE més un codi alfanumèric, vàlid per a SQL estàndard.

Exemple: SQLSTATE '23000' -- Clau duplicada

Un codi SQLSTATE equival a molts codis d'error de MySQL. Exemples:

DESCRIPCIÓ ERROR CODI MySQL CODI SQLSTATE
Clau duplicada en taula 1022 '23000'
Columna no pot ser nula 1048
Columna ambigua 1052
Violació de clau aliena 1216
... ...
Taula desconeguda 1051 '42S02'
Taula inexistent 1146
... ...
Accés denegat a la BD 1044 '42000'
BD desconeguda 1049
... ...

Podem consultar els codis d'error de MySQL i SQLSTATE ací: https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html

A més, SQLSTATE 'HY000' es pot usar com a codi d'error general.

4.2.3. nom_error

És un nom que li posem a l'error, el qual haurem declarat prèviament. A eixe nom d'error se li coneix com una "condició".

Exemple de condició: taula_desconeguda

La forma de declarar una condició és:

SQL
DECLARE taula_desconeguda CONDITION FOR 1051;

O bé:

SQL
DECLARE error_de_taula CONDITION FOR SQLSTATE '42S02';

4.2.4. SQLWARNING

És una abreviació per a tots els codis SQLSTATE que comencen per 01.

4.2.5. NOT FOUND

És una abreviació per a tots els SQLSTATE que comencen per 02.

Sol usar-se per a establir la condició de recórrer un cursor (ja ho vorem).

4.2.6. SQLEXCEPTION

És una abreviació per a tots els codis SQLSTATE que no són SQLWARNING ni NOT FOUND.

Nota

Els handlers s'han de definir després de les variables i condicions.

4.3. Exercicis de handlers

7. Volem fer inserts en la taula de jugadors, però de forma que si dóna algun error, que faça constància en algun lloc del moment on s'ha produït l'error i quin error. Per a fer això:

  • a) Crea una taula on es guardaran els errors:

    SQL
    1
    2
    3
    4
    5
    6
    CREATE TABLE errors(
    dia date,
    hora time,
    taula char(20),
    error char(40)
    );
    
  • b) Crear un procediment que faça les insercions en la taula de jugadors i, si cal, també en la taula d'errors:

    • Passa-li com a paràmetres els valors que necessites per a inserir un jugador: codi d'equip, dorsal, nom, lloc i sou.
    • Crea un handler per a que quan done l'error de clau duplicada, 1062, (degut a que ja existia el jugador) inserisca l'error "Jugador ja existeix".
    • Crea un handler per a que quan done l'error de clau aliena, 1452, (degut a que l'equip del jugador no existeix) inserisca l'error "Equip inexistent".
    • Fes l'insert en la taula de jugadors amb els valors passats com a paràmetre al procediment.

    Notes

    • Pensa si en este cas donaria igual declarar els handlers CONTINUE o EXIT.
    • Data actual: current_date.
    • Hora actual: current_time.
  • c) Insereix, mitjançant crides a eixe procediment, diversos jugadors correctes (que no existisquen però sí que existisca l'equip), que no existisca l'equip o que ja existisca el jugador. Després mira el contingut de la taula d'errors per a comprovar si tot ha funcionat com s'esperava.