Bug #120297 query_term.cc:320 assert(false) crash — UNION query triggers unhandled AccessPath

Submitted: 20 Apr 8:44 Modified: 20 Apr 10:04
Reporter: Chunling Qin Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S2 (Serious)
Version: 8.0.32 OS:Any
Assigned to: CPU Architecture:Any

[20 Apr 8:44] Chunling Qin
Description:
  Description

  When SET SESSION debug='+d,ast' is enabled, executing a UNION query with an aggregate
  function triggers assert(false) in dumpAccessPath(), causing the mysqld process to abort.

  Root Cause

  The dumpAccessPath() function in sql/query_term.cc (lines 249–335) is an AST
  debug-printing helper that iterates over the AccessPath tree via a switch-case statement.
  Currently, it only handles the following AccessPath types:

  - LIMIT_OFFSET, TABLE_SCAN, SORT, MATERIALIZE, FAKE_SINGLE_ROW
  - TABLE_VALUE_CONSTRUCTOR, AGGREGATE, FILTER, HASH_JOIN
  - FOLLOW_TAIL, MATERIALIZED_TABLE_FUNCTION, INDEX_SCAN

  Not all AccessPath enum values are covered. When the optimizer produces an AccessPath type
   not listed above (e.g., REMOVE_DUPLICATES, STREAM, etc.) for a UNION query, execution
  falls through to the default: assert(false) branch at line 319–320, which terminates the
  process.

  // sql/query_term.cc:319-321
  default:
    assert(false);   // <-- crash: unhandled AccessPath type

  Call Stack

  Query_expression::optimize()
    → Query_term_union::debugPrint()          (query_term.cc:229)
      → Query_term_set_op::print()
        → Query_block::debugPrint()
          → Query_block::qbPrint()
            → dumpAccessPath()                 (query_term.cc:249)
              → assert(false)                  (query_term.cc:320)

  Reproduction

  -- 1. Create table and insert data
  CREATE DATABASE IF NOT EXISTS test_repro;
  USE test_repro;
  DROP TABLE IF EXISTS t3;
  CREATE TABLE t3 (a INT);
  INSERT INTO t3 VALUES (1),(2),(3),(1),(2);

  -- 2. Enable AST debug and execute UNION query
  SET SESSION debug='+d,ast';
  SELECT COUNT(*) FROM t3 UNION SELECT COUNT(*) FROM t3;

  Result: ERROR 2013 (HY000): Lost connection to MySQL server during query

  Crash Log

  mysqld: /data/mysql-server/sql/query_term.cc:320:
    void dumpAccessPath(int, AccessPath *, std::ostringstream &):
    Assertion `false' failed.

  Query: SELECT COUNT(*) FROM t3 UNION SELECT COUNT(*) FROM t3

  Full Backtrace

  dumpAccessPath(int, AccessPath*, std::ostringstream&)
  Query_block::qbPrint(int, std::ostringstream&) const
  Query_block::debugPrint(int, std::ostringstream&) const
  Query_term_set_op::print(int, std::ostringstream&, char const*) const
  Query_term_union::debugPrint(int, std::ostringstream&) const
  Query_expression::optimize(THD*, TABLE*, bool, bool)
  Sql_cmd_dml::execute_inner(THD*)
  Sql_cmd_dml::execute(THD*)
  mysql_execute_command(THD*, bool)
  dispatch_sql_command(THD*, Parser_state*)
  dispatch_command(THD*, COM_DATA const*, enum_server_command)
  do_command(THD*)

How to repeat:
  -- 1. create table
  CREATE DATABASE IF NOT EXISTS test_repro;
  USE test_repro;
  DROP TABLE IF EXISTS t3;
  CREATE TABLE t3 (a INT);
  INSERT INTO t3 VALUES (1),(2),(3),(1),(2);

  -- 2. core
  SET SESSION debug='+d,ast';
  SELECT COUNT(*) FROM t3 UNION SELECT COUNT(*) FROM t3;
[20 Apr 10:04] Roy Lyseng
Thank you for the bug report.
Verified as described.

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.040 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.