MySQL enums empty value - mysql

I am trying to understand how enums could be used in mysql.
If I insert anything to enum field that is out of the enum type -- mysql inserts empty string (with value 0).
fruit ENUM ('APPLE','BANANA','PEACH');
INSERT ... fruit='BANNANA'
Simple misspelling and MySQL inserts empty value, breaks database integrity and makes enums extremely useless.
CHECK constraints could help here but MySQL does not support them (pretty funny for "most popular" database in 2011)
The only way I see is to write the trigger to prevent empty string but it is too much work to write trigger for such a simple case.
Does there is a way to disable "empty string" MySQL behavior for enums?
Thanks

As per the documentation:
If you insert an invalid value into an ENUM (that is, a string not present in the list of permitted values), the empty string is inserted instead as a special error value. This string can be distinguished from a “normal” empty string by the fact that this string has the numeric value 0.
On a sidenote, I (and others) recommend you avoid enums, as they are not very efficient.
If you really need enums, consider using strict mode. Strict mode will at least throw an error when you try to insert an invalid value into an ENUM column. Otherwise only a warning is thrown and the value is simply set to an empty string ' ' (referenced internally as 0). Note: Errors can still be suppressed in strict mode if you use IGNORE.
Here is a link to the documentation on setting your MySQL server mode.
Happy coding!
Update: Nick's answer is one way to set your server in strict mode. TRADITIONAL mode is equivalent to STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, so keep in mind you will have additional data validation performed on other datatypes, such as DATE for example.

Take a look at sql modes
SET SQL_MODE='TRADITIONAL';

Related

Is it safe for me to turn off STRICT_TRANS_TABLES?

My PHP/mySQL backend hosted on an external site has been running fine since 2014. Recently, it started throwing up "field has no default value" errors.
I checked the config and found STRICT_TRANS_TABLES, which gives these errors for fields with no default in some cases.
My question is whether or not it is safe for me to remove this config value. It's mySQL 5.5.5-10.3.12-MariaDB.
Alternatively I could give everything default values, but I don't know which of these solutions is more likely to cause the existing codebase to stop working properly.
I encourage use of strict mode in MySQL because if you disable strict mode, you risk causing some unwanted effects, such as:
If you insert a value to a column where it can't fit, the value is silently truncated. Like inserting a long string into a shorter varchar column, or inserting a big integer into an INT column. This leads you to potentially have bogus values in your database. I prefer these cases to be errors, to prevent such bogus values.
Non-strict mode allows nonsensical dates, like 0000-00-00. There is no such date in the calendar. I'd rather this value not be allowed. If I need to symbolize an absence of a value, I'll use NULL.
Will these cases affect your app? There's no way I or anyone else on Stack Overflow can predict that. You need to test it yourself.

Mysql - String data, right truncated: 1406 Data too long for column [duplicate]

I have two MySQL instances. The 1st one truncates strings on insert when data is too long. The 2nd one raises an error:
ERROR 1406 (22001): Data too long for column 'xxx' at row 1
I want the 2nd one to truncate the data as well.
Is there any MySQL setting to manage this behavior?
You can disable STRICT_TRANS_TABLES and STRICT_ALL_TABLES. This allows the automatic truncation of the inserted string.
Quote 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.)
Reference: MySQL Server SQL Modes
If strict SQL mode is not enabled and you assign a value to a CHAR or VARCHAR column that exceeds the column's maximum length, the value is truncated to fit and a warning is generated. For truncation of nonspace characters, you can cause an error to occur (rather than a warning) and suppress insertion of the value by using strict SQL mode. See Section 6.1.7, “Server SQL Modes”.
How you can change it:
http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html
Found two ways to disable strict mode:
add below to my.cnf
sql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
way is using mysql console.
SET ##global.sql_mode= '';
Please test them before running on production environment.
if you use cpanel ,
replace
sql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
into /usr/my.cnf
to
sql-mode=""
run
/etc/init.d/mysql restart

MySQL Configuration to auto truncate decimal value

I've a table with a field DECIMAL(9,2) and I've 2 servers running both mysql 5.7
If I run this code
INSERT INTO `money_accounts` (`balance`) VALUES (9999999999.99);
On one of the servers it got inserted and value is truncated, on the other it raise a Out of range value for column balance error.
My question is, what is the configuration value that makes this happen? or why it's happening in one server and not in the other?
The definition
DECIMAL(9,2)
means 9 digits of total precision, with 2 digits after the decimal place. The value
9999999999.99
has 12 total digits of precision, with 2 after the decimal place. Hence, the value is out of range. Rightfully, MySQL should have thrown an out of range error in both cases. In the case where it "worked," my guess is that truncation occurred.
By the way, you should be using DECIMAL(12,2) or wider to store the value in your question.
Update:
One possible explanation for why one of your servers was doing the insertion while the other failed is that the first has traditional mode turned off. Run the following on both servers:
SELECT ##SESSION.sql_mode
If you see output looking like
STRICT_TRANS_TABLES, STRICT_ALL_TABLES, ...
then the server is running in traditional mode, which means it won't truncate but will reject. To turn it off, try running
SET SESSION sql_mode=''
and them the insert should succeed (with truncation). But in any case, you should not be relying on truncation in production. If you need more precision, then widen the column.
Reference: Automatically trimming length of string submitted to MySQL
If we read the documentation: http://dev.mysql.com/doc/refman/5.7/en/out-of-range-and-overflow.html
When MySQL stores a value in a numeric column that is outside the
permissible range of the column data type, the result depends on the
SQL mode in effect at the time
If strict SQL mode is enabled, MySQL rejects the out-of-range value
with an error, and the insert fails, in accordance with the SQL
standard.
If no restrictive modes are enabled, MySQL clips the value to the
appropriate endpoint of the range and stores the resulting value
instead.
So it means that You should set necessary sql mode that will not fail when out-of-range error happens.
There is no config parameter about that.
And resolution of same issue we can see here that says that disabling STRICT_TRANS_TABLES and STRICT_ALL_TABLES modes can fix Your problem.

MySQL too long varchar truncation/error setting

I have two MySQL instances. The 1st one truncates strings on insert when data is too long. The 2nd one raises an error:
ERROR 1406 (22001): Data too long for column 'xxx' at row 1
I want the 2nd one to truncate the data as well.
Is there any MySQL setting to manage this behavior?
You can disable STRICT_TRANS_TABLES and STRICT_ALL_TABLES. This allows the automatic truncation of the inserted string.
Quote 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.)
Reference: MySQL Server SQL Modes
If strict SQL mode is not enabled and you assign a value to a CHAR or VARCHAR column that exceeds the column's maximum length, the value is truncated to fit and a warning is generated. For truncation of nonspace characters, you can cause an error to occur (rather than a warning) and suppress insertion of the value by using strict SQL mode. See Section 6.1.7, “Server SQL Modes”.
How you can change it:
http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html
Found two ways to disable strict mode:
add below to my.cnf
sql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
way is using mysql console.
SET ##global.sql_mode= '';
Please test them before running on production environment.
if you use cpanel ,
replace
sql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
into /usr/my.cnf
to
sql-mode=""
run
/etc/init.d/mysql restart

What validation does MySQL do when strict mode is enabled?

I was quite surprised when MySQL allowed me to insert a NULL into a field that was created with NOT NULL. I did some research and discovered how to enable strict mode. However, I am not quite sure what validation MySQL does when STRICT_ALL_TABLES is enabled.
The manual says:
Strict mode controls how MySQL handles input values that are invalid or missing. A value can be invalid for several reasons. (emphasis mine) For example, it might have the wrong data type for the column, or it might be out of range.
I understand what it considers missing and how it handles that. I am unclear what it considers invalid. I've done some testing and discovered the following:
strings that are too long are invalid
numbers that are out of range are invalid
NULLs for a non-NULL column are invalid
TRUE and FALSE always seem to be valid (they become 1 and 0 respectively)
invalid dates are invalid
zero dates are valid (additional modes can be enabled to change this behaviour)
floats in an integer field are valid (they get rounded)
letters in a number field are invalid
Does MySQL do any other validation checks other than what is mentioned above?
The manual says 'wrong data type for the column', but the only situation I see where this actually comes into play is letters in a number field. Are there other examples of data type errors?
Is there a list somewhere of exactly what checks MySQL performs?
EDIT: For the record, my application already does extensive validation. I am using strict mode as a last-chance, just-in-case check. If I forget to check something, I want it to fail fast rather than 'silently mangle my data'.
A good resource is to check the MySQL source, and read mysql-test/t/strict.test to see all the cases they test for after setting STRICT mode or TRADITIONAL mode (which is a superset of STRICT).
You did excellent research and testing, but there are a few more cases, such as:
Trying to insert an undefined ENUM value.
Trying to insert a default value for a NOT NULL column with no DEFAULT defined.
Trying to use CAST() to convert strings to integers, etc.
Conversion of VARCHAR to MEDIUMTEXT or LONGTEXT if you give a length greater than 65536.
Truncation of COMMENT strings for tables and columns.
Conversion of string to YEAR type.
Defining a SET or ENUM column with duplicate entries.
Also mysql-test/include/strict_autoinc.inc, because it tests for overflow when an auto-inc value grows too large.
There are a few other test files that use STRICT mode for specific tests, but I didn't examine them.
I grepped the source code of MySQL 5.5.28 (Community Server Edition) to find instances of STRICT_ALL_TABLES being used.
From what I saw, it looks like your list is already pretty complete, but below are a few more things I learned about the use of STRICT_ALL_TABLES. The first one is another validation, while the rest all deal with errors and warnings.
Geometry columns can't have a default value. (sql/field.cc:9394)
If a table comment is longer than 2048 characters, MySQL produces an error rather than truncating the comment with a warning. (sql/unireg.cc:231)
If a field comment is longer than 1024 characters, MySQL produces an error rather than truncating the comment with a warning. (sql/unireg.cc:739)
On an insert or update, if a duplicate value exists in a SET or ENUM MySQL produces an error rather than a warning. (sql/sql_table.cc:2503)
There are a bunch of operations that will abort on warning with STRICT_ALL_TABLES rather than proceeding with just a warning. These are too numerous for me to list, and the setting of the abort_on_warning flag is too far removed from the code that creates the warnings for me to easily document (or even understand) all of them. But if anybody wants to get their hands dirty in the source code, a few places to start would be sql/sql_update.cc:630 and sql/sql_insert.cc:841