Bug #120298 opt_explain_json.cc:507 assert failure — EXPLAIN FORMAT=JSON on INTERSECT subquery crashes mysqld
Submitted: 20 Apr 8:58 Modified: 20 Apr 10:56
Reporter: Chunling Qin Email Updates:
Status: Can't repeat Impact on me:
None 
Category:MySQL Server: DML Severity:S3 (Non-critical)
Version:8.0.31-tr-debug OS:Any
Assigned to: CPU Architecture:Any

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

  Executing EXPLAIN FORMAT=JSON on a query that contains an INTERSECT set operation inside a
   derived table (subquery) triggers an assertion failure in subquery_ctx::set_child(),
  causing the mysqld process to abort and generate a core dump.

  The crash occurs because the EXPLAIN FORMAT=JSON infrastructure only expects child context
   types of CTX_JOIN or CTX_UNION, but the INTERSECT set operation introduces a context type
   that is neither, hitting the assert(false) guard.

  Root Cause

  In sql/opt_explain_json.cc:505-509, the subquery_ctx::set_child() method asserts that any
  child context must be either CTX_JOIN or CTX_UNION:

  // sql/opt_explain_json.cc:505-509
  void set_child(context *child) override {
    assert(subquery == nullptr);
    assert(child->type == CTX_JOIN || child->type == CTX_UNION);  // <-- crash
    subquery = child;
  }

  When debug_enable_extended_set_ops=ON is enabled and an INTERSECT query is wrapped in a
  derived table, the EXPLAIN FORMAT=JSON code walks the query tree via
  Query_expression::explain_query_term(). The INTERSECT query term produces a context type
  outside the expected {CTX_JOIN, CTX_UNION} set (likely a new context type for
  INTERSECT/EXCEPT), which violates the assertion.

  Call Stack

  subquery_ctx::set_child(context*)                     (opt_explain_json.cc:507)
  Explain_format_JSON::begin_context(...)               (opt_explain_json.cc)
  Query_expression::explain_query_term(THD*, THD*, Query_term*)
  Query_expression::explain(THD*, THD const*)
  Explain::explain_subqueries()
  Explain::send()
  explain_query_specification(THD*, THD const*, Query_term*, ...)
  explain_query(THD*, THD const*, Query_expression*)
  Sql_cmd_dml::execute_inner(THD*)
  Sql_cmd_dml::execute(THD*)
  mysql_execute_command(THD*, bool)
  dispatch_sql_command(THD*, Parser_state*)

How to repeat:
  SET SESSION debug_enable_extended_set_ops=ON;
  EXPLAIN FORMAT=JSON SELECT * FROM (SELECT 1 INTERSECT SELECT 2) AS t;

Suggested fix:
I was unable to reproduce this issue on version 8.0.32. Based on AI analysis, it appears to have been resolved by WL#349. I am submitting this report for official confirmation.

mysql>   SET SESSION debug_enable_extended_set_ops=ON;
ERROR 1193 (HY000): Unknown system variable 'debug_enable_extended_set_ops'
mysql> select version();
+--------------+
| version()    |
+--------------+
| 8.0.32-debug |
+--------------+
1 row in set (0.00 sec)
[20 Apr 10:48] Roy Lyseng
Thank you for the bug report.
I am not sure what you are seeing here.
With the patch for WL#349 that added support for INTERSECT and EXCEPT, the set_child() function is also extended to add support for CTX_INTERSECT and CTX_EXCEPT.
In any case, the problem is not reproducible on later 8.0 releases.
[20 Apr 10:56] Chunling Qin
mysql> select version();
+-----------------+
| version()       |
+-----------------+
| 8.0.31-tr-debug |
+-----------------+
1 row in set (0.00 sec)

mysql>   EXPLAIN FORMAT=JSON SELECT * FROM (SELECT 1 INTERSECT SELECT 2) AS t;
ERROR 1235 (42000): This version of MySQL doesn't yet support 'INTERSECT'
mysql>  SET SESSION debug_enable_extended_set_ops=ON;
Query OK, 0 rows affected (0.00 sec)

mysql>   EXPLAIN FORMAT=JSON SELECT * FROM (SELECT 1 INTERSECT SELECT 2) AS t;
ERROR 2013 (HY000): Lost connection to MySQL server during query
No connection. Trying to reconnect...
ERROR 2003 (HY000): Can't connect to MySQL server on '9.134.129.225:3306' (111)
ERROR: 
Can't connect to the server