Skip to content

[fix](join) preserve decimal precision for string comparison#65693

Open
yx-keith wants to merge 6 commits into
apache:masterfrom
yx-keith:master-join-cast-fix
Open

[fix](join) preserve decimal precision for string comparison#65693
yx-keith wants to merge 6 commits into
apache:masterfrom
yx-keith:master-join-cast-fix

Conversation

@yx-keith

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: close #xxx

Related PR: #xxx

Problem Summary:

Release note

None

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason
  • Behavior changed:

    • No.
    • Yes.
  • Does this need documentation?

    • No.
    • Yes.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@yx-keith

Copy link
Copy Markdown
Contributor Author

/review

1 similar comment
@yx-keith

Copy link
Copy Markdown
Contributor Author

/review

@yx-keith

Copy link
Copy Markdown
Contributor Author

run buildall

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: the new lossless comparison mode has nine correctness gaps across SQL NULL semantics, BE memory safety, cache/clone identity, parser boundaries, predicate families, type-domain coverage, complex types, and COPY INTO translation.

Accepted issues:

  1. Conversion rejection is encoded as SQL NULL, breaking <=> and typed NOT IN.
  2. Rejected/source-NULL rows leave nested decimal storage uninitialized before comparison kernels read it.
  3. VCastExpr::get_digest() aliases ordinary and lossless predicates in the condition cache.
  4. Generic and format-v2 clone paths discard the mode and can prefilter an exact external-file match.
  5. Independent 1024 caps reject exact scientific values whose offsets cancel.
  6. Range/BETWEEN predicates use the changed common type but still round at full-width decimal boundaries.
  7. LARGEINT is narrowed to a decimal type with only 38 integer digits although its domain needs 39.
  8. Array/struct common-type recursion never enables lossless nested conversion.
  9. COPY INTO's translator override drops the flag.

Critical checkpoint conclusions:

  • Goal and proof: the patch fixes the covered decimal/string join happy path, but does not accomplish the goal end to end because the cases above still miss matches or return false matches/NULL. The added tests prove only type shape, scalar parsing, and two happy-path counts.
  • Focus and clarity: the change is conceptually focused, but a semantic expression flag necessarily spans planner reconstruction, FE-to-BE translation, BE cloning, digest identity, and alternate scan/load paths; several required paths were missed.
  • Concurrency: the new state is per-expression/per-FunctionContext and the clone copies the context flag; no shared mutable-state, lock-order, or deadlock issue was found.
  • Lifecycle: prepare/open/clone lifecycles were traced. No static-initialization or release issue was found, but expression cloning loses the semantic field as noted inline.
  • Configuration: no new setting is added. Existing decimal256 and old/new coercion modes were checked; the boundary defects persist or move to the wider limit.
  • Compatibility: the optional Thrift field is compatible with Doris's documented BE-then-FE upgrade order; a proposed reverse-order concern was dismissed with repository evidence.
  • Parallel paths: ordering/BETWEEN, complex values, COPY INTO, and external-file localization are concrete missed paths.
  • Conditional checks: the new exactness precheck is understandable, but its independent fixed caps are not equivalent to the parser's combined decimal-point calculation.
  • Test coverage/results: expected counts in the new regression are consistent for its inputs, but negative coverage is not comprehensive. Missing cases include <=>, typed NOT IN, range/BETWEEN, LARGEINT extrema, nested complex values, external files, COPY INTO, cache identity, vectorized NULL/failure rows, and long cancelling exponents. The regression also uses inline test/result assertions and drops tables afterward instead of the repository's requested generated ordered result pattern/debug-preserving cleanup.
  • Observability: no new metrics/logging requirement was identified; these are deterministic result-correctness paths best covered by tests.
  • Transactions, persistence, and data writes: no transaction/edit-log/storage-format mutation is introduced.
  • FE/BE propagation: the ordinary Nereids translator and Thrift path carry the flag, but COPY INTO and BE clone/localization paths do not.
  • Performance: no separate performance blocker was established. The extra string precheck is linear; condition-cache identity is a correctness defect, not merely a cache-efficiency concern.
  • Other issues: BE nullable payload memory safety and live cache reuse are covered by the inline findings.

Validation was static-only as required by the review task; no build or test command was run. Live CI currently shows FE UT failed (the linked log requires authentication), two Clang Formatter jobs failed, and CheckStyle passed. The macOS BE UT failure is an environment setup/JDK mismatch; BE UT, compile, Cloud UT, and performance remain pending. No user focus area was supplied.

right = castIfNotSameType(right, commonType.get());
boolean losslessDecimalCast = comparisonPredicate instanceof EqualPredicate;
left = castComparisonOperand(left, commonType.get(), losslessDecimalCast);
right = castComparisonOperand(right, commonType.get(), losslessDecimalCast);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[correctness] Keep conversion rejection distinct from SQL NULL. NullSafeEqual is an EqualPredicate, so this analyzes (decimal_col <=> string_col) as NullSafeEqual(decimal_col, LosslessCast(string_col AS DECIMAL(38,0))). For a row (NULL, '100.4'), the cast marks the non-null string NULL because scale 0 cannot represent it, and eq_for_null then returns true because both null maps are set. The same sentinel makes CAST(100 AS DECIMAL(38,0)) NOT IN ('100.4') evaluate UNKNOWN instead of true. Please preserve source NULL separately from an inexact non-match (or use comparison-specific failure handling), and cover both <=> and typed NOT IN regressions.

size_t next_offset = offsets[i];
size_t string_size = next_offset - current_offset;
bool source_is_null = null_map != nullptr && null_map[i];
null_map_to[i] = source_is_null

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[correctness] Initialize the nested decimal slot on every NULL/failure path. nullable_to.resize() reaches PODArray::resize(), which only advances the end pointer. Here source_is_null || ... skips parsing for source NULLs, and from_string_lossless() returns before writing values_to[i] for rejected strings. Existing eq and eq_for_null paths evaluate the nested decimal vectors before applying their null maps, so these rows read indeterminate storage (UB/MSAN failure) even when the final value is NULL. Write a decimal default before the short circuit or on both failure paths, and add a vectorized test with source NULL and an inexact string.

Comment thread be/src/exprs/vcast_expr.h
std::string _target_data_type_name;

DataTypePtr _cast_param_data_type;
bool _lossless_decimal_cast = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[correctness] Include this mode in VCastExpr::get_digest(). The current digest hashes the child/base expression and target type only, so ordinary and lossless casts collide despite different results. For a granule containing (d=100, s='100.4'), the implicit lossless predicate can cache the granule as all-false; a later explicit d = CAST(s AS DECIMAL(38,0)) has the same condition-cache key even though ordinary casting rounds and should match, so the cached bitmap suppresses the row. Hash _lossless_decimal_cast (or disable condition caching for this mode) and add a digest/cache distinction test.

Comment thread be/src/exprs/vcast_expr.h
#endif
VCastExpr(const TExprNode& node) : VExpr(node) {}
VCastExpr(const TExprNode& node)
: VExpr(node), _lossless_decimal_cast(node.lossless_decimal_cast) {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[correctness] Preserve the lossless mode in prefilter clones. VCastExpr::clone_node() rebuilds from clone_texpr_node(), which omits this field, while the format-v2 override recreates a cast from only its target type. For an external row (d=0, s='0e2147483648'), the original lossless cast treats zero as exact and accepts the parser's overflow status as value 0, but the localized ordinary cast returns NULL and filters the row before Scanner::_filter_output_block() can run the original residual. Copy the flag through both clone paths or refuse localization, and add this external-file false-negative regression.

}
++pos;
}
if (exponent_magnitude > max_relevant_exponent) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[correctness] Combine the exponent and significand offset before applying a cap. For example, "0." + 1024 zeroes + "1e1025" is only 1032 bytes and equals exactly 1, which the existing StringParser accepts. This branch rejects every nonzero exponent above 1024 before adding the opposite base_decimal_point, so the new lossless equality turns that exact value into NULL and misses a match. Use overflow-safe signed arithmetic for the combined decimal-point position, and test large positive and negative offsets that cancel.

}
left = castIfNotSameType(left, commonType.get());
right = castIfNotSameType(right, commonType.get());
boolean losslessDecimalCast = comparisonPredicate instanceof EqualPredicate;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[correctness] Do not use the scale-exhausted equality type for ordering. The new numeric/string common type also reaches <, <=, >, >=, and BETWEEN, but this flag is enabled only for equality. With DECIMAL(38,0), the common type remains scale 0, so ordinary parsing rounds '100.4' to 100: 100 >= '100.4' becomes true and 100 < '100.4' becomes false. Decimal256 just moves the same boundary to DECIMAL(76,0). Preserve enough information to order the fractional string without rounding, and add range/BETWEEN boundary tests in both coercion modes.

}

private static DecimalV3Type getNumericStringComparisonType(NumericType numericType) {
DecimalV3Type decimalType = DecimalV3Type.forType(numericType);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[correctness] Preserve the full LARGEINT integer range here. DecimalV3Type.forType(LargeIntType) is DECIMAL(38,0), but signed LARGEINT extrema require 39 digits. This helper therefore chooses DECIMAL(38,0) with decimal256 off, or e.g. DECIMAL(44,6) with it on—still only 38 integer digits. The analyzed tree casts both the LARGEINT slot and string slot to that type, so a maximum LARGEINT and its identical text overflow to NULL instead of matching. Derive capacity from the actual 39-digit range (with a non-narrowing fallback when decimal256 is unavailable) and test both extrema under both settings.


private static Expression castComparisonOperand(
Expression input, DataType targetType, boolean losslessDecimalCast) {
if (losslessDecimalCast && input.getDataType().isStringLikeType()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[correctness] Apply lossless coercion recursively for complex comparison types. Common-type derivation recurses, so ARRAY<DECIMAL(38,0)> = ARRAY<STRING> becomes an outer cast to ARRAY<DECIMAL(38,0)>; this scalar-only check sees neither an outer string nor an outer decimal and creates an ordinary cast. BE then rounds the nested '100.4' to 100, making [100] = ['100.4'] true. Struct-valued IN has the same gap. Detect nested numeric/string coercion and mark the containing cast (the BE wrapper propagates its context), or reject these shapes until supported; add array equality and struct-IN controls.

// left child of cast is expression, right child of cast is target type
CastExpr castExpr = new CastExpr(cast.getDataType().toCatalogDataType(),
cast.child().accept(this, context), cast.nullable());
cast.child().accept(this, context), cast.nullable(), cast.isLosslessDecimalCast());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[correctness] Update the COPY INTO visitCast override as well. CopyIntoInfo.ExpressionToExpr analyzes file filters/column mappings with this coercion, but then reconstructs every cast with the three-argument CastExpr constructor, which defaults losslessDecimalCast to false. A numeric/string file filter therefore reaches BE as ordinary CAST and can round '100.4' to scale-zero 100. Forward both isLosslessDecimalCast() and the implicit/explicit bit there (or delegate to this implementation), and add a COPY INTO translation/end-to-end regression.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes. Nine correctness comments landed on the unchanged head while this review was in progress; I reread them and suppressed every overlap. This review adds two distinct issues below.

Review completeness: the third and final allowed convergence round produced the nested-column-pruning finding below. All currently known candidates have clear dispositions, but because a valuable candidate appeared at the three-round cap, this review is incomplete under the automated-review contract.

Critical checkpoint conclusions:

  • Goal and proof: The direct scalar = join examples are improved and their new counts are internally consistent, but the live threads show incomplete null-aware, range, LARGEINT, nested-type, parser, copy/clone, cache, and COPY INTO behavior. The additional inline findings show that reusable server-prepared point queries bypass the semantics and nested-column pruning later erases the marker.
  • Scope and focus: Marker propagation is localized in the direct path, but common-type selection changes non-equality comparisons and several parallel execution/translation/rewrite paths were not updated. The implementation is not yet focused enough to preserve existing semantics outside the target case.
  • Concurrency: No new threads, shared mutable state, locks, or lock-order concerns are introduced.
  • Lifecycle: Direct VCastExpr::prepare and FunctionContext::clone setup is sound. Existing live threads cover lost mode in BE/file-local copies, while the new pruning comment covers a later FE expression lifecycle; no static-initialization or ownership-cycle issue was found.
  • Configuration: No configuration item is added. Existing Decimal256/overflow-scale and nested-pruning settings affect behavior, and the tests do not cover the important on/off boundaries.
  • Compatibility: The optional Thrift field is backward-readable, old-FE/new-BE safely defaults false, and the documented BE-first/FE-last rolling-upgrade order avoids the unsafe direction. No supported-upgrade blocker was retained.
  • Parallel paths and conditions: Existing threads cover null-safe/IN behavior, ordering, LARGEINT, outer nested casts, COPY INTO, BE clones/digests, nullable storage, and exponent cancellation. The two comments below add cached prepared point-query reuse and nested-column-pruning reconstruction.
  • Tests and expected results: Added scalar join counts look correct, but negative/end-to-end coverage is incomplete. No build was run because this review runner explicitly prohibits builds. CheckStyle and Cloud UT pass; both Clang Formatter checks fail, and a local non-mutating clang-format dry run confirms violations in changed C++ files. FE UT and BE UT are failing; compile and performance checks are still pending at review time.
  • Observability: No new persistent operational state needs logs or metrics; existing query diagnostics are sufficient once the semantic gaps are fixed.
  • Transactions, persistence, and writes: No EditLog, visible-version, delete-bitmap, transaction atomicity, or crash-recovery behavior is changed.
  • FE-to-BE passage: Direct expression translation, Thrift serialization, BE construction, and function-context setup carry the flag. Existing threads and the new comments identify incomplete semantic copy/identity, rewrite, and alternate serialization paths.
  • Performance and safety: The validator adds a linear lexical pass before parsing, but no independent performance, memory-tracking, or unchecked-Status blocker was substantiated. A live thread already covers the nested-column initialization safety issue.
  • User focus: No additional focus points were supplied; the full PR was reviewed.

The regression also drops tables at suite end instead of preserving them for debugging, and the changed C++ files need repository formatting before merge.

left = castIfNotSameType(left, commonType.get());
right = castIfNotSameType(right, commonType.get());
boolean losslessDecimalCast = comparisonPredicate instanceof EqualPredicate;
left = castComparisonOperand(left, commonType.get(), losslessDecimalCast);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Apply lossless coercion to cached point parameters

A cached server-prepared point query never reaches this coercion on later executions. For a row-store MOW table with a DECIMAL(38,0) key 100, execute WHERE k = ? once with VARCHAR 100 to cache the plan, then again with VARCHAR 100.4. ExecuteCommand reuses the context, PointQueryExecutor substitutes the raw string and serializes a DECIMAL_LITERAL, and BE's schema-scale decimal parser rounds it to key 100, returning a row that the uncached lossless predicate rejects. Validate replacement values losslessly before point-key serialization or invalidate/replan, and add this two-execution regression.

public Cast withChildren(List<Expression> children) {
Preconditions.checkArgument(children.size() == 1);
return new Cast(children, targetType, isExplicitType);
return new Cast(children, targetType, isExplicitType, losslessDecimalCast);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve lossless mode in nested-column pruning rewrites

This withChildren path now keeps the flag, but default nested-column pruning bypasses it. For k DECIMAL(38,0) = s.a with s STRUCT<a:STRING,...>, pruning rewrites the struct slot/ElementAt; SlotTypeReplacer.rewriteCast then rebuilds the marked scalar cast with new Cast(newChild, newType), whose constructor resets losslessDecimalCast to false. A row with k=100 and s.a='100.4' is consequently rounded and falsely matches. Preserve the original explicit/lossless attributes in that rewrite and add a pruning-enabled STRUCT/MAP/ARRAY field regression.

@yx-keith

Copy link
Copy Markdown
Contributor Author

/review

@yx-keith

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.62% (1908/2458)
Line Coverage 64.46% (34141/52966)
Region Coverage 64.86% (17561/27076)
Branch Coverage 54.04% (9416/17424)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review result: REQUEST_CHANGES

Review completed against c93579194bc8f2254a38b8a5d5afa23fd3d202d4. Three new, non-duplicate blocking issues remain: malformed overflowing exponents can become exact zero matches; external predicate translation can erase the exact-cast semantics before a pushed LIMIT; and the lossless wrapper silently bypasses enable_strict_cast. After the M2 proof example was corrected, all three final-round review tracks returned NO_NEW_VALUABLE_FINDINGS for the same bodies and anchors.

Critical checkpoint conclusions:

  • Goal and proof: The patch's goal is exact DECIMAL/STRING equality without rounding. The normal Nereids-to-Thrift-to-BE path implements that goal for the basic join cases, and the added counts are correct, but M1-M3 show the proof is incomplete at lexical validation, external execution, and strict-mode boundaries.
  • Scope and focus: The cross-layer flag changes are mostly focused and reuse existing cast machinery. The same-version reconstruction fixes cover normal/COPY translation, nested-slot replacement, folding, simplification, point-query recognition, BE cloning, and format-v2 localization. Generic external cast consumers were not included, producing M2.
  • Concurrency and thread safety: No new threads, shared mutable state, lock ordering, or atomic synchronization are introduced. The FE expression attribute and BE function-context flag are per-plan/per-context state.
  • Lifecycle and ownership: Cast, function-context, and format-v2 clone/prepare lifecycles were traced. Same-version clones preserve the flag, nullable storage is initialized on rejection paths, and no new ownership cycle, static initialization, or teardown issue remains.
  • Configuration: No new configuration is added. Existing decimal_overflow_scale influences the comparison type as designed, but the existing enable_strict_cast contract is bypassed by the new branch (M3).
  • Compatibility: Optional Thrift field 43 defaults safely on a new BE, and the documented BE-then-FE rolling order does not require new-FE/old-BE execution. Independent older Remote Doris endpoints remain a supported external surface and can apply pre-fix coercion after the cast is stripped, which is part of M2.
  • Parallel paths and conditions: Normal/COPY translators, runtime filters, predicate inference, partition evaluation, fresh point queries, prepared-query context, format-v2 residuals, ORC/Parquet pruning, and cache digests were checked. Known prepared, NULL-semantics, range, complex-type, and nested-pruning cases were deduplicated against existing threads. The distinct missed parallel path is external SQL/connector translation plus remote LIMIT.
  • Conditional logic: The EqualTo-only marking and exactness arithmetic were traced across DecimalV2/V3 and decimal128/256 boundaries. The exponent-overflow early return is not grammar-safe (M1), and lossless-before-strict precedence changes error behavior (M3).
  • Test coverage: Unit and regression tests cover representative exact/inexact strings and two join counts, but they do not cover malformed suffixes after exponent overflow, strict-mode expected errors, or external predicate plus LIMIT. The trailing table drops also depart from the repository's preferred test-cleanup form, although a failing assertion exits before them and preserves failure state; this was treated as nonblocking hygiene.
  • Test results: No local build or repository test command was run because the review contract explicitly forbids builds. A standalone 500,000-case exact-rational property check found no bounded-valid mismatch beyond the malformed huge-exponent-zero family. Current CI has CheckStyle, both Clang Formatter jobs, Cloud UT, license, secrets, and dependency checks passing; macOS BE UT failed because the runner selected JDK 25 instead of required JDK 17, while BE UT, FE UT, compile, and performance jobs remain pending.
  • Observability: This change adds expression semantics rather than a new long-running or distributed state machine; existing query errors/explain/debug paths are sufficient once correctness is fixed. No new metric or log is required.
  • Transactions, persistence, and data writes: No production transaction, EditLog, persisted metadata, storage format, or write atomicity path is changed.
  • FE-BE propagation: Same-version FE-to-BE transport, legacy CastExpr clone/Gson state, VCastExpr, FunctionContext, format-v2 clones, equality/hash, and condition-cache digesting preserve the bit. M2 is specifically outside that path: external translators unwrap the semantic cast.
  • Performance: The validator adds a linear scan and the selected decimal type can widen join keys, but no independent safe optimization was established: narrowing the type under the current nullable-cast encoding would turn more unequal finite fractions from false into NULL. No additional blocking CPU, allocation, or memory-lifetime issue was found.
  • Other correctness: M1 is distinct from the existing valid cancelling-exponent thread because it accepts malformed input rather than rejecting valid input. M3 is distinct from the existing SQL-NULL thread because it changes query failure into success for ordinary equality.

User-provided focus: no additional focus points were supplied; the complete PR was reviewed.

// left child of cast is expression, right child of cast is target type
CastExpr castExpr = new CastExpr(cast.getDataType().toCatalogDataType(),
cast.child().accept(this, context), cast.nullable());
cast.child().accept(this, context), cast.nullable(), cast.isLosslessDecimalCast());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Keep this semantic cast out of generic remote pushdown — This bit survives BE translation here, but both ExprToExternalSqlVisitor and ExprToConnectorExpressionConverter erase every CastExpr. Remote Doris/JDBC can therefore execute a lossy d = s predicate and also receive the scan LIMIT. For remote rows (9007199254740992,'9007199254740992.0000004') before the exact (9007199254740992,'9007199254740992'), legacy DOUBLE coercion loses the fraction and the newer pre-fix fixed-numeric path rounds it at scale six, so WHERE d = s LIMIT 1 can return only the false positive; the local lossless residual drops it and cannot recover the exact row. Please preserve an equivalent exact predicate only for connectors that support it, or leave this as a local residual and suppress remote LIMIT pushdown.

if constexpr (type_allow_cast_to_decimal<FromDataType>) {
if (context->enable_strict_mode()) {
if constexpr (std::is_same_v<FromDataType, DataTypeString>) {
if (context->enable_lossless_decimal_cast()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve strict-cast failures in lossless comparisons — Because this branch runs before enable_strict_mode(), a marked comparison under enable_strict_cast=true no longer uses from_string_strict_mode_batch: malformed text such as 100abc and decimal overflow become NULL non-matches instead of failing the query. The new regression explicitly demonstrates that behavior, but it contradicts the existing session contract (“Use strict mode for cast”) and changes failure into silent success. Please keep strict lexical/overflow errors while separately rejecting well-formed but inexact comparison values, and add expected-error coverage.

return false;
}
if (exponent_magnitude > (std::numeric_limits<int64_t>::max() - (ch - '0')) / 10) {
return first_non_zero == 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Finish validating the exponent before accepting zero — For 0e9223372036854775808x, this returns true as soon as the exponent overflows because the significand is zero, without ever validating the trailing x. StringParser::string_to_decimal also stops at its smaller exponent cap, returns PARSE_OVERFLOW with value 0, and from_string_lossless accepts that status, so this malformed VARCHAR becomes a non-NULL zero and incorrectly matches DECIMAL zero. Please keep scanning the exponent grammar after magnitude overflow and only accept zero once the whole token is valid; this is the opposite direction from the existing cancelling-exponent thread.

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29683 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit c93579194bc8f2254a38b8a5d5afa23fd3d202d4, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17735	4114	4107	4107
q2	2032	328	206	206
q3	10249	1459	873	873
q4	4685	497	344	344
q5	7523	853	575	575
q6	185	169	135	135
q7	774	813	603	603
q8	9343	1614	1632	1614
q9	5588	4379	4341	4341
q10	6780	1727	1487	1487
q11	504	360	318	318
q12	753	577	456	456
q13	18109	3587	2781	2781
q14	265	269	250	250
q15	q16	788	789	710	710
q17	949	1019	1001	1001
q18	7106	5829	5592	5592
q19	1174	1147	1056	1056
q20	809	703	547	547
q21	5526	2593	2385	2385
q22	435	361	302	302
Total cold run time: 101312 ms
Total hot run time: 29683 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4415	4364	4463	4364
q2	303	314	215	215
q3	4670	4982	4379	4379
q4	2070	2166	1379	1379
q5	4411	4320	4287	4287
q6	227	176	129	129
q7	1712	2027	1790	1790
q8	2593	2287	2200	2200
q9	8062	8140	7746	7746
q10	4743	4733	4237	4237
q11	572	446	393	393
q12	759	780	566	566
q13	3310	3596	3046	3046
q14	314	311	289	289
q15	q16	706	722	648	648
q17	1371	1387	1384	1384
q18	7946	7376	7421	7376
q19	1178	1124	1078	1078
q20	2211	2223	1946	1946
q21	5271	4622	4443	4443
q22	520	458	400	400
Total cold run time: 57364 ms
Total hot run time: 52295 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 177996 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit c93579194bc8f2254a38b8a5d5afa23fd3d202d4, data reload: false

query5	4367	637	491	491
query6	465	226	209	209
query7	4931	632	333	333
query8	343	194	169	169
query9	8757	4123	4161	4123
query10	470	355	341	341
query11	5914	2329	2141	2141
query12	160	105	104	104
query13	1344	628	465	465
query14	6262	5265	4931	4931
query14_1	4302	4283	4310	4283
query15	221	216	181	181
query16	1014	493	481	481
query17	957	711	584	584
query18	2476	467	360	360
query19	225	195	154	154
query20	111	111	108	108
query21	236	163	140	140
query22	13613	13550	13325	13325
query23	17414	16587	16158	16158
query23_1	16265	16268	16239	16239
query24	7557	1767	1277	1277
query24_1	1319	1292	1277	1277
query25	571	465	398	398
query26	1346	367	220	220
query27	2652	630	389	389
query28	4493	2000	1982	1982
query29	1079	645	507	507
query30	342	262	230	230
query31	1115	1093	987	987
query32	121	70	62	62
query33	539	334	271	271
query34	1215	1177	655	655
query35	808	816	698	698
query36	1211	1204	1055	1055
query37	162	119	96	96
query38	1927	1726	1656	1656
query39	891	865	851	851
query39_1	827	853	834	834
query40	243	161	142	142
query41	66	68	63	63
query42	92	92	91	91
query43	325	337	281	281
query44	1399	769	763	763
query45	194	185	173	173
query46	1032	1247	759	759
query47	2112	2138	1969	1969
query48	414	433	302	302
query49	580	405	304	304
query50	1151	422	336	336
query51	10931	10670	10668	10668
query52	90	89	74	74
query53	264	274	209	209
query54	282	231	214	214
query55	75	69	67	67
query56	286	295	289	289
query57	1314	1291	1223	1223
query58	286	271	264	264
query59	1582	1655	1403	1403
query60	300	280	256	256
query61	154	151	152	151
query62	551	497	435	435
query63	244	200	204	200
query64	2848	1077	861	861
query65	4742	4611	4630	4611
query66	1820	496	375	375
query67	29342	29292	29085	29085
query68	3334	1510	1019	1019
query69	422	292	269	269
query70	1083	977	962	962
query71	367	318	322	318
query72	3141	2746	2373	2373
query73	818	771	436	436
query74	5144	5040	4740	4740
query75	2534	2491	2143	2143
query76	2329	1201	753	753
query77	361	378	281	281
query78	12005	11945	11305	11305
query79	1412	1135	699	699
query80	623	560	465	465
query81	449	328	282	282
query82	566	157	123	123
query83	413	328	292	292
query84	334	160	127	127
query85	953	628	519	519
query86	378	277	288	277
query87	1825	1829	1760	1760
query88	3712	2762	2767	2762
query89	433	378	331	331
query90	1964	200	198	198
query91	203	194	167	167
query92	67	61	57	57
query93	1686	1523	947	947
query94	545	366	309	309
query95	827	507	554	507
query96	1107	799	351	351
query97	2655	2603	2477	2477
query98	211	206	196	196
query99	1098	1110	959	959
Total cold run time: 264118 ms
Total hot run time: 177996 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 25.16 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit c93579194bc8f2254a38b8a5d5afa23fd3d202d4, data reload: false

query1	0.01	0.01	0.01
query2	0.11	0.05	0.05
query3	0.26	0.13	0.13
query4	1.62	0.14	0.13
query5	0.24	0.23	0.23
query6	1.26	1.10	1.10
query7	0.04	0.01	0.01
query8	0.05	0.04	0.05
query9	0.41	0.31	0.30
query10	0.54	0.56	0.54
query11	0.21	0.14	0.14
query12	0.19	0.14	0.14
query13	0.47	0.46	0.46
query14	1.03	1.00	1.02
query15	0.61	0.58	0.60
query16	0.32	0.31	0.32
query17	1.08	1.13	1.18
query18	0.24	0.22	0.21
query19	2.12	1.98	1.98
query20	0.02	0.01	0.02
query21	15.46	0.23	0.13
query22	4.86	0.06	0.05
query23	16.06	0.31	0.12
query24	2.83	0.42	0.36
query25	0.12	0.05	0.05
query26	0.73	0.20	0.14
query27	0.04	0.04	0.04
query28	3.52	0.96	0.52
query29	12.47	4.04	3.27
query30	0.28	0.15	0.15
query31	2.78	0.58	0.32
query32	3.23	0.58	0.48
query33	3.22	3.19	3.23
query34	15.56	4.22	3.50
query35	3.48	3.52	3.52
query36	0.58	0.45	0.43
query37	0.11	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.18	0.16	0.16
query41	0.08	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 96.59 s
Total hot run time: 25.16 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 66.30% (122/184) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 57.45% (23942/41676)
Line Coverage 41.19% (235527/571835)
Region Coverage 37.01% (186064/502700)
Branch Coverage 38.14% (83385/218644)

@yx-keith

Copy link
Copy Markdown
Contributor Author

/review

@yx-keith

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.62% (1908/2458)
Line Coverage 64.45% (34138/52966)
Region Coverage 64.90% (17571/27076)
Branch Coverage 54.07% (9422/17424)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review result: COMMENT — no new non-duplicate inline findings

Reviewed head 81c97d5c9db1dafcef62c6918908a9779c998d3b against the authoritative 26-file patch and all 14 existing inline threads. After a main scan, three independent reviews, deduplication, and convergence, no additional inline issue survived. This is not an approval: the remaining blocking correctness concerns are already covered by existing threads, notably conversion rejection leaking SQL NULL semantics, nested complex comparisons, prepared point-query reuse, remote predicate/LIMIT pushdown, strict-cast error suppression, and malformed huge exponents. Reposting them would duplicate the current review context.

Current-head progress: the patch now narrows the feature to ordinary EqualTo, initializes rejected decimal payloads, preserves the marker through FE/BE and format-v2 clones, includes it in the scanner digest, carries it through COPY and nested-slot rewrites, skips unsafe fold/simplify and the direct marked point-query shortcut, and fixes cancelling exponents. Those changes address the corresponding earlier comments.

Critical checkpoint conclusions:

  • Goal and proof: The scalar decimal/string equality path now prevents rounded false matches and has BE helper, FE coercion/Thrift, and hash-join regression coverage. The goal is not yet complete because the existing correctness threads above remain unresolved, and negative coverage does not exercise those paths.
  • Scope and clarity: The implementation is cross-layer but focused on one semantic marker and the reconstruction/serialization paths that must preserve it. No unrelated production behavior was found.
  • Concurrency: No new shared mutable state, thread entry, lock, atomic, or lock-order dependency is introduced. The mode is immutable per expression and copied into thread-local FunctionContext clones.
  • Lifecycle: Expression/function-context preparation and clone lifetimes were traced through ordinary execution and format-v2 localization. No new static-initialization, ownership cycle, cleanup, or shutdown boundary is added; changed Status results are propagated.
  • Configuration: No configuration item is added. Existing enable_decimal256, decimal_overflow_scale, strict-cast, and coercion settings affect planning/execution as expected, subject to the existing strict-mode comment.
  • Compatibility: Optional Thrift field 43 defaults false for older senders. A new FE has no old-BE field gate, but the supported BE-first cluster-upgrade sequence excludes that execution state; no storage/function-symbol compatibility change is introduced.
  • Parallel paths and conditions: Generic/COPY translation, expression and slot reconstruction, folding, simplification, runtime-filter translation, point-query eligibility, format-v2 localization, residual filtering, and cache identity were checked. Still-live remote, complex, prepared-parameter, NULL, and strict/error variants are existing-thread duplicates. The EqualTo eligibility condition is clear but does not by itself resolve those existing families.
  • Tests/results: Added tests cover the core helper, FE coercion/marker/Thrift behavior, both coercion settings, and one end-to-end hash join. They do not comprehensively cover existing negative/error/NULL/remote/point/complex/format-v2 cases. No local build or test was run because the review contract prohibits it. At submission time, style checks pass; COMPILE, performance, and macOS BE UT are failing, while Linux BE UT and FE UT are pending.
  • Observability: This is a local expression semantic mode; existing query error/profile facilities are sufficient, and no new log or metric is warranted.
  • Transactions, persistence, and writes: None are involved; there is no EditLog, failover, storage-format, atomic-write, or crash-recovery boundary.
  • FE/BE propagation: The new value is serialized by the FE, read by BE, and preserved across the changed translators, CastExpr/VCastExpr, function-context, and format-v2 clone paths. Remaining erasure/alternate-execution cases are already covered by existing threads.
  • Performance and other risks: Lossless parsing adds one bounded lexical validation pass. Maximum-width decimal coercion is not a new default-path regression—the base default already selected the same DECIMAL128/256 common type—and narrowing locally would change projected/negated equality semantics. No new allocation, memory-safety, CPU, or observability defect survived review.

Validation was static only, per the review-runner contract.

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 66.30% (122/184) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 57.42% (23930/41678)
Line Coverage 41.14% (235229/571846)
Region Coverage 36.96% (185813/502750)
Branch Coverage 38.11% (83324/218634)

@yx-keith
yx-keith force-pushed the master-join-cast-fix branch from 81c97d5 to 4b47820 Compare July 17, 2026 09:10
@yx-keith

Copy link
Copy Markdown
Contributor Author

run buildall

@yx-keith

Copy link
Copy Markdown
Contributor Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review result: REQUEST_CHANGES

Reviewed head 18ad9ebad643e1e9a3c1549788a4f9d0afb2cf75. Three new, non-duplicate P1 issues remain: format-v2 localization can hide strict-cast errors after selected-row compaction; legacy catalog predicate converters can lexically prune numerically equivalent strings; and the legacy Trino scan can push LIMIT before the marked comparison's local residual. Three independent round-2 full-PR reviews returned NO_NEW_VALUABLE_FINDINGS for this exact comment set after all candidates and existing threads were deduplicated.

Critical checkpoint conclusions:

  • Goal and proof: The primary scalar DECIMAL/STRING equality path now rejects rounded false matches and preserves malformed/overflow failures in strict mode. The parser, FE coercion, Thrift, and core join tests support that path, but the three inline issues show the goal is not complete across file-local and legacy connector execution.
  • Scope and clarity: The marker-based implementation is conceptually focused, but its semantics necessarily span FE rewrites, FE-to-BE transport, BE clones, file-local expressions, and every predicate/LIMIT pushdown path. The direct path is clear; the missed parallel paths are blocking.
  • Concurrency and thread safety: No new thread entry, shared mutable state, lock, atomic, or lock-order dependency is introduced. The flag is immutable per expression and copied into per-query FunctionContext clones.
  • Lifecycle and ownership: Cast construction, prepare/open/close, deep clone, format-v2 localization, connector filter planning, and residual evaluation were traced. No static-initialization, ownership-cycle, or teardown defect was found; M-BE-001 is the selected-row execution-contract loss during localization.
  • Configuration: No configuration item is added. Existing strict-cast, Decimal256, overflow-scale, and coercion-mode settings were checked; the accepted issues do not depend on dynamic configuration races.
  • Compatibility: Optional Thrift field 43 defaults false and is compatible with Doris's supported BE-then-FE rolling-upgrade order. No storage-format or function-symbol change is introduced.
  • Parallel paths and conditions: Normal/COPY translation, nested-slot replacement, folding, simplification, direct point-query eligibility, VCastExpr/FunctionContext clones, generic plugin scans, Remote Doris, condition-cache identity, Hudi/Paimon hybrid readers, and legacy Paimon/Iceberg/LakeSoul/HMS/Trino paths were checked. The three inline comments are the remaining distinct gaps; NULL-safe/IN, prepared point-query, ordering, LARGEINT, complex-type, and earlier pushdown concerns were suppressed as existing-thread duplicates.
  • Tests and expected results: The new parser unit test is registered, FE coercion/Thrift tests cover the marker, and the join regression's counts and strict failures are consistent. Coverage is missing for the three accepted paths, as requested inline. The regression's inline fixed results and trailing table drops also depart from the repository's preferred generated-result/debug-preserving pattern, but that is non-blocking hygiene.
  • Observability: This is deterministic expression behavior with existing query errors, explain output, and scanner profiles; no additional log or metric is required.
  • Transactions, persistence, and writes: No EditLog, transaction, visible-version, persisted metadata, storage write, atomicity, or crash-recovery behavior is changed.
  • FE-BE propagation: The marker survives current Nereids reconstruction, legacy CastExpr, ordinary and COPY translation, Thrift, VCastExpr, FunctionContext, digesting, and the value-mode portion of format-v2 localization. The accepted defects occur after that transport in selected-row scheduling and separate connector implementations.
  • Performance and safety: The lexical validator and expression marker scans are linear, localized condition caching is conservatively disabled, and no independent CPU, allocation, nullable-storage, unchecked-Status, or memory-lifetime blocker remains. M-BE-001 is an error-preservation issue, not a performance optimization request.
  • Other issues: The literal pre-coercion lead was dismissed because precision/scale validation precedes decimal scale adjustment. Exhaustive/random parser differential checks found no remaining exact-token mismatch. No additional user focus was supplied; the full PR was reviewed.

Validation was static-only because the review contract prohibits builds and repository test commands. Live style checks pass. The macOS BE UT failure is an unrelated runner JDK 25 versus required JDK 17 setup failure; the main compile and unit-test jobs were still pending at the final audit.

Status clone_node(VExprSPtr* cloned_expr) const override {
DORIS_CHECK(cloned_expr != nullptr);
*cloned_expr = Cast::create_shared(_data_type);
*cloned_expr = Cast::create_shared(_data_type, _lossless_decimal_cast);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve the selected-row safety of this localized cast — The source VCastExpr always reports is_safe_to_execute_on_selected_rows() == false, but format::Cast inherits the deterministic-child default. Hudi/Paimon native readers replace the source with this class, so Parquet can run an earlier single-column predicate on the full batch, compact it, and evaluate a strict marked comparison only on survivors. For id=1,s='bad' plus WHERE id > 1 AND d = s, that suppresses the strict parse error that the original conjunct would raise. Please override the safety method to return false (or preserve it during cloning) and add the selected-row differential test.

} else if (expr instanceof LiteralExpr) {
return convertLiteral((LiteralExpr) expr);
} else if (expr instanceof CastExpr) {
if (((CastExpr) expr).isLosslessDecimalCast()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Apply this guard to the catalog-specific predicate converters — Paimon, Iceberg, LakeSoul, and HMS do not call this converter; their legacy converters unwrap every CastExpr without checking the marker. For a Paimon VARCHAR s, WHERE s = 100.0 is analyzed as a lossless decimal comparison, but PaimonPredicateConverter pushes raw string equality to "100.0". That prunes s='1e2' or s='100.00', both of which the local lossless cast would match, and the residual cannot recover them. Please reject marked casts before each specialized file/partition/reader pushdown and add a noncanonical-string connector regression.

return castExprs.stream().anyMatch(CastExpr::isLosslessDecimalCast);
}

public static boolean canPushDownLimit(List<Expr> conjuncts) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Use this LIMIT guard in the legacy Trino scan too — TrinoConnectorPredicateConverter cannot convert d = LosslessCast(s) when both sides are slots, so it leaves TupleDomain.all() and Doris retains the comparison as a local residual. TrinoConnectorScanNode.applyPushDown, however, still calls connectorMetadata.applyLimit whenever the scan has a limit. With (100,'100.4') before (100,'100') and WHERE d = s LIMIT 1, Trino can return only the first row; the residual rejects it and the exact row is lost. Please gate Trino applyLimit with this helper and add a scan-level regression.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 43.40% (46/106) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29920 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 18ad9ebad643e1e9a3c1549788a4f9d0afb2cf75, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17704	4068	4091	4068
q2	2027	330	206	206
q3	10335	1401	830	830
q4	4692	475	343	343
q5	7493	857	569	569
q6	196	176	140	140
q7	790	842	619	619
q8	9375	1696	1624	1624
q9	5621	4362	4359	4359
q10	6749	1757	1522	1522
q11	518	351	322	322
q12	736	597	464	464
q13	18143	3320	2820	2820
q14	271	276	254	254
q15	q16	789	782	712	712
q17	1050	915	1035	915
q18	6996	5882	5576	5576
q19	1248	1256	1194	1194
q20	821	666	575	575
q21	5524	2620	2500	2500
q22	429	351	308	308
Total cold run time: 101507 ms
Total hot run time: 29920 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4371	4281	4281	4281
q2	286	320	209	209
q3	4529	4967	4408	4408
q4	2066	2143	1377	1377
q5	4387	4208	4278	4208
q6	237	175	131	131
q7	1734	1858	1871	1858
q8	2725	2167	2168	2167
q9	7938	8069	7739	7739
q10	4742	4666	4225	4225
q11	573	417	384	384
q12	757	778	550	550
q13	3343	3644	2948	2948
q14	308	304	286	286
q15	q16	711	734	648	648
q17	1357	1324	1336	1324
q18	8052	7318	7342	7318
q19	1199	1130	1096	1096
q20	2224	2225	1925	1925
q21	5266	4544	4446	4446
q22	506	450	401	401
Total cold run time: 57311 ms
Total hot run time: 51929 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 178267 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 18ad9ebad643e1e9a3c1549788a4f9d0afb2cf75, data reload: false

query5	4348	660	501	501
query6	467	246	216	216
query7	4853	622	363	363
query8	367	192	170	170
query9	8757	4151	4132	4132
query10	442	373	297	297
query11	5873	2327	2187	2187
query12	154	100	99	99
query13	1240	638	430	430
query14	6229	5228	4869	4869
query14_1	4270	4248	4216	4216
query15	219	204	177	177
query16	1019	492	459	459
query17	1105	701	549	549
query18	2454	475	343	343
query19	222	190	149	149
query20	113	107	102	102
query21	230	161	134	134
query22	13741	13711	13481	13481
query23	17413	16446	16093	16093
query23_1	16247	16290	16300	16290
query24	7513	1802	1255	1255
query24_1	1331	1313	1294	1294
query25	585	466	397	397
query26	1350	371	224	224
query27	2601	602	418	418
query28	4504	2025	2011	2011
query29	1136	625	514	514
query30	364	268	233	233
query31	1127	1103	985	985
query32	111	72	63	63
query33	539	330	261	261
query34	1191	1148	648	648
query35	776	790	673	673
query36	1235	1189	1033	1033
query37	155	114	100	100
query38	1888	1715	1670	1670
query39	890	872	865	865
query39_1	862	835	858	835
query40	261	173	154	154
query41	91	92	87	87
query42	104	95	99	95
query43	330	334	290	290
query44	1484	793	772	772
query45	199	192	178	178
query46	1055	1189	757	757
query47	2104	2042	1973	1973
query48	413	429	302	302
query49	591	410	341	341
query50	1050	440	356	356
query51	10733	10709	10428	10428
query52	89	96	80	80
query53	263	279	203	203
query54	307	254	237	237
query55	78	75	69	69
query56	333	309	310	309
query57	1319	1289	1183	1183
query58	326	284	287	284
query59	1534	1751	1420	1420
query60	327	289	267	267
query61	205	152	145	145
query62	541	492	429	429
query63	250	202	203	202
query64	2818	1053	855	855
query65	4735	4658	4667	4658
query66	1840	491	382	382
query67	29415	29413	29130	29130
query68	3284	1523	962	962
query69	431	304	267	267
query70	1086	954	940	940
query71	393	332	322	322
query72	3092	2719	2388	2388
query73	809	774	438	438
query74	5125	4938	4752	4752
query75	2534	2510	2151	2151
query76	2314	1169	774	774
query77	358	379	292	292
query78	11971	12025	11435	11435
query79	1368	1160	720	720
query80	671	578	470	470
query81	465	340	293	293
query82	573	158	122	122
query83	384	338	298	298
query84	286	161	139	139
query85	927	601	535	535
query86	362	301	291	291
query87	1832	1821	1758	1758
query88	3787	2802	2787	2787
query89	451	382	326	326
query90	1960	204	198	198
query91	205	192	171	171
query92	65	62	56	56
query93	1655	1498	947	947
query94	556	359	324	324
query95	796	577	472	472
query96	1036	794	344	344
query97	2639	2647	2494	2494
query98	215	207	201	201
query99	1091	1114	979	979
Total cold run time: 263841 ms
Total hot run time: 178267 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 25.28 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 18ad9ebad643e1e9a3c1549788a4f9d0afb2cf75, data reload: false

query1	0.00	0.00	0.00
query2	0.10	0.04	0.05
query3	0.26	0.14	0.14
query4	1.61	0.14	0.14
query5	0.24	0.23	0.23
query6	1.24	1.06	1.05
query7	0.04	0.01	0.00
query8	0.06	0.04	0.04
query9	0.39	0.32	0.32
query10	0.56	0.57	0.53
query11	0.20	0.14	0.14
query12	0.19	0.15	0.15
query13	0.48	0.48	0.48
query14	1.03	1.02	1.01
query15	0.65	0.62	0.61
query16	0.31	0.34	0.31
query17	1.09	1.11	1.09
query18	0.23	0.21	0.21
query19	2.08	1.99	1.95
query20	0.02	0.01	0.02
query21	15.44	0.20	0.13
query22	4.94	0.05	0.05
query23	16.15	0.30	0.12
query24	3.03	0.41	0.33
query25	0.11	0.05	0.04
query26	0.75	0.20	0.16
query27	0.05	0.04	0.04
query28	3.51	0.86	0.57
query29	12.48	4.04	3.28
query30	0.30	0.17	0.16
query31	2.78	0.60	0.32
query32	3.21	0.61	0.49
query33	3.11	3.23	3.22
query34	15.46	4.23	3.52
query35	3.51	3.57	3.57
query36	0.57	0.44	0.45
query37	0.09	0.07	0.07
query38	0.05	0.05	0.04
query39	0.04	0.03	0.03
query40	0.19	0.17	0.16
query41	0.09	0.03	0.04
query42	0.05	0.03	0.03
query43	0.05	0.04	0.03
Total cold run time: 96.74 s
Total hot run time: 25.28 s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants