为了绕过触发器中缺少准备好的语句,我试着写一个执行其agrument的UDF。
udf依赖于MySQL C api并使用有限的特定用户。
#include "string"
#include "string.h"
#include "stdio.h"
#include "mysql.h"
#include <sstream>
extern "C" my_bool execsql_init(UDF_INIT* initid, UDF_ARGS* args, char* msg) {
if (args->arg_count != 1) {
memcpy(msg, "Missing message argument.", 26);
return 1;
}
if (args->arg_type[0] != STRING_RESULT) {
args->arg_type[0] = STRING_RESULT;
}
return 0;
}
char* setError(unsigned long* length, std::string message) {
*length = message.size();
return (char*)message.c_str();
}
extern "C" char* execsql(UDF_INIT* initid, UDF_ARGS* args, char* result, unsigned long* length, my_bool* is_null, my_bool* error) {
MYSQL *con = mysql_init(NULL);
if (con == NULL) {
return setError(length, "Erreur d'initialisation");
}
if (mysql_real_connect(con, "172.31.72.6", "execsqluser", "qwerty", "nvannuaire", 0, NULL, 0) == NULL) {
mysql_close(con);
return setError(length, "Erreur de connexion");
}
mysql_query(con, "use nvannuaire;");
if (mysql_query(con, args->args[0])) {
std::ostringstream ss;
ss << mysql_errno(con) << ": " << mysql_error(con);
std::string error = ss.str();
return setError(length, (char*)error.c_str());
mysql_close(con);
}
mysql_close(con);
std::string retour = "ok !";
*length = retour.size();
return (char*)retour.c_str();
}
这似乎运作良好,但出现问题。 在调用execsql()之后,没有其他事情发生。 该语句将被执行,但不会执行存储过程中的下一个语句。
SELECT execsql(statement_requete) INTO i_retour FROM t_requete WHERE id_requete = a_id_requete;
-- test la valeur de retour
IF i_retour != 'ok !' THEN
-- si pas ok, on renseigne l'erreur via update
UPDATE t_requete SET erreur_requete = i_retour WHERE id_requete = a_id_requete;
ELSE
-- si == 'ok !', on delete
DELETE FROM t_requete WHERE id_requete = a_id_requete;
END IF;
dbForge Studio引发了“已超时读取通信包”。
这是mysql.log文件:
.
.
.
140709 10:33:21 2020 Init DB nvannuaire
2020 Query select * from ta_avancement order by id_tache desc limit 0, 20
140709 10:33:22 2020 Query select * from t_tache order by id_tache desc limit 0, 20
2020 Query SHOW TABLE STATUS FROM `nvannuaire` LIKE 't_tache'
2020 Query SHOW VARIABLES LIKE 'auto_increment%'
2020 Query select * from t_requete order by id_evenement desc limit 0, 20
2020 Query SHOW TABLE STATUS FROM `nvannuaire` LIKE 't_requete'
2020 Query SHOW VARIABLES LIKE 'auto_increment%'
2020 Query select * from t_comptenovell where id_comptenovell = 115 limit 0,1000
2020 Query SHOW TABLE STATUS FROM `nvannuaire` LIKE 't_comptenovell'
2020 Query SHOW VARIABLES LIKE 'auto_increment%'
2020 Query CALL pr_si_avancement_avancer(55, 115, 2)
2029 Connect execsqluser@172.31.72.6 on nvannuaire
2029 Query use nvannuaire
2029 Query UPDATE t_comptenovell SET login_comptenovell = "Test" WHERE id_comptenovell = 115
140709 10:33:52 2020 Init DB annuaire
140709 10:33:58 2020 Init DB nvannuaire
2020 Query select * from ta_avancement order by id_tache desc limit 0, 20
2020 Query select * from t_tache order by id_tache desc limit 0, 20
.
.
.
编辑:直接调用execsql函数时,没有错误。它仅在触发器内调用函数时发生。
编辑2:存储引擎是InnoDB。
存储在t_requete中的语句从不适用于t_requete表,但适用于其他表。
经过进一步研究,似乎如果存储在t_requete中的语句包含一些SQL语法错误,则没有超时并且所有过程都成功执行(它将错误存储在t_requete表的erreur_requete中)。 因此,当执行的语句不包含错误以及在触发器内执行时,问题似乎只会发生。
在此测试用例中,触发器在表A后更新。该语句存储在表B中,并在表C上执行更新。
知道为什么会发生这种错误以及如何解决它?