Skip to content

Triggers e Stored Procedures

Introdução

De acordo com Silberschatz et al., os triggers são uma ferramenta importante em bancos de dados, permitindo a execução automática de ações em resposta a eventos, como inserções, atualizações ou exclusões. Esses gatilhos são úteis para garantir integridade referencial, além de automatizar tarefas como o controle de estoque ou o monitoramento de alterações em dados críticos. Funções, por outro lado, oferecem uma maneira de encapsular lógicas complexas em operações reutilizáveis, frequentemente integradas diretamente na execução das consultas SQL, aumentando a flexibilidade e a eficiência dos SGBDs modernos .

Stored Procedures

DELIMITER $$

CREATE TRIGGER check_exclusividade_entidade
BEFORE INSERT ON entidade
FOR EACH ROW
BEGIN
    DECLARE count_tipo INT;
    IF NEW.tipo = 'npc' THEN
        SELECT COUNT(*) INTO count_tipo FROM entidade WHERE tipo = 'protagonista' 
                        AND identidade = NEW.identidade;
        IF count_tipo > 0 THEN
            SIGNAL SQLSTATE '45000'
            SET MESSAGE_TEXT = 'Entidade não pode ser um NPC 
                            e um Protagonista ao mesmo tempo';
        END IF;
    END IF;
    IF NEW.tipo = 'protagonista' THEN
        SELECT COUNT(*) INTO count_tipo FROM entidade WHERE tipo = 'npc' 
        AND identidade = NEW.identidade;
        IF count_tipo > 0 THEN
            SIGNAL SQLSTATE '45000'
            SET MESSAGE_TEXT = 'Entidade não pode ser um Protagonista 
                                            e um NPC ao mesmo tempo';
        END IF;
    END IF;
END$$


CREATE TRIGGER check_npc_tipo
BEFORE INSERT ON npc
FOR EACH ROW
BEGIN
    DECLARE count_tipos INT;
    SELECT COUNT(*) INTO count_tipos FROM (
        SELECT id_entidade FROM zumbi WHERE id_entidade = NEW.id_entidade
        UNION ALL
        SELECT id_entidade FROM chefe WHERE id_entidade = NEW.id_entidade
        UNION ALL
        SELECT id_entidade FROM cachorro_zumbi WHERE id_entidade = NEW.id_entidade
    UNION ALL
        SELECT id_entidade FROM plaga WHERE id_entidade = NEW.id_entidade
    UNION ALL
        SELECT id_entidade FROM vendedor WHERE id_entidade = NEW.id_entidade
    ) AS subclasses;
    IF  count_tipos = 0 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Cada NPC deve ser pelo menos de um tipo 
                    (zumbi, chefe, cachorro_zumbi,plaga,vendedor)';
    END IF;
END$$


CREATE TRIGGER check_item_tipo
BEFORE INSERT ON item
FOR EACH ROW
BEGIN
    DECLARE count_tipos INT;
    SELECT COUNT(*) INTO count_tipos FROM (
        SELECT id_item FROM equipamento WHERE id_item = NEW.id_item
        UNION ALL
        SELECT id_item FROM arma WHERE id_item = NEW.id_item
        UNION ALL
        SELECT id_item FROM consumivel WHERE id_item = NEW.id_item
        UNION ALL
        SELECT id_item FROM dinheiro WHERE id_item = NEW.id_item
    ) AS subclasses;
    IF  count_tipos = 0 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Cada item deve pertencer a pelo menos um tipo 
                            (equipamento, arma, consumível ou dinheiro)';
    END IF;
END$$


CREATE TRIGGER check_missao_tipo
BEFORE INSERT ON missao
FOR EACH ROW
BEGIN
    DECLARE count_tipos INT;
    SELECT COUNT(*) INTO count_tipos FROM (
        SELECT nome FROM assassinato WHERE nome = NEW.nome
        UNION ALL
        SELECT nome FROM recuperacao WHERE nome = NEW.nome
    ) AS subclasses;
    IF  count_tipos = 0 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Cada missão deve pertencer a pelo menos um 
                                    tipo (assassinato ou recuperação)';
    END IF;
END$$


CREATE TRIGGER check_vida_protagonista
BEFORE UPDATE ON protagonista
FOR EACH ROW
BEGIN
    IF NEW.vida > 100 THEN
        SET NEW.vida = 100;
    END IF;
END$$


CREATE PROCEDURE inserirProtagonista(IN pNickname VARCHAR(25))
BEGIN
    INSERT INTO entidade (vida, dano) VALUES (100, 10);
    SET @id_ent = LAST_INSERT_ID();

    INSERT INTO protagonista (id_entidade, nickname, killcount, dinheirorecebido, fk_sala_numero)
    VALUES (@id_ent, pNickname, 0, 0, 1);
END$$


CREATE PROCEDURE resetarVidaBoss(
    IN p_idInstancia INT
)
BEGIN
    DECLARE p_idEnt INT;
    DECLARE p_tipo VARCHAR(20);
    DECLARE p_vidaMax INT DEFAULT 0;

    SELECT i.id_entidadenpc, n.tipo
      INTO p_idEnt, p_tipo
      FROM instancianpc i
      JOIN npc n ON i.id_entidadenpc = n.id_entidade
      WHERE i.idinstancianpc = p_idInstancia;

    IF p_tipo = 'chefe' THEN
        SELECT vida INTO p_vidaMax FROM chefe WHERE id_entidade = p_idEnt;
    ELSE
        SIGNAL SQLSTATE '45000' 
            SET MESSAGE_TEXT = 'O tipo do NPC não é chefe.';
    END IF;

    -- Atualiza a instância do boss com o valor máximo de vida
    UPDATE instancianpc
       SET vida_atual = p_vidaMax
     WHERE idinstancianpc = p_idInstancia;

    SELECT CONCAT('Vida do boss (instância ', p_idInstancia, ') resetada para ', p_vidaMax) AS Resultado;
END $$


CREATE TRIGGER before_npc_delete
BEFORE DELETE ON instancianpc
FOR EACH ROW
BEGIN
    INSERT INTO backup_instancianpc (id_entidadenpc, fk_sala_numero, missao_nome, vida_atual)
    VALUES (OLD.id_entidadenpc, OLD.fk_sala_numero, OLD.missao_nome, OLD.vida_atual);
END$$


CREATE TRIGGER after_protagonist_insert
AFTER INSERT ON protagonista
FOR EACH ROW
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE v_npc_id INT;
    DECLARE v_last_room_id INT;
    DECLARE v_missao_nome VARCHAR(30);
    DECLARE v_vida_atual INT;

    DECLARE npc_record CURSOR FOR 
        SELECT id_entidadenpc, fk_sala_numero, missao_nome, vida_atual
        FROM backup_instancianpc;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    OPEN npc_record;

    FETCH npc_record INTO v_npc_id, v_last_room_id, v_missao_nome, v_vida_atual;

    WHILE NOT done DO
        INSERT INTO instancianpc (id_entidadenpc, fk_sala_numero, missao_nome, id_protagonista, vida_atual)
        VALUES (v_npc_id, v_last_room_id, v_missao_nome, NEW.id_entidade, v_vida_atual);
        FETCH npc_record INTO v_npc_id, v_last_room_id, v_missao_nome, v_vida_atual;
    END WHILE;

    CLOSE npc_record;
END$$


DELIMITER ;
Versão Descrição Autor(es) Data
1.0 Criação Bruno Cruz 03/02/2025
2.0 Alteração Final Bruno Cruz 03/02/2025