MySQL NOT NULL insert behavior - mysql

I am currently working with a MySQL 5.5 and want to upgrade to 5.6 or 5.7.
However I ran into strange behavior (may be mysql bug or some global default variable).
Following code works fine with 5.5, but doesn't work with 5.6, 5.7.
So either 5.5 has an issue or I am missing some settings with 5.6/5.7.
create table null_test( not_null VARCHAR(255) NOT NULL);
insert into null_test values();
As expected, following doesn't work.
insert into null_test values(NULL);
Based on some early digging, it might have to do with the SQL MODE, especially ER_NO_DEFAULT_FOR_FIELD.
https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sql-mode-full

This is a result of Strict SQL mode being enabled by default in the newer MySQL versions.
When Strict mode is disabled, omitting a value for a column that's declared NOT NULL and doesn't have an explicit DEFAULT value produces a warning and assumes an automatic default. For VARCHAR, this automatic default is an empty string.
When Strict mode is enabled, this condition causes an error unless you use INSERT IGNORE.
There's no specific SQL mode that just controls this behavior; if you want to turn off this check, you'll need to disable Strict mode entirely. Since Strict mode is likely to produce other incompatibilities (e.g. ONLY_FULL_GROUP_BY errors), this may be the most expedient way for you to handle the migration.
But if you just want to deal with this specific error, the best solution is to declare an explicit default in the schema:
create table null_test(not_null VARCHAR(255) NOT NULL DEFAULT '');

Related

Mysql: Not getting an error when updating a NOT NULL column to null

Why does mysql accepts null data when updating a not null column and then converts the data to 0.
I am expecting an error it just does not show up. How can I get an error if someone tries to update a not null column to null? I need it so I can rollback the transaction if I get an error.Is there any configuration needed within the database to do this? Thank you
You've not specified which version of Mysql you're using, and in which mode. I'll answer this assuming you're running Mysql 5.7 without strict mode.
Strict mode controls how MySQL handles invalid or missing values in data-change statements such as INSERT or UPDATE. A value can be invalid for several reasons. For example, it might have the wrong data type for the column, or it might be out of range. A value is missing when a new row to be inserted does not contain a value for a non-NULL column that has no explicit DEFAULT clause in its definition. (For a NULL column, NULL is inserted if the value is missing.) Strict mode also affects DDL statements such as CREATE TABLE.
If strict mode is not in effect, MySQL inserts adjusted values for invalid or missing values and produces warnings (see Section 13.7.5.40, “SHOW WARNINGS Syntax”). In strict mode, you can produce this behavior by using INSERT IGNORE or UPDATE IGNORE.
Source: https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sql-mode-full
I recommend you to enable strict mode (STRICT_ALL_TABLES) and fix your application to support it; this will also enforce other query limitations where people are most commonly hit by ONLY_FULL_GROUP_BY.
To set the SQL mode at server startup, use the --sql-mode="modes" option on the command line, or sql-mode="modes" in an option file such as my.cnf (Unix operating systems) or my.ini (Windows). modes is a list of different modes separated by commas. To clear the SQL mode explicitly, set it to an empty string using --sql-mode="" on the command line, or sql-mode="" in an option file.
To change the SQL mode at runtime, set the global or session sql_mode system variable using a SET statement:
SET GLOBAL sql_mode = 'modes';
SET SESSION sql_mode = 'modes';
Source: https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sql-mode-setting
Why does mysql accepts null data when updating a not null column and
then converts the data to 0.
You question is not clear as we need the DDL of the table and the update , but as from what you are saying, Well logically because the column not null has a default value 0. check the below example.
create table Test_table ( name varchar(100) null , position_s varchar(100) default 'Y' not null)
SQL>
Table created
insert into Emp_table (name) values('Me')
SQL>
1 row inserted
SQL>
NAME POSITION_S
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Me Y
#aaron0207 #Moudiz I am using laravel and updates data like this.
$specificReservation = Reservation::where('reference_id',$reference_id)->first();
$specificReservation->res_status = 1;
$specificReservation->payment_id = null;
$specificReservation->save();
I also tried to update manually in the database with this
UPDATE reservations SET payment_id = null
and it also shows no error so I think this is a database problem.

SQL Mode Is NO_UNSIGNED_SUBTRACTION But Still Getting Out of Range Error

After upgrading a client from MySQL 5.4 to 5.7 I started getting "BIGINT UNSIGNED value is out of range..." errors. I edited my.cnf and set sql_mode = "NO_UNSIGNED_SUBTRACTION" and used SHOW VARIABLES to ensure it was indeed using that mode. That did fix the initial problem in the application but today an unsigned int column is throwing the same error (BTW inventory is 2)...
UPDATE table SET inventory = inventory - 1
I don't understand why since I thought the new sql_mode would revert behavior to pre 5.5? I don't want to start casting everything in my statements just to make simple arithmetic work so the logical solution in my mind is just to convert all of my unsigned int cols to signed ints with the exception of primary auto increment keys.
Is this the best solution to escape these out of range errors?
I did some more digging and found my answer and wanted to share here for anyone stuck on this in the future. The SQL mode NO_UNSIGNED_SUBTRACTION was indeed working and had not reverted for this table/column. In short, the problem was that there was a trigger on that table and I discovered from a somewhat related MySQL bug report from 2009 that as stated in user comments by Davi Arnaut that triggers and prepared statements use the SQL mode that was in use when they were created... aaah! So, I redefined the trigger and everything works as expected.

When to use strict mode in MySql or MariaDB

I can find plenty of information on what strict mode does in MySql and MariaDB, but nothing on when to use it. This is common sense to a degree, but I would still like to have some general guidelines. For example, perhaps you:
Always use strict mode
Never use strict mode
Always use strict mode on tables that have financial data
etc
First, from MySQL documentation:
Strict mode controls how MySQL handles invalid or missing values in data-change statements such as INSERT or UPDATE. A value can be invalid for several reasons. For example, it might have the wrong data type for the column, or it might be out of range. A value is missing when a new row to be inserted does not contain a value for a non-NULL column that has no explicit DEFAULT clause in its definition. (For a NULL column, NULL is inserted if the value is missing.) Strict mode also affects DDL statements such as CREATE TABLE.
So, as #rick-james said: Always use strict mode. That is, until you get fed up with its restrictions. The mode is there to help you, but it may be painful.
Strict mode is also default on MariaDB since >10.2.3.
Get current mode: SHOW VARIABLES LIKE 'sql_mode';
Disable: mysql> SET sql_mode = '';
Enable: mysql> SET sql_mode = 'STRICT_ALL_TABLES'; (or STRICT_TRANS_TABLES).
For permanent change edit /etc/mysql/my.conf, [mysqld] section, sql_mode= variable.

In mySQL 5.6, whats the default behavior of the ALGORITHM parameter?

I'm using MySQL 5.6 (and its Online-DDL feature) to generate some in-place alter table operations like "ADD COLUMN." I see that the LOCK parameter defaults to the highest level of concurrency allowed (for ADD COLUMN this should be "NONE") but what is the default behavior for the ALGORITHM parameter? In the documentation it says "ALGORITHM = DEFAULT is the same a specifying no ALGORITHM clause at all." but that's not helpful because it doesn't say what ALGORITHM = DEFAULT is equal to.
http://dev.mysql.com/doc/refman/5.6/en/alter-table.html
Anyone know?
The default depends on what kind of change you're trying to apply.
Some changes can make use of ALGORITHM=INPLACE, so this is their default. Other changes can never use online DDL, so their default is ALGORITHM=COPY. For example, changing a data type or dropping a primary key cannot be done inplace.
See https://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html. They document how different operations are handled, and the ones that say "No" in the "Inplace" column use ALGORITHM=COPY by default, and fail if you try to use ALGORITHM=INPLACE.
You can force an operation to use ALGORITHM=COPY even if it could do its work inplace, but you cannot request a operation to use ALGORITHM=INPLACE if it can't do it.

Mysql datetime DEFAULT CURRENT_TIMESTAMP error

1.
When I ran this MYSQL syntax on windows it ran properly:
CREATE TABLE New
(
id bigint NOT NULL AUTO_INCREMENT,
timeUp datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
)
But when I tried running this code on Linux I got an error:
#1067 - Invalid default value for 'time'
2.
On windows the case is not sensitive eg. New and new both are considered to be same. But on linux the case is sensitive.
Configuration of Linux:
MySQL 5.5.33, phpMyAdmin: 4.0.5, PHP: 5.2.17
Configuration of Windows:
MySql: 5.6.11, phpMyAdmin: 4.0.4.1, PHP: 5.5.0
Is there any way to make them common for both systems? Or any alternative approach?
The DEFAULT CURRENT_TIMESTAMP support for a DATETIME (datatype) was added in MySQL 5.6.
In 5.5 and earlier versions, this applied only to TIMESTAMP (datatype) columns.
It is possible to use a BEFORE INSERT trigger in 5.5 to assign a default value to a column.
DELIMITER $$
CREATE TRIGGER ...
BEFORE INSERT ON mytable
FOR EACH ROW
BEGIN
IF NEW.mycol IS NULL THEN
SET NEW.mycol = NOW();
END IF;
END$$
Case sensitivity (of queries against values stored in columns) is due to the collation used for the column. Collations ending in _ci are case insensitive. For example latin1_swedish_ci is case insensitive, but latin1_general_cs is case sensitive.
The output from SHOW CREATE TABLE foo will show the character set and collation for the character type columns. This is specified at a per-column level. The "default" specified at the table level applies to new columns added to the table when the new column definition doesn't specify a characterset.
UPDATE
Kaii pointed out that my answer regarding "case sensitivity" deals with values stored within columns, and whether queries will return a value from a column containing a value of "New" will be returned with a predicate like "t.col = 'new'".
See Kaii's answer regarding identifiers (e.g. table names) being handled differently (by default) on Windows than on Linux.
As the DEFAULT CURRENT_TIMESTAMP question is already answered, i will only respond to the case-sensitivity mismatch in table names between windows and linux.
On Windows, file systems are by default case-insensitive.
But on Linux and other *NIX like Operating Systems, they are case-sensitive by default.
The reason why you get a mismatch in behaviour here is the file system, as each table is created as a separate file and the filesystem handles case-sensitivity for you.
MySQL has a parameter to override this behaviour:
For example, on Unix, you can have two different tables named my_table
and MY_TABLE, but on Windows these two names are considered identical.
To avoid data transfer problems arising from lettercase of database or
table names, you have two options:
Use lower_case_table_names=1 on all systems. The main disadvantage with this is that when you use SHOW TABLES or SHOW DATABASES, you do
not see the names in their original lettercase.
Use lower_case_table_names=0 on Unix and lower_case_table_names=2 on Windows. This preserves the lettercase of database and table names.
The disadvantage of this is that you must ensure that your statements
always refer to your database and table names with the correct
lettercase on Windows. If you transfer your statements to Unix, where
lettercase is significant, they do not work if the lettercase is
incorrect.Exception: If you are using InnoDB tables and you are trying to avoid these data transfer problems, you should set lower_case_table_names=1 on all platforms to force names to be converted to lowercase.
[...]
To avoid problems caused by such differences,
it is best to adopt a consistent convention, such as always creating
and referring to databases and tables using lowercase names. This
convention is recommended for maximum portability and ease of use.
This is an excerpt from the MySQL manual on the case sensitivity of identifiers
if you wants to default time to must change to timestamp in your datatype,
the datetime is going to display the user input of table...
http://dev.mysql.com/doc/refman/5.0/en/timestamp-initialization.html
http://dev.mysql.com/doc/refman/5.6/en/timestamp-initialization.html