[fix](const_expr) fix coredump caused by unsupported cast const expr (#14825)
This commit is contained in:
@ -254,12 +254,15 @@ Status NewOlapScanNode::_build_key_ranges_and_filters() {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
VScanNode::PushDownType NewOlapScanNode::_should_push_down_function_filter(
|
||||
VectorizedFnCall* fn_call, VExprContext* expr_ctx, StringVal* constant_str,
|
||||
doris_udf::FunctionContext** fn_ctx) {
|
||||
Status NewOlapScanNode::_should_push_down_function_filter(VectorizedFnCall* fn_call,
|
||||
VExprContext* expr_ctx,
|
||||
StringVal* constant_str,
|
||||
doris_udf::FunctionContext** fn_ctx,
|
||||
VScanNode::PushDownType& pdt) {
|
||||
// Now only `like` function filters is supported to push down
|
||||
if (fn_call->fn().name.function_name != "like") {
|
||||
return PushDownType::UNACCEPTABLE;
|
||||
pdt = PushDownType::UNACCEPTABLE;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
const auto& children = fn_call->children();
|
||||
@ -273,19 +276,24 @@ VScanNode::PushDownType NewOlapScanNode::_should_push_down_function_filter(
|
||||
}
|
||||
if (!children[1 - i]->is_constant()) {
|
||||
// only handle constant value
|
||||
return PushDownType::UNACCEPTABLE;
|
||||
pdt = PushDownType::UNACCEPTABLE;
|
||||
return Status::OK();
|
||||
} else {
|
||||
DCHECK(children[1 - i]->type().is_string_type());
|
||||
if (const ColumnConst* const_column = check_and_get_column<ColumnConst>(
|
||||
children[1 - i]->get_const_col(expr_ctx)->column_ptr)) {
|
||||
ColumnPtrWrapper* const_col_wrapper = nullptr;
|
||||
RETURN_IF_ERROR(children[1 - i]->get_const_col(expr_ctx, &const_col_wrapper));
|
||||
if (const ColumnConst* const_column =
|
||||
check_and_get_column<ColumnConst>(const_col_wrapper->column_ptr)) {
|
||||
*constant_str = const_column->get_data_at(0).to_string_val();
|
||||
} else {
|
||||
return PushDownType::UNACCEPTABLE;
|
||||
pdt = PushDownType::UNACCEPTABLE;
|
||||
return Status::OK();
|
||||
}
|
||||
}
|
||||
}
|
||||
*fn_ctx = func_cxt;
|
||||
return PushDownType::ACCEPTABLE;
|
||||
pdt = PushDownType::ACCEPTABLE;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
// PlanFragmentExecutor will call this method to set scan range
|
||||
|
||||
@ -44,9 +44,10 @@ protected:
|
||||
Status _process_conjuncts() override;
|
||||
bool _is_key_column(const std::string& col_name) override;
|
||||
|
||||
PushDownType _should_push_down_function_filter(VectorizedFnCall* fn_call,
|
||||
VExprContext* expr_ctx, StringVal* constant_str,
|
||||
doris_udf::FunctionContext** fn_ctx) override;
|
||||
Status _should_push_down_function_filter(VectorizedFnCall* fn_call, VExprContext* expr_ctx,
|
||||
StringVal* constant_str,
|
||||
doris_udf::FunctionContext** fn_ctx,
|
||||
PushDownType& pdt) override;
|
||||
|
||||
PushDownType _should_push_down_bloom_filter() override { return PushDownType::ACCEPTABLE; }
|
||||
|
||||
|
||||
@ -368,7 +368,8 @@ Status VScanNode::_normalize_conjuncts() {
|
||||
}
|
||||
if (_vconjunct_ctx_ptr) {
|
||||
if ((*_vconjunct_ctx_ptr)->root()) {
|
||||
VExpr* new_root = _normalize_predicate((*_vconjunct_ctx_ptr)->root());
|
||||
VExpr* new_root;
|
||||
RETURN_IF_ERROR(_normalize_predicate((*_vconjunct_ctx_ptr)->root(), &new_root));
|
||||
if (new_root) {
|
||||
(*_vconjunct_ctx_ptr)->set_root(new_root);
|
||||
} else {
|
||||
@ -392,7 +393,7 @@ Status VScanNode::_normalize_conjuncts() {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
VExpr* VScanNode::_normalize_predicate(VExpr* conjunct_expr_root) {
|
||||
Status VScanNode::_normalize_predicate(VExpr* conjunct_expr_root, VExpr** output_expr) {
|
||||
static constexpr auto is_leaf = [](VExpr* expr) { return !expr->is_and_expr(); };
|
||||
auto in_predicate_checker = [](const std::vector<VExpr*>& children, const VSlotRef** slot,
|
||||
VExpr** child_contains_slot) {
|
||||
@ -427,9 +428,10 @@ VExpr* VScanNode::_normalize_predicate(VExpr* conjunct_expr_root) {
|
||||
SlotDescriptor* slot = nullptr;
|
||||
ColumnValueRangeType* range = nullptr;
|
||||
PushDownType pdt = PushDownType::UNACCEPTABLE;
|
||||
_eval_const_conjuncts(cur_expr, *_vconjunct_ctx_ptr, &pdt);
|
||||
RETURN_IF_ERROR(_eval_const_conjuncts(cur_expr, *_vconjunct_ctx_ptr, &pdt));
|
||||
if (pdt == PushDownType::ACCEPTABLE) {
|
||||
return nullptr;
|
||||
*output_expr = nullptr;
|
||||
return Status::OK();
|
||||
}
|
||||
if (_is_predicate_acting_on_slot(cur_expr, in_predicate_checker, &slot, &range) ||
|
||||
_is_predicate_acting_on_slot(cur_expr, eq_predicate_checker, &slot, &range)) {
|
||||
@ -461,18 +463,23 @@ VExpr* VScanNode::_normalize_predicate(VExpr* conjunct_expr_root) {
|
||||
*range);
|
||||
}
|
||||
if (pdt == PushDownType::ACCEPTABLE && _is_key_column(slot->col_name())) {
|
||||
return nullptr;
|
||||
*output_expr = nullptr;
|
||||
return Status::OK();
|
||||
} else {
|
||||
// for PARTIAL_ACCEPTABLE and UNACCEPTABLE, do not remove expr from the tree
|
||||
return conjunct_expr_root;
|
||||
*output_expr = conjunct_expr_root;
|
||||
return Status::OK();
|
||||
}
|
||||
} else {
|
||||
VExpr* left_child = _normalize_predicate(conjunct_expr_root->children()[0]);
|
||||
VExpr* right_child = _normalize_predicate(conjunct_expr_root->children()[1]);
|
||||
VExpr* left_child;
|
||||
RETURN_IF_ERROR(_normalize_predicate(conjunct_expr_root->children()[0], &left_child));
|
||||
VExpr* right_child;
|
||||
RETURN_IF_ERROR(_normalize_predicate(conjunct_expr_root->children()[1], &right_child));
|
||||
|
||||
if (left_child != nullptr && right_child != nullptr) {
|
||||
conjunct_expr_root->set_children({left_child, right_child});
|
||||
return conjunct_expr_root;
|
||||
*output_expr = conjunct_expr_root;
|
||||
return Status::OK();
|
||||
} else {
|
||||
// here only close the and expr self, do not close the child
|
||||
conjunct_expr_root->set_children({});
|
||||
@ -481,10 +488,12 @@ VExpr* VScanNode::_normalize_predicate(VExpr* conjunct_expr_root) {
|
||||
}
|
||||
|
||||
// here do not close Expr* now
|
||||
return left_child != nullptr ? left_child : right_child;
|
||||
*output_expr = left_child != nullptr ? left_child : right_child;
|
||||
return Status::OK();
|
||||
}
|
||||
}
|
||||
return conjunct_expr_root;
|
||||
*output_expr = conjunct_expr_root;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status VScanNode::_normalize_bloom_filter(VExpr* expr, VExprContext* expr_ctx, SlotDescriptor* slot,
|
||||
@ -528,8 +537,9 @@ Status VScanNode::_normalize_function_filters(VExpr* expr, VExprContext* expr_ct
|
||||
if (TExprNodeType::FUNCTION_CALL == fn_expr->node_type()) {
|
||||
doris_udf::FunctionContext* fn_ctx = nullptr;
|
||||
StringVal val;
|
||||
PushDownType temp_pdt = _should_push_down_function_filter(
|
||||
reinterpret_cast<VectorizedFnCall*>(fn_expr), expr_ctx, &val, &fn_ctx);
|
||||
PushDownType temp_pdt;
|
||||
RETURN_IF_ERROR(_should_push_down_function_filter(
|
||||
reinterpret_cast<VectorizedFnCall*>(fn_expr), expr_ctx, &val, &fn_ctx, temp_pdt));
|
||||
if (temp_pdt != PushDownType::UNACCEPTABLE) {
|
||||
std::string col = slot->col_name();
|
||||
_push_down_functions.emplace_back(opposite, col, fn_ctx, val);
|
||||
@ -568,11 +578,13 @@ bool VScanNode::_is_predicate_acting_on_slot(
|
||||
return true;
|
||||
}
|
||||
|
||||
void VScanNode::_eval_const_conjuncts(VExpr* vexpr, VExprContext* expr_ctx, PushDownType* pdt) {
|
||||
Status VScanNode::_eval_const_conjuncts(VExpr* vexpr, VExprContext* expr_ctx, PushDownType* pdt) {
|
||||
char* constant_val = nullptr;
|
||||
if (vexpr->is_constant()) {
|
||||
ColumnPtrWrapper* const_col_wrapper = nullptr;
|
||||
RETURN_IF_ERROR(vexpr->get_const_col(expr_ctx, &const_col_wrapper));
|
||||
if (const ColumnConst* const_column =
|
||||
check_and_get_column<ColumnConst>(vexpr->get_const_col(expr_ctx)->column_ptr)) {
|
||||
check_and_get_column<ColumnConst>(const_col_wrapper->column_ptr)) {
|
||||
constant_val = const_cast<char*>(const_column->get_data_at(0).data);
|
||||
if (constant_val == nullptr || *reinterpret_cast<bool*>(constant_val) == false) {
|
||||
*pdt = PushDownType::ACCEPTABLE;
|
||||
@ -580,14 +592,14 @@ void VScanNode::_eval_const_conjuncts(VExpr* vexpr, VExprContext* expr_ctx, Push
|
||||
}
|
||||
} else if (const ColumnVector<UInt8>* bool_column =
|
||||
check_and_get_column<ColumnVector<UInt8>>(
|
||||
vexpr->get_const_col(expr_ctx)->column_ptr)) {
|
||||
const_col_wrapper->column_ptr)) {
|
||||
// TODO: If `vexpr->is_constant()` is true, a const column is expected here.
|
||||
// But now we still don't cover all predicates for const expression.
|
||||
// For example, for query `SELECT col FROM tbl WHERE 'PROMOTION' LIKE 'AAA%'`,
|
||||
// predicate `like` will return a ColumnVector<UInt8> which contains a single value.
|
||||
LOG(WARNING) << "Expr[" << vexpr->debug_string()
|
||||
<< "] should return a const column but actually is "
|
||||
<< vexpr->get_const_col(expr_ctx)->column_ptr->get_name();
|
||||
<< const_col_wrapper->column_ptr->get_name();
|
||||
DCHECK_EQ(bool_column->size(), 1);
|
||||
if (bool_column->size() == 1) {
|
||||
constant_val = const_cast<char*>(bool_column->get_data_at(0).data);
|
||||
@ -603,9 +615,10 @@ void VScanNode::_eval_const_conjuncts(VExpr* vexpr, VExprContext* expr_ctx, Push
|
||||
} else {
|
||||
LOG(WARNING) << "Expr[" << vexpr->debug_string()
|
||||
<< "] should return a const column but actually is "
|
||||
<< vexpr->get_const_col(expr_ctx)->column_ptr->get_name();
|
||||
<< const_col_wrapper->column_ptr->get_name();
|
||||
}
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
template <PrimitiveType T>
|
||||
@ -664,9 +677,10 @@ Status VScanNode::_normalize_in_and_eq_predicate(VExpr* expr, VExprContext* expr
|
||||
StringRef value;
|
||||
int slot_ref_child = -1;
|
||||
|
||||
PushDownType temp_pdt =
|
||||
_should_push_down_binary_predicate(reinterpret_cast<VectorizedFnCall*>(expr),
|
||||
expr_ctx, &value, &slot_ref_child, eq_checker);
|
||||
PushDownType temp_pdt;
|
||||
RETURN_IF_ERROR(_should_push_down_binary_predicate(
|
||||
reinterpret_cast<VectorizedFnCall*>(expr), expr_ctx, &value, &slot_ref_child,
|
||||
eq_checker, temp_pdt));
|
||||
if (temp_pdt == PushDownType::UNACCEPTABLE) {
|
||||
return Status::OK();
|
||||
}
|
||||
@ -736,9 +750,10 @@ Status VScanNode::_normalize_not_in_and_not_eq_predicate(VExpr* expr, VExprConte
|
||||
auto ne_checker = [](const std::string& fn_name) { return fn_name == "ne"; };
|
||||
StringRef value;
|
||||
int slot_ref_child = -1;
|
||||
if ((temp_pdt = _should_push_down_binary_predicate(
|
||||
reinterpret_cast<VectorizedFnCall*>(expr), expr_ctx, &value, &slot_ref_child,
|
||||
ne_checker)) == PushDownType::UNACCEPTABLE) {
|
||||
RETURN_IF_ERROR(_should_push_down_binary_predicate(
|
||||
reinterpret_cast<VectorizedFnCall*>(expr), expr_ctx, &value, &slot_ref_child,
|
||||
ne_checker, temp_pdt));
|
||||
if (temp_pdt == PushDownType::UNACCEPTABLE) {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
@ -824,9 +839,10 @@ Status VScanNode::_normalize_noneq_binary_predicate(VExpr* expr, VExprContext* e
|
||||
};
|
||||
StringRef value;
|
||||
int slot_ref_child = -1;
|
||||
PushDownType temp_pdt = _should_push_down_binary_predicate(
|
||||
PushDownType temp_pdt;
|
||||
RETURN_IF_ERROR(_should_push_down_binary_predicate(
|
||||
reinterpret_cast<VectorizedFnCall*>(expr), expr_ctx, &value, &slot_ref_child,
|
||||
noneq_checker);
|
||||
noneq_checker, temp_pdt));
|
||||
if (temp_pdt != PushDownType::UNACCEPTABLE) {
|
||||
DCHECK(slot_ref_child >= 0);
|
||||
const std::string& fn_name =
|
||||
@ -956,11 +972,13 @@ Status VScanNode::clone_vconjunct_ctx(VExprContext** _vconjunct_ctx) {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
VScanNode::PushDownType VScanNode::_should_push_down_binary_predicate(
|
||||
Status VScanNode::_should_push_down_binary_predicate(
|
||||
VectorizedFnCall* fn_call, VExprContext* expr_ctx, StringRef* constant_val,
|
||||
int* slot_ref_child, const std::function<bool(const std::string&)>& fn_checker) {
|
||||
int* slot_ref_child, const std::function<bool(const std::string&)>& fn_checker,
|
||||
VScanNode::PushDownType& pdt) {
|
||||
if (!fn_checker(fn_call->fn().name.function_name)) {
|
||||
return PushDownType::UNACCEPTABLE;
|
||||
pdt = PushDownType::UNACCEPTABLE;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
const auto& children = fn_call->children();
|
||||
@ -972,18 +990,23 @@ VScanNode::PushDownType VScanNode::_should_push_down_binary_predicate(
|
||||
}
|
||||
if (!children[1 - i]->is_constant()) {
|
||||
// only handle constant value
|
||||
return PushDownType::UNACCEPTABLE;
|
||||
pdt = PushDownType::UNACCEPTABLE;
|
||||
return Status::OK();
|
||||
} else {
|
||||
if (const ColumnConst* const_column = check_and_get_column<ColumnConst>(
|
||||
children[1 - i]->get_const_col(expr_ctx)->column_ptr)) {
|
||||
ColumnPtrWrapper* const_col_wrapper = nullptr;
|
||||
RETURN_IF_ERROR(children[1 - i]->get_const_col(expr_ctx, &const_col_wrapper));
|
||||
if (const ColumnConst* const_column =
|
||||
check_and_get_column<ColumnConst>(const_col_wrapper->column_ptr)) {
|
||||
*slot_ref_child = i;
|
||||
*constant_val = const_column->get_data_at(0);
|
||||
} else {
|
||||
return PushDownType::UNACCEPTABLE;
|
||||
pdt = PushDownType::UNACCEPTABLE;
|
||||
return Status::OK();
|
||||
}
|
||||
}
|
||||
}
|
||||
return PushDownType::ACCEPTABLE;
|
||||
pdt = PushDownType::ACCEPTABLE;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
VScanNode::PushDownType VScanNode::_should_push_down_in_predicate(VInPredicate* pred,
|
||||
|
||||
@ -134,18 +134,21 @@ protected:
|
||||
// 2. in/not in predicate
|
||||
// 3. function predicate
|
||||
// TODO: these interfaces should be change to become more common.
|
||||
virtual PushDownType _should_push_down_binary_predicate(
|
||||
virtual Status _should_push_down_binary_predicate(
|
||||
VectorizedFnCall* fn_call, VExprContext* expr_ctx, StringRef* constant_val,
|
||||
int* slot_ref_child, const std::function<bool(const std::string&)>& fn_checker);
|
||||
int* slot_ref_child, const std::function<bool(const std::string&)>& fn_checker,
|
||||
PushDownType& pdt);
|
||||
|
||||
virtual PushDownType _should_push_down_in_predicate(VInPredicate* in_pred,
|
||||
VExprContext* expr_ctx, bool is_not_in);
|
||||
|
||||
virtual PushDownType _should_push_down_function_filter(VectorizedFnCall* fn_call,
|
||||
VExprContext* expr_ctx,
|
||||
StringVal* constant_str,
|
||||
doris_udf::FunctionContext** fn_ctx) {
|
||||
return PushDownType::UNACCEPTABLE;
|
||||
virtual Status _should_push_down_function_filter(VectorizedFnCall* fn_call,
|
||||
VExprContext* expr_ctx,
|
||||
StringVal* constant_str,
|
||||
doris_udf::FunctionContext** fn_ctx,
|
||||
PushDownType& pdt) {
|
||||
pdt = PushDownType::UNACCEPTABLE;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
virtual PushDownType _should_push_down_bloom_filter() { return PushDownType::UNACCEPTABLE; }
|
||||
@ -272,8 +275,8 @@ private:
|
||||
Status _append_rf_into_conjuncts(std::vector<VExpr*>& vexprs);
|
||||
|
||||
Status _normalize_conjuncts();
|
||||
VExpr* _normalize_predicate(VExpr* conjunct_expr_root);
|
||||
void _eval_const_conjuncts(VExpr* vexpr, VExprContext* expr_ctx, PushDownType* pdt);
|
||||
Status _normalize_predicate(VExpr* conjunct_expr_root, VExpr** output_expr);
|
||||
Status _eval_const_conjuncts(VExpr* vexpr, VExprContext* expr_ctx, PushDownType* pdt);
|
||||
|
||||
Status _normalize_bloom_filter(VExpr* expr, VExprContext* expr_ctx, SlotDescriptor* slot,
|
||||
PushDownType* pdt);
|
||||
|
||||
@ -28,7 +28,9 @@ Status VArrayLiteral::prepare(RuntimeState* state, const RowDescriptor& row_desc
|
||||
Field array = is_null ? Field() : Array();
|
||||
for (const auto child : _children) {
|
||||
Field item;
|
||||
child->get_const_col(context)->column_ptr->get(0, item);
|
||||
ColumnPtrWrapper* const_col_wrapper = nullptr;
|
||||
RETURN_IF_ERROR(child->get_const_col(context, &const_col_wrapper));
|
||||
const_col_wrapper->column_ptr->get(0, item);
|
||||
array.get<Array>().push_back(item);
|
||||
}
|
||||
_column_ptr = _data_type->create_column_const(1, array);
|
||||
|
||||
@ -308,13 +308,15 @@ bool VExpr::is_constant() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
ColumnPtrWrapper* VExpr::get_const_col(VExprContext* context) {
|
||||
Status VExpr::get_const_col(VExprContext* context, ColumnPtrWrapper** output) {
|
||||
*output = nullptr;
|
||||
if (!is_constant()) {
|
||||
return nullptr;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
if (_constant_col != nullptr) {
|
||||
return _constant_col.get();
|
||||
*output = _constant_col.get();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int result = -1;
|
||||
@ -322,13 +324,12 @@ ColumnPtrWrapper* VExpr::get_const_col(VExprContext* context) {
|
||||
// If block is empty, some functions will produce no result. So we insert a column with
|
||||
// single value here.
|
||||
block.insert({ColumnUInt8::create(1), std::make_shared<DataTypeUInt8>(), ""});
|
||||
if (!execute(context, &block, &result).ok()) {
|
||||
return nullptr;
|
||||
}
|
||||
RETURN_IF_ERROR(execute(context, &block, &result));
|
||||
DCHECK(result != -1);
|
||||
const auto& column = block.get_by_position(result).column;
|
||||
_constant_col = std::make_shared<ColumnPtrWrapper>(column);
|
||||
return _constant_col.get();
|
||||
*output = _constant_col.get();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void VExpr::register_function_context(doris::RuntimeState* state, VExprContext* context) {
|
||||
@ -348,7 +349,9 @@ Status VExpr::init_function_context(VExprContext* context,
|
||||
if (scope == FunctionContext::FRAGMENT_LOCAL) {
|
||||
std::vector<ColumnPtrWrapper*> constant_cols;
|
||||
for (auto c : _children) {
|
||||
constant_cols.push_back(c->get_const_col(context));
|
||||
ColumnPtrWrapper* const_col_wrapper = nullptr;
|
||||
RETURN_IF_ERROR(c->get_const_col(context, &const_col_wrapper));
|
||||
constant_cols.push_back(const_col_wrapper);
|
||||
}
|
||||
fn_ctx->impl()->set_constant_cols(constant_cols);
|
||||
}
|
||||
|
||||
@ -148,7 +148,7 @@ public:
|
||||
/// the output. Returns nullptr if the argument is not constant. The returned ColumnPtr is
|
||||
/// owned by this expr. This should only be called after Open() has been called on this
|
||||
/// expr.
|
||||
virtual ColumnPtrWrapper* get_const_col(VExprContext* context);
|
||||
Status get_const_col(VExprContext* context, ColumnPtrWrapper** output);
|
||||
|
||||
int fn_context_index() const { return _fn_context_index; };
|
||||
|
||||
|
||||
@ -40,10 +40,6 @@ public:
|
||||
}
|
||||
const std::string& expr_name() const override;
|
||||
|
||||
ColumnPtrWrapper* get_const_col(VExprContext* context) override {
|
||||
return _impl->get_const_col(context);
|
||||
}
|
||||
|
||||
const VExpr* get_impl() const override { return _impl; }
|
||||
|
||||
// if filter rate less than this, bloom filter will set always true
|
||||
|
||||
@ -25,6 +25,23 @@ suite("test_cast_function") {
|
||||
qt_sql """ select cast (NULL AS CHAR(1)); """
|
||||
qt_sql """ select cast ('20190101' AS CHAR(2)); """
|
||||
|
||||
test {
|
||||
sql """
|
||||
select
|
||||
ref_0.`k0` as c1
|
||||
from
|
||||
`test_query_db`.`baseall` as ref_0
|
||||
where
|
||||
cast(
|
||||
case
|
||||
when BITMAP_EMPTY() is NULL then null
|
||||
else null
|
||||
end as bitmap
|
||||
) is NULL
|
||||
"""
|
||||
exception "errCode = 2, detailMessage = Conversion from UInt8 to BitMap is not supported"
|
||||
}
|
||||
|
||||
sql """ SET enable_vectorized_engine = FALSE; """
|
||||
|
||||
qt_sql """ select cast (1 as BIGINT) """
|
||||
|
||||
Reference in New Issue
Block a user