ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA...

今天创建function

CREATE FUNCTION `func_get_split_string_total`(
f_string varchar(1000),f_delimiter varchar(5)
) RETURNS int(11)
BEGIN
  return 1+(length(f_string) - length(replace(f_string,f_delimiter,'')));
END

报错信息:

    ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)


查了一些资料,解决办法是把log_bin_trust_function_creators = 1


但是log_bin_trust_function_creators这个参数是做什么的呢?开启后会有哪些影响呢?


接下来开始介绍一下相关的作用及影响:

    对存储子程序语句的二进制日志功能的特征在下面列表中描述。一些条目指出你应该注意到的问题。


    CREATE PROCEDURE, CREATE FUNCTION, ALTER PROCEDURE,和ALTER FUNCTION 语句被写进二进制日志,CALL, DROP PROCEDURE, 和DROP FUNCTION 也一样。


    尽管如此,对复制有一个安全暗示:要创建一个子程序,用户必须有CREATE ROUTINE权限,但有这个权限的用户不能写一个 子程序在从服务器上执行任何操作。因为在从服务器上的SQL线程用完全权限来运行。例如,如果主服务器和从服务器分别有服务器ID值1和2,在主服务器上的用户可能创建并调用如下一个 程序:


mysql> delimiter //
mysql> CREATE PROCEDURE mysp ()
-> BEGIN
-> IF @@server_id=2 THEN DROP DATABASE accounting; END IF;
-> END;
-> //
mysql> delimiter ;
mysql> CALL mysp();

    CREATE PROCEDURE和CALL语句将被写进二进制日志,所以从服务器将执行它们。因为从SQL线程有完全权限,它将移除accounting数据库。


    要使允许二进制日志功能的服务器避免这个危险,MySQL 5.1已经要求 存储程序和函数的创建者除了通常需要的CREATE ROUTINE的权限外,还必须有SUPER 权限。类似地,要使用ALTER PROCEDURE或ALTER FUNCTION,除了ALTER ROUTINE权限外你必须有SUPER权限。没有SUPER权限,将会发生一个错误:
    ERROR 1419 (HY000): You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)


    你可能不想强制要求子程序创建者必须有SUPER权限。例如,你系统上所有有CREATE ROUTINE权限的用户可能是有经验的应用程序开发者。要禁止掉对SUPER权限的要求,设置log_bin_trust_routine_creators 全局系统变量为1。默认地,这个变量值为0。


    如果二进制日志功能不被允许,log_bin_trust_routine_creators 没有被用上,子程序创建需要SUPER权限。
i.  一个执行更新的非确定子程序是不可重复的,它能有两个不如意的影响:
ii. 它会使得从服务器不同于主服务器。
iii.恢复的数据与原始数据不同。


    要解决这些问题,MySQL强制做下面要求:在主服务器上,除非子程序被声明为确定性的或者不更改数据,否则创建或者替换子程序将被拒绝。这意味着当你创建一个子程序的时候,你必须要么声明它是确定性的,要么它不改变数据。两套子程序特征在这里适用:
i.  DETERMINISTIC和NOT DETERMINISTIC指出一个子程序是否对给定的输入总是产生同样的结果。如果没有给定任一特征,默认是NOTDETERMINISTIC,所以你必须明确指定DETERMINISTIC来 声明一个 子程序是确定性的。

ii. 使用NOW() 函数(或它的同义)或者RAND() 函数不是必要地使也一个子程序非确定性。对NOW()而言,二进制日志包括时间戳并正确复制。RAND()只要在一个 子程序内被调用一次也可以正确复制。(你可以认为子程序执行时间戳和随机数种子作为毫无疑问地输入,它们在主服务器和从服务器上是一样的。)
iii.CONTAINS SQL, NO SQL, READS SQL DATA, 和 MODIFIES SQL数据提供子程序是读还是写数据的信息。无论NO SQL 还是READS SQL DATA 都指出,子程序没有改变数据,但你必须明白地指明这些中的一个,因为如果任何这些特征没有被给出, 默认的特征是CONTAINS SQL。


    当你开启binlog,要一个 CREATE PROCEDURE 或 CREATE FUNCTION 语句被接受,DETERMINISTIC 或 NO SQL与READS SQL DATA 中的一个必须明白地指定,否则会产生如下错误:
    ERROR 1418 (HY000): This routine has none of DETERMINISTIC, NO SQL,or READS SQL DATA in its declaration and binary logging is enabled(you *might* want to use the less safe log_bin_trust_routine_creators variable)。


    注意,子程序本性的评估是基于创建者的“诚实度” :MySQL不检查声明为确定性的子程序是否不含产生非确定性结果的语句。


    如果子程序返回无错,CALL语句被写进二进制日志,否则就不写。当一个子程序修改数据失败了,你会得到这样的警告:
    ERROR 1417 (HY000): A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes.


    这个记日志行为潜在地导致问题.如果一个子程序部分地修改一个非交互表(比如一个MyISAM表able)并且返回一个错误,二进制日志将反映这些变化。要防止这种情况,你应该在 子程序中使用交互表并且在交互动作内修改表。


    在一个子程序内,如果你在INSERT, DELETE, 或者UPDATE里使用IGNORE关键词来忽略错误,可能发生一个部分更新,但没有错误产生。这样的语句被记录日志,且正常复制。


    如果一个存储函数在一个如SELECT这样不修改数据的语句内被调用,即使函数本身更改数据,函数的执行也将不被写进二进制日志里。这个记录日志的行为潜在地导致问题。假设函数myfunc()如下定义:


CREATE FUNCTION myfunc () RETURNS INT
BEGIN
INSERT INTO t (i) VALUES(1);
RETURN 0;
END;


按照上面定义,下面的语句修改表t,因为myfunc()修改表t, 但是语句不被写进二进制日志,因为它是一个SELECT语句:
    SELECT myfunc();


在一个子程序内执行的语句不被写进二进制日志。假如你发布下列语句:
    CREATE PROCEDURE mysp INSERT INTO t VALUES(1);
    CALL mysp;


    对于这个例子来说,CREATE PROCEDURE 和CALL语句出现在二进制日志里,但INSERT语句并未出现。在从服务器上,当决定复制哪个来自主服务器的事件时,下列限制被应用:--replicate-*-table规则不适用于CALL语句或子程序内的语句:在这些情况下,总是返回“复制!”


    触发程序类似于存储函数,所以前述的评论也适用于触发程序,除了下列情况: CREATE TRIGGER没有可选的DETERMINISTIC特征,所以触发程序被假定为总是确定性的。然而,这个假设在一些情况下是非法的。比如,UUID()函数是非确定性的(不能复制)。你应该小心在 触发程序中使用这个函数。


    触发程序目前不能更新表,但是在将来会支持。因为这个原因,如果你没有SUPER权限且log_bin_trust_routine_creators 被设为0,得到的错误信息类似于存储子程序与CREATE TRIGGER产生的错误信息。



    到这就介绍完了,最后来总结一下,log_bin_trust_function_creators的作用就是定义create procedure或者create function的时候,屏蔽super权限和去除必须明白地指定 DETERMINISTIC 或 NO SQL与READS SQL DATA 的要求(DETERMINISTIC 或 NO SQL与READS SQL DATA只是声明的作用,而非约束

    在同步中,如果启用log_bin_trust_function_creators,创建修改表数据的function,可能会导致主从同步不一致。而在用binlog做数据恢复的时候,可能会导致恢复数据不完整而丢失,原因上述已阐明。

附:官方相关介绍http://dev.mysql.com/doc/refman/5.7/en/stored-programs-logging.html

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。