← Back to team overview

maria-developers team mailing list archive

MDEV-9541 Selecting a time using a datetime fails


Hi Monty,

Please have a look into the latest comments in MDEV-9541 on how
PostgreSQL, SQL Server, Oracle 11i and MySQL-5.7 work when
comparing temporal data types.

There is no a general rule. Every vendor implements it in a different way.

1. PostgreSQL almost follows the standard, which disallows direct
comparison of TIME and TIMESTAMP/DATETIME.

The only exception, it allows to compare a TIME field to a string
literal which looks like TIMESTAMP:

SELECT * FROM t1 WHERE a='2001-01-01 10:20:30';
    a     |          b
 10:20:30 | 2001-01-01 10:20:30

But strangely not the other way around!
Comparing of a TIMESTAMP field to a string which looks like TIME does not work. I did not find an explanation for this.

2. SQL Server

- Comparison of TIME + VARCHAR is done as TIME
- Comparison of DATETIME + VARCHAR is done as DATETIME
- Comparison of TIME and DATETIME is not allowed
- Comparison of TIME and INT is not allowed
- Comparison of DATETIME and INT is allowed (not sure how exactly it
  works though)
- Temporal literals {t'10:20:30'} have data type VARCHAR, this is just
  a syntactic variation of a string literal '10:20:30', with no any
  additional difference.

3. Oracle 11i

Oracle does not have the TIME data type.
So mixture of TIME and TIMESTAMP is not possible.

But comparison of TIMESTAMP and VARCHAR is always done as TIMESTAMP,
no matter what kind expressions are involved (fields, functions, literals).

4. MySQL-5.7
It has a special code: for a TIME field compared to a non-DATE constant,
the constant argument is converted to TIME. But as soon as you
wrap the field say into COALESCE, or put a non-constant instead of a
constant, this works in a different way.

So, comparing of a TIME field to a string literal that looks like a TIMESTAMP/DATETIME works similar in PostgreSQL, SQL Server, MySQL-5.7.
However, this looks only as a coincidence for this particular corner

Perhaps we should not fix that in 10.0. It seems that MariaDB since 5.3
handles comparison of TIME in a more consistent way (less exceptions).

Btw, why not to add a warning every time when an implicit
non-standard type conversion happens and suggest an explicit CAST?
This will encourage users to avoid doubtful constructions.

Also, I noticed that the SQL Server documentation says that comparison
of different data types is a subject to change in the future versions,
and using this is not recommended. Perhaps we should also say something
like this.

I propose instead of adding a quick fix for this exception,
to introduce a conception of "type strength" or "type derivation"
in 10.2.

The idea is simple:
1. Comparison is done according to the type of the strongest side.
2. Strengths(derivations) are as follows:
- A field or an SP variable has the strongest type derivation, say 4.
- Functions have derivation between field and typified constants, say 3.
- Some functions that return input arguments (e.g. COALESCE, LEFT) can
  repeat derivations of their arguments.
- A typified constant like TIME'10:20:30' has derivation 2.
- A typeless constant like '10:20:30' has a very weak derivation, say 1.
- An explicit NULL has the weakest derivation, say 0.
3. Only in case of equal strengths the result depends on the data
   types. Perhaps data types can have some sort of "minor strength",
   for conflict resolution. Say DATETIME/TIMESTAMP can have more minor
   strength over TIME or DATE. So a DATETIME field is compared to a TIME
   field as DATETIME rather than TIME.

This will give some advantages:

- Universal comparison rules for all data types

- This idea will simplify adding new data types a lot.
  They will just follow the universal rule.
  Otherwise, new data types (say INET6), we'll have to have
  different execution paths with some exceptions and
  exceptions from exceptions :)

- The problem mentioned in MDEV-9541 will be gone: it will compare as
  TIME just because it's a field compared to a typeless constant.
- We'll remove a special code covering comparison of YEAR and LONGLONG
  fields. They will just work as before, but now because a field always
  wins a constant, according to the universal rules.
- We'll probably remove some examples of a special code covering
  explicit NULLs  (i.e. Item::NULL_ITEM).
- A field compared to a constant will always be able to use indexes.
  Less chances to put the server into a heavy load because of a
  non-smart query executed.
- The same results for a field compared to some expression,
  and for the same field wrapped into a hybrid function like COALESCE.
- Hybrid functions with field arguments will also be able to use
  indexes in some cases.
- Equal field propagation will be possible in more cases.
- It should be easier to add a new SQL mode for the strict SQL standard
  compliant comparison style. I think it's good to have this option.