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
Related
I am using EF to update a field in my MySql DB and ran across the issue of attempting to save data that is not allowable due to collation. For example, ^âÂêÊîÎôÔûÛŵŷ has characters outside the column with character set of latin1.
Running an update/insert with above example I get the exception:
The database update did not take place due to..Incorrect string value
I know what the problem is, but I don't want to keep the characters, the data being provided is usually via UI which would often control what is passed in, however it is also callable by API allowing whatever data the caller would like to send. In the above case, I would like to drop those characters or just replace with a question mark, basically ignore them.
This system already exists in an older language and the rule to (silently..) ignore them exists, I need the error not to be raised and for it to save what it can. I have seen how I can modify the statements for this, or how I can modify the string data coming in. I have 1000s of these. Is there another method to achieve this?
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.
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.
I have been using MySQL to create a database and sometimes warnings come up rather than errors. An example is when I entered a page of full stops as a value. I do not really understand the point of these are why they appear instead of errors. Surely every incorrect value entered into a database should come up with an error, not just some. Please could somebody explain?
If you declared a column to be an integer but are attempting to insert a string, MySQL may perform implicit type conversion and emit an warning. See this question for a detailed example.
If you want to treat all warnings as errors, you should try strict mode.
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';