General error: 1364 Field 'xxxx' doesn't have a default value - mysql

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"')
);

Related

SET a variable in mysql only once

I am using classic ASP and MySQL (using PHP wouldn't change the point of the question).
I need to set a variable over my homepage:
SET block_encryption_mode = 'aes-256-cbc'
I can not set it as global variable as other users are using the server and may use the default block_encryption_mode.
I know I can use the statement using ASP/PHP on the beginning of each webpage, but that seems like using too much resources; every user will execute the SET statement on every page...
Is there a way to SET variable or execute some other SQL statement at the beggining on each session, like an onstart event like ASP has, maybe? Or how could I achieve my goal without executing the query for each user on every page I have?
You can use the init_connect variable.
A string to be executed by the server for each client that connects. The string consists of one or more SQL statements, separated by semicolon characters.
You can also distinguish the users with code like this:
IF (CURRENT_USER() = 'special_crypto_dude#localhost') THEN
SET SESSION block_encryption_mode = 'aes-256-cbc';
END IF;
It is safe to call SET on every page as it executes in orders of microseconds. There is literally no overhead calling SET on already open connection.
Unless you can apply this setting globally, I would not bother. Just set the block_encryption_mode (together with collation and timezone) directly after acquiring the database connection handle.

Issues deleting a row using OPENQUERY() with RPC enabled, obeying case sensitivity

I'm using T-SQL and I want to delete a row from a linked server using MYSQL.
For this I've tried:
delete from openquery(MYSQLServer,
'select * from dTable where date = cast(cast(date_add(now(),interval -6 day)as date) as int)
and ProductKey = 38410 and StoreKey = 3201')
But this gives the error
There was a recoverable, provider-specific error, such as an RPC failure.
I then Googled this issue and realized that I need to adjust the RPC settings in management studios by right clicking the linked server and set RPC = True and RPC Out = True. Refreshing the linked servers and executing the Query again yield the same error.
From searching the web I've also realized that delete is case sensitive.
However, using
exec sp_tables_ex MYSQLServer
showed me that I use the exact same case on the table. I've also controlled that each column has the same case. I've tried to rewrite the Query to have only upper case values just in case, but then I got the error that the table with uppercase does not exist.
I've also tried to use
SELECT * FROM MYSQLServer.Catalog.dbo.dTable
but that gave the error Invalid object name.
I've also tried:
select * from openquery(MYSQLServer,
'delete from dTable where date = cast(cast(date_add(now(),interval -6 day)as date) as int)
and ProductKey = 38410 and StoreKey = 3201')
but this gave the error that either object has no columns, or the current user does not have permissions on that object.
Does anyone have any clue?
EDIT
I've found that Another linked server, from which I have successfully deleted a row earlier, had a user name with a remote userID and password defined under Security settings at the specific Linked Server in management studios.
I tried to mimic this by using:
EXEC sp_addlinkedsrvlogin 'MYSQL_UNIC', 'false', 'uid', 'rmtid', 'rmtpw'
but this gives me the error
Access denied for user rmtid (using password: YES)
when I try to use the delete Query.
I'll try to find how to get permission to Query using a remote user.
Here’s the solution:
Make sure the RPC and RPC Out are set to TRUE on the LinkedServer’s properties.
Then use the following syntax (This is specifically for Teradata):
declare #SQL varchar(1000)
SET #SQL = ‘DELETE FROM DB.tableName ALL’
EXEC (#SQL) AT TERADATA_LINKEDSERVER

Disable strict sql mode for a inline query in mysql

Can some how i could Disable strict sql mode for a stored procedure or inline query in mysql?
I just wanted to either disable for single sp/query or a single database.
What i have tried is
set sql_mode='' ;INSERT INTO system_log(appname, action, level, thread_id, context,
context_id,market_id, message,transaction_id,primary_msisdn,primary_issuer
,secondary_msisdn,secondary_issuer, merchant_id,acquirer_id)
VALUES(
#appname, #action,#level, #thread_id, #context
, #context_id
,#market_id
,CASE WHEN #message = 'NULL' THEN NULL ELSE #message END
,#transaction_id
,#primary_msisdn
,#primary_issuer
,#secondary_msisdn,#secondary_issuer, #merchant_id,#acquirer_id
);
You have to set the session version of the sql_mode server system variable:
SET SESSION sql_mode = ''; --no mode set
After that you can restore sql_mode by setting it to the appropriate value.
However, I would rather consider rewriting the stored procedure so that you do not have to change the sql mode.

How do I require a mysql field?

I just discovered NOT NULL does not make a field required.
When creating a mysql table, how do I create a field that cannot contain null or blank (must have something in it)?
By default, MySQL accepts invalid values. You can set MySQL to strict mode to force valid values. This will reject a query that does not provide a value for a NOT NULL column as well as enforce integrity on all types of columns.
Update: MySQL 5.7 and above now have strict mode on by default. So it would not accept invalid values by default like previous versions.
http://dev.mysql.com/doc/refman/5.0/en/sql-mode.html#sql-mode-important
http://dev.mysql.com/doc/refman/5.0/en/sql-mode.html#sqlmode_strict_all_tables
Edit:
#Barranka and #RocketHazmat made good points in the comments. '' is not the same as null, so MySQL will allow that in a NOT NULL column. In that instance, you would have to resort to your code or a trigger.
In the code (PHP for example), this could be easy enough, running something like:
if (!strlen($value)) {
// Exclude value or use NULL in query
}
I think you should do two things:
Set the column to NOT NULL to force the input of a value
Use a trigger to validate the values.
Within the trigger you can cancel the operation if the desired column does not fulfill a required condition (for example, having zero-length).
This question and its answers address this second thing, and here is an example:
delimiter $$
CREATE TRIGGER `cancel_insert_if_empty`
BEFORE INSERT ON `your_table`
FOR EACH ROW
BEGIN
declare msg varchar(255);
if NEW.your_column is null or length(NEW.your_column) = 0 then
set msg = "You're doing something wrong! Now suffer the consequences";
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
end if;
END$$
delimiter ;
In this example, if you try to insert a null value or a zero-length string in your_column an error will rise and the insert will be canceled. Quoting from the reference manual:
MySQL handles errors during trigger execution as follows:
If a BEFORE trigger fails, the operation on the corresponding row is not performed.
A BEFORE trigger is activated by the attempt to insert or modify the row, regardless of whether the attempt subsequently succeeds.
An error during either a BEFORE or AFTER trigger results in failure of the entire statement that caused trigger invocation.
Of course, you can write a trigger to check the updates too.
Hope this helps.
You can set default value for that field: City varchar(40) DEFAULT 'Sandnes'

super priviliege not set for master user in aws rds mysql

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.