Skip to content

MDEV-39843: Prefix index causes incorrect range query result#5394

Open
raghunandanbhat wants to merge 1 commit into
11.8from
11.8-mdev-39843
Open

MDEV-39843: Prefix index causes incorrect range query result#5394
raghunandanbhat wants to merge 1 commit into
11.8from
11.8-mdev-39843

Conversation

@raghunandanbhat

Copy link
Copy Markdown
Contributor

Fixes MDEV-39843

Problem:

When a prefix index is built on ignorable characters (under NON1TO1 collation), it has an empty weight, which sorts at the bottom of the index, even though full value's real weight is large.

The range scan for col >= c therefore positions past that empty weight entry and never reads it, even though full value actually satisfies col >= c. That's why the row is missing from the output.

Fix:

In Field::stored_field_make_mm_leaf do not derive an inequality range bound (<, <=, >, >=) from a prefix key segment(HA_PART_KEY_SEG) when the field's collation is MY_CS_NON1TO1. The prefix cannot be trusted as a range bound in that case and let the optimizer fall back to a scan with the full condition re-checked. Equality lookups and full-length (non-prefix) keys are unaffected.

Problem:
  When a prefix index is built on ignorable characters (under NON1TO1
  collation), it has an empty weight, which sorts at the bottom of the
  index, even though full value's real weight is large.

  The range scan for col >= c therefore positions past that empty weight
  entry and never reads it, even though full value actually satisfies
  col >= c. That's why the row is missing from the output.

Fix:
  In `Field::stored_field_make_mm_leaf` do not derive an inequality
  range bound (<, <=, >, >=) from a prefix key segment(HA_PART_KEY_SEG)
  when the field's collation is MY_CS_NON1TO1. The prefix cannot be
  trusted as a range bound in that case and let the optimizer fall back
  to a scan with the full condition re-checked. Equality lookups and
  full-length (non-prefix) keys are unaffected.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request addresses MDEV-39843, where a prefix index causes incorrect range query results under collations with complex, non one-to-one character-to-weight mappings. It introduces a helper function prefix_key_part_unsafe_for_range to identify these unsafe cases and returns early in Field::stored_field_make_mm_leaf for inequality comparison operators. The review feedback suggests consolidating the duplicated checks for inequality operators before the switch statement to improve code maintainability.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread sql/opt_range.cc
Comment on lines 9735 to 9751
switch (op) {
case SCALAR_CMP_LE:
if (prefix_key_part_unsafe_for_range(key_part, this))
DBUG_RETURN(0);
DBUG_RETURN(new (mem_root) SEL_ARG_LE(str, this));
case SCALAR_CMP_LT:
if (prefix_key_part_unsafe_for_range(key_part, this))
DBUG_RETURN(0);
DBUG_RETURN(new (mem_root) SEL_ARG_LT(thd, str, key_part, this, value));
case SCALAR_CMP_GT:
if (prefix_key_part_unsafe_for_range(key_part, this))
DBUG_RETURN(0);
DBUG_RETURN(new (mem_root) SEL_ARG_GT(thd, str, key_part, this, value));
case SCALAR_CMP_GE:
if (prefix_key_part_unsafe_for_range(key_part, this))
DBUG_RETURN(0);
DBUG_RETURN(new (mem_root) SEL_ARG_GE(thd, str, key_part, this, value));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The check prefix_key_part_unsafe_for_range(key_part, this) is duplicated across all four inequality comparison cases (SCALAR_CMP_LE, SCALAR_CMP_LT, SCALAR_CMP_GT, SCALAR_CMP_GE). Consolidating this check before the switch statement reduces code duplication and improves maintainability.

  if ((op == SCALAR_CMP_LE || op == SCALAR_CMP_LT ||
       op == SCALAR_CMP_GT || op == SCALAR_CMP_GE) &&
      prefix_key_part_unsafe_for_range(key_part, this))
    DBUG_RETURN(0);

  switch (op) {
  case SCALAR_CMP_LE:
    DBUG_RETURN(new (mem_root) SEL_ARG_LE(str, this));
  case SCALAR_CMP_LT:
    DBUG_RETURN(new (mem_root) SEL_ARG_LT(thd, str, key_part, this, value));
  case SCALAR_CMP_GT:
    DBUG_RETURN(new (mem_root) SEL_ARG_GT(thd, str, key_part, this, value));
  case SCALAR_CMP_GE:
    DBUG_RETURN(new (mem_root) SEL_ARG_GE(thd, str, key_part, this, value));

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant