Skip to content

MDEV-40809 GREATEST should return NULL but returns date. - #5719

Open
DerZc wants to merge 1 commit into
MariaDB:11.4from
DerZc:fix-mdev-40809
Open

DerZc wants to merge 1 commit into
MariaDB:11.4from
DerZc:fix-mdev-40809

Conversation

@DerZc

@DerZc DerZc commented Sep 21, 2026 •

Copy link
Copy Markdown

GREATEST(DATE(''), DATE('2026-08-20')) currently returns 2026-08-20: the comparison context converts the failed DATE cast to a zero date before the existing NULL check runs. This change disables that fallback for DATE/DATETIME arguments of LEAST and GREATEST, while retaining permissive calendar-date comparison.

Bug report: https://jira.mariadb.org/browse/MDEV-40809

Why DATE('') behaves differently in this context

DATE('') does not have a context-independent NULL result. With sql_mode='', the unmodified server returns NULL for SELECT DATE(''), but returns 1 for SELECT DATE('') = DATE'0000-00-00'. The relevant path in LEAST/GREATEST is:

  1. Item_func_min_max::get_date_native() calls val_datetime_packed(). The default implementation constructs a Datetime using Options_cmp, which supplies both TIME_INVALID_DATES and TIME_FUZZY_DATES.
  2. Item_date_typecast::get_date() and Item_datetime_typecast::get_date() combine those caller flags with sql_mode_for_dates(thd) and pass them to the input conversion.
  3. Parsing the empty string fails. Temporal::make_from_str() calls make_fuzzy_date(): with TIME_FUZZY_DATES, it constructs a zero DATETIME; without that flag, it leaves MYSQL_TIMESTAMP_NONE.
  4. In the former case the cast sets null_value=false, so the existing NULL check correctly sees a non-NULL zero date. GREATEST selects the valid date. An actual SQL NULL, such as DATE(NULL), already propagates through the old code.

ALLOW_INVALID_DATES controls a separate case: dates such as February 30 with individually valid month/day fields. It does not make an empty string parseable. Comparison also deliberately sets TIME_INVALID_DATES independently of SQL mode, then validates the selected result against the caller's flags. For example, with sql_mode='', GREATEST(DATE('2026-02-30'), DATE'2026-08-20') returns the valid August date, while LEAST returns NULL. With ALLOW_INVALID_DATES, LEAST returns February 30. These behaviors are retained.

Change and compatibility

Start with the existing comparison flags and clear only TIME_FUZZY_DATES for DATE/DATETIME arguments. Check the resulting Datetime before packing it, with one evaluation per visited argument. The conversion context changes; this does not add a missing NULL check to val_datetime_packed().

  • Keep TIME_INVALID_DATES; the previous revision cleared it as well, unnecessarily changing the February 30 example above.
  • Keep all comparison flags for string, numeric and TIME arguments, including their existing conversion warnings.
  • Keep zero dates and zero month/day components when allowed, and honor NO_ZERO_DATE / NO_ZERO_IN_DATE in explicit casts. Stored temporal values continue to participate in comparison before the selected result is validated.
  • Leave temporal equality and other callers of val_datetime_packed() unchanged. The DATE('') = DATE'0000-00-00' example is covered as an unchanged control.

The main.type_date regression covers both functions and argument orders, DATE and DATETIME casts, actual NULLs, mixed input types, columns/views, stored zero dates, permissive dates, and the SQL modes above. Its results before the new regression block are unchanged. The PR contains one commit.

Validation

Built and tested on the original 11.4 parent, d10e5d726799b1cd57cc866f40aad68c720803da:

  • Release build passed.
  • Eight MTR tests passed in both normal and prepared-statement protocols: main.type_date, main.type_datetime, main.func_time, main.func_hybrid_type, json.type_json, vcol.wrong_arena, innodb.innodb_mysql, and main.select.
  • All 36 independently specified SQL statements matched expected rows, columns and warnings. The unmodified parent reproduces 13 targeted differences; the previous PR head fails the two added calendar-comparison controls.
  • The expanded main.type_date fixture fails on the unmodified parent only within the new regression block.
  • All 154 comparisons across seven SQL modes matched independently classified expectations: 85 retain the baseline rows/errors/warnings, and 69 change only the targeted failed-conversion fallback. Ten calendar-comparison cases changed by the previous revision are restored to baseline behavior.
  • git diff --check passed. The upstream 11.4 head at validation time was 511d7527eb356aab52fa183456333c5ba9741bcf; its 17 newer commits do not overlap the three changed files or the inspected conversion implementations.

The full test suite and Windows/ARM64/sanitizer builds were not run locally.

@CLAassistant

CLAassistant commented Sep 21, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@gkodinov gkodinov added the External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements. label Sep 23, 2026
@gkodinov gkodinov self-assigned this Sep 23, 2026

@gkodinov gkodinov left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution! This is a preliminary review.

The fix looks valid to me.

Before I approve please squash the two commits into one. There's also a bunch of test failures that need review.

@gkodinov gkodinov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that the formal requirements are met please find below an honest attempt to review the substance.

Comment thread sql/item_func.cc
for (uint i=0; i < arg_count ; i++)
{
longlong res= args[i]->val_datetime_packed(thd);
/*

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the implementation needs more work.

First of all, I believe that val_datetime_packed() can and will check nullness, if there's an actual NULL.

The basic premise of the bug report that DATE('') must return NULL is IMHO flawed. This is not always the case and that's for a reason. MariaDB supports things like fuzzy dates, allow invalid dates etc.

I'd suggest that you explore why DATE('') does not return NULL and what causes it to do that exactly. Then add this to the pull request description.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I suggested here is not resolved even by the latest change. But, since this looks like a final review issue (and I have said my peace), I'll let this one slide to final review.

val_datetime_packed() evaluates arguments with TIME_FUZZY_DATES and
TIME_INVALID_DATES. DATE/DATETIME casts pass these flags to their input
conversion, so a failed cast such as DATE('') becomes a zero date and
sets null_value to false before the existing NULL check runs.

Clear only TIME_FUZZY_DATES for DATE/DATETIME arguments. Keep
TIME_INVALID_DATES for calendar-date comparison, all comparison flags
for other input types, and the caller's validation of the selected
result. Evaluate each visited argument once and check the Datetime
before packing it.

Cover failed casts, actual NULLs, mixed input types, columns and views,
stored zero dates, temporal equality, and permissive/invalid calendar
dates under ALLOW_INVALID_DATES, NO_ZERO_DATE and NO_ZERO_IN_DATE.

@gkodinov gkodinov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Please stand by for the final review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

External Contribution All PRs from entities outside of MariaDB Foundation, Corporation, Codership agreements.

Development

Successfully merging this pull request may close these issues.

4 participants