When to use strict mode in MySql or MariaDB - mysql

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.

Related

MySQL NOT NULL insert behavior

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

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.

How to allow empty string for integer in MySQL?

I have integer fields in a table. The POSTs are sent by a complicated JavaScript. They send empty strings like "" but as you guessed MySQL doesn't allow empty strings in integer fields. Are there any options to allow empty strings? Like if it takes an empty string it will save it as NULL.
There are 2 ways to do this.
For Current Mysql Session (Temporary Solution)
First execute query to get current SQL mode of your mysql server.
mysql> SELECT ##sql_mode;
+----------------------------------------------------------------+
| ##sql_mode |
+----------------------------------------------------------------+
|STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+----------------------------------------------------------------+
1 row in set (0.00 sec)
If result contains STRICT_TRANS_TABLES, you have to remove that value to allow insert query to pass NULL value. Make sure your mysql User have privileges to apply this changes and restart Mysql Server after applying this.
SET GLOBAL sql_mode = '';
For Life Time of Mysql (Permanent Solution)
You have to update my.cnf file. Location of that file is : \etc\my.cnf or \etc\mysql\mysql.cnf
There will be some default parameters set under [mysqld] like
[mysqld]
innodb_file_per_table=1
default-storage-engine=MyISAM
performance-schema=0
max_allowed_packet=268435456
open_files_limit=10000
Just add one line under that
sql-mode=""
Make sure to restart Mysql Server after changing this file. Normally root user will be the owner of file so you have to login with root user on server.
For more details to understand what this SQL mode do.
STRICT_TRANS_TABLES
Enable strict SQL mode for transactional storage engines, and when possible for non-transactional storage engines. For details, see Strict SQL Mode.
Refer : http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_trans_tables
NO_AUTO_CREATE_USER
Prevent the GRANT statement from automatically creating new user accounts if it would otherwise do so, unless authentication information is specified. The statement must specify a nonempty password using IDENTIFIED BY or an authentication plugin using IDENTIFIED WITH.
Refer: http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_auto_create_user
NO_ENGINE_SUBSTITUTION
Control automatic substitution of the default storage engine when a statement such as CREATE TABLE or ALTER TABLE specifies a storage engine that is disabled or not compiled in.
Refer : http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_engine_substitution
Removing sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" from my.ini has solved the issue.
Edit: Removing the line above works but it is a bad idea. It allows to have things like 0000-00-00 or empty string dates. Better keep the line above and don't insert empty sting into an integer field, instead convert empty string into NULL and then insert that NULL into integer field.
Assuming that the column allows for NULL values, you must explicitly tell MySQL to use a value of NULL, rather than passing an empty string (which is cast to 0):
INSERT INTO table (column_name) VALUES (NULL);

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.

Restrictions on type ENUM not enough?

Can't find a straight answer to the following problem / question.
I created a database, and one of the fields is of type ENUM and restriction NOT NULL.
It works fine, but when I try to insert a record with a value that is not allowed for this field, the records is not rejected but inserted anyway with the field empty. That is, I think that it is an empty string (""), since I added the restriction NOT NULL.
I want the record of course rejected as a whole. How can I achieve that.
I assume sample code is not necessary since it is common knowledge.
If you insert an incorrect value into an ENUM column or if you force a value into an ENUM column with IGNORE, it is set to the reserved enumeration value of 0, which is displayed as an empty string in string context.
http://dev.mysql.com/doc/refman/5.1/en/constraint-enum.html
Try this:
SET sql_mode = 'STRICT_ALL_TABLES'; or STRICT_TRANS_TABLES
Depending on if your table is transactional or nontransactional. This should take care of it through mySQL and cause it to abort and rollback with an integrity constraint before the method even tries to operate.
I found that you should enable strict mode in mysql. To do this you should:
edit /etc/mysql/my.cnf
add/edit sql-mode = STRICT_ALL_TABLES
restart MySQL
This is solution on MySQL level. If you try inserting an empty value in an ENUM field, it should now be rejected.