Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/expression_evaluator/specializations/cast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <sirius/exception.hpp>

// cudf
#include <cudf/column/column_factories.hpp>
#include <cudf/cudf_utils.hpp>
#include <cudf/unary.hpp>

Expand Down Expand Up @@ -82,7 +83,10 @@ evaluate_result expression_evaluator::evaluate(sirius::ast::cast const& alt, eva
//===----------3: MATERIALIZE Mode, evaluate node with unary/binary ops----------===//
auto const return_type = sirius::get_cudf_type(alt.target_type);
auto child = evaluate(*alt.child, evaluation_mode::MATERIALIZE);
D_ASSERT(!child.is_scalar()); // CAST should never be called on a scalar
if (child.is_scalar()) {
child = evaluate_result(
cudf::make_column_from_scalar(child.get_scalar(), _input_table.num_rows(), _stream, _mr));
}
// Only planner-certified carrier restoration may tunnel through the narrowed representation.
// A semantic cast delegates to cuDF and is never reinterpreted as a physical DATE restore.
auto result_column =
Expand Down
53 changes: 53 additions & 0 deletions test/cpp/expression_evaluator/test_expression_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1119,6 +1119,59 @@ TEMPLATE_TEST_CASE("evaluate projects references, constants, and comparisons",
}
}

TEMPLATE_TEST_CASE("evaluate casts scalar constants including HUGEINT and NULL",
"[expression_evaluator][scalar_cast]",
mat_strategy,
ast_interpret_strategy,
ast_jit_strategy)
{
auto* space = get_default_gpu_space();
REQUIRE(space != nullptr);
auto const hugeint = logical_type::make(type_id::HUGEINT);
auto const bigint = logical_type::make(type_id::BIGINT);
auto const integer = logical_type::make(type_id::INTEGER);

for (auto const row_count : {0, 1, 7}) {
CAPTURE(row_count);
std::vector<std::unique_ptr<cudf::column>> columns;
columns.push_back(cudf::make_numeric_column(cudf::data_type{cudf::type_id::INT32},
row_count,
cudf::mask_state::UNALLOCATED,
cudf::get_default_stream(),
get_resource_ref(*space)));
auto input = std::make_unique<cudf::table>(std::move(columns));

std::vector<std::unique_ptr<ast_node>> nodes;
nodes.push_back(make_cast(make_int_const(-42), hugeint, false));
// The outer AST cast consumes the materialized HUGEINT cast as a temporary column.
nodes.push_back(make_cast(make_cast(make_int_const(1), hugeint, false), bigint, false));
nodes.push_back(make_cast(make_null_const(integer), hugeint, false));
nodes.push_back(make_cast(make_cast(make_null_const(integer), hugeint, false), bigint, false));
nodes.push_back(make_cast(make_int_const(42), logical_type::make(type_id::DOUBLE), false));
std::vector<ast_node const*> expressions;
for (auto const& node : nodes) {
expressions.push_back(node.get());
}
exp_executor executor(
expressions, get_resource_ref(*space), cudf::get_default_stream(), TestType::value, 1);
auto output = executor.evaluate(input->view());
auto const view = output->view();
REQUIRE(view.num_rows() == row_count);
REQUIRE(view.num_columns() == 5);
for (int i = 0; i < 4; ++i) {
REQUIRE(view.column(i).type() == cudf::data_type{cudf::type_id::INT64});
}
REQUIRE(copy_column_to_host<int64_t>(view.column(0)) == std::vector<int64_t>(row_count, -42));
REQUIRE(copy_column_to_host<int64_t>(view.column(1)) == std::vector<int64_t>(row_count, 1));
REQUIRE(view.column(0).null_count() == 0);
REQUIRE(view.column(1).null_count() == 0);
REQUIRE(view.column(2).null_count() == row_count);
REQUIRE(view.column(3).null_count() == row_count);
REQUIRE(view.column(4).type() == cudf::data_type{cudf::type_id::FLOAT64});
REQUIRE(copy_column_to_host<double>(view.column(4)) == std::vector<double>(row_count, 42.0));
}
}

// ---------------------------------------------------------------------------
// select() — basic filter + edge cases
// ---------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,23 @@ TEST_CASE_METHOD(SemanticCastFixture,
REQUIRE(rows == cpu_rows);
}
}

TEST_CASE_METHOD(SemanticCastFixture,
"scalar cast - sum_rewriter arithmetic runs without CPU fallback",
"[integration][gpu_execution][scalar_cast]")
{
run_ok("CREATE TABLE hits(ResolutionWidth INTEGER, grp INTEGER);");
run_ok("INSERT INTO hits VALUES (1920, 1), (1280, 1), (NULL, 1), (-1, 2), (0, 2), (NULL, 3);");
run_ok("CHECKPOINT;");
// Keep Sirius's optimizer exclusions; sum_rewriter is enabled by default.
auto disabled = con->Query("SELECT current_setting('disabled_optimizers');");
REQUIRE(disabled);
REQUIRE_FALSE(disabled->HasError());
REQUIRE(disabled->GetValue(0, 0).ToString().find("sum_rewriter") == std::string::npos);
run_ok("SET enable_duckdb_fallback = false;");

compare_gpu_vs_cpu("SELECT SUM(ResolutionWidth + 1) FROM hits;");
compare_gpu_vs_cpu("SELECT grp, SUM(ResolutionWidth + 1) FROM hits GROUP BY grp;");
compare_gpu_vs_cpu("SELECT SUM(ResolutionWidth + 1) FROM hits WHERE grp = 3;");
compare_gpu_vs_cpu("SELECT SUM(ResolutionWidth + 1) FROM hits WHERE grp = 99;");
}
Loading