Bug #71220 | pow() function returns an error for bad values | ||
---|---|---|---|
Submitted: | 23 Dec 2013 16:25 | Modified: | 25 Dec 2013 5:53 |
Reporter: | Philip Smolen | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: Errors | Severity: | S2 (Serious) |
Version: | 5.5.13, 5.5.35, 5.6.16, 5.7.3 | OS: | Linux |
Assigned to: | CPU Architecture: | Any | |
Tags: | regression |
[23 Dec 2013 16:25]
Philip Smolen
[23 Dec 2013 16:45]
Peter Laursen
5.1.72 returns NULL. 5.5.35 and 5.6.15 both return the error. Peter (not a MySQL/Oracle person)
[23 Dec 2013 19:19]
Roy Lyseng
The handling is compatible with the SQL standard: <power function> ::= POWER <left paren> <numeric value expression base> <comma> <numeric value expression exponent> <right paren> 12) If <power function> is specified, then let NVEB be the <numeric value expression base>, then let VB be the value of NVEB, let NVEE be the <numeric value expression exponent>, and let VE be the value of NVEE. Case: a) If at least one of VB and VE is the null value, then the result is the null value. b) If VB is 0 (zero) and VE is negative, then an exception condition is raised: data exception — invalid argument for power function. c) If VB is 0 (zero) and VE is 0 (zero), then the result is 1 (one). d) If VB is 0 (zero) and VE is positive, then the result is 0 (zero). e) If VB is negative and VE is not equal to an exact numeric value with scale 0 (zero), then an exception condition is raised: data exception — invalid argument for power function. f) If VB is negative and VE is equal to an exact numeric value with scale 0 (zero) that is an even number, then the result is the result of EXP(NVEE*LN(-NVEB)) g) If VB is negative and VE is equal to an exact numeric value with scale 0 (zero) that is an odd number, then the result is the result of -EXP(NVEE*LN(-NVEB)) h) Otherwise, the result is the result of EXP(NVEE*LN(NVEB)) Thus, invalid input should cause an exception to be raised. A NULL value should be returned only when one of the input values is NULL.
[23 Dec 2013 19:41]
Peter Laursen
MySQL returns (according to documentation and according to how it always did) NULL on impossible parameters to mathematical functions. If "SQL Standard* should be a guideline, MySQL could be scrapped. What then about "SELECT LOG(-1);"? It returns NULL in all versions. Such change would at least need an sql_mode (like 'null_on_impossible_math') so that old behavior could be preserved IMO. It is a somewhat severe (in)compability change (not that that function is used a lot, but when it is, it may cause scripts to abort and render a server environment unusable after an upgrade to 5.5 or 5.6). And further it is completely un-announced and undocumented and probably passed tests and any code review unnoticed. It has to be reversed in 5.5 and 5.6 at least. Please drop the attitude that this is OK and and intended change. It is an overlook by a specific developersof MySQL works and always did simply! And a test failure and code review failure. If it was intended for which version will the release notes tell about this change?
[23 Dec 2013 21:57]
Peter Laursen
Even "SELECT 1/0" returns NULL in all versions! And that could be the (historical) reason for this *speciality* of MySQL: unsupported/invalid/impossible math expressions may cause overflows, infinite loops etc. causing the server to become irresponsible and even to crash. MySQL solves this by returning NULL for all math expressions that cannot be calculated. Returning an error could be better sometimes and sometimes not. But it should not be an undocumented change and a workaround (like an sql_mode) should be provided for behavior compatible with previous versions.
[23 Dec 2013 22:38]
Philip Smolen
Yes, this is a huge change. It can cause my automated code to fail. At a bare minimum the documentation should be fixed to reflect this. I'm not sure how I'll work around this. I typically select a lot of rows and a lot of columns at once. If just one value is bad, the whole thing fails. Returning a null for most failures is nice because it limits damage done by any one error. Between this and the recent changes to integer overflow, I don't know how I can avoid whole statements failing. http://dev.mysql.com/doc/refman/5.5/en/out-of-range-and-overflow.html "As of MySQL 5.5.5, overflow during numeric expression evaluation results in an error."
[24 Dec 2013 16:39]
Sveta Smirnova
Thank you for the report. Verified as described. Although one can argue that error returned in time when arguments are proceed, user manual does not specify negative numbers should not be passed to function POW().
[25 Dec 2013 3:24]
Philip Smolen
I've been digging into this further. It appears that this new error is reported to the API client in a different way than older errors. Can you comment on this? Is this the expected behavior? Is this documented anywhere? Let me offer some examples: A1) select * from table_that_doesnt_exist A2) xyz B1) select pow(-2,0.5) B2) select 2000000000*2000000000*2000000000 In the MySQL command line client, all of these look very similar. They will all print an error message instead of a result. When I try these in the PHP client, B1 and B2 give me a warning, like PHP is confused. Other than the warning, everything works as expected. mysql_error() and mysql_errno() report something reasonable in all three cases and I get no result in any of the three cases. See details, below. When I try these in my own C++ program using the MySQL API, I see something strange. When I call mysql_real_query() on A1 or A2 (or any other bad query I've seen before now) I get a result of 1, saying there was an error. I can immediately call mysql_errno() and get more details on the error. That's what I expect. But when I call mysql_real_query() on B1 or B2, I get a result of 0, which means success! When I call mysql_errno() it also returns 0, to say success. I don't see a problem until I call mysql_store_result(). That returns NULL. If I call mysql_errno() again, then I see details about the error. I have never before called mysql_errno() at that time. I've never needed to. I looked at the documentation for mysql_store_result(). It says that function can fail because the system is out of memory, the network connection was broken, and similar cases. It doesn't say anything about a bad value in a function. http://dev.mysql.com/doc/refman/5.5/en/mysql-store-result.html PHP example: php > $result = mysql_query("select * from table_that_doesnt_exist"); php > if (!$result) echo mysql_errno(), ": ", mysql_error(), "\n"; 1146: Table 'mydb.table_that_doesnt_exist' doesn't exist php > $result = mysql_query("xyz"); php > if (!$result) echo mysql_errno(), ": ", mysql_error(), "\n"; 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xyz' at line 1 php > $result = mysql_query("select pow(-2,0.5)"); PHP Warning: mysql_query(): Unable to save result set in php shell code on line 1 php > if (!$result) echo mysql_errno(), ": ", mysql_error(), "\n"; 1690: DOUBLE value is out of range in 'pow(-(2),0.5)' php > $result = mysql_query("select 2000000000*2000000000*2000000000"); PHP Warning: mysql_query(): Unable to save result set in php shell code on line 1 php > if (!$result) echo mysql_errno(), ": ", mysql_error(), "\n"; 1690: BIGINT value is out of range in '((2000000000 * 2000000000) * 2000000000)' Again, it seems like there was a big change which could break at lot of existing code. At a bare minimum this should be documented. But I really hope you go back to the old way.
[25 Dec 2013 5:53]
Philip Smolen
One more detail to go with my last comment: When I try to execute queries B1 or B2, mysql_field_count() returns 1 but mysql_store_result() returns NULL. This is contrary to the documentation. http://dev.mysql.com/doc/refman/5.5/en/mysql-field-count.html goes into great detail on the subject. The behavior of the server has changed. The change can break client software. The change is not documented.
[14 Jan 2014 18:08]
Sveta Smirnova
Thank you for the feedback. I discussed this case with our Connectors team and they say that connectors simply return information which server provides. Therefore this is only server issue.