I have created an AWS RDS instance, I have created my master user with master password, and it is working/connecting fine.
But when I am going to create a function on that instance, it shows me the following error:
ERROR 1418: 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_creator variable).
In my instance the variable log_bin_trust_function_creators shows OFF, and if I try to change the variable using SET GLOBAL log_bin_trust_function_creators = 1;, it gives me another error "Error Code: 1227. Access denied; you need (at least one of) the SUPER privilege(s) for this operation"
Set log_bin_trust_function_creators = 1 for Parameter group of the RDS instance.
Note: Default Parameter-Group is not editable. Create a new Parameter-Group and assign it to the RDS instance by modifying it from UI (AWS Admin Console) OR maybe using commands
DELIMITER $$
CREATE DEFINER=`DB_USERNAME_HERE`#`%` FUNCTION `GetDistance`(coordinate1 VARCHAR(120), coordinate2 VARCHAR(120)) RETURNS decimal(12,8)
READS SQL DATA
BEGIN
DECLARE distance DECIMAL(12,8);
/*Business logic goes here for the function*/
RETURN distance;
END $$
DELIMITER ;
Here, you have to replace DB_USERNAME_HERE with you RDS database username and function names according to you need.
Important thing is: DEFINER=`DB_USERNAME_HERE`#`%`
This was the problem I was facing after setting log_bin_trust_function_creators = 1 in parameter group. And it worked like a charm.
A better way is to apply your own parameter group, with log_bin_trust_function_creators set to true. (its false by default)
This happens when you try to create a procedure/function/view with a DEFINER that is not the current user.
To solve this remove or update the DEFINER clause.
Related
In MySQL 8.0, even with binlog_format set to "ROW" or "MIXED" I seem to be unable to create a non-deterministic function. e.g:
DELIMITER //
CREATE FUNCTION nonDeterministicFunc()
RETURNS CHAR(4)
BEGIN
RETURN LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0');
END
//
DELIMITER ;
gives the error:
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)
I'm aware that during replication, if binlog_format is set to STATEMENT then the slave DB will re-call the function and get a different result, but I thought when set to "ROW" or "MIXED" it would replicate the row changes not the function calls and so non-deterministic functions were fine?
The comment from MySQL support Margaret Fisher seems to say this is a feature:
https://bugs.mysql.com/bug.php?id=101480#c511192
"This ensures that if the binary logging format changes after the function is created, it will still work."
I understand the danger that someone changes the replication format later.... but surely that is an extreme corner case and that adding non-deterministic functions should to be allowed when replication is currently set to ROW or MIXED?
Or am I completely missing the obvious?
Any session may override the binlog_format, so the MySQL Server cannot rely on the global setting to ensure that the function is safe. If the function's code performs an INSERT/UPDATE/DELETE, and the session has been changed to binlog_format=STATEMENT, it would cause a different change on the replica than on the source.
I recommend you add the NO SQL option to your function definition to satisfy the error check.
When am trying to create a simple trigger in mysql, am encountering the below error message. Please suggest me how to overcome this.
delimiter $$
create trigger trg_addresses_ins before insert on addresses
for each row
begin
declare msg varchar(128);
if length(new.addressstate) > 2 then
set msg = concat('MyTriggerError: Trying to insert a state value of more than 2 character: ', new.addressstate);
signal sqlstate '45000' set message_text = msg;
end if;
end$$
delimiter ;
`
Error Code: 1419. You do not have the SUPER privilege and binary logging is enabled (you might want to use the less safe log_bin_trust_function_creators variable) 0.078 sec
Super user is enabled but still get the same error and also am unable to change database parameter group associated with mysql aws db instance to 1. I am unable to modify db instance to select newly created group as the parameter group field is read only.
Appreciate your valuable inputs.
Thanks!
I guess you are using the default DB parameter group which you can not modify, the solution is you need to create your own parameter group, and set log_bin_trust_function_creators = 1, and apply your own parameter group to your current instance.
I got a project, which make insertions which inserting no values(not empty values) to the columns with NOT NULL and NO DEFAULT values.
I believed that is impossible to make insertion with missing required values, and it always throws an error: Field 'xxxx' doesn't have a default value. But as I see here mysql can be set to
sql-mode="NO_ENGINE_SUBSTITUTION"
I am confused, cause I think it is dangerous. And if I switch it OFF it will apply to all projects and it could be really bad. So what should I do? Is it possible to set the mode only for one mysql database while other databases will be on STRICT mode? What do you think about it? Is it an issue or not?
The sql-mode system variable is available at both global and session level. Which means either you have to set this for entire server or particular connection. So there is no way to configure this for subset of DBs at server level. However you can specify the sql mode when you are making the connection. So those connections will run in strict mode.
The solution that i propose is to made a trigger so when there is a no value it will insert a null value to that column
this is an example :
CREATE TRIGGER upd_check BEFORE UPDATE ON account
FOR EACH ROW
BEGIN
IF NEW.amount < 0 THEN
SET NEW.amount = 0;
END IF;
END;
So if somebody wants to know how it looks like in PHP/PDO for one concrete session:
$pdo = new PDO(
$dsn,
$username,
$password,
array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET sql_mode="NO_ENGINE_SUBSTITUTION"')
);
For a Google CloudSQL 2nd generation instance, with Failover replication was enabled. After that when tried to import the database it is not allowing to create the procedure. Receiving below error.
Error Code: 1419. You do not have the SUPER privilege and binary
logging is enabled (you might want to use the less safe
log_bin_trust_function_creators variable)
Is it true that CloudSQL with failover will not support function ?
Sample execute query
DELIMITER ;;
CREATE FUNCTION `stutzen`(amount INT) RETURNS int(11)
DETERMINISTIC
BEGIN
DECLARE charges FLOAT DEFAULT 1.0;
SELECT valuesettings INTO charges FROM dreamer_tbl WHERE namesettings='stutzen.co';
RETURN FLOOR((amount / 100) * charges) ;
END ;;
DELIMITER ;
You just need to set 'log_bin_trust_function_creators' to ON
To do it, open https://console.cloud.google.com
Select SQL
Select your instance
Select EDIT
DB signals
Add:
log_bin_trust_function_creators on
general_log on
SAVE
You should run:
gcloud sql instances patch [INSTANCE_NAME] --database-flags
log_bin_trust_function_creators=ON
as mentioned here
Google Cloud SQL support both, stored procedures and functions.
In your case the problem seems to be that you're trying to import a sql file that has some kind of routine that needs the SUPER privilege, and this is not permitted.
That is not a Stored Procedure, that is a User Defined Function.
You would need to rewrite this UDF as a Stored Procedure, which would work.
I tried using the SET GLOBAL log_bin_trust_function_creators, which should allow creating functions without the SUPER privilege but setting that variable is also not allowed in Cloud SQL. It needs SUPER privilege for setting it.
Our database has a function to generate an order number. It reads a value from a Settings table, increments it, then returns the new value. For example:
CREATE FUNCTION NextOrderNumber() RETURNS INTEGER UNSIGNED NOT DETERMINISTIC
BEGIN
DECLARE number INTEGER UNSIGNED;
UPDATE Settings SET IntegerValue=LAST_INSERT_ID(IntegerValue+1) WHERE KeyName='NextOrderNumber';
SET number=LAST_INSERT_ID();
return number;
END
Note: Don't critique this function I know it has flaws it's just for illustration.
We use this function as follows:
INSERT INTO Orders(OrderNumber, ...)
SELECT NextOrderNumber(), ...
When binary logging is enabled, CREATE FUNCTION gives this error:
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)
Regardless of what binlog_format is set, is there really a problem with the above function? According to my reading of the relevant MySQL page I can't see any reason why this function would be incompatible with replication, with either ROW or STATEMENT level binary logging.
If the function is safe, setting the global log_bin_trust_function_creators=1 makes me uneasy. I don't want to disable this check for all functions, just this one. Could I instead just flag the function as NO SQL to suppress the warning? I tried it and it worked. Will this cause any problem?
I've googled and here I am.
I've found a way :
SET GLOBAL log_bin_trust_function_creators = 1;
But be careful, it may be unsafe for data recovery or replication...
As per my understating it cause problem when data recovery or replication
Ref: http://dev.mysql.com/doc/refman/5.0/en/stored-programs-logging.html
MySQL 5.0.6: Statements that create stored routines and CALL statements are logged. Stored function invocations are logged when they occur in statements that update data (because those statements are logged).
However, function invocations are not logged when they occur in statements such as SELECT that do not change data, even if a data change occurs within a function itself; this can cause problems.
Under some circumstances, functions and procedures can have different effects if executed at different times or on different (master and slave) machines, and thus can be unsafe for data recovery or replication.
E.g.
CREATE FUNCTION myfunc () RETURNS INT DETERMINISTIC
BEGIN
INSERT INTO t (i) VALUES(1);
RETURN 0;
END;
SELECT myfunc();
If a stored function is invoked within a statement such as SELECT that does not modify data, execution of the function is not written to the binary log, even if the function itself modifies data. This logging behavior has the potential to cause problems. Suppose that a function myfunc() is defined as above.
There are two ways to fix this:
Execute the following in the MySQL console:
SET GLOBAL log_bin_trust_function_creators = 1;
Add the following to the mysql.ini configuration file:
log_bin_trust_function_creators = 1
The setting relaxes the checking for non-deterministic functions. Non-deterministic functions are functions that modify data (i.e. have update, insert or delete statement(s)). For more info, see here.
Please note, if binary logging is NOT enabled, this setting does not apply.
Have a think about what's getting written to the binary log.
You can't ensure that an order created on a master would have the same sequence generated for it when the transaction is played on a slave - or, what would much more likely, by another master in the cluster. e.g.
0) Node 1 and Node 2 are in sync, NextOrderNumber=100
1) Node 1 receives insert statement wrt order from customer A and assigns
order number 100, changes its NextOrderNumber to 101
2) Node 1 writes the settings update to the log
3) Node 1 writes the insert statement to the log
4) Node 2 processes for customer B, asigns order number 100 and increments
5) Node 2 writes the settings update from to the log
6) Node 2 writes the insert statement to the log
7) Nodes 2 reads settings update from the log #2
- Its NextOrderNumber is now 102
8) Node 2 reads insert from log #3, tries to apply it but it fails
due to duplicate key
9) Node 1 reads the update #5 - Its nextOrderNumber is also now 102
10) Node1 reads insert from log #6 -
but this fails due to duplicate key
Now orders 100 on the 2 nodes refer to different data, and there is no order 101.
There is a reason that there has been a lot of functionality added to modify the behaviour of auto_increment variables.
If you wrap the insert in a procedure - which retrieves a value from the sequence generator then embeds it in the insert statement the immediate problem will be resolved, however you need to think about how you avoid assigning the same number twice using different database nodes.
Could I instead just flag the function as NO SQL to suppress the warning? I tried it and it worked. Will this cause any problem?
According to this Mysql doc:
Assessment of the nature of a function is based on the “honesty” of the creator: MySQL does not check that a function declared DETERMINISTIC is free of statements that produce nondeterministic results.
So it's up to you. If you are sure the method won't cause any problem...
Writing the attribute helped me. In this function, you need to write - MODIFIES SQL DATA - because the function uses UPDATE. If only SELECT is used in the function, then we would write READS SQL DATA. You can also write these two attributes if both data read and write operators are used in the function body.
CREATE FUNCTION NextOrderNumber()
RETURNS INTEGER
UNSIGNED
NOT DETERMINISTIC
MODIFIES SQL DATA
BEGIN
DECLARE number INTEGER UNSIGNED;
UPDATE Settings SET IntegerValue=LAST_INSERT_ID(IntegerValue+1)
WHERE KeyName='NextOrderNumber';
SET number=LAST_INSERT_ID();
return number;
END
Execute this just before creating the function:
SET ##global.log_bin_trust_function_creators = 1;
And add MODIFIES SQL DATA to the declaration.
Also... well, you asked not to comment the function itself, but I suggest that you drop the number variable and simply do RETURN LAST_INSERT_ID().
add READS SQL DATA which declare that is a read only function :
CREATE FUNCTION NextOrderNumber() RETURNS INTEGER UNSIGNED NOT DETERMINISTIC
READS SQL DATA
BEGIN
DECLARE number INTEGER UNSIGNED;
UPDATE Settings SET IntegerValue=LAST_INSERT_ID(IntegerValue+1) WHERE KeyName='NextOrderNumber';
SET number=LAST_INSERT_ID();
return number;
END