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 934233d8160 [fix](regression) Stabilize external profile and VARIANT
cases (#68165)
934233d8160 is described below
commit 934233d8160e8bdfeb9f511f4453b36231880049
Author: Gabriel <[email protected]>
AuthorDate: Fri Sep 18 17:18:20 2026 +0800
[fix](regression) Stabilize external profile and VARIANT cases (#68165)
### What problem does this PR solve?
Two external regression cases rely on assumptions that no longer hold:
- The Parquet join runtime filter case requires exactly two counter
matches, so repeated profile sections fail despite sufficient filtering.
Wait for profile completion, scope counters to the fact scan, and check
the largest merged or instance value against the original thresholds
without summing duplicates.
- The remote Doris VARIANT case implicitly casts JSON text to VARIANT
and compares against obsolete output. String casts now preserve strings.
Explicitly parse valid JSON fixtures, cast numeric predicates, and
compare all eight non-Arrow queries with the internal source table. Two
known predicate-result checks prevent empty nested-path results from
passing both sides. Keep the Arrow error assertion and remove the unused
golden file.
Only regression cases and their expected-data file change.
### Release note
None
### Check List (For Author)
- Test
- [ ] Regression test
- [ ] Unit Test
- [x] Manual test
Local Groovy checks reproduced the old assertions and validated the
changes:
- Profile parsing: normal, repeated, merged, multiple-instance,
missing-counter, unrelated-table and insufficient-filtering inputs, plus
archived profiles and normalized whitespace.
- Polling: delayed completion, transient read errors and timeouts. The
full Parquet suite DSL ran with simulated SQL/profile responses for all
four queries and three wait settings.
- VARIANT suite DSL: explicit JSON parsing, SQL NULL and
malformed-string fixtures, eight matching catalog/source query pairs,
two semantic checks, ordering and the Arrow error assertion.
- Current framework result-comparison code: matching values pass; stale
output, SQL/JSON null confusion, missing/extra/reordered rows and
changed boolean values fail.
- `git diff --check` passed. Live Doris/Hive regression was not run; CI
is requested.
- Behavior changed:
- [x] No production behavior changes.
- [ ] Yes.
- Does this need documentation?
- [x] No.
- [ ] Yes.
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label
---
.../test_remote_doris_variant_select.out | 81 ----------------------
.../hive/test_parquet_join_runtime_filter.groovy | 75 ++++++++------------
.../test_remote_doris_variant_select.groovy | 70 +++++++++++++------
3 files changed, 76 insertions(+), 150 deletions(-)
diff --git
a/regression-test/data/external_table_p0/remote_doris/test_remote_doris_variant_select.out
b/regression-test/data/external_table_p0/remote_doris/test_remote_doris_variant_select.out
deleted file mode 100644
index 438583116fb..00000000000
---
a/regression-test/data/external_table_p0/remote_doris/test_remote_doris_variant_select.out
+++ /dev/null
@@ -1,81 +0,0 @@
--- This file is automatically generated. You should know what you did if you
want to edit this
--- !sql --
-1 {}
-2 \N
-3 true
-4 -17
-5 123.12
-6 1.912
-7 "A quote"
-8 [-1,12,false]
-9 {"x":"abc","y":0,"z":10}
-10 "2021-01-01"
-11 {"a":"a","b":"0.1","c":{"c1":"c1","c2":"1"}}
-12 {"a":"b","b":"0.1X","c":{"c1":"2","c2":"2"}}
-13 "{\\"a\\":\\"ab\\"cde\\", \\"b\\":NULL, \\"d\\":{\\"d1\\":NULL,
\\"d2\\":NULL}}"
-14 "{\\"a\\":\\"ab{{c\\"de\\"}}\\""
-15 "{\\"a\\":\\"abc{{{de\\""
-
--- !sql --
-11 {"a":"a","b":"0.1","c":{"c1":"c1","c2":"1"}}
-
--- !sql --
-12 {"a":"b","b":"0.1X","c":{"c1":"2","c2":"2"}}
-
--- !sql --
-\N
-\N
-\N
-\N
-\N
-\N
-\N
-\N
-\N
-\N
-a
-b
-\N
-\N
-\N
-
--- !sql --
-\N
-\N
-\N
-\N
-\N
-\N
-\N
-\N
-\N
-\N
-0.1
-0.1X
-\N
-\N
-\N
-
--- !sql --
-0.1
-
--- !sql --
-\N
-\N
-\N
-\N
-\N
-\N
-\N
-\N
-\N
-\N
-c1
-2
-\N
-\N
-\N
-
--- !sql --
-2
-
diff --git
a/regression-test/suites/external_table_p0/hive/test_parquet_join_runtime_filter.groovy
b/regression-test/suites/external_table_p0/hive/test_parquet_join_runtime_filter.groovy
index 2c1ea07576f..a9a1ca1e175 100644
---
a/regression-test/suites/external_table_p0/hive/test_parquet_join_runtime_filter.groovy
+++
b/regression-test/suites/external_table_p0/hive/test_parquet_join_runtime_filter.groovy
@@ -15,55 +15,34 @@
// specific language governing permissions and limitations
// under the License.
-import groovy.json.JsonSlurper
+import org.apache.doris.regression.action.ProfileAction
suite("test_parquet_join_runtime_filter", "p0,external") {
- def getProfileList = {
- def dst = 'http://' + context.config.feHttpAddress
- def conn = new URL(dst + "/rest/v1/query_profile").openConnection()
- conn.setRequestMethod("GET")
- def encoding =
Base64.getEncoder().encodeToString((context.config.feHttpUser + ":" +
- (context.config.feHttpPassword == null ? "" :
context.config.feHttpPassword)).getBytes("UTF-8"))
- conn.setRequestProperty("Authorization", "Basic ${encoding}")
- return conn.getInputStream().getText()
- }
-
- def getProfile = { id ->
- def dst = 'http://' + context.config.feHttpAddress
- def conn = new URL(dst +
"/api/profile/text/?query_id=$id").openConnection()
- conn.setRequestMethod("GET")
- def encoding =
Base64.getEncoder().encodeToString((context.config.feHttpUser + ":" +
- (context.config.feHttpPassword == null ? "" :
context.config.feHttpPassword)).getBytes("UTF-8"))
- conn.setRequestProperty("Authorization", "Basic ${encoding}")
- return conn.getInputStream().getText()
- }
-
+ def profileAction = new ProfileAction(context)
def extractFilteredGroupsValue = { String profileText ->
- def values = (profileText =~ /RowGroupsFiltered:\s*(\d+)/).collect {
it[1].toLong() }
+ def values = []
+ boolean inFactScan = false
+ profileText.eachLine { line ->
+ if (line =~ /^\s*[A-Z_]+_OPERATOR\(/) {
+ inFactScan = (line =~
/^\s*FILE_SCAN_OPERATOR\([^)]*\btable_name=fact_big\):/).find()
+ }
+ if (inFactScan) {
+ def counter = (line =~ /RowGroupsFiltered:\s*(?:sum\s+)?(\d+)/)
+ if (counter.find()) {
+ values.add(counter.group(1).toLong())
+ }
+ }
+ }
+ // A profile can repeat scan sections. Use the largest fact scan
count, not the
+ // number or sum of matches, so duplicates cannot inflate the
filtering result.
return values.sort { a, b -> b <=> a }
}
def getProfileWithToken = { token ->
- String profileId = ""
- int attempts = 0
- while (attempts < 10 && (profileId == null || profileId == "")) {
- List profileData = new
JsonSlurper().parseText(getProfileList()).data.rows
- for (def profileItem in profileData) {
- if (profileItem["Sql Statement"].toString().contains(token)) {
- profileId = profileItem["Profile ID"].toString()
- break
- }
- }
- if (profileId == null || profileId == "") {
- Thread.sleep(300)
- }
- attempts++
- }
- assertTrue(profileId != null && profileId != "")
- Thread.sleep(800)
- return getProfile(profileId).toString()
+ // Wait for asynchronous profile collection instead of assuming a
fixed delay is enough.
+ return profileAction.getProfileBySql(token, ["table_name=fact_big)",
"RowGroupsFiltered:"])
}
// session vars
sql "unset variable all;"
@@ -108,8 +87,8 @@ suite("test_parquet_join_runtime_filter", "p0,external") {
logger.info("sql_result = ${sql_result}");
logger.info("filter_result = ${filter_result}");
- assertTrue(filter_result.size() == 2)
- assertTrue(filter_result[0] > 40)
+ assertFalse(filter_result.isEmpty(), "Missing
RowGroupsFiltered for fact_big")
+ assertTrue(filter_result[0] > 40, "Insufficient fact_big
filtering: ${filter_result}")
}
@@ -123,8 +102,8 @@ suite("test_parquet_join_runtime_filter", "p0,external") {
logger.info("sql_result = ${sql_result}");
logger.info("filter_result = ${filter_result}");
- assertTrue(filter_result.size() == 2)
- assertTrue(filter_result[0] > 30)
+ assertFalse(filter_result.isEmpty(), "Missing
RowGroupsFiltered for fact_big")
+ assertTrue(filter_result[0] > 30, "Insufficient fact_big
filtering: ${filter_result}")
}
@@ -139,8 +118,8 @@ suite("test_parquet_join_runtime_filter", "p0,external") {
logger.info("sql_result = ${sql_result}");
logger.info("filter_result = ${filter_result}");
- assertTrue(filter_result.size() == 2)
- assertTrue(filter_result[0] > 30)
+ assertFalse(filter_result.isEmpty(), "Missing
RowGroupsFiltered for fact_big")
+ assertTrue(filter_result[0] > 30, "Insufficient fact_big
filtering: ${filter_result}")
}
@@ -154,8 +133,8 @@ suite("test_parquet_join_runtime_filter", "p0,external") {
logger.info("sql_result = ${sql_result}");
logger.info("filter_result = ${filter_result}");
- assertTrue(filter_result.size() == 2)
- assertTrue(filter_result[0] > 40)
+ assertFalse(filter_result.isEmpty(), "Missing
RowGroupsFiltered for fact_big")
+ assertTrue(filter_result[0] > 40, "Insufficient fact_big
filtering: ${filter_result}")
}
diff --git
a/regression-test/suites/external_table_p0/remote_doris/test_remote_doris_variant_select.groovy
b/regression-test/suites/external_table_p0/remote_doris/test_remote_doris_variant_select.groovy
index c9718856902..23bd689eddd 100644
---
a/regression-test/suites/external_table_p0/remote_doris/test_remote_doris_variant_select.groovy
+++
b/regression-test/suites/external_table_p0/remote_doris/test_remote_doris_variant_select.groovy
@@ -54,20 +54,21 @@ suite("test_remote_doris_variant_select", "p0,external") {
);
"""
+ // String-to-VARIANT casts preserve strings; parse JSON explicitly to
exercise nested paths.
sql """
INSERT INTO `${db_name}`.`test_remote_doris_variant_select_t` values
- (1, 'null'),
+ (1, parse_to_variant('null')),
(2, NULL),
- (3, 'true'),
- (4, '-17'),
- (5, '123.12'),
- (6, '1.912'),
- (7, '"A quote"'),
- (8, '[-1, 12, false]'),
- (9, '{ "x": "abc", "y": false, "z": 10 }'),
- (10, '"2021-01-01"'),
- (11, '{"a":"a", "b":"0.1", "c":{"c1":"c1", "c2":"1"}}'),
- (12, '{"a":"b", "b":"0.1X", "c":{"c1":"2", "c2":"2"}}'),
+ (3, parse_to_variant('true')),
+ (4, parse_to_variant('-17')),
+ (5, parse_to_variant('123.12')),
+ (6, parse_to_variant('1.912')),
+ (7, parse_to_variant('"A quote"')),
+ (8, parse_to_variant('[-1, 12, false]')),
+ (9, parse_to_variant('{ "x": "abc", "y": false, "z": 10 }')),
+ (10, parse_to_variant('"2021-01-01"')),
+ (11, parse_to_variant('{"a":"a", "b":"0.1", "c":{"c1":"c1",
"c2":"1"}}')),
+ (12, parse_to_variant('{"a":"b", "b":"0.1X", "c":{"c1":"2",
"c2":"2"}}')),
(13, '{"a":"ab\\"cde", "b":NULL, "d":{"d1":NULL, "d2":NULL}}'),
(14, '{"a":"ab{{c\\"de\\"}}"'),
(15, '{"a":"abc{{{de"');
@@ -104,8 +105,21 @@ suite("test_remote_doris_variant_select", "p0,external") {
);
"""
- qt_sql """
+ // Keep nested-path coverage non-empty before comparing catalog reads with
the source table.
+ check_sqls_result_equal """
+ select id from
`internal`.`${db_name}`.`test_remote_doris_variant_select_t`
+ where cast(v['b'] as double) >= 0 order by id
+ """, "select 11"
+ check_sqls_result_equal """
+ select id from
`internal`.`${db_name}`.`test_remote_doris_variant_select_t`
+ where cast(v['c']['c2'] as int) > 1 order by id
+ """, "select 12"
+
+ // Compare with the source instead of golden text tied to an older VARIANT
representation.
+ check_sqls_result_equal """
select * from
`${catalog_name}`.`${db_name}`.`test_remote_doris_variant_select_t` order by id
+ """, """
+ select * from
`internal`.`${db_name}`.`test_remote_doris_variant_select_t` order by id
"""
test {
sql """
@@ -116,32 +130,46 @@ suite("test_remote_doris_variant_select", "p0,external") {
+ "file format ARROW is not supported")
}
- qt_sql """
- select * from
`${catalog_name}`.`${db_name}`.`test_remote_doris_variant_select_t` where
v['b'] >= 0 order by id
+ check_sqls_result_equal """
+ select * from
`${catalog_name}`.`${db_name}`.`test_remote_doris_variant_select_t` where
cast(v['b'] as double) >= 0 order by id
+ """, """
+ select * from
`internal`.`${db_name}`.`test_remote_doris_variant_select_t` where cast(v['b']
as double) >= 0 order by id
"""
- qt_sql """
- select * from
`${catalog_name}`.`${db_name}`.`test_remote_doris_variant_select_t` where
v['c']['c2'] > 1 order by id
+ check_sqls_result_equal """
+ select * from
`${catalog_name}`.`${db_name}`.`test_remote_doris_variant_select_t` where
cast(v['c']['c2'] as int) > 1 order by id
+ """, """
+ select * from
`internal`.`${db_name}`.`test_remote_doris_variant_select_t` where
cast(v['c']['c2'] as int) > 1 order by id
"""
- qt_sql """
+ check_sqls_result_equal """
select v['a'] from
`${catalog_name}`.`${db_name}`.`test_remote_doris_variant_select_t` order by id
+ """, """
+ select v['a'] from
`internal`.`${db_name}`.`test_remote_doris_variant_select_t` order by id
"""
- qt_sql """
+ check_sqls_result_equal """
select v['b'] from
`${catalog_name}`.`${db_name}`.`test_remote_doris_variant_select_t` order by id
+ """, """
+ select v['b'] from
`internal`.`${db_name}`.`test_remote_doris_variant_select_t` order by id
"""
- qt_sql """
+ check_sqls_result_equal """
select sum(cast(v['b'] as double)) from
`${catalog_name}`.`${db_name}`.`test_remote_doris_variant_select_t`
+ """, """
+ select sum(cast(v['b'] as double)) from
`internal`.`${db_name}`.`test_remote_doris_variant_select_t`
"""
- qt_sql """
+ check_sqls_result_equal """
select v['c']['c1'] from
`${catalog_name}`.`${db_name}`.`test_remote_doris_variant_select_t` order by id
+ """, """
+ select v['c']['c1'] from
`internal`.`${db_name}`.`test_remote_doris_variant_select_t` order by id
"""
- qt_sql """
+ check_sqls_result_equal """
select sum(cast(v['c']['c1'] as double)) from
`${catalog_name}`.`${db_name}`.`test_remote_doris_variant_select_t`
+ """, """
+ select sum(cast(v['c']['c1'] as double)) from
`internal`.`${db_name}`.`test_remote_doris_variant_select_t`
"""
sql """ DROP DATABASE IF EXISTS `${db_name}` """
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]