[MDEV-390] ALLOW_INVALID_DATE and >= <= don´t working Created: 2012-07-11  Updated: 2012-07-12  Resolved: 2012-07-11

Status: Closed
Project: MariaDB Server
Component/s: None
Affects Version/s: 5.5.25
Fix Version/s: None

Type: Bug Priority: Minor
Reporter: roberto spadim Assignee: Unassigned
Resolution: Not a Bug Votes: 0
Labels: None
Environment:

mariadb 5.5.23 linux



 Description   

hi guys i´m running a simple query with

date_field>="2001-07-06 00:00:00" AND
date_field<"2012-07-31 24:00:00"

the second part is 'invalid' "2012-07-31 24:00:00" since hour 24:00:00 don´t exists for this date...
but, i´m using
sql_mode=PIPES_AS_CONCAT,ALLOW_INVALID_DATES
what it should do? convert 24:00:00 to "2012-08-01 00:00:00" ? or just compare as string?



 Comments   
Comment by roberto spadim [ 2012-07-11 ]

show warnings result:
warning 1292 Incorrect datetime value: '2012-07-31 24:00:00'

Comment by roberto spadim [ 2012-07-11 ]

if i execute this:
set sql_mode=PIPES_AS_CONCAT
and after the query, no error is displayed (query run nice, but no result...) and at show warnings i have the same result
warning 1292 Incorrect datetime value: '2012-07-31 24:00:00'

if i correct it to 2012-07-31 23:59:59 i can see some rows in table without problem (and no warning)

so, what´s the expected result of sql_mode=allow_invalid_dates? it only works for update, replace and insert?

Comment by Elena Stepanova [ 2012-07-11 ]

Roberto,

If you consider it a bug, please provide a test case and an explanation (preferably confirmed by the manual, unless it's obvious) why it should work differently. Please also try to collect all essential information and put it in the description, rather than keep adding pieces as separate comments, because this way it's very unreadable and difficult to work with. Which, again, shows that for questions like that IRC (the chat) is a much better place.

Comment by roberto spadim [ 2012-07-11 ]

how to repeat:
CREATE TABLE `t` (
`data_compensacao_origem` datetime NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-01-13 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-02-17 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-02-09 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-02-08 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-02-24 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-05-02 00:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-04-09 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-04-09 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-04-09 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-03-21 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-03-15 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-03-15 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-03-14 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-03-14 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-02-29 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-01-11 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-01-11 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-12-23 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-01-05 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-01-06 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-08-02 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-08-31 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-09-02 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-10-13 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-10-13 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-10-18 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-10-18 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-10-24 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-11-11 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-11-11 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-12-13 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-12-13 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-12-14 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-11-18 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-11-18 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-06-25 16:57:39');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-05-08 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-05-08 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-05-08 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-05-08 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2010-11-15 06:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2010-10-22 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-11-21 06:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-05-22 00:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-05-22 00:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-05-22 00:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-10-14 05:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-05-29 05:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-06-06 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-06-06 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-06-06 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-06-06 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-06-06 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-06-08 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-06-11 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-06-14 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-12-14 06:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-04-19 15:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-05-14 15:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-11-16 16:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-12-16 16:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-01-16 16:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-03-15 15:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-04-16 15:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-06-18 15:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2011-10-17 16:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-02 08:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-02 08:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-02 08:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-02 08:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-02 08:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-02 08:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-06 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-06 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-06 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-06 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-06 18:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-04 08:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-10 08:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-06 08:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-06 08:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-05 08:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-05 08:00:00');
INSERT INTO `t` (`data_compensacao_origem`) VALUES ('2012-07-10 08:00:00');

set sql_mode=allow_invalid_dates;

// THIS DON´T WORK, BUT DON´T GIVE ERROR, JUST WARNINGS:

SELECT * FROM t WHERE
data_compensacao_origem>="2001-07-06 00:00:00" AND
data_compensacao_origem<"2012-07-31 24:00:00"

// THIS WORK WITHOUT WARNINGS

SELECT * FROM t WHERE
data_compensacao_origem>="2001-07-06 00:00:00" AND
data_compensacao_origem<"2012-07-31 23:59:59"

SELECT * FROM t WHERE
data_compensacao_origem>="2001-07-06 00:00:00" AND
data_compensacao_origem<"2012-08-01 00:00:00"

//AT MANUAL:
http://dev.mysql.com/doc/refman/5.6/en/server-sql-mode.html#sqlmode_allow_invalid_dates

Do not perform full checking of dates. Check only that the month is in the range from 1 to 12 and the day is in the range from 1 to 31. This is very convenient for Web applications where you obtain year, month, and day in three different fields and you want to store exactly what the user inserted (without date validation). This mode applies to DATE and DATETIME columns. It does not apply TIMESTAMP columns, which always require a valid date.

The server requires that month and day values be legal, and not merely in the range 1 to 12 and 1 to 31, respectively. With strict mode disabled, invalid dates such as '2004-04-31' are converted to '0000-00-00' and a warning is generated. With strict mode enabled, invalid dates generate an error. To permit such dates, enable ALLOW_INVALID_DATES.

///
the point is, should it consider hour,minute and second? or, is my date being changed to 0000-00-00 00:00:00 ?

Comment by roberto spadim [ 2012-07-11 ]

just more information...
explain extended
SELECT * FROM t
WHERE
data_compensacao_origem>="2001-07-06 00:00:00" AND
data_compensacao_origem<"2012-07-31 24:00:00"


show warnings result:

select `spd_cashflow`.`t`.`data_compensacao_origem` AS `data_compensacao_origem` from `spd_cashflow`.`t` where ((`spd_cashflow`.`t`.`data_compensacao_origem` >= '2001-07-06 00:00:00') and (`spd_cashflow`.`t`.`data_compensacao_origem` < '2012-07-31 24:00:00'))

no conversion to 0000-00-00 00:00:00

Comment by Elena Stepanova [ 2012-07-11 ]

Roberto,
Again, please specify what is the bug here. What, to your opinion, is supposed to be the result of the set of commands you provided, as opposed to what you observe, and why.
E.g. what do you mean by "THIS DON´T WORK, BUT DON´T GIVE ERROR, JUST WARNINGS:"? What do you expect it to do, what it does, and why do you think it's wrong?

And please put it all together, rather than through scattered comments.

Please also use the version of the manual which corresponds the version of your server.

Comment by roberto spadim [ 2012-07-11 ]


expected values:
for allow_invalid_date turned off, a error
for allow_invalid_date turned on, a warning, maybe a better explanation of what happened (does the datetime 'converted' to 0000-00-00 00:00:00 or other result? any other explain)

well, let me show the query results...

SELECT * FROM t WHERE data_compensacao_origem>="2001-07-06 00:00:00" AND data_compensacao_origem<"2012-07-31 23:59:59"
it return about 84 rows (ok, no warnings and no error)
for this:

SELECT * FROM t WHERE data_compensacao_origem>="2001-07-06 00:00:00" AND data_compensacao_origem<"2012-07-31 24:00:00"
it return 0 rows, with warning, AND NO ERROR, with or WITHOUT allow_invalid_date

when I turn off allow_invalid_date, it should (at least) give an error instead of a warning (like explained in manual "With strict mode enabled, invalid dates generate an error.", check that this part of manual didn´t changed since version 5.1, maybe it should check invalid hours too? that´s why it don´t return a error?)


why i´m reporting this as bug:
my problem started when a client told me that a query wasn´t running, since it was a datetime field, i tried to turn off allow_invalid_dates to check if it´s a datetime error (in application errors are showed to users, warnings not)
since no erros was returned by the query, i didn´t found the error at user interface
i got inside code and output the sql to user, with the sql query I executed at database and checked that the problem was the 24:00:00
rewrite it to 2012-08-01 00:00:00, and it worked (ok i put this workaround in my program and it´s working now)

but why not an error with allow_invalid_dates turned off?


just a opnion about what should be done:
when using a invalid DATE and a valid HOUR it runs nice:

set sql_mode=allow_invalid_dates; (with sql_mode='' it give the same result!, should show a error of invalid date, day 31 don´t exist in november)
SELECT * FROM t
WHERE
data_compensacao_origem>="2001-07-06 00:00:00" AND
data_compensacao_origem<"2012-11-31 00:00:00"
with 84 rows, no warnings!!!

but when used a invalid HOUR it always return 0 rows
maybe it should run invalid hour like it run invalid date, and return 84 rows to user...

Comment by Elena Stepanova [ 2012-07-11 ]

Hi Roberto,
Thank you, it's much better, now I see what you meant. Your logic has a couple of flaws.

1. As you yourself quoted earlier, the manual says "With strict mode enabled, invalid dates generate an error. To permit such dates, enable ALLOW_INVALID_DATES". Note the "strict mode" part! It means that ALLOW_INVALID_DATES is supplementary to the strict mode (that is, to STRICT_ALL_TABLES, in your case). In other words, with the default sql_mode='' invalid values are permitted; with sql_mode='STRICT_ALL_TABLES' invalid values are forbidden; with sql_mode='STRICT_ALL_TABLES,ALLOW_INVALID_DATES' invalid values are generally forbidden, but an exception is made for certain invalid dates.

2. Now, taking this into consideration, you'll see that you also need to read a section about STRICT_ALL_TABLES mode. You'll find there that the mode is applied, specifically, to invalid values when rows are inserted or updated (not to the values used for comparison). So, even if you used STRICT_ALL_TABLES, it would not be applicable to your case (SELECT with a wrong constant in comparison would not start producing an error).

But what I do agree with, regardless the whole thing with sql modes, is that the very last result you observed looks weird. I mean this (simplified):

mysql> select * from t where d < '2012-11-31 00:00:00';
---------------------

d

---------------------

2012-07-11 21:04:44

---------------------
1 row in set (0.00 sec)

Logically, it should produce a warning and most likely shouldn't return the row (logic based on http://dev.mysql.com/doc/refman/5.5/en/datetime.html saying how invalid values are interpreted). Fast check confirms that it works the same way on MySQL 5.1.63, but I'm not sure if it's a new bug or it has always been this way. You might want to file it in MySQL bug base, at least to find out whether it was filed before or not, and track the progress; or, if it turns out to be intentional behavior, to request mentioning it in the manual.

Comment by roberto spadim [ 2012-07-11 ]

nice i will put there
i was reading 5.2.5 code, at my_time.c
line 417

if (number_of_fields < 3 ||
l_time->year > 9999 || l_time->month > 12 ||
l_time->day > 31 || l_time->hour > 23 ||
l_time->minute > 59 || l_time->second > 59)
{
/* Only give warning for a zero date if there is some garbage after */
if (!not_zero_date) /* If zero date */
{
for (; str != end ; str++)
{
if (!my_isspace(&my_charset_latin1, *str))

{ not_zero_date= 1; /* Give warning */ break; }

}
}
*was_cut= test(not_zero_date);
goto err;
}

maybe here:

l_time->day > 31 || l_time->hour > 23 ||
l_time->minute > 59 || l_time->second > 59)

should be changed to
(l_time->hour > 24 && l_time->minute > 0 && l_time->second > 0) ||
(l_time->hour < 24 && (l_time->minute > 59 || l_time->second > 59))

i will talk with mysql bug, i think it´s running since mysql 3.xxx in this way
thanks

Comment by roberto spadim [ 2012-07-11 ]

check that this can be a bug, since http://en.wikipedia.org/wiki/Leap_second consider that this time : "2012-06-30 23:59:60" exists (maybe my 24:00:00 don´t exists... =] )
check that :
select * from t where data_compensacao_origem<'2012-06-30 23:59:60'
return a warning (Incorrect datetime value: '2012-06-30 23:59:60')

bug at mysql created
http://bugs.mysql.com/bug.php?id=65875

Comment by roberto spadim [ 2012-07-11 ]

well tested with mysql 5.5.25a
and it works

just in mariadb don´t work
maybe because the checks at my_time.c

Comment by Elena Stepanova [ 2012-07-11 ]

Roberto,

In MySQL it "works" due to sheer luck, I would not advise to rely on this, at least until it is documented as intentional behavior – so far it directly contradicts the manual, and hence can change any time, just as many other over-relaxed conversions already changed between MySQL 5.1 and 5.5.

MariaDB works as currently documented. "If one of the arguments is a TIMESTAMP or DATETIME column and the other argument is a constant, the constant is converted to a timestamp before the comparison is performed". The constant is invalid, it's converted to 0000-00-00 00:00:00 (as the documented conversion rules require), and comparison is done with the result of this conversion. If you insert zero values into your table and try to do "less or equal" comparison, they will be returned.

In MySQL they are compared as strings. If you want to replicate this behavior on MariaDB, you can convert your datetime values to strings and proceed.

Comment by roberto spadim [ 2012-07-11 ]

nice, in others words i would rewrite it to:
SELECT * FROM t WHERE (data_compensacao_origem || "")<"2012-11-31 24:00:00"

does i will have problems with index optimizations?

could check if leap second will work in mariadb? i didn´t tryed and nobody talked it as an error, maybe never will talk since nobody is using my system at 23:59:60 they normally use between 08:00:00 and 20:00:00, at test 23:59:60 returned a warning (and no result) and it´s a 'legal' datetime value at least to UTC timezone

Comment by Elena Stepanova [ 2012-07-11 ]

http://dev.mysql.com/doc/refman//5.5/en/time-zone-leap-seconds.html
"Leap second values are returned with a time part that ends with :59:59. This means that a function such as NOW() can return the same value for two or three consecutive seconds during the leap second. It remains true that literal temporal values having a time part that ends with :59:60 or :59:61 are considered invalid."

Comment by roberto spadim [ 2012-07-11 ]

nice, but they are for timestamp fields, what about datetime fields? i´m asking because i read some parts of manual and didn´t found the information (i agree with you that mysql isn´t like manual but for a user changing from mysql to maria maybe this could be a problem to port code, for me no problem i can rewrite the query but for someone that have many queries this can be a problem)

Comment by roberto spadim [ 2012-07-11 ]

in others words...
to allow a easy user port from mysql to mariadb, could we add a new sql_mode option? (feature request)
maybe COMPARE_DATETIME_AS_STRING to make things easier?

i´m considering this as a feature request instead of a bug

Comment by roberto spadim [ 2012-07-12 ]

please close this bug, i reported a feature request since i understood that mysql isn´t doing a datetime comparision, it´s doing string comparision... \o/ mariadb rocks =)
new feature request id is MDEV-391

Generated at Thu Feb 08 06:28:23 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.