Skip to content

Commit b10af16

Browse files
committed
fix: CAST(BOOLEAN AS numeric) rejected — true/false now cast to 1/0
BOOLEAN -> INTEGER/BIGINT/FLOAT/DOUBLE failed: the cast string- roundtripped ('true'/'false') and the numeric parser rejected it. CAST(true AS INT) -> "Cannot cast 'true' to INTEGER" (was) -> 1 (now) CAST(false AS DOUBLE) -> error -> 0 SUM(CAST(pred AS INT)) -> error -> count Symmetric counterpart to the numeric->BOOLEAN cast (commit 189342b). Postgres/DuckDB: true -> 1, false -> 0. Fix: typed BOOLEAN -> numeric branch in ExecuteCast, before the string fallback. Covers TINYINT/SMALLINT/INTEGER/BIGINT/FLOAT/DOUBLE. Verified manually: CAST(true AS INT) / CAST(false AS INT) -> 1 / 0 CAST(true AS BIGINT) / (false AS DOUBLE) -> 1 / 0 int->bool->int roundtrip -> 1 SUM(CAST(x>1 AS INT)) -> counts predicate Regression int->bool / varchar->bool -> unchanged Regression int->varchar -> unchanged Zero physical_planner.cpp fast-path dispatch impact. ExecuteCast branch only. This is the architect-spawn pattern's hidden-bug-find for the round: the SUM(CAST(predicate AS INT)) counting idiom — extremely common for conditional counts — was completely blocked by the missing BOOLEAN->numeric cast.
1 parent 7514aba commit b10af16

1 file changed

Lines changed: 21 additions & 0 deletions

File tree

‎src/execution/expression_executor.cpp‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4604,6 +4604,27 @@ void ExpressionExecutor::ExecuteCast(const BoundCast &expr, DataChunk &input,
46044604
}
46054605
continue;
46064606
}
4607+
// BOOLEAN -> numeric (Postgres/DuckDB): true -> 1, false -> 0.
4608+
// Previously the cast string-roundtripped ('true'/'false')
4609+
// and the numeric parser rejected it.
4610+
if (from_type == LogicalTypeId::BOOLEAN &&
4611+
(to_type == LogicalTypeId::TINYINT ||
4612+
to_type == LogicalTypeId::SMALLINT ||
4613+
to_type == LogicalTypeId::INTEGER ||
4614+
to_type == LogicalTypeId::BIGINT ||
4615+
to_type == LogicalTypeId::FLOAT ||
4616+
to_type == LogicalTypeId::DOUBLE)) {
4617+
bool b = val.GetValue<bool>();
4618+
switch (to_type) {
4619+
case LogicalTypeId::TINYINT: result.SetValue(i, Value::TINYINT(b ? 1 : 0)); break;
4620+
case LogicalTypeId::SMALLINT: result.SetValue(i, Value::SMALLINT(b ? 1 : 0)); break;
4621+
case LogicalTypeId::INTEGER: result.SetValue(i, Value::INTEGER(b ? 1 : 0)); break;
4622+
case LogicalTypeId::BIGINT: result.SetValue(i, Value::BIGINT(b ? 1 : 0)); break;
4623+
case LogicalTypeId::FLOAT: result.SetValue(i, Value::FLOAT(b ? 1.0f : 0.0f)); break;
4624+
default: result.SetValue(i, Value::DOUBLE(b ? 1.0 : 0.0)); break;
4625+
}
4626+
continue;
4627+
}
46074628
auto str = val.ToString();
46084629
switch (to_type) {
46094630
case LogicalTypeId::TINYINT:

0 commit comments

Comments
 (0)