【オリジナル】mysqlエラーバッファスタック


エラーバッファスタックとは?簡単な例を挙げます.たとえば、次の文を実行します.
mysql> INSERT INTO t_datetime VALUES(2,'4','5');
ERROR 1292 (22007): Incorrect datetime value: '4' for column 'log_time' at row 1

上の1292というコードが示すエラー情報はどこに保存されていますか?エラーバッファスタックに保存され、MySQLではDIAGNOSTICS AREAと呼ばれます.この概念について、ずっとMySQL 5にいます.7で確定した更新が得られました. 
MySQL 5.5以前は、このエリアのデータを取得するには、CのAPIでしか取得できず、SQLレベルでは検索できませんでした.MySQL5.5まずこの概念を発表した.
MySQL 5.6リリース後、この領域を検索するだけでなく、再パッケージして、私たちが望んでいるデータを得ることができます.しかし、この領域は依然としてエラーコードを1回しか保存できず、リセットされやすい.
MySQL 5.7リリース後、このエリアをより簡単に検索でき、ここのデータを1つのSTACKに入れることで、リセットの条件がより緩和されます.以下に例を挙げて説明する.
表の構成例は次のとおりです.
CREATE TABLE `t_datetime` (
  `id` int(11) NOT NULL,
  `log_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `end_time` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

エラー・データを記録するためのログ・テーブル.
CREATE TABLE tb_log (errorno int,errortext TEXT,error_timestamp DATETIME);

MySQL 5.6環境では、このように複雑なコードを書いてエラー情報を取得します.
DELIMITER $$
USE `new_feature`$$
DROP PROCEDURE IF EXISTS `sp_do_insert`$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_do_insert`(
IN f_id INT,
IN f_log_time VARCHAR(255),
IN f_end_time VARCHAR(255)
)
BEGIN
  DECLARE done1 TINYINT DEFAULT 0; --             。
  DECLARE i TINYINT DEFAULT 1;
  DECLARE v_errcount INT DEFAULT 0;  --           
  DECLARE v_errno INT DEFAULT 0; --       
  DECLARE v_msg TEXT; --         
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION --          
  BEGIN
    SET done1 = 1; --     ,   1.
    get  diagnostics v_errcount = number;
    SET v_msg = '';
    WHILE i <= v_errcount
    DO
      GET  DIAGNOSTICS CONDITION i
        v_errno = MYSQL_ERRNO, v_msg = MESSAGE_TEXT;
        SET @stmt = CONCAT('select ',v_errno,',"',v_msg,'","',NOW(),'" into @errno',i,',@msg',i,',@log_timestamp',i,';');
        PREPARE s1 FROM @stmt;
        EXECUTE s1;
      SET i = i + 1;
    END WHILE;
    DROP PREPARE s1;
  END;
    INSERT INTO t_datetime (id,log_time,end_time) VALUES(f_id,f_log_time,f_end_time);
    IF done1 = 1 THEN --          tb_log 。
      SET i = 1;
      WHILE i <= v_errcount
      DO
        SET @stmt = CONCAT('insert into tb_log ');
        SET @stmt = CONCAT(@stmt,' select @errno',i,',@msg',i,',@log_timestamp');
        PREPARE s1 FROM @stmt;
        EXECUTE s1;
        SET i = i + 1;
      END WHILE;
      DROP PREPARE s1;
    END IF;
END$$
DELIMITER ;

MySQL5.7リリース後、私のコードを簡素化できます.
DELIMITER $$
USE `new_feature`$$
DROP PROCEDURE IF EXISTS `sp_do_insert`$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_do_insert`(
IN f_id INT,
IN f_log_time VARCHAR(255),
IN f_end_time VARCHAR(255)
)
BEGIN
  DECLARE i TINYINT DEFAULT 1;
  DECLARE v_errcount INT DEFAULT 0; --           
  DECLARE v_errno INT DEFAULT 0;  --       
  DECLARE v_msg TEXT; --         
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION  --          
  BEGIN
    get stacked diagnostics v_errcount = number;
    WHILE i <= v_errcount
    DO
      GET stacked DIAGNOSTICS CONDITION i --              
        v_errno = MYSQL_ERRNO, v_msg = MESSAGE_TEXT;
        INSERT INTO tb_log VALUES (v_errno,v_msg,NOW());
      SET i = i + 1;
    END WHILE;
  END;
    INSERT INTO t_datetime (id,log_time,end_time) VALUES(f_id,f_log_time,f_end_time);  
END$$
DELIMITER ;

次に、
mysql> call sp_do_insert(2,'4','5');
Query OK, 1 row affected (0.01 sec)

テーブルtbを取得するlogのデータ.
mysql> select * from tb_log\G
*************************** 1. row ***************************
        errorno: 1265
      errortext: Data truncated for column 'log_time' at row 1
error_timestamp: 2015-11-17 11:53:10
*************************** 2. row ***************************
        errorno: 1265
      errortext: Data truncated for column 'end_time' at row 1
error_timestamp: 2015-11-17 11:53:10
*************************** 3. row ***************************
        errorno: 1062
      errortext: Duplicate entry '2' for key 'PRIMARY'
error_timestamp: 2015-11-17 11:53:10
3 rows in set (0.00 sec)

まとめて、DIAGNOSTICS AREAを先に使用する場合は、ストレージプロセスにSQLをコードパッケージするように書くのが望ましい.