This is an automated email from the ASF dual-hosted git repository.
Gabriel39 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new b004396f7b0 [improvement](external) Enable FileScannerV2 for batch
mode (#65437)
b004396f7b0 is described below
commit b004396f7b016f40470d08d62bfe2114e21a1180
Author: Gabriel <[email protected]>
AuthorDate: Fri Jul 10 23:16:06 2026 +0800
[improvement](external) Enable FileScannerV2 for batch mode (#65437)
---
be/src/exec/operator/file_scan_operator.cpp | 24 ++++++-
be/src/exec/operator/file_scan_operator.h | 6 ++
be/src/exec/scan/file_scanner_v2.cpp | 28 +++++++-
be/src/exec/scan/file_scanner_v2.h | 5 ++
be/src/exec/scan/split_source_connector.h | 29 --------
be/test/exec/scan/file_scanner_v2_test.cpp | 80 +++++++++++++---------
.../doris/datasource/hive/source/HiveScanNode.java | 10 +++
.../java/org/apache/doris/qe/SessionVariable.java | 10 ++-
.../datasource/hive/source/HiveScanNodeTest.java | 12 ++++
.../org/apache/doris/qe/SessionVariablesTest.java | 10 +++
10 files changed, 147 insertions(+), 67 deletions(-)
diff --git a/be/src/exec/operator/file_scan_operator.cpp
b/be/src/exec/operator/file_scan_operator.cpp
index d4035d37e27..58aadfc87a6 100644
--- a/be/src/exec/operator/file_scan_operator.cpp
+++ b/be/src/exec/operator/file_scan_operator.cpp
@@ -102,6 +102,26 @@ ScannerScheduler*
FileScanLocalState::scan_scheduler(RuntimeState* state) const
return state->get_query_ctx()->get_remote_scan_scheduler();
}
+#ifdef BE_TEST
+bool FileScanLocalState::TEST_should_use_file_scanner_v2(const TQueryOptions&
query_options,
+ bool is_load,
+ const
TFileScanRangeParams& scan_params) {
+ return _should_use_file_scanner_v2(query_options, is_load, scan_params);
+}
+#endif
+
+bool FileScanLocalState::_should_use_file_scanner_v2(const TQueryOptions&
query_options,
+ bool is_load,
+ const
TFileScanRangeParams& scan_params) {
+ const bool is_transactional_hive =
+ scan_params.__isset.table_format_params &&
+ scan_params.table_format_params.table_format_type ==
"transactional_hive";
+ return query_options.__isset.enable_file_scanner_v2 &&
query_options.enable_file_scanner_v2 &&
+ !is_load && scan_params.format_type != TFileFormatType::FORMAT_WAL
&&
+ scan_params.format_type != TFileFormatType::FORMAT_ES_HTTP &&
+ scan_params.format_type != TFileFormatType::FORMAT_LANCE &&
!is_transactional_hive;
+}
+
Status FileScanLocalState::_init_scanners(std::list<ScannerSPtr>* scanners) {
if (_split_source->num_scan_ranges() == 0) {
_eos = true;
@@ -131,9 +151,7 @@ Status
FileScanLocalState::_init_scanners(std::list<ScannerSPtr>* scanners) {
state()->desc_tbl().get_tuple_descriptor(scan_params->src_tuple_id) != nullptr;
// TODO: Use scanner v2 for all queries.
const bool use_file_scanner_v2 =
- state()->query_options().__isset.enable_file_scanner_v2 &&
- state()->query_options().enable_file_scanner_v2 && !is_load &&
- _split_source->all_scan_ranges_match(*scan_params,
FileScannerV2::is_supported);
+ _should_use_file_scanner_v2(state()->query_options(), is_load,
*scan_params);
_operator_profile->add_info_string("UseScannerV2", use_file_scanner_v2 ?
"true" : "false");
for (int i = 0; i < _max_scanners; ++i) {
ScannerSPtr scanner;
diff --git a/be/src/exec/operator/file_scan_operator.h
b/be/src/exec/operator/file_scan_operator.h
index c47488fa357..7d8fae51b78 100644
--- a/be/src/exec/operator/file_scan_operator.h
+++ b/be/src/exec/operator/file_scan_operator.h
@@ -54,6 +54,10 @@ public:
int max_scanners_concurrency(RuntimeState* state) const override;
int min_scanners_concurrency(RuntimeState* state) const override;
ScannerScheduler* scan_scheduler(RuntimeState* state) const override;
+#ifdef BE_TEST
+ static bool TEST_should_use_file_scanner_v2(const TQueryOptions&
query_options, bool is_load,
+ const TFileScanRangeParams&
scan_params);
+#endif
private:
friend class FileScanner;
@@ -65,6 +69,8 @@ private:
return PushDownType::PARTIAL_ACCEPTABLE;
}
bool _push_down_topn(const RuntimePredicate& predicate) override;
+ static bool _should_use_file_scanner_v2(const TQueryOptions&
query_options, bool is_load,
+ const TFileScanRangeParams&
scan_params);
PushDownType _should_push_down_is_null_predicate(VectorizedFnCall*
fn_call) const override {
return fn_call->fn().name.function_name == "is_null_pred" ||
diff --git a/be/src/exec/scan/file_scanner_v2.cpp
b/be/src/exec/scan/file_scanner_v2.cpp
index 10327f37374..10b5f850ea3 100644
--- a/be/src/exec/scan/file_scanner_v2.cpp
+++ b/be/src/exec/scan/file_scanner_v2.cpp
@@ -212,6 +212,11 @@ Status rewrite_slot_refs_to_global_index(
} // namespace
#ifdef BE_TEST
+Status FileScannerV2::TEST_validate_scan_range(const TFileScanRangeParams&
params,
+ const TFileRangeDesc& range) {
+ return _validate_scan_range(params, range);
+}
+
Status FileScannerV2::TEST_to_file_format(TFileFormatType::type format_type,
format::FileFormat* file_format) {
return _to_file_format(format_type, file_format);
@@ -273,6 +278,16 @@ bool FileScannerV2::is_supported(const
TFileScanRangeParams& params, const TFile
}
}
+Status FileScannerV2::_validate_scan_range(const TFileScanRangeParams& params,
+ const TFileRangeDesc& range) {
+ if (!is_supported(params, range)) {
+ return Status::NotSupported(
+ "FileScannerV2 does not support table format {} with file
format {}",
+ table_format_name(range),
to_string(get_range_format_type(params, range)));
+ }
+ return Status::OK();
+}
+
FileScannerV2::FileScannerV2(RuntimeState* state, FileScanLocalState*
local_state, int64_t limit,
std::shared_ptr<SplitSourceConnector>
split_source,
RuntimeProfile* profile, ShardedKVCache* kv_cache,
@@ -321,7 +336,7 @@ Status FileScannerV2::init(RuntimeState* state, const
VExprContextSPtrs& conjunc
Status FileScannerV2::_open_impl(RuntimeState* state) {
RETURN_IF_CANCELLED(state);
RETURN_IF_ERROR(Scanner::_open_impl(state));
- RETURN_IF_ERROR(_split_source->get_next(&_first_scan_range,
&_current_range));
+ RETURN_IF_ERROR(_get_next_scan_range(&_first_scan_range));
if (_first_scan_range) {
RETURN_IF_ERROR(_create_table_reader_for_format(_current_range,
&_table_reader));
DORIS_CHECK(_table_reader != nullptr);
@@ -331,6 +346,15 @@ Status FileScannerV2::_open_impl(RuntimeState* state) {
return Status::OK();
}
+Status FileScannerV2::_get_next_scan_range(bool* has_next) {
+ DORIS_CHECK(has_next != nullptr);
+ RETURN_IF_ERROR(_split_source->get_next(has_next, &_current_range));
+ if (*has_next) {
+ RETURN_IF_ERROR(_validate_scan_range(*_params, _current_range));
+ }
+ return Status::OK();
+}
+
Status FileScannerV2::_get_block_impl(RuntimeState* state, Block* block, bool*
eof) {
while (true) {
RETURN_IF_CANCELLED(state);
@@ -373,7 +397,7 @@ Status FileScannerV2::_prepare_next_split(bool* eos) {
while (true) {
bool has_next = _first_scan_range;
if (!_first_scan_range) {
- RETURN_IF_ERROR(_split_source->get_next(&has_next,
&_current_range));
+ RETURN_IF_ERROR(_get_next_scan_range(&has_next));
}
_first_scan_range = false;
if (!has_next || _should_stop) {
diff --git a/be/src/exec/scan/file_scanner_v2.h
b/be/src/exec/scan/file_scanner_v2.h
index 07e772b4188..66242b610f4 100644
--- a/be/src/exec/scan/file_scanner_v2.h
+++ b/be/src/exec/scan/file_scanner_v2.h
@@ -65,6 +65,8 @@ public:
static bool is_supported(const TFileScanRangeParams& params, const
TFileRangeDesc& range);
#ifdef BE_TEST
+ static Status TEST_validate_scan_range(const TFileScanRangeParams& params,
+ const TFileRangeDesc& range);
static Status TEST_to_file_format(TFileFormatType::type format_type,
format::FileFormat* file_format);
static bool TEST_is_partition_slot(const TFileScanSlotInfo& slot_info,
@@ -104,6 +106,9 @@ protected:
bool _should_update_load_counters() const override;
private:
+ static Status _validate_scan_range(const TFileScanRangeParams& params,
+ const TFileRangeDesc& range);
+ Status _get_next_scan_range(bool* has_next);
TFileFormatType::type _get_current_format_type() const;
Status _init_io_ctx();
Status _init_expr_ctxes();
diff --git a/be/src/exec/scan/split_source_connector.h
b/be/src/exec/scan/split_source_connector.h
index 320f6f90d0d..5926baff303 100644
--- a/be/src/exec/scan/split_source_connector.h
+++ b/be/src/exec/scan/split_source_connector.h
@@ -17,8 +17,6 @@
#pragma once
-#include <functional>
-
#include "common/config.h"
#include "core/custom_allocator.h"
#include "runtime/runtime_state.h"
@@ -47,15 +45,6 @@ public:
virtual TFileScanRangeParams* get_params() = 0;
- virtual bool all_scan_ranges_match(
- const TFileScanRangeParams& params,
- const std::function<bool(const TFileScanRangeParams&, const
TFileRangeDesc&)>&
- predicate) {
- (void)params;
- (void)predicate;
- return false;
- }
-
protected:
template <typename T, typename V1 = std::vector<T>, typename V2 =
std::vector<T>>
requires(std::is_same_v<std::remove_cvref_t<V1>,
@@ -136,24 +125,6 @@ public:
throw Exception(
Status::FatalError("Unreachable, params is got by
file_scan_range_params_map"));
}
-
- bool all_scan_ranges_match(
- const TFileScanRangeParams& params,
- const std::function<bool(const TFileScanRangeParams&, const
TFileRangeDesc&)>&
- predicate) override {
- if (_scan_ranges.empty()) {
- return false;
- }
- for (const auto& scan_range : _scan_ranges) {
- const auto& file_scan_range =
scan_range.scan_range.ext_scan_range.file_scan_range;
- for (const auto& range : file_scan_range.ranges) {
- if (!predicate(params, range)) {
- return false;
- }
- }
- }
- return true;
- }
};
/**
diff --git a/be/test/exec/scan/file_scanner_v2_test.cpp
b/be/test/exec/scan/file_scanner_v2_test.cpp
index 6ce0f4ce4cd..9df8dcb54f4 100644
--- a/be/test/exec/scan/file_scanner_v2_test.cpp
+++ b/be/test/exec/scan/file_scanner_v2_test.cpp
@@ -31,7 +31,7 @@
#include "core/assert_cast.h"
#include "core/data_type/data_type_number.h"
#include "core/data_type/data_type_string.h"
-#include "exec/scan/split_source_connector.h"
+#include "exec/operator/file_scan_operator.h"
#include "exprs/runtime_filter_expr.h"
#include "exprs/vdirect_in_predicate.h"
#include "exprs/vslot_ref.h"
@@ -59,12 +59,6 @@ TFileRangeDesc hudi_range_with_delta_logs() {
return range;
}
-TScanRangeParams scan_range_param(const TFileRangeDesc& range) {
- TScanRangeParams params;
- params.scan_range.ext_scan_range.file_scan_range.ranges.push_back(range);
- return params;
-}
-
VExprSPtr slot_ref(int slot_id, int column_id, DataTypePtr type, const
std::string& name) {
return VSlotRef::create_shared(slot_id, column_id, -1, std::move(type),
name);
}
@@ -109,6 +103,7 @@ TEST(FileScannerV2Test, SupportedFormatMatrix) {
{"jdbc", TFileFormatType::FORMAT_PARQUET, std::nullopt, false},
{"", TFileFormatType::FORMAT_JNI, std::nullopt, false},
{"hive", TFileFormatType::FORMAT_ORC, std::nullopt, true},
+ {"transactional_hive", TFileFormatType::FORMAT_ORC, std::nullopt,
false},
{"jdbc", TFileFormatType::FORMAT_JNI, std::nullopt, true},
{"hive", TFileFormatType::FORMAT_JNI, std::nullopt, false},
{"", TFileFormatType::FORMAT_CSV_PLAIN, std::nullopt, true},
@@ -132,6 +127,8 @@ TEST(FileScannerV2Test, SupportedFormatMatrix) {
{"hive", TFileFormatType::FORMAT_ARROW, std::nullopt, false},
{"", TFileFormatType::FORMAT_ARROW, std::nullopt, false},
{"", TFileFormatType::FORMAT_WAL, std::nullopt, false},
+ {"", TFileFormatType::FORMAT_ES_HTTP, std::nullopt, false},
+ {"", TFileFormatType::FORMAT_LANCE, std::nullopt, false},
};
for (const auto& test_case : cases) {
@@ -153,35 +150,54 @@ TEST(FileScannerV2Test, SupportedFormatMatrix) {
EXPECT_FALSE(FileScannerV2::is_supported(params,
hudi_range_with_delta_logs()));
}
-// Scenario: SplitSourceConnector should route to FileScannerV2 only when
every scan range in the
-// source is supported; one unsupported table format or file format must make
the match fail.
-TEST(FileScannerV2Test,
SplitSourceAllScanRangesMatchRequiresEveryRangeSupported) {
+TEST(FileScannerV2Test, FileScanLocalStateSelectsV2ForSupportedQueriesOnly) {
+ TQueryOptions query_options;
+ TFileScanRangeParams params;
+ params.__set_format_type(TFileFormatType::FORMAT_PARQUET);
+
+
EXPECT_FALSE(FileScanLocalState::TEST_should_use_file_scanner_v2(query_options,
false, params));
+
+ query_options.__set_enable_file_scanner_v2(true);
+
EXPECT_TRUE(FileScanLocalState::TEST_should_use_file_scanner_v2(query_options,
false, params));
+
EXPECT_FALSE(FileScanLocalState::TEST_should_use_file_scanner_v2(query_options,
true, params));
+
+ const std::vector<TFileFormatType::type> unsupported_formats {
+ TFileFormatType::FORMAT_WAL,
+ TFileFormatType::FORMAT_ES_HTTP,
+ TFileFormatType::FORMAT_LANCE,
+ };
+ for (const auto format : unsupported_formats) {
+ params.__set_format_type(format);
+ EXPECT_FALSE(
+
FileScanLocalState::TEST_should_use_file_scanner_v2(query_options, false,
params));
+ }
+
+ params.__set_format_type(TFileFormatType::FORMAT_ORC);
+ TTableFormatFileDesc table_format_params;
+ table_format_params.__set_table_format_type("transactional_hive");
+ params.__set_table_format_params(table_format_params);
+
EXPECT_FALSE(FileScanLocalState::TEST_should_use_file_scanner_v2(query_options,
false, params));
+
+ params.table_format_params.__set_table_format_type("hive");
+
EXPECT_TRUE(FileScanLocalState::TEST_should_use_file_scanner_v2(query_options,
false, params));
+
+ query_options.__set_enable_file_scanner_v2(false);
+
EXPECT_FALSE(FileScanLocalState::TEST_should_use_file_scanner_v2(query_options,
false, params));
+}
+
+// Scenario: Once FileScannerV2 is selected, an unsupported range must fail
instead of falling back
+// to FileScanner.
+TEST(FileScannerV2Test, ValidateScanRangeRejectsUnsupportedRange) {
TFileScanRangeParams params;
params.__set_format_type(TFileFormatType::FORMAT_PARQUET);
const auto supported = range_with_format("hive",
TFileFormatType::FORMAT_PARQUET);
- const auto unsupported_table = range_with_format("lakesoul",
TFileFormatType::FORMAT_PARQUET);
- const auto unsupported_format = range_with_format("hive",
TFileFormatType::FORMAT_WAL);
-
- LocalSplitSourceConnector all_supported(
- {scan_range_param(supported),
- scan_range_param(range_with_format("iceberg",
TFileFormatType::FORMAT_PARQUET))},
- 1);
- EXPECT_TRUE(all_supported.all_scan_ranges_match(params,
FileScannerV2::is_supported));
-
- LocalSplitSourceConnector hudi_supported(
- {scan_range_param(supported),
- scan_range_param(range_with_format("hudi",
TFileFormatType::FORMAT_PARQUET))},
- 1);
- EXPECT_TRUE(hudi_supported.all_scan_ranges_match(params,
FileScannerV2::is_supported));
-
- LocalSplitSourceConnector table_mismatch(
- {scan_range_param(supported),
scan_range_param(unsupported_table)}, 1);
- EXPECT_FALSE(table_mismatch.all_scan_ranges_match(params,
FileScannerV2::is_supported));
-
- LocalSplitSourceConnector format_mismatch(
- {scan_range_param(supported),
scan_range_param(unsupported_format)}, 1);
- EXPECT_FALSE(format_mismatch.all_scan_ranges_match(params,
FileScannerV2::is_supported));
+ EXPECT_TRUE(FileScannerV2::TEST_validate_scan_range(params,
supported).ok());
+
+ const auto unsupported = range_with_format("lakesoul",
TFileFormatType::FORMAT_PARQUET);
+ const auto status = FileScannerV2::TEST_validate_scan_range(params,
unsupported);
+ EXPECT_TRUE(status.is<ErrorCode::NOT_IMPLEMENTED_ERROR>());
+ EXPECT_NE(status.to_string().find("lakesoul"), std::string::npos);
}
// Scenario: FileScannerV2 converts only the file formats implemented by
format_v2 readers and
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/source/HiveScanNode.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/source/HiveScanNode.java
index 5d1bb33f59a..f936eccd59e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/source/HiveScanNode.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/hive/source/HiveScanNode.java
@@ -58,6 +58,7 @@ import org.apache.doris.thrift.TFileAttributes;
import org.apache.doris.thrift.TFileCompressType;
import org.apache.doris.thrift.TFileFormatType;
import org.apache.doris.thrift.TFileRangeDesc;
+import org.apache.doris.thrift.TFileScanRangeParams;
import org.apache.doris.thrift.TFileTextScanRangeParams;
import org.apache.doris.thrift.TPushAggOp;
import org.apache.doris.thrift.TTableFormatFileDesc;
@@ -135,6 +136,7 @@ public class HiveScanNode extends FileQueryScanNode {
super.doInitialize();
if (hmsTable.isHiveTransactionalTable()) {
+ markTransactionalHiveScanParams(params);
this.hiveTransaction = new
HiveTransaction(DebugUtil.printId(ConnectContext.get().queryId()),
ConnectContext.get().getQualifiedUser(), hmsTable,
hmsTable.isFullAcidTable());
Env.getCurrentHiveTransactionMgr().register(hiveTransaction);
@@ -142,6 +144,14 @@ public class HiveScanNode extends FileQueryScanNode {
}
}
+ static void markTransactionalHiveScanParams(TFileScanRangeParams
scanParams) {
+ // BE selects the scanner before remote batch splits are fetched, so
expose the table format
+ // in scan-level params as well as in each range.
+ TTableFormatFileDesc tableFormatParams = new TTableFormatFileDesc();
+
tableFormatParams.setTableFormatType(TableFormatType.TRANSACTIONAL_HIVE.value());
+ scanParams.setTableFormatParams(tableFormatParams);
+ }
+
protected List<HivePartition> getPartitions() throws AnalysisException {
long startTime = System.currentTimeMillis();
List<HivePartition> resPartitions = Lists.newArrayList();
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
index edae724ae16..907f2f0b538 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java
@@ -3032,9 +3032,10 @@ public class SessionVariable implements Serializable,
Writable {
public static final String ENABLE_MC_LIMIT_SPLIT_OPTIMIZATION =
"enable_mc_limit_split_optimization";
@VarAttrDef.VarAttr(
name = ENABLE_EXTERNAL_TABLE_BATCH_MODE,
+ fuzzy = true,
description = {"使能外表的 batch mode 功能", "Enable the batch mode
function of the external table."},
needForward = true)
- public boolean enableExternalTableBatchMode = false;
+ public boolean enableExternalTableBatchMode = true;
@VarAttrDef.VarAttr(
name = ENABLE_MC_LIMIT_SPLIT_OPTIMIZATION,
@@ -4001,6 +4002,13 @@ public class SessionVariable implements Serializable,
Writable {
this.hiveTextCompression = Util.getRandomString(
"gzip", "defalte", "bzip2", "zstd", "lz4", "lzo", "snappy",
"plain");
+ // batch mode
+ this.enableExternalTableBatchMode = random.nextBoolean();
+ if (this.enableExternalTableBatchMode) {
+ this.numPartitionsInBatchMode = Util.getRandomInt(0, 1024,
Integer.MAX_VALUE);
+ this.numFilesInBatchMode = Util.getRandomInt(0, 1024,
Integer.MAX_VALUE);
+ }
+
// common
this.enableCountPushDownForExternalTable = random.nextBoolean();
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/source/HiveScanNodeTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/source/HiveScanNodeTest.java
index 197d8c1fc61..e0c7b0464e0 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/source/HiveScanNodeTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/hive/source/HiveScanNodeTest.java
@@ -19,6 +19,7 @@ package org.apache.doris.datasource.hive.source;
import org.apache.doris.analysis.TupleDescriptor;
import org.apache.doris.analysis.TupleId;
+import org.apache.doris.datasource.TableFormatType;
import org.apache.doris.datasource.hive.HMSExternalCatalog;
import org.apache.doris.datasource.hive.HMSExternalTable;
import org.apache.doris.datasource.hive.HiveExternalMetaCache;
@@ -26,6 +27,7 @@ import
org.apache.doris.nereids.trees.plans.logical.LogicalFileScan.SelectedPart
import org.apache.doris.planner.PlanNodeId;
import org.apache.doris.planner.ScanContext;
import org.apache.doris.qe.SessionVariable;
+import org.apache.doris.thrift.TFileScanRangeParams;
import com.google.common.collect.ImmutableMap;
import org.junit.Assert;
@@ -115,6 +117,16 @@ public class HiveScanNodeTest {
Assert.assertFalse(node.hasPartitionPredicate());
}
+ @Test
+ public void testMarkTransactionalHiveScanParams() {
+ TFileScanRangeParams scanParams = new TFileScanRangeParams();
+ HiveScanNode.markTransactionalHiveScanParams(scanParams);
+
+ Assert.assertTrue(scanParams.isSetTableFormatParams());
+ Assert.assertEquals(TableFormatType.TRANSACTIONAL_HIVE.value(),
+ scanParams.getTableFormatParams().getTableFormatType());
+ }
+
private HiveScanNode createHiveScanNode() {
return createHiveScanNode(false);
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/qe/SessionVariablesTest.java
b/fe/fe-core/src/test/java/org/apache/doris/qe/SessionVariablesTest.java
index a8446efb451..5f86bf41f85 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/qe/SessionVariablesTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/qe/SessionVariablesTest.java
@@ -171,6 +171,16 @@ public class SessionVariablesTest extends
TestWithFeService {
}, varAttr.description());
}
+ @Test
+ public void testExternalTableBatchModeDefaultsAndFuzzyAttribute() throws
Exception {
+ SessionVariable sessionVar = new SessionVariable();
+ Assertions.assertTrue(sessionVar.getEnableExternalTableBatchMode());
+
+ Field field =
SessionVariable.class.getDeclaredField("enableExternalTableBatchMode");
+ VarAttrDef.VarAttr varAttr =
field.getAnnotation(VarAttrDef.VarAttr.class);
+ Assertions.assertTrue(varAttr.fuzzy());
+ }
+
@Test
public void testForceEagerAggHintParseWhenSetSessionVariable() throws
Exception {
SessionVariable sessionVar = new SessionVariable();
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]