jose1003 opened a new issue, #68685:
URL: https://github.com/apache/doris/issues/68685

   ### Search before asking
   
   - [x] I had searched in the 
[issues](https://github.com/apache/doris/issues?q=is%3Aissue) and found no 
similar issues.
   
   
   ### Version
   
   ustom build, binary reports `2.1.12-stable` (docker image tag 
`local/doris-be:4.0.8` is misleading).
   Built from `doris_release` with ldb-toolchain v0.26 (GCC 15), per the stack 
trace paths
   (`/home/zcp/repo_center/doris_release/doris/be/...`).
   
   ### What's Wrong?
   
   The BE process **aborts (SIGABRT)** when a query contains a binary predicate 
on a VARCHAR column
   whose constant side is a constant *expression* (e.g. 
`COALESCE(NULLIF(CAST('' AS CHAR), ''), 'x')`)
   instead of a plain literal.
   
   During predicate pushdown, 
`OlapScanLocalState::_should_push_down_binary_predicate`
   (`be/src/pipeline/exec/olap_scan_operator.cpp:113`) does an unchecked 
`assert_cast<const ColumnConst*>`
   on the constant side of the predicate. When the constant was const-folded by 
BE, the resulting column
   is a plain `ColumnStr<uint32_t>` (not wrapped in `ColumnConst`), so 
`assert_cast` throws:
   
   ```
   [E-7412] Bad cast from type:doris::vectorized::ColumnStr<unsigned int>* to 
doris::vectorized::ColumnConst const*
   ```
   
   The same predicate is first rejected several times as a `Status` warning 
(recoverable), but on the
   next fragment the exception escapes through a `noexcept` frame and hits 
`std::terminate`:
   
    0# doris::signal::FailureSignalHandler at be/src/common/signal_handler.h:420
    1-4# libc: pthread_kill / raise / abort
    5# ... in /opt/apache-doris/be/lib/doris_be
    6# __cxxabiv1::__terminate
    7# __cxa_call_terminate
    8# __gxx_personality_v0
    9# _Unwind_RaiseException_Phase2
   10# _Unwind_Resume
   11# doris::vectorized::assert_cast<ColumnConst const*, ...> at 
be/src/vec/common/assert_cast.h:75
   12# doris::pipeline::OlapScanLocalState::_should_push_down_binary_predicate 
at be/src/pipeline/exec/olap_scan_operator.cpp
   :113
   13# 
doris::pipeline::ScanLocalState<OlapScanLocalState>::_normalize_binary_predicate<(doris::PrimitiveType)10>
 at be/src/p
   ipeline/exec/scan_operator.cpp:812
   14# ... ScanLocalState::_normalize_predicate / _normalize_conjuncts
   17# doris::pipeline::OlapScanLocalState::_process_conjuncts at 
be/src/pipeline/exec/olap_scan_operator.cpp:386
   18# doris::pipeline::ScanLocalState<...>::open at 
be/src/pipeline/exec/scan_operator.cpp:189
   20# doris::pipeline::PipelineTask::_open at 
be/src/pipeline/pipeline_task.cpp:269
   22# doris::pipeline::TaskScheduler::_do_work at 
be/src/pipeline/task_scheduler.cpp:153
   ```
   
   `(PrimitiveType)10` = `TYPE_VARCHAR`, i.e. the predicate is on a varchar 
column.
   
   Because the failing query keeps being re-submitted (in our case by a BI 
dashboard every ~30s), the
   BE enters a **crash loop** and all other queries/loads on the node fail with
   "tablet has no queryable replicas" while it is down.
   
   ## What You Expected?
   
   The query should execute (or fail with a query-level error). A user-level 
SQL expression must never
   be able to abort the BE process.
   
   
   ### What You Expected?
   
   Fix the bug
   
   ### How to Reproduce?
   
   
   1. Create any table with a VARCHAR column, e.g.:
   
   ```sql
   CREATE TABLE t (k INT, v VARCHAR(64)) DUPLICATE KEY(k) DISTRIBUTED BY 
HASH(k) BUCKETS 1;
   INSERT INTO t VALUES (1, 'a');
   ```
   
   2. Run a query where the constant side of a binary predicate on the varchar 
column is a
      const-folded expression instead of a plain literal:
   
   ```sql
   SELECT * FROM t
   WHERE v = COALESCE(NULLIF(CAST('' AS CHAR), ''), 'a');
   ```
   
   3. The BE aborts with the stack above. (The exact folding shape may matter; 
the key point is that
      the constant side is a constant expression rather than a plain literal, 
so BE's folded column is
      a bare `ColumnStr` instead of a `ColumnConst`.)
   
   Real-world trigger in our case (dashboard-generated SQL):
   
   ```sql
   SELECT MAX(_date) AS period, COUNT(*) AS value
   FROM player_sessions
   WHERE _date >= '2026-08-31' AND _date < '2026-09-30'
     AND session_state = 'session_end'
     AND player_nr = COALESCE(NULLIF(CAST('' AS CHAR), ''), '224768403')
   
   ### Anything Else?
   
   Root cause and suggested fix:
   
   - `_should_push_down_binary_predicate` assumes `expr->is_constant()` implies 
the impl column is a
     `ColumnConst` wrapper and uses an unchecked `assert_cast`. That assumption 
does not hold for
     const-folded expressions.
   - The sibling function `_should_push_down_function_filter` already handles 
this safely using
     `get_const_col()` + `check_and_get_column<ColumnConst>()` and falls back to
     `PushDownType::UNACCEPTABLE`. Applying the same pattern in
     `_should_push_down_binary_predicate` (skip pushdown instead of casting) 
should fix the crash.
   
   
   Workaround for affected users: rewrite the predicate so the constant side is 
a plain literal
   (e.g. `player_nr = '224768403'`).
   
   ### Are you willing to submit PR?
   
   - [ ] Yes I am willing to submit a PR!
   
   ### Code of Conduct
   
   - [x] I agree to follow this project's [Code of 
Conduct](https://www.apache.org/foundation/policies/conduct)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to