Repository navigation
Conversation
…6761) Docs: apache/doris-website#4091 Problem Summary: Doris DATETIME only support at most six fractional digits, it's not sufficient for event times, traces, etc which require higher precision of sub-seconds. Introduce `TIMESTAMP_NS` as a separate fixed-scale SQL type backed by signed Int64 Unix-epoch nanoseconds. It always has scale 9 and supports values from `1677-09-21 00:12:43.145224192` through `2262-04-11 23:47:16.854775807`. Wire the type through Thrift and protobuf metadata, the FE catalog and Nereids, BE columns and SerDe, storage and indexes, result protocols, JNI and Java UDF transport, complex and VARIANT types, and schema metadata. Add exact casts, comparisons, type inference, and constant folding across date-like types while preserving nanoseconds and rejecting partial or precision-losing implicit conversions. Add timestamp-aware scalar and calendar functions, aggregation, joins and ASOF joins, scan predicates, runtime filters, partition pruning, query-cache normalization, automatic partitions, and MTMV roll-up. Keep FE folding and BE runtime behavior consistent at signed endpoints, leap years, DST gaps, calendar-clamped boundaries, and fractional formatting and rounding boundaries. Keep existing DATETIME and DATETIMEV2 scale semantics unchanged. FROM_UNIXTIME retains a DECIMAL64 microsecond path for scale 0 through 6 and uses the DECIMAL128 nanosecond path only for scale 7 through 9. The %f formatter rounds half-up to microseconds with second carry, while %n preserves the nanosecond fraction. - Test: Unit Test and Regression Test - Added targeted BE unit coverage for TIMESTAMP_NS values, casts, functions, SerDe, predicates, aggregates, joins, and compatibility paths - Added targeted FE unit coverage for literals, casts, constant folding, type inference, partitions, query-cache and MTMV boundaries, and statement-time semantics - Added regression coverage under datatype_p0/timestamp_ns and focused MTMV and Java UDF suites - Built FE and BE with the standard build scripts - Behavior changed: Yes. Adds TIMESTAMP_NS and nanosecond function semantics without changing the scale limits of DATETIME or DATETIMEV2. - Does this need documentation: Yes. Document TIMESTAMP_NS syntax, range, casts and coercion rules, function behavior, and integration support. ### Release note Add `TIMESTAMP_NS`, a fixed-scale nanosecond timestamp type stored as signed Unix-epoch nanoseconds. It supports SQL literals, casts, date/time functions, storage and indexes, partitions, joins, aggregates, complex types, Java UDF/JNI transport, and FE constant folding and type inference. Existing DATETIME and DATETIMEV2 types remain limited to scale 0 through 6. ### Check List (For Author) - Test <!-- At least one of them must be included. --> - [x] Regression test - [x] 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 <!-- Add your reason? --> - Behavior changed: - [ ] No. - [x] Yes. <!-- Explain the behavior change --> - Does this need documentation? - [ ] No. - [x] Yes. <!-- Add document PR link here. eg: apache/doris-website#1214 --> ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label <!-- Add branch pick label that this PR should merge into -->
Problem Summary: A review that fails with `refresh_token_reused` leaves its credentials eligible because the runner only records usage limits. Later reviews can repeatedly select the same unusable credentials. Record explicit reuse failures in a separate OSS object keyed by the selected refresh token's SHA-256, then check that marker before selecting a downloaded auth snapshot. A replacement refresh token restores eligibility; metadata-only changes do not. Separate objects keep late failures and usage-context writes from overwriting another token's quarantine state. Marker read/write failures are surfaced explicitly. The marker applies to the selected token version. Runs that already selected credentials before the marker was written can still fail. This does not add credential leasing or change auth writeback.
…ine (apache#67490) When FE local shuffle planning inserted a local exchange into a pipeline whose parent pipeline was serial, it could increase only the downstream pipeline task count while the paired sink and source operators remained one-to-one. This produced inconsistent pipeline concurrency and could fail during execution. Root cause: FE did not propagate the serial state of a parent pipeline across pipeline boundaries. This change tracks that state and skips local exchange insertion when the parent pipeline is serial, matching the existing BE planning constraint. ### Release note None ### Check List (For Author) - Test <!-- At least one of them must be included. --> - [ ] 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 <!-- Add your reason? --> - Behavior changed: - [ ] No. - [ ] Yes. <!-- Explain the behavior change --> - Does this need documentation? - [ ] No. - [ ] Yes. <!-- Add document PR link here. eg: apache/doris-website#1214 --> ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label <!-- Add branch pick label that this PR should merge into -->
…pache#67508) ### What problem does this PR solve? Issue Number: close apache#67091 Related PR: None Problem Summary: A BE restart indexed row-binlog rowsets only by transaction ID, so multiple tablet pairs in one transaction could attach the wrong companion rowset. Persist each base tablet's companion ID and recover using both transaction and tablet IDs. ### Release note Fix incorrect row-binlog companion recovery after a BE restart for multi-tablet transactions. ### Check List (For Author) - Test: Unit Test - Added and ran GroupRowsetBuilderTest.recoverMultipleRowBinlogPairsInOneTxn and GroupRowsetBuilderTest.* - Behavior changed: Yes. BE restart recovery now attaches each base rowset to its persisted companion tablet. - Does this need documentation: No
### What problem does this PR solve?
Issue Number: None
Related PR: None
Problem Summary:
The connector metastore SPI refactor removed DLF provider registration
and the plugin-local DLF client path, so existing Iceberg and Paimon
catalogs using `dlf` can no longer be created or replayed on master.
This PR restores DLF support for both connectors:
- Register engine-specific DLF metastore providers and restore legacy
property aliases, endpoint derivation, catalog-id fallback, and
sensitive credential handling.
- Restore the Iceberg DLF catalog and client pool, with catalog-scoped
client caching and OSS-backed `S3FileIO`.
- Route Paimon DLF through its Hive catalog using
`ProxyMetaStoreClient`, while preserving legacy alias-only OSS and
OSS-HDFS storage configurations.
- Bundle the matching Hive 3 and Hive 2 DLF clients into the existing
Iceberg/HMS and Paimon private shades, including their Thrift and Tea
namespace isolation.
### Release note
Restore Aliyun DLF metastore support for Iceberg and Paimon catalogs.
### Check List (For Author)
- Test
- [ ] Regression test
- [x] Unit Test
- [x] Manual test (add detailed scripts or steps below)
- Targeted Iceberg, Paimon, metastore provider, property-binding, and
DLF catalog tests passed.
- The 19-module connector package build passed with tests skipped; FE
Checkstyle reported zero violations.
- Verified both generated private shade jars contain the DLF proxy
client and relocated Thrift and Tea classes.
- The full Iceberg connector suite was also attempted; 1 of 1,376 tests
failed in the unrelated
`IcebergWritePlanProviderTest.planMergePreservesExplicitlyEmptyReadAcrossConcurrentFirstAppend`
case. The focused rerun reproduces the same failure, and this PR does
not modify that code path.
- [ ] 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.
- [x] Yes. Iceberg and Paimon catalogs can use the DLF metastore backend
again.
- Does this need documentation?
- [x] No. Existing DLF catalog properties and behavior are restored.
- [ ] Yes.
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label
Problem Summary: When cloud warm-up jobs outnumber the configured active slots, the scheduler can over-submit tasks because a job is recorded as active only after its worker starts. The direct-handoff thread pool previously discarded rejected tasks, and unordered map traversal could repeatedly favor the same jobs, leaving other runnable jobs pending indefinitely. This PR keeps the direct-handoff pool and makes scheduling bounded and retryable: - Scan runnable jobs once and keep only the jobs needed by the current slots in a bounded priority heap. - Reserve the active slot before submission and roll it back when submission is rejected. - Schedule the least-recently-run jobs first, with never-scheduled one-time jobs taking the first turn. - Surface pool rejection so the scheduler can retry the job in the next cycle. - Apply mutable scheduler concurrency and interval configuration without requiring an FE restart. ### Release note Fix cloud warm-up jobs remaining pending when the scheduler thread pool is saturated.
…achable forward branch (apache#67572) ### What problem does this PR solve? Problem Summary: Two pieces of dead weight in the connect layer, found while reading the Arrow Flight SQL and MySQL paths side by side. No behavior change. **1. `ConnectType` was declared twice.** Once in `ConnectContext` and once in `ConnectProcessor`, so a processor's `connectType` and its session's `connectType` were unrelated types that only happened to carry the same two constants — nothing stopped them from disagreeing, and neither could be passed where the other was expected. Keep the `ConnectContext` one, which is the session's own property, and let the processors import it. Every subclass (including the four test-only ones) was resolving the enum through inheritance, so they now import it explicitly. **2. `FrontendServiceImpl.createForwardProcessor()` dispatched on an outcome that cannot happen.** It branched on the connect type of the forwarded context, but the context comes from `createForwardContext()` one line above, which builds it with `new ConnectContext(null, true, sessionId)` — and that constructor always sets `ConnectType.MYSQL`. So the Arrow Flight branch and the `unknown ConnectType` throw were unreachable: the master replays a forwarded statement over a `ProxyMysqlChannel` no matter which protocol the client speaks on the origin FE. The MySQL processor is now constructed directly at the one call site, with a comment recording why that is the only possibility.
Problem: Peer reads create an uncached BRPC client for every request. When a peer is unreachable, readers across tablets repeatedly connect to the same address with the default 2-second connect timeout and 10 retries. Impact: An unavailable cache peer can repeatedly delay reads before remote-storage fallback and generate unnecessary connection attempts and warning logs. Fix: - Add a BE-wide, address-level circuit breaker shared by peer readers. - Open the circuit after a configurable number of consecutive connection or RPC failures (3 by default) for a configurable cooldown (30 seconds by default). - Reject reads while the circuit is open, allow one probe after cooldown, and clear the failure state after a successful RPC. - Make uncached BRPC connect timeout and retry count configurable at the call site, and use a 200 ms timeout with no retries for peer reads. Test: Stop the peer test server and verify that four reads issue only three RPC attempts, with the final read rejected by the circuit breaker.
### What problem does this PR solve? Issue Number: ref apache#48203 Related PR: apache/doris-website#4102 Problem Summary: Add the `ST_IsClosed` spatial scalar function. For a valid LineString, the function returns: * `true` when the first and last points are exactly equal * `false` when the LineString is open * `NULL` for a `NULL` input * `NULL` for a non-LineString or invalid encoded geometry The implementation uses exact S2 point equality without introducing a tolerance. This PR also adds Nereids registration and visitor support, FE and BE unit tests, and a self-asserting SQL regression suite. ### Release note Add the `ST_IsClosed` spatial function.
…7566) ### What problem does this PR solve? Issue Number: None Related PR: apache#61762 Problem Summary: The TPC-H SF100 MOR suite loads the same data twice into MOR and DUP tables, then compares their results with `read_mor_as_dup_tables` enabled. Automatic compaction can merge the MOR versions before the comparison, leaving fewer rows than the DUP tables. Add eight dedicated `*_mor_as_dup` tables with automatic compaction disabled. Prepare them in the existing two-round `load.groovy` flow by reusing the existing S3 import SQL with a distinct table name and load label. Route the MOR-as-DUP queries to these tables, preserving the shared MOR table definitions used by the normal TPC-H and predicate-pushdown cases. ### Release note None ### Check List (For Author) - Test - [ ] Regression test - [ ] Unit Test - [ ] Manual test - [x] No need to test or manual test. Explain why: - [x] Other reason: Test fixture change. Both modified Groovy scripts passed compilation with the existing regression framework's Groovy compiler; all eight dedicated DDL schemas and import substitution anchors were checked; shared MOR DDLs are unchanged; `git diff --check` passed. The full SF100 suite was not run locally. - Behavior changed: - [x] No. Test setup only. - [ ] 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
) Problem Summary: Different BEs may generate different rowsets for the same transaction and tablet. After rowset A is committed, the temporary rowset key points to A while the recycle rowset key for B still exists. The recycle key check ran before comparing rowset IDs, so commit_rowset incorrectly treated tmp(A) and recycle(B) as an invalid conflict. Compare rowset IDs first and only check the tmp and recycle key conflict when they belong to the same rowset. For different rowsets, return ALREADY_EXISTED with rowset A.
### What problem does this PR solve? Related PR: apache#67527, apache#67396 Problem Summary: apache#67527 added seven JUnit 4 `Assert` calls to `ConfigTest` after apache#67396 migrated the class to JUnit 5, causing `fe-common:testCompile` to fail with `cannot find symbol: Assert`. Use the existing JUnit 5 `Assertions` import. Also migrate the scheduler test introduced by the same PR to JUnit 5 assertions and lifecycle annotations, consistent with the FE test migration. ### Release note None ### Check List (For Author) - Test: `./run-fe-ut.sh --run org.apache.doris.common.ConfigTest,org.apache.doris.cloud.CacheHotspotManagerSchedulerTest` completed with BUILD SUCCESS: ConfigTest 10/10 and CacheHotspotManagerSchedulerTest 4/4 passed, with no failures, errors, or skipped tests. Checkstyle passed for fe-common and fe-core with zero violations; `git diff --check` passed. - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve?
A background sender could finish all of its work and then crash while
destroying
`AddThreadMemTrackerConsumer`:
```text
AddThreadMemTrackerConsumer::~AddThreadMemTrackerConsumer()
VTabletWriter::_send_batch_process()
periodic_send_batch(void*)
bthread::TaskGroup::task_runner(...)
```
The core file shows that `thread_context()` returned `nullptr`; the
`ThreadMemTrackerMgr` and its consumer stack were not corrupted. The
original
`ThreadContext` was still present in the bthread key table, but it could
no longer be
retrieved:
```text
global btls_key: { index = 0, version = 1 }
bthread key-table slot 0: { version = 0, ptr = valid ThreadContext }
```
`btls_key` was zero-initialized as `{0, 0}` and was not created until
`PInternalService` was constructed. The BE starts its Thrift backend
service before
constructing the BRPC internal service, so work can arrive during that
startup window.
A bthread could therefore store its context with `{0, 0}`. BRPC accepts
that value
before the real key is created because key slot 0 also starts at version
0.
Later, `bthread_key_create()` changed the global key to `{0, 1}`. A
lookup using the
new version did not match the existing version-0 entry and returned
`nullptr`, causing
the crash during scoped tracker cleanup.
This is a key-initialization race. It is not caused by a bthread
migrating between
worker pthreads or by `pthread_context_ptr_init` changing during
migration.
### What is changed?
- Move the bthread ThreadContext key and its deleter into the
`thread_context` module.
- Initialize the key with `std::call_once` before any
`ThreadLocalHandle` creates or
accesses a context. The BE's early `SCOPED_INIT_THREAD_CONTEXT()`
initializes it
before services start, while the lazy guard also protects other entry
points.
- Keep the key valid for the complete process lifetime instead of
deleting it with
`PInternalService`, so existing bthread contexts cannot be invalidated
by service
lifetime.
- Revert the earlier context-pointer caching and lookup-order changes.
Those changes
only masked the null lookup and did not fix the key-version mismatch.
The change does not alter memory-accounting semantics. It guarantees
that every
bthread context is stored and retrieved with the same valid key version.
) ### What problem does this PR solve? Issue Number: N/A Related PR: N/A Problem Summary: Iceberg V2 scans could retain a stale nested file projection after a predicate on a missing child was demoted, shifting projected sibling values by physical ordinal. Separately, ID-less migrated files fell back to current-name mapping after the explicit default name mapping was removed, exposing stale physical values instead of NULL. This PR reapplies the finalized scan projection to column mappings and requires authoritative name mapping for V2 ID-less file reads. ### Release note Fix Iceberg V2 reads when a rejected nested predicate widens projection and when migrated ID-less files lose their default name mapping. ### Check List (For Author) - Test: Unit Test and Regression test - All 82 `IcebergV2ReaderTest` tests and all 15 `ColumnMapperTest` tests passed. - The four equality-delete tests affected by the stricter ID-less mapping invariant passed after explicitly mapping their projected result carrier. - Both new Iceberg external-table regressions passed: nested projection alignment and migrated ID-less nested NULL semantics. - The existing `test_gen_iceberg_by_api` suite passed while validating the required-field error for an ID-less fixture without authoritative name mapping. - ASAN BE build and FE build passed. - Build hygiene and clang-format 16 checks passed. - Behavior changed: Yes. Iceberg V2 nested projections preserve field-ID alignment, and migrated ID-less fields without default name mapping materialize as NULL. - Does this need documentation: No
…up (apache#67539) ### What problem does this PR solve? `ExportMgr.removeOldExportJobs()` removes export jobs when the number of stored jobs exceeds `Config.max_export_history_job_num`. The old implementation removed the oldest jobs without checking their states, so PENDING, EXPORTING, or IN_QUEUE jobs could also be deleted. An active export job can still write a later `OP_EXPORT_UPDATE_STATE` edit log. After FE restart or master transfer, journal replay then looks up the job by ID in `exportIdToJob`. Because the cleanup task may have already removed the job, the lookup returns null and replay fails with: ``` java.lang.NullPointerException: Cannot invoke "org.apache.doris.load.ExportJob.replayExportJobState(...)" because "job" is null ``` The cleanup also removed label mappings by label only. If an old cancelled job and a newer active job used the same label, deleting the old job could remove the newer job's label mapping and allow an invalid duplicate export job to be created. ### How does this PR solve the problem? - Only remove export jobs in `CANCELLED` or `FINISHED` states when enforcing the maximum history-job limit. - Keep active jobs even when their total number is greater than `Config.max_export_history_job_num`, because active jobs may still produce state-transition edit logs. - Iterate through the sorted job list safely and stop when there are no more removable candidates, avoiding an endless cleanup loop when all jobs are active. - Remove a label mapping only when both the label and the mapped job ID match the job being deleted. This prevents an old job from deleting the mapping owned by a newer job with the same label. ### Test - Add coverage to verify that PENDING and EXPORTING jobs are retained while terminal jobs are removed. - Add coverage to verify that all active jobs are retained when the history limit is smaller than the number of active jobs. - Add coverage to verify that a running job keeps its label reservation after an older job with the same label is cleaned up.
### What problem does this PR solve?
Issue Number: DORIS-28543
Related PR: None
Problem Summary:
`HttpFileReader` expands small reads to a 1 MiB read-ahead request. Near
EOF, the generated byte range can extend beyond the file size. Some
Range-capable object stores respond to that overlong range with HTTP 200
and the complete object, so Doris incorrectly reports that Range support
changed after it was successfully detected during open.
This change clamps speculative read-ahead to the known file boundary. It
also adds a local HTTP server unit test that reproduces the 206-at-open
followed by 200-on-overlong-range behavior.
### Release note
Fix HTTP range reads near EOF for servers that return the complete
object for ranges extending past EOF.
### Check List (For Author)
- Test
- [ ] Regression test
- [x] 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.
- [x] Yes. HTTP read-ahead now respects the known EOF boundary.
- 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
…ch defaults (apache#67559) ### What problem does this PR solve? Slow CDC control requests, including snapshot split discovery for unevenly distributed keys, can exceed the default 60-second BE HTTP timeout. Retrying split discovery can repeat expensive work before the FE receives progress. This PR changes only two defaults: - Increase `request_cdc_client_timeout_ms` from `60000` to `120000` (120 seconds). - Reduce `streaming_cdc_fetch_splits_batch_size` from `100` to `16` to return smaller batches on batched split-discovery paths.
…hing the MySQL channel (apache#67569) ### What problem does this PR solve? Related PR: apache#61050 Problem Summary: **1. A Flight session could not forward a statement at all.** An Arrow Flight SQL session has no `MysqlChannel`: `FlightSqlConnectContext` overrides `getMysqlChannel()` to throw `getMysqlChannel not in mysql connection`. Since apache#61050, `FEOpExecutor.buildStmtForwardParams()` reads the client's `CLIENT_DEPRECATE_EOF` capability straight off that channel, so on a multi-FE deployment every statement a Flight connection has to forward to the master fails with that message before the request is even sent: - any DDL issued over Arrow Flight SQL to a follower or observer FE; - any statement at all when `force_forward_all_queries` is on. `CLIENT_DEPRECATE_EOF` is a MySQL protocol capability, so only read it for a MySQL connection. The thrift field is `optional` with no IDL default, and leaving it unset for other protocols puts the master back on the packet layout it used before apache#61050 — `ConnectProcessor` applies it only when `isSetClientDeprecatedEOF() && isClientDeprecatedEOF()`, so unset is equivalent to set-false for every reader in every rolling-upgrade direction. **2. Once the forward succeeds, nothing carries the master's answer back to the Flight client.** `ConnectProcessor.finalizeCommand()` is the only place a forwarded statement's status and result set are replayed, and it is MySQL-only: it opens with `Preconditions.checkState(connectType.equals(ConnectType.MYSQL))`. Nothing else reads `getProxyStatusCode()` / `getShowResultSet()` / `getOutputPacket()` except the audit log. So after the RPC, `ctx.getState()` stays at the `OK` that `executeQuery()` set with `reset()`, the `FlightSqlChannel` stays empty, and `DorisFlightSqlProducer` answers with `addOKResult()`'s synthesized one-row `StatusResult = 0`. With a client connected over Arrow Flight SQL to a follower or observer: - a DDL that **failed** on the master was reported to the client as success — only the follower's audit event recorded the real error; - a forwarded statement that returns rows (`SHOW FRONTENDS`, `SHOW LOAD`, … — about 33 `ShowCommand` subclasses both forward and return rows) returned that single `StatusResult` row instead of the master's rows. The same statement run against the master returns real rows, because `StmtExecutor.sendResultSet()` already has a working Arrow Flight branch. This gap is older than apache#61050 (`finalizeCommand()` was already MySQL-only before it), so fixing only part 1 would have turned a loud, diagnosable error into a silent wrong answer, which the repository's "Error Means Failure" invariant does not allow. Part 2 is therefore fixed here too: - `ConnectProcessor.carryForwardedOutcomeToFlightSession()` is the Arrow Flight counterpart of `finalizeCommand()`'s forwarded-statement branch. It copies a non-zero master status into `ctx.getState()` (and logs it at WARN — the follower used to say nothing), and otherwise replays the master's result set through the existing `sendResultSet()` Arrow Flight branch. - It is called from the branch of `executeQuery()` that is **already** scoped to `ARROW_FLIGHT_SQL`, so it structurally cannot fire on a MySQL connection and `finalizeCommand()`'s `getStateType() != ERR` condition is untouched. - `StmtExecutor` now refuses to forward a *query* on an Arrow Flight SQL connection, before the RPC. A query result comes back as MySQL wire packets in `TMasterOpResult.queryResultBufList`, which only `finalizeCommand()` can replay and which cannot be converted to Arrow batches; answering it with a synthesized empty success would be the same silent wrong answer. This is reachable only under `force_forward_all_queries`, which `Config` documents as "For testing purposes". The MySQL path is byte-for-byte unchanged.
…#67454) Problem Summary: `CloudSchemaChangeJob::_convert_historical_rowsets()` builds its `RowsetWriterContext` with `write_file_cache` but never sets `file_cache_ttl_sec`. For a table with `file_cache_ttl_seconds`, the schema change output is therefore written into the NORMAL/INDEX file cache queues instead of the TTL queue. The other two cloud write paths both set it: - load: `CloudRowsetBuilder::init()` — `context.file_cache_ttl_sec = _tablet->ttl_seconds();` - compaction: `CloudCompactionMixin::construct_output_rowset_writer()` — `ctx.file_cache_ttl_sec = _tablet->ttl_seconds();`
…67663) Problem Summary: FE/BE startup and shutdown scripts silently skip the final environment assignment in `fe.conf` or `be.conf` when the file has no trailing newline. For example, a final `PID_DIR=/custom/pid` is ignored, so the script uses the default or an earlier PID directory. Bash `read` sets `line` but returns failure when EOF terminates a partial line. Keep each of the four configuration loops running when that final line is nonempty so the existing parser exports it. ### Release note Fix FE/BE startup and shutdown scripts ignoring the last configuration assignment when the file has no trailing newline.
…pache#67664) Problem Summary: Building the Doris compose image fails during apt-get update because openjdk:17.0.1-jdk-slim is based on Debian 11. Bullseye LTS ended on August 31, 2026, and its security repository metadata subsequently expired. The same expired metadata is served by both the Aliyun mirror and Debian upstream, so switching mirror hosts does not resolve the failure. Use bellsoft/liberica-openjdk-debian:17, currently based on Debian 12, while preserving the JDK_IMAGE build argument and the base image's Java environment. Update mirror rewriting to support both legacy .list and deb822 .sources files, and install python-is-python3 because Debian 12 does not provide the old python package. Document the new default image. ### Release note The Doris compose image now uses Debian 12 with BellSoft Liberica JDK 17. The python command now runs Python 3. ### Check List (For Author) - Test: Manual test - Build the complete Docker image using existing local output artifacts. - Run docker build --check: no warnings. - Verify mirror rewriting for both legacy .list and deb822 .sources files. - Verify Debian 12, Java/javac 17, JAVA_HOME/libjvm, Python, MySQL client, and JaCoCo agent loading in the built image. - Run FE start_fe.sh --version and BE doris_be --version successfully. - Run git diff --check. - No kernel rebuild or full cluster regression: this changes image packaging. - Behavior changed: Yes; update the base OS/JDK distribution and use Python 3. - Does this need documentation: Yes; update the Doris compose README in this commit. ### What problem does this PR solve? Issue Number: close #xxx Related PR: #xxx Problem Summary: ### Release note None ### Check List (For Author) - Test <!-- At least one of them must be included. --> - [ ] Regression test - [ ] Unit Test - [ ] Manual test (add detailed scripts or steps below) - [x] 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 <!-- Add your reason? --> - Behavior changed: - [x] No. - [ ] Yes. <!-- Explain the behavior change --> - Does this need documentation? - [x] No. - [ ] Yes. <!-- Add document PR link here. eg: apache/doris-website#1214 --> ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label <!-- Add branch pick label that this PR should merge into -->
…7584) ### What problem does this PR solve? Issue Number: N/A Related PR: N/A Problem Summary: `sequence(2147483646, 2147483647, 2)` and its `array_range` equivalent should return `[2147483646]`. The current Int32 generator overflows when incrementing past the last element and can keep appending instead of terminating. The wider preflight size calculation does not protect the Int32 generation loop. Use Int64 distance/cursor arithmetic, check the exact element count before allocation, resize the nested output once per multi-element row, and fill it with a counted loop. Initialize the element null map once per block. Empty and singleton fast paths avoid division and general-fill overhead for short ranges. The Int32 return type, exclusive upper bound, invalid-input NULLs and array-size limit remain unchanged. Four BE unit tests cover both function names, all constant/vector argument combinations, overflow boundaries, default arguments, NULL/invalid inputs, mixed growing/empty/NULL rows, and the exact size limit and limit+1. ### Performance Function-level Google Benchmark calls through the real function factory, including output allocation. Both binaries use the same benchmark and master baseline `eea19b3f3cfef9e1bbbd559f9ea42954d8891e0f`; only the generator implementation differs. Intel Xeon Platinum 8457C, Clang 20.1.8, Release `-O3`, AVX2, pinned to CPU 24. Each case uses non-constant input columns, `start = row % 17`, and the length/step below. Run order: before, after, after, before; 7 repetitions per run, minimum 0.3 s measurement and 0.2 s warmup. Values are the median CPU time across 14 samples per case. | Input rows | Elements per array | Step | Before (µs/batch) | After (µs/batch) | Speedup | |---:|---:|---:|---:|---:|---:| | 4096 | 0 | 1 | 9.34 | 9.27 | 1.01× | | 4096 | 1 | 1 | 15.64 | 11.37 | 1.38× | | 4096 | 16 | 1 | 119.95 | 32.01 | 3.75× | | 4096 | 256 | 1 | 2737.57 | 931.27 | 2.94× | | 4096 | 1024 | 1 | 20430.45 | 3763.61 | 5.43× | | 4096 | 256 | 7 | 2615.14 | 942.04 | 2.78× | | 1 | 1000000 | 1 | 1973.84 | 214.92 | 9.18× | This is a shared host with CPU scaling enabled, so the empty-array result should be treated as unchanged. These are BE function timings, not end-to-end SQL speedups. Raw samples show higher variation for the large multi-row allocation cases; the reported values are medians. Reproduce with the registered `BM_ArrayRange` benchmark: ```bash BUILD_TYPE=Release ./build.sh --benchmark -j 48 taskset -c 24 be/build_Release/bin/benchmark_test \ --benchmark_filter=BM_ArrayRange \ --benchmark_min_time=0.3s --benchmark_min_warmup_time=0.2 \ --benchmark_repetitions=7 --benchmark_out=results.json \ --benchmark_out_format=json ``` ### Release note Fix integer overflow in `sequence`/`array_range` near INT32_MAX and accelerate integer range generation with batched output filling. ### Check List (For Author) - Test - [ ] Regression test - [x] Unit Test: `./run-be-ut.sh --run --filter='FunctionArrayRangeTest.*' -j 48` — all 4 ASAN tests passed and the process exited normally. - [x] Manual test: actual-function Release benchmarks above. - Behavior changed: - [ ] No. - [x] Yes: valid ranges whose final increment exceeds INT32_MAX now terminate with the expected array. - Does this need documentation? - [x] No. - [ ] Yes. Validation notes: - clang-format 16 and build-hygiene checks passed. - The Release benchmark compiled, linked, installed and ran successfully. The build script's subsequent generic packaging step fails because benchmark-only builds do not populate `be/output/bin/*`. - The repository clang-tidy script was attempted but did not pass because of the existing unmatched `NOLINTEND` in `be/src/core/types.h` and signed comparisons in unchanged array-range code. No unrelated fixes are included. ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label
### What problem does this PR solve? Issue Number: None Related PR: apache#66337 Problem Summary: Schema change compaction cases created only five post-alter versions. After the NOTREADY tablet policy started protecting its latest ten versions, no rowsets remained eligible for cumulative compaction, so the cases expected a merge that could no longer occur. The inverted-index cumulative compaction case also assumed that the first trigger always found input and that an initial run_status=false meant completion, which races the BE visible-version refresh. Create enough double-write versions to exercise both the eligible and protected ranges, assert the resulting active rowset topology in the no-restart, FE-restart, and BE-restart variants, and use completion checks that cannot finish before compaction starts. For the inverted-index case, retry only the transient E-2000 response while forcing tablet reports and wait for observable rowset reduction.
Primary-key lookup copied each rowset’s segment key bounds into a temporary vector before pruning candidate segments. This caused repeated allocation and protobuf object copying on the lookup hot path, with overhead increasing alongside the number of segments. Co-authored-by: yangtao555 <[email protected]>
…che#67533) ### What problem does this PR solve? Issue Number: close apache#67094
### What problem does this PR solve? Issue Number: None Related PR: apache#64580 Problem Summary: INSERT OVERWRITE auto-detect must fail when source rows do not match an existing target partition and automatic partition creation is disabled. With multiple parallel sink instances, several equivalent failure messages can race to reach the client. The regression test accepted only one message, making repeated executions flaky. Accept the known equivalent errors while still requiring every statement to fail. ### Release note None ### Check List (For Author) - Test: Regression test updated; not run locally as requested, CI will execute it - Behavior changed: No - Does this need documentation: No
…67685) ### What problem does this PR solve? Problem Summary: The `errorCapturingIdentifier` rule always entered a nullable helper for valid identifiers. In the tracked SQL corpus this created 25,406 empty CST contexts. Move the optionality to the caller and make `errorCapturingIdentifierExtra` non-empty, while preserving the existing unquoted-identifier error action. This avoids allocating an empty `RealIdentContext` on the common path and keeps the grammar structure straightforward. This PR also removes stale `PostProcessor` references from two JMH harnesses. Identifier post-processing already moved into grammar actions and the class no longer exists, so those references prevented the benchmark profile from compiling. Add a multipart-identifier JMH workload and a direct CST regression test. Across two JMH runs, normalized allocation for that workload decreased from 174,368.9 to 159,004.1 B/op (-8.81%) end-to-end and from 146,097.7 to 130,741.3 B/op (-10.51%) with pre-tokenized input.
…7666) ### What problem does this PR solve? Problem Summary: DISTINCT window rewrites for SUM and GROUP_CONCAT manually reconstructed their multi-distinct functions with the default non-nullable flag. For empty window frames over NOT NULL inputs, the backend consequently materialized empty aggregate states (0 or an empty string) instead of NULL. This change reuses each aggregate function's canonical multi-distinct conversion, preserving the always-nullable contract established during window-function analysis. COUNT(DISTINCT) behavior remains unchanged. ### Release note Fix SUM(DISTINCT ...) and GROUP_CONCAT(DISTINCT ...) window functions to return NULL for empty frames.
update mtmv code owner
…ed fields (apache#65805) ### What problem does this PR solve? Issue Number: None Related PR: apache#65591, apache#66380 Problem Summary: Nested-column pruning (feature series apache#59263 / apache#61888 / apache#64535) makes Doris read only the referenced parts of a struct/map/array column. Two kinds of special *meta* access paths serve that purpose: a terminal `NULL` component means the query only needs the null flag (`IS [NOT] NULL` on a column or nested field), and a terminal `OFFSET` component means only offsets are needed (`length`/`cardinality`-style functions). The BE satisfies them in `NULL_MAP_ONLY` / `OFFSET_ONLY` meta-read modes that skip the payload data entirely. While the optimization itself is sound, the way meta paths were expressed on the wire and handled on both sides had several correctness holes: * **Wire ambiguity.** Every access path was sent as a `DATA`-typed list of string components, and `NULL`/`OFFSET` lived in the same list as real child names. There was no way to tell a metadata selector apart from a struct field literally named `OFFSET` or `NULL`, so such a field could be swallowed as metadata and its data silently pruned away (wrong query results), and there was no FE/BE version contract to evolve the encoding during rolling upgrades. * **FE null-map correctness.** A slot can be nullable for two different reasons: its physical column has a null bitmap, or an outer join merely made the output slot nullable. The old logic keyed on expression/slot nullability, so a physical `NOT NULL` dimension column of a `LEFT JOIN` received a `[col, NULL]` path and the BE aborted trying to read a null map from a `NOT NULL` column. Meta paths were also generated for non-nullable struct fields / non-null structs and for variant sub-columns, which do not support meta-only reads. * **FE pruning bookkeeping.** `NULL`/`OFFSET` were detected by string suffix, so real fields with those names collided inside the pruning logic too; and predicate meta paths were stripped or broadened (map-star) whenever regular data paths existed, losing metadata-only reads or over-reading payload data. * **BE routing/read-mode logic.** A terminal `NULL`/`OFFSET` was treated as current-level metadata at every container, meta-only modes could be entered even when a sibling `DATA` path still required payload reads, sibling `META` paths were dropped when unrelated data projections existed, and Map descendant routing depended on physical key/value child column names while silently ignoring unknown selectors. What this PR does: * **Versioned, type-selected access paths.** Adds an optional `version` to `TColumnAccessPath` (thrift + protobuf + FE/BE descriptor conversion; `TCOLUMN_ACCESS_PATH_VERSION_LEGACY = 0`, `TCOLUMN_ACCESS_PATH_VERSION_TYPED = 1`). In the typed format the path type is authoritative: `DATA` selects `data_access_path`, `META` selects `meta_access_path`, and `NULL`/`OFFSET` are only ever emitted as typed `META` paths. New BEs still decode the legacy all-`DATA` encoding from old FEs, so the supported rolling upgrade is: upgrade all BEs first, then let FEs send typed paths. * **FE** (`AccessPathExpressionCollector`, `NestedColumnPruning`, `AccessPathPlanCollector`, `DescriptorToThriftConverter`): marks `NULL`/`OFFSET` collector contexts as `META`; checks the physical column's nullability (`getOriginalColumn().isAllowNull`) instead of slot nullability before emitting null-map paths, so outer-join-nullable `NOT NULL` columns and non-nullable fields/structs no longer get `NULL` paths; emits the parent-struct `NULL` path for `element_at(...) IS NULL` only when actually needed; falls back to plain data reads for variant sub-columns; keeps the exact meta path when a sibling data path is also read; preserves fields referenced by unchanged predicates; and keys pruning on the path type instead of string suffixes, rejecting unsupported `META` paths. * **BE** (`ColumnIterator` / `column_reader.cpp`): validates path versions and type-selected payloads; partitions current data / current metadata / descendant routing with explicit per-container ownership (Struct owns the null map; Map/Array and string-like scalar columns own both null map and offsets); derives `NULL_MAP_ONLY` / `OFFSET_ONLY` only when no current or predicate data path requires payload, and marks data children `SKIP` consistently; keeps sibling `META` paths explicit so an unrelated `DATA` projection cannot disable a metadata-only predicate read; routes Map children by the logical `KEYS`/`VALUES` selectors (wildcard expansion, arbitrary nesting) independent of physical child column names; rejects unrecognized Map selectors instead of silently pruning everything; and documents the full routing flow. * **Tests & docs.** BE `ColumnReaderTest` coverage for typed-vs-legacy encoding, metadata-vs-same-named-data disambiguation, meta-read-mode legality, sibling-data-path handling and Map selector validation; `SlotDescriptor` protobuf round-trip of versions and payloads; FE `PruneNestedColumnTest` / `DescriptorToThriftConverterTest` cases; the `nereids_rules_p0/column_pruning` regression suites updated to assert the typed `META` paths, plus the new `left_join_not_null_column` suite guarding the outer-join null-map crash. ### Release note None ### Check List (For Author) - Test: - FE unit test: `./run-fe-ut.sh --run 'org.apache.doris.nereids.rules.rewrite.PruneNestedColumnTest,org.apache.doris.analysis.DescriptorToThriftConverterTest'` (74 passed on the final rebased FE tree) - BE unit test: `./run-be-ut.sh --run --filter='ColumnReaderTest.*:SlotDescriptorTest.AccessPathsPreservedThroughProtobuf'` (50 passed before the final rebase; the final rebuild was blocked before GTest by the missing master-added `thirdparty/installed/lib64/liblance_c.a` in this environment) - Regression test: `nereids_rules_p0/column_pruning` — `string_length_column_pruning`, `null_column_pruning`, `nested_container_offset_pruning`, `lambda_null_pruning`, `left_join_not_null_column` (passed before the final rebase; the final rerun was blocked by the same missing dependency) - Format checks: `build-support/check-format.sh`, `git diff --check` - Behavior changed: Yes. Typed `META` access paths with an explicit version replace the legacy all-`DATA` encoding between new FEs and BEs (upgrade BEs before FEs); struct fields literally named `NULL`/`OFFSET` are now read correctly instead of being pruned as metadata; `IS NULL` on outer-join-nullable `NOT NULL` columns no longer crashes the BE; invalid Map descendant selectors now return an internal error instead of being silently ignored. - Does this need documentation: No --------- Co-authored-by: Hu Shenggang <[email protected]>
Problem Summary: due to apache#50783 ,SHOW PROCESSLIST read the cached policy-selected compute group directly, while query routing gives precedence to the session compute group. When a session or per-query hint selected another compute group, the query ran there but PROCESSLIST reported the stale cached group. Prefer the active session compute group when rendering process rows and retain the cached value as the fallback. SHOW PROCESSLIST now reports the compute group used by the running query. - Test: Unit Test - ./run-fe-ut.sh --run org.apache.doris.qe.ConnectContextTest - Behavior changed: Yes. The CloudCluster column now reports the active session compute group instead of a stale cached value.
### What problem does this PR solve? An Iceberg snapshot can reference a data file that has been removed from storage. With the default `ignore_not_found_file_in_external_table=true`, both file scanners can skip the missing file and return a successful but incomplete result. Exclude Iceberg ranges from the missing-file skip policy, regardless of that setting, while preserving the existing behavior for other table formats. Apply the shared policy at reader initialization and read boundaries. This also prevents a missing delete file reported as `NOT_FOUND` from being swallowed by the scanner. Add unit coverage for Iceberg Parquet/ORC/JNI and ordinary external ranges with both setting values. Add an external regression that creates multiple data files, deletes one actual object, and expects row scans to fail with V1/V2 and both setting values. The regression disables file/result caches and restores the BE configuration after testing. ### Release note Iceberg scans now fail when a required snapshot file is missing instead of silently skipping it, including when `ignore_not_found_file_in_external_table` is enabled. ### Check List (For Author) - Test: The shared-policy GoogleTests passed in a standalone build with actual generated Thrift types; the Iceberg assertion failed with the extracted original policy. Groovy compilation, clang-format 16, and whitespace checks passed. The full BE UT runner was blocked during local clucene/Zstd dependency configuration. The external regression has not been executed locally. - Behavior changed: Yes; missing Iceberg files are no longer ignored. Other table formats retain their existing behavior. - Does this need documentation: No new configuration or API; the corrected behavior is described above.
…oaded (apache#67317) remove() bumped _queue_evict_size_metrics and _total_evict_size_metrics unconditionally, while the physical delete happened only for DOWNLOADED blocks. Removing an EMPTY or SKIP_CACHE block therefore charged a full range().size() -- for an EMPTY block the entire preallocated block size -- while freeing nothing on disk. That is why the reported eviction rate ran far above read plus write traffic combined: 300MiB/s average against 70MiB/s of real traffic, with the difference coming from blocks created and dropped without ever being downloaded. Read the block state once, move both counters into the DOWNLOADED branch, and add evict_not_downloaded_size / evict_not_downloaded_num so that churn becomes measurable instead of hiding inside the eviction rate. DOWNLOADING blocks are not counted here: they are only tagged for deletion and get counted on the removal that actually frees them. test_evict_metrics_only_count_downloaded_blocks covers both directions, including the per-queue counter, which the total alone would not catch. The evict_in_advance test now restores the two configs it changes, so it cannot leave background eviction enabled for whatever runs after it under --gtest_shuffle.
…68051) Inverted-index evaluation for `is_ip_address_in_range` discarded the source column's NULL bitmap. A `NOT` predicate could therefore treat NULL rows as ordinary non-matching rows and return them incorrectly. The evaluator now reads and propagates the index NULL bitmap so bitmap complement evaluation preserves SQL three-valued logic. ### Release note None ### Check List (For Author) - Test <!-- At least one of them must be included. --> - [ ] 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 <!-- Add your reason? --> - Behavior changed: - [ ] No. - [ ] Yes. <!-- Explain the behavior change --> - Does this need documentation? - [ ] No. - [ ] Yes. <!-- Add document PR link here. eg: apache/doris-website#1214 --> ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label <!-- Add branch pick label that this PR should merge into -->
…che#68150) ### What problem does this PR solve? Two external regression cases can report empty result mismatches without first confirming that the preceding operation succeeded. In `test_iceberg_deletion_vector`, the Trino container is restarted before the comparison query. The test previously retried the data query while ignoring command failures, so a startup or query error with empty stdout became a row mismatch. Wait for a successful `SELECT 1` with a bounded startup deadline, then require the comparison command to succeed before checking its rows. Report stdout and stderr on failure, and keep successful empty or incorrect results as assertion failures. In `test_s3_tvf_number_range`, the HDFS Broker Load waiter previously returned normally after cancellation or roughly ten seconds of polling. The caller could then query a freshly truncated table before loading completed. Wait up to 120 seconds using a monotonic clock, return only on `FINISHED`, and fail on cancellation or timeout with the job label and last `SHOW LOAD` result. ### Release note None. Regression-test changes only. ### Check List (For Author) - Test: Both modified suites compile with Groovy 4.0.19; `git diff --check` passes. A local harness evaluates the actual modified control-flow blocks with simulated command/load responses and virtualized waiting. All eight scenarios pass: delayed load completion, cancellation, timeout, missing load job, delayed Trino readiness, comparison-command failure, readiness timeout, and a successful query returning no rows. The original implementation fails these checks. Full external integration execution remains pending CI. - Behavior changed: Test startup/load failures now report their execution status before row comparison; expected data results are unchanged. - Does this need documentation: No.
…apache#68133) ### What problem does this PR solve? 1. `LIKE 'a_b'` is converted to `^a.b\z`, not `^a.b$`. Hyperscan follows PCRE, where `$` also matches right before a newline that ends the value, so `^a.b$` wrongly matched 'acb\n'. `\z` is the end of the value in both Hyperscan and RE2. 2. `LIKE 'a_b%'` is converted to `^a.b`, not `^a.b.*\z`. A trailing `%` matches anything, and so does appending nothing. The anchored form would force `.*` to consume the value to its end, and `.*` only matches valid UTF-8, so RE2 would not match 'acb\xff' while Hyperscan still would. 3. `LIKE 'a_*'` is converted to `^a.\*\z`, not `^a.\*`. The tail anchor used to be skipped whenever the produced regex ended with `*`, a check meant to detect the `.*` expanded from a trailing `%`. An escaped literal `*` ends the regex with the same character, so the pattern lost its anchor entirely and `'ab*xyz'` matched. The decision now comes from the position in the pattern instead of from the produced string. Issue Number: close #xxx Related PR: #xxx Problem Summary: ### Release note None ### Check List (For Author) - Test <!-- At least one of them must be included. --> - [x] Regression test - [x] 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 <!-- Add your reason? --> - Behavior changed: - [ ] No. - [ ] Yes. <!-- Explain the behavior change --> - Does this need documentation? - [ ] No. - [ ] Yes. <!-- Add document PR link here. eg: apache/doris-website#1214 --> ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label <!-- Add branch pick label that this PR should merge into --> Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
…cks (apache#67313) Problem Summary: The disk-pressure protection mode is meant to enter at `enter` (85%) and stay on until usage drops below `exit` (80%), holding its previous state in between. That hold is implemented by `_disk_resource_limit_mode` remembering the previous round — and `check_disk_resource_limit()` wiped it before reading `statfs`: ```cpp if (_capacity > _cur_cache_size) { _disk_resource_limit_mode = false; // runs before statfs is read } ... } else if (_disk_resource_limit_mode && space < exit && inode < exit) { ``` With the memory gone, the exit branch is dead code: the mode dropped as soon as usage fell below `enter`, never holding down to `exit`. The `disk_resource_limit_mode` bvar was unusable for the same reason — a single round wrote 0 and then 1 whenever the mode was immediately re-entered, so it could not be used to tell whether a node was in the mode. ### What this PR changes 1. Drop the pre-clear so the band holds, and publish `_disk_limit_mode_metrics` once, after the decision. 2. Drop the `_disk_resource_limit_mode = true` that `reset_capacity()` forces on when shrinking — see below. 3. Make `_disk_resource_limit_mode` and `_need_evict_cache_in_advance` `std::atomic<bool>`. `run_background_monitor()` writes them without the cache lock while `try_reserve()`, `is_overflow()` and `run_background_gc()` read them, so both plain bools were already racy on master. ### Why the `reset_capacity()` force goes too Both lines are halves of a mechanism that no longer exists. They arrived together in apache#37484, when shrinking was asynchronous: ```cpp cell->is_deleted = true; // tagged only, nothing freed here ... _disk_resource_limit_mode = true; _async_clear_file_cache = true; // a background thread does the removal ``` `reset_capacity()` returned with `_cur_cache_size` still above the new capacity, so the force made `try_reserve()` drain aggressively while the background cleanup caught up, and `if (_capacity > _cur_cache_size)` was the matching "drained, stop" condition. Shrinking is synchronous now — `reset_capacity()` calls `remove()` under the cache lock and returns at the new capacity, and `_async_clear_file_cache` no longer exists in `be/src`. So the force has nothing left to accelerate, while the pre-clear kept firing on its own condition, which holds in ordinary operation whenever the cache is under its budget, not only while a shrink drains. That is the bug. Removing only the pre-clear would leave the force with nothing to turn it off: a shrink on a node whose disk sits in `[exit, enter)` for unrelated reasons — BE logs, another data dir on the same mount — would pin the mode on permanently, and every reservation would evict five times the requested size. The force was also not capacity enforcement during async metadata load: - The loader inserts restored cells through `add_cell()` and never calls `try_reserve()` (`fs_file_cache_storage.cpp:818`, `:1007`, `:1179`). - `try_reserve_during_async_load()` does not consult `_capacity`, and cannot: while loading, `_cur_cache_size` is a partial count growing from zero toward the restored total, so comparing it against the full budget is meaningless. `statfs` is the only signal valid at that point, which is why the mode is the only thing that function checks. ### Deliberately out of scope Real, pre-existing on master, independent of the state machine touched here, each getting its own PR: - **Capacity admission during async metadata load.** Making it work needs the loader to publish the on-disk total up front, or admission deferred until loading completes — a change to the loader's publication protocol, not an `if` in the reservation path. - **The eviction target reused as the admitted size.** `try_reserve()` does `size = 5 * size` under disk pressure and passes that to `QueryFileCacheContext::reserve()`, while `add_cell()` creates a cell of the original size, so `DCHECK(iter->size == cell_size)` at `block_file_cache.cpp:1483` can fire and release builds mis-account query usage. Already reachable on master whenever the disk is at or above `enter` with `enable_file_cache_query_limit` on. - **Republication over deleted files during load.** `load_cache_info_into_memory_from_db()` buffers 10k `BatchLoadArgs` outside `_mutex` (`fs_file_cache_storage.cpp:995`) and `handle_already_loaded_block()` checks only whether a cell exists, never whether the file is still on disk.
`next_day` and `previous_day` reused a mutated date value when the date
argument was constant, producing cumulative cross-row results. Nullable
inputs were also unpacked before execution, causing NULL weekday rows to
be parsed as empty strings and fail the entire query. The functions now
use `ColumnView` to handle constant and nullable columns directly,
compute each row from an independent date value, propagate NULL results,
and continue rejecting invalid non-NULL weekdays.
### Release note
None
### Check List (For Author)
- Test <!-- At least one of them must be included. -->
- [ ] 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 <!-- Add your reason? -->
- Behavior changed:
- [ ] No.
- [ ] Yes. <!-- Explain the behavior change -->
- Does this need documentation?
- [ ] No.
- [ ] Yes. <!-- Add document PR link here. eg:
apache/doris-website#1214 -->
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label <!-- Add branch pick label that this PR
should merge into -->
…8146) Problem Summary: An empty regexp produces a zero-width match, so the expected result is 1. The constant pattern was recognized as a substring pattern and routed to the long-buffer substring optimization. However, this path treated an empty needle as not found. ```sql DROP TABLE IF EXISTS tmp_b8_c01; CREATE TABLE tmp_b8_c01 ( id INT, s STRING, p STRING ) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1 PROPERTIES("replication_num" = "1"); INSERT INTO tmp_b8_c01 VALUES (1, 'abc', ''); SELECT regexp('abc', '') AS const_empty, regexp(s, p) AS column_empty FROM tmp_b8_c01 WHERE id = 1; -- before: +-------------+--------------+ | const_empty | column_empty | +-------------+--------------+ | 0 | 1 | +-------------+--------------+ -- now: +-------------+--------------+ | const_empty | column_empty | +-------------+--------------+ | 1 | 1 | +-------------+--------------+ ``` ### What is changed? - Handle an empty constant substring pattern as matching every non-null input. - Move the long-buffer substring implementation into `constant_substring_fn`. - Remove the separate execute_substring implementation and its special dispatch logic. - Preserve row-boundary checks to prevent matches across adjacent ColumnString rows.
…nded incremental reads (apache#67820) ### What problem does this PR solve? Issue Number: None Related PR: apache#67181, apache#67594 Problem Summary: Bounded cloud `@incr` reads need a safe end timestamp. Waiting by transaction ID can include transactions outside the requested time window, while one slow transaction can hold a global committed prefix and block unrelated tables. FE failover also needs to prevent an old master or an uncertain commit RPC from later committing a TSO that FE has already treated as finished. This PR introduces a durable committed TSO and keeps the active commit-attempt set in the FE master: - Allocate and register a commit TSO immediately before the first Meta Service commit RPC, under the TSO allocator lock. Retries after a fenced response replace the registration with a fresh TSO above the returned fence. - On an explicit success, already-visible result or already-aborted result, remove the transaction registration. On another explicit failure, remove only the exact attempted TSO. - On `KV_TXN_MAYBE_COMMITTED`, an RPC timeout, connection loss or another uncertain result, synchronously advance the per-instance Meta Service fence to the attempted TSO before removing it. If fencing fails, deactivate the TSO service so reads and allocations cannot use an unsafe prefix. - Disable transport-level retries for commits carrying a positive TSO. `MS_TOO_BUSY` remains retryable because Meta Service explicitly rejects it before processing. Non-TSO transactions keep the existing retry behavior. - Derive the committed TSO from the current allocated TSO and the oldest registered attempt, and persist it together with the allocation-window end in one BDB journal record. The default persistence window is reduced from five seconds to one second. - Remove the startup transaction scan, recovery RPC, recovery state, and periodic `checkTransactions()`. A new master persists a fresh window and advances the same global fence before enabling TSO service, so commits using an older TSO are rejected without waiting for PREPARED transactions. - A successful lazy commit can be released from FE memory. Incremental scans ask Meta Service to wait for pending transactions on the selected partitions before fixing their visible versions, preserving readability without a global recovery list. For a strongly consistent cloud read with an explicit end on every incremental relation, FE applies these rules: | Requested end | Behavior | | --- | --- | | After the current TSO physical time | Return `5100 / ERR_INCR_WINDOW_NOT_READY` immediately. | | At or before the durable committed TSO physical time | Admit the window directly. | | Between committed and current TSO physical times | Wait only for the captured FE registrations whose TSO is within the window and whose tables are queried. Return `5101 / ERR_INCR_VISIBLE_WAIT_TIMEOUT` when the wait expires. | After admission, version resolution waits only for pending transactions on the selected partitions. Unrelated tables do not participate in either wait. `information_schema.tso_status` exposes `COMMITTED_TSO` and `COMMITTED_TSO_PHYSICAL_TIME`; the latter is epoch milliseconds and is the maximum globally admitted end timestamp. The existing current TSO and allocation-window columns remain available. The Meta Service fence is one monotonic, non-versioned current-state key in the instance transaction namespace. Commit reads it in the same FDB transaction as the metadata commit and rejects `commit_tso <= fence` with `TXN_COMMIT_TSO_EXPIRED`, returning the effective fence. The check runs only when both the FE request flag and the mutable Meta Service configuration are enabled. Cloud snapshot, clone and rollback do not restore this leadership/commit fence; a restored or cloned instance publishes its current fence when its FE master initializes. Upgrade Meta Service before FE. A missing or unavailable fence RPC keeps a new FE TSO service uninitialized. The new Meta Service error code uses `actual_code` while old clients receive the compatible fallback code. #### Connector error handling | Code | Name | Meaning | Connector action | | --- | --- | --- | --- | | 5100 | `ERR_INCR_WINDOW_NOT_READY` | The requested end is after current TSO, or the FE master/TSO generation changed while establishing the window. | Retry the same end timestamp after `retryAfterMs`; do not advance the incremental offset. Route a retry through the current master when the reason is `TSO_MASTER_CHANGED`. | | 5101 | `ERR_INCR_VISIBLE_WAIT_TIMEOUT` | Relevant commit attempts did not finish within `change_visible_timeout_ms`. | Retry the same end timestamp; do not advance the incremental offset. | MySQL returns SQLSTATE `HY000`; the message contains `reason`, requested end, current TSO, committed TSO, their physical times, timeout and retry delay. Arrow Flight SQL returns `UNAVAILABLE` only for these two errors and includes `doris-error-code` and `doris-error-name` metadata. Other Flight failures retain the original `INTERNAL` wrapping. ### Release note Improve bounded, strongly consistent cloud incremental reads with a durable committed TSO, table-scoped waits and per-instance commit TSO fencing. Expose the committed TSO through `information_schema.tso_status`, distinguish an unavailable window (5100) from a visibility wait timeout (5101), and remove FE startup/periodic transaction recovery scans. Upgrade Meta Service before FE. ### Check List (For Author) - Test - [x] FE unit tests for TSO service/tracker, commit-result handling, Meta Service retry behavior, incremental version waits, MySQL error propagation and Arrow Flight SQL error mapping. - [x] Cloud ASAN unit tests for fence monotonicity and stale-commit rejection, fence-key encoding, and response-code compatibility. - [x] Regression tests `test_committed_tso` and `test_binlog_changes_syntax` passed earlier in this PR with outputs generated by the standard runner. - [x] `./build.sh -j32` and `./build.sh --cloud -j32`. - [x] clang-format 16, check-format, Cloud clang-tidy and build-hygiene checks. - Behavior changed: Yes. Bounded cloud reads use committed TSO/table-scoped waits; uncertain TSO commit attempts are fenced before release; FE no longer scans transactions during startup or periodically. - Does this need documentation: Yes. Connector-facing error handling is documented above.
…ache#68066) Problem Summary: When a BE in a non-normal cloud cluster stays offline, every failed heartbeat after the lost-heartbeat threshold submits another transaction cleanup task. Each task queries get_prepare_txn_by_coordinator, which scans the instance transaction metadata even after cleanup finishes. Restrict these submissions to lost-heartbeat durations in [T, 2T), where T is abort_txn_after_lost_heartbeat_time_second. Keep the existing behavior for NORMAL cloud clusters and non-cloud deployments. This deliberately stops further submissions after the window even if earlier cleanup attempts failed. ### Release note Limit repeated transaction cleanup task submissions for offline BEs in non-normal cloud clusters to a bounded window (5 to 10 minutes after the last successful heartbeat with the default configuration). ### Check List (For Author) - Test: Add HeartbeatMgrTest coverage for all four non-normal cluster states, durations before/inside/after the window, NORMAL and non-cloud behavior, replay, and missing successful heartbeats. Tests and local compilation were not run as requested. Checkstyle on both changed files and git diff --check passed. - Behavior changed: Yes, stop submitting BE-down cleanup tasks for non-normal cloud clusters once the lost-heartbeat duration reaches twice the threshold. - Does this need documentation: No
…#68135) ### What problem does this PR solve? Problem Summary: Ordinary Paimon queries request table cardinality during planning. On a row-count cache miss, the connector planned every split and summed file record counts, consuming CPU and memory proportional to the table's manifests and files even when the query selects only a small partition.
apache#68114) ### What problem does this PR solve? Issue Number: None Problem Summary: When constant folding is skipped (`debug_skip_fold_constant = true`), `element_at(NULL, 1)` is not folded on the FE and reaches the BE with the container typed as a null literal (`TYPE_NULL`, mocked as `UInt8` in the BE). `element_at` opts out of the default null handling, so its return type resolution treated the mock type as a real `BOOL` container and failed with: ``` [INVALID_ARGUMENT][E33] element_at only support array and map so far, but got BOOL ``` In debug builds the preceding `DCHECK` fires before that error is raised. This change makes `element_at` recognize a null-literal container the same way the default null implementation does: the return type resolves to `Nullable(Nothing)` and execution produces a NULL for every row, which matches the folded result. ```sql SET debug_skip_fold_constant = true; SELECT element_at(NULL, 1); -- NULL (previously: error "got BOOL") SELECT element_at(NULL, 'k'); -- NULL ``` ### Release note None ### Check List (For Author) - Test: - Unit Test: `function_array_element_test.element_at_null_literal_container` - Regression test: `query_p0/sql_functions/array_functions/test_element_at_null_container` - Behavior changed: No - Does this need documentation: No ### Check List (For Reviewer who merge this PR) - Confirm the release note - Confirm test cases - Confirm document - Add branch pick label https://claude.ai/code/session_01HXcF45DSFT6fMDvtdNz2w8
… a nullable condition (apache#67931) ### What problem does this PR solve? Issue Number: None Problem Summary: When the condition of `IF` is a `Nullable(Boolean)` column, both `VectorizedIfExpr` and `FunctionIf` normalize it by treating NULL as false. They did this by writing `nested[i] &= !null_map[i]` directly into the nested column of the nullable condition. That nested column can be shared with other columns of the same block. `NULLIF(b, p)` is implemented as `if(b = p, NULL, b)` and wraps `b` itself as the nested column of its `Nullable(Boolean)` result, so `IF(NULLIF(b, p), f, b)` overwrote `b` in place: the else branch read the polluted values and returned a wrong result, and any other projection of `b` in the same block was polluted as well. With `short_circuit_evaluation=true` the expression goes through a different path and returned the correct result, which hid the bug. Build a fresh condition column from `nested & !null_map` instead of mutating the shared nested column in place. ### Release note None ### Check List (For Author) - Test: - Unit Test: `VConditionExprIfTest.NullableCondition_NotPolluteSharedNestedColumn`, `FunctionIfTest.NullableConditionNotPolluteSharedNestedColumn` (both fail without the fix) - Regression test: `test_if_nullable_condition` - Behavior changed: No - Does this need documentation: No https://claude.ai/code/session_013PjVxV5VYPRduC2fubqCzD
…ache#68113) ### What problem does this PR solve? Issue Number: None Problem Summary: Sliding `ROWS` window frames evaluate `sum`/`avg` incrementally: the outgoing row is subtracted from the accumulator and the incoming row is added. For floating-point accumulators this is not exact. Once `2^54 + 1` rounds to `2^54`, subtracting `2^54` again leaves `0` instead of `1`, so the rounding lost by a value that already left the frame keeps distorting later results. ```sql WITH t AS ( SELECT 1 AS id, CAST(18014398509481984 AS DOUBLE) AS v UNION ALL SELECT 2, CAST(1 AS DOUBLE) UNION ALL SELECT 3, CAST(1 AS DOUBLE) ) SELECT id, v, avg(v) OVER (ORDER BY id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS got FROM t ORDER BY id; ``` Before: the third row returned `0.5` (frame `[1, 1]`, sum `1`, count `2`). After: the third row returns `1`. Fix: `AggregateFunctionSum` and `AggregateFunctionAvg` now report `supported_incremental_mode() == false` when the accumulator is a floating-point type, so the analytic sink recomputes each sliding frame from its rows (the same approach PostgreSQL takes by not providing inverse transition functions for `float4`/`float8`). Integer and decimal accumulators are exact and keep the incremental path. Frames that only grow (`UNBOUNDED PRECEDING`) never removed rows and are unaffected. Cost: sliding `ROWS` frames over `FLOAT`/`DOUBLE` columns now cost O(frame size) per row instead of O(1). This is the trade-off for exact results; wide sliding frames over floating-point columns will be slower. ### Release note None ### Check List (For Author) - Test: - Unit Test: `AnalyticSinkOperatorTest.SlidingRowsDouble{Avg,Sum}IgnoresRoundingOfOutgoingRow`, `AggregateFunction{Avg,Sum}Test.test_incremental_mode_only_for_exact_sum` - Regression test: `query_p0/sql_functions/window_functions/test_window_float_sliding_frame` - Behavior changed: Yes (sliding window sum/avg over FLOAT/DOUBLE now return the exact per-frame result; wide frames are slower) - Does this need documentation: No https://claude.ai/code/session_01KSyhoeWWGWukpHP6MBTbEt
…he#68154) ### What problem does this PR solve? Problem Summary: INSERT value normalization directly folds already bound expressions without enabling `keepFunctionSignature`. When `repeat` inside `struct` is folded from an always-nullable function to a non-null string literal, `CreateStruct.withChildren` can recompute the nested field nullability while surrounding array and cast nodes retain their bound types. FE then sends an inconsistent nested column layout and BE aborts when casting the string column to `ColumnNullable`. Preserve the bound function signature around both post-bind constant-folding entry points in `InsertUtils`. For the fast INSERT VALUES analyzer, split binding jobs from post-bind jobs: binding remains under `keepFunctionSignature(false)`, while ordinary and batch post-bind rewrites run under `keepFunctionSignature(true)`. Add regression coverage for both fast and normal INSERT VALUES analysis paths. ### Release note Fix BE crashes when inserting arrays of structs containing foldable nullable functions.
…TABLE LIKE (apache#67809) ### What problem does this PR solve? Problem Summary: CREATE TABLE LIKE reconstructs generated columns from SQL using the caller's session settings, losing the expression settings saved in the source columns. For a generated expression `a * b` over `DECIMAL(20,5)` and `DECIMAL(21,6)`, a source created with `enable_decimal256=true` produces `1.26212529751`, but a clone created with the option disabled produces `1.26212530000` for the same input. SQL mode also affects parsing: a source expression `a || 'x'` created with `PIPES_AS_CONCAT` produces `ax`, while its clone can produce NULL under a different SQL mode. Snapshot each generated column's session settings under the source table's read lock and carry them through `GeneratedColumnDesc`. Restore these settings temporarily when parsing and analyzing the cloned expression, then persist them in the new `Column`. The caller's session is restored after analysis, including on exceptions. Ordinary CREATE TABLE retains its existing session behavior. Existing incorrectly created clones and stored data are not automatically repaired. ### Release note Fix CREATE TABLE LIKE changing generated column results when the caller's expression-related session settings differ from the source table's settings. ### Check List (For Author) - Test - [x] Regression test - Passed `test_generated_column_like_session`, `test_generated_column`, and `test_generated_column_fault_tolerance_nereids` on the final branch's FE. - New coverage includes both decimal256 setting directions, repeated LIKE, SQL mode, NULL values, and preservation of the caller's session. Expected output was generated by `run-regression-test.sh` and verified in subsequent runs. - [x] Unit Test - All 11 `CreateTableLikeTest` tests passed via `run-fe-ut.sh` on the initial validation baseline with the same repair and test files. - The final upstream baseline has an unrelated test-compilation error in `IvmNormalizeMTMVJoinTest` (an outdated `IvmRewriteContext` constructor call). Final FE packaging therefore used `DISABLE_BUILD_UI=ON MVN_OPT=-Dmaven.test.skip=true ./build.sh --fe`. No unrelated test code was changed. Checkstyle passed. - [x] Manual test (add detailed scripts or steps below) - Reproduced both precision and SQL mode differences before replacing FE libraries; verified correct results after replacement. - Restarted the final FE and cloned previously created fixed tables again, verifying persisted session settings and unchanged caller settings. - The test FE used `be_exec_version=13` to match its existing BE. - [ ] No need to test or manual test. Explain why: - Behavior changed: - [ ] No. - [x] Yes. Generated columns created through LIKE preserve the source columns' expression semantics.
…e#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
…pache#68147) Rstrict AI resource creation by user identity
…che#68095) Issue Number: close apache#68035 Related feature: apache#68036 Doris reconstructs loaded Iceberg tables as BaseTable snapshot views. BaseTable implements SupportsDistributedScanPlanning with a default true result, so wrapping RESTTable loses its false override. The existing scan-entry guard then allows unsupported local planning. With restricted metadata credentials this surfaces as an S3 error; a separately documented simulated server residual demonstrates why ignoring the server plan can also change results. Check the original table before statement snapshot conversion, tracked-table publication, and cached TableOwner metadata serialization/weight estimation. Reject unsupported tables before local manifest access and release acquired table/catalog ownership on failure. Preserve the existing scan-entry guard and normal client-planned snapshot semantics. **Rejection includes metadata acquisition, not only SELECT scans.** DESC, SHOW CREATE TABLE, and INSERT target-column binding also fail for server-planned tables. Row-count and partition metadata paths using the same read acquisition are subject to this guard. The sharedWritableTable method itself is unchanged; this does not imply SQL INSERT remains supported. Add a dedicated native Iceberg REST fixture, pinned by multi-platform digest, to the existing Iceberg Compose stack. Keep the existing Spark/Postgres REST baseline. MinIO initialization creates a private test bucket and data-only credentials. The enabled regression requires a working /plan endpoint: an old or missing fixture fails instead of skipping. The fixture digest fixes the contents of an upstream `main` snapshot, built on 2026-04-29 from `b0df3ca01d61b2f7ae7143ac660c6b16e33b6e46` (recorded in the JAR build properties). This commit precedes the `apache-iceberg-1.11.0` tag by 105 commits; the image is not a release build. Moving `latest` cannot change the pinned contents. The retention risk is that the old manifest can become untagged and later be removed upstream, breaking fresh pulls. **Request to CI maintainers:** build a linux/amd64 + linux/arm64 fixture from the upstream `apache-iceberg-1.11.0` tag using the upstream shadowJar task and Dockerfile, and publish it as `doristhirdpartydocker/iceberg-rest-fixture:1.11.0`. Keep the current digest until that artifact exists; verify source/architectures and rerun this regression, then switch to the versioned image with its verified digest. Mirroring the current image into the Doris namespace is a retention fallback, but remains a snapshot. We do not assume the upstream release-image workflow will be repaired in time for this PR. The regression invokes the real /plan endpoint, verifies restricted data-file reads succeed and manifest access returns 403, and checks explicit Doris rejection for SELECT, metadata statements, INSERT, empty tables, and $files with cache enabled/disabled. Client-planned reads remain four rows before and after. No policy proxy is part of this Docker regression. Server-forced planning mode is additionally covered by HTTP RESTCatalog unit tests.
### What problem does this PR solve? Issue Number: None Related PR: apache#67904 Problem Summary: Paimon ORC tables can store timestamp values with nanosecond precision, while Doris exposes timestamps at microsecond precision. The Paimon JNI reader truncates sub-microsecond digits, but the native ORC reader rounded them. For example, `2024-01-02 10:04:05.123456789` was exposed as `.123456` by JNI and `.123457` by the native reader, causing equality predicates to return inconsistent results. The existing Paimon predicate conversion keeps `TIMESTAMP(7/8/9)` comparisons as residual predicates. This change makes the native ORC path use the same truncation semantics as Doris and the JNI reader for row decoding, stripe statistics, and ORC search argument bounds. ### Release note Fix inconsistent timestamp values and predicate results between native ORC and JNI readers for sub-microsecond timestamps. ### Check List (For Author) - Test - [x] Regression test - `./run-regression-test.sh --conf /tmp/yuze-regression-full-conf.groovy --run -d external_table_p0/paimon -s paimon_timestamp_types` - [x] Unit Test - `./run-be-ut.sh --run --filter=NewOrcReaderTest.*Timestamp*:NewOrcReaderTest.ReadTimestampNanosecondsTruncatesToMicroseconds` - [ ] Manual test - [ ] No need to test or manual test - Behavior changed: - [x] Yes. Native ORC timestamps now truncate sub-microsecond digits consistently with Doris precision and the JNI reader. - [ ] No. - 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
…rs on pruned STRUCT columns (apache#68110) ### What problem does this PR solve? Issue Number: None Problem Summary: With `enable_prune_nested_column = true`, the planner splits a STRUCT column's access paths into predicate paths (read before filtering) and lazy paths (read only for surviving rows). SegmentIterator relies on this split when a common expression references the column: it reads the column in the PREDICATE phase, evaluates the expression, and recovers the lazy nested fields afterwards. The TopN filter is a common expression that BE attaches to the scan at runtime, after the planner computed the access paths. When ORDER BY and WHERE reference different fields of the same STRUCT, for example ```sql SELECT struct_element(s, 'a') FROM t WHERE struct_element(s, 'b') IS NOT NULL ORDER BY 1 NULLS LAST LIMIT 1; ``` the predicate paths only contain `s.b.NULL`, so `s.a` is a placeholder (NULL) while the TopN filter `struct_element(s, 'a') <= current_top` is evaluated. Every row of the later tablets is rejected and the global minimum is lost, silently returning a wrong LIMIT result. This PR marks columns referenced by runtime-generated common expressions (TopN filters and runtime filters) and keeps them in the NORMAL read phase, so all access paths are materialized before the expression is evaluated. The lazy split is still used for planner-visible expressions. ### Release note None ### Check List (For Author) - Test: - Unit Test: `SegmentIteratorRuntimeCommonExprTest` covers the lazy split decision for planner expressions, TopN filters, and both on one column. - Regression test: `topn_filter_nested_column_pruning` reproduces the wrong result with TIMESTAMPTZ/INT/DATE STRUCT fields, ASC/DESC, NULLS FIRST/LAST, selective predicates and multi-tablet scans. - Behavior changed: No - Does this need documentation: No https://claude.ai/code/session_01E3gDAafAXZELs6AHVfD9UG
### What problem does this PR solve? Issue Number: N/A Related PR: apache#64093 Problem Summary: With `ASAN_OPTIONS=fast_unwind_on_malloc=0`, an ASAN BE can abort before `main`, including when running `doris_be --version`. OpenMP initialization reached from OpenBLAS probes optional symbols with `dlsym`. On affected glibc versions, a subsequent lookup frees the previous `dlerror` string before clearing its pointer. ASAN's free interceptor collects a slow stack, which reaches Doris' global `dl_iterate_phdr` interposer. Its fallback calls `dlsym` again, reenters the pending error cleanup and frees the same string twice. Exclude only the global `dl_iterate_phdr` interposer from ASAN builds. ASAN then uses the system implementation without reentering `dlsym` through Doris. Keep the PHDR snapshot and dedicated `doris_unwind_iterate_phdr` hook for GNU libunwind; non-ASAN interposition is unchanged. Add an ASAN subprocess regression that re-execs with slow unwinding enabled and performs two failed symbol lookups without consuming `dlerror` between them. Adapt the existing late-`dlopen` test to assert that ASAN keeps the live system view even inside `ScopedPHDRCacheRead`, while the dedicated GNU hook still uses the snapshot. ### Release note Fix an ASAN BE startup double-free when allocation/free stack collection uses slow unwinding. ### Check List (For Author) - Test - [ ] Regression test - [ ] Unit Test execution: added a subprocess regression and updated the PHDR cache test; full local execution is blocked by the installed AWS SDK missing `aws/core/auth/GeneralHTTPCredentialsProvider.h` while compiling unchanged `common/cpp/aws_common.cpp`. - [x] Manual test: - Compiled the actual pre-fix and fixed `phdr_cache.cpp` into the same ASAN startup reproducer (two failed `dlsym` calls, `fast_unwind_on_malloc=0`): pre-fix reports double-free; fixed reaches `main`. - OpenMP initialization from a pre-main constructor with the fixed source and slow unwinding: passed. - Live-loader versus PHDR snapshot checks in ASAN and non-ASAN standalone probes, including a late-loaded DSO and cache refresh: passed. - Updated unit-test source syntax check: passed. - clang-format 16, build hygiene and clang-tidy checks on all three changed files: passed. - Full local test command attempted: `./run-be-ut.sh -j 48 --run --filter='PhdrCache*'` (ASAN; dependency failure noted above). - Behavior changed: - [x] Yes. ASAN uses the system `dl_iterate_phdr` even inside a scoped cache read; its dedicated GNU libunwind hook remains cached. Non-ASAN behavior is unchanged. - Does this need documentation? - [x] No. Internal sanitizer compatibility fix; the source API comment documents the ASAN exception. ### Check List (For Reviewer who merge this PR) - [ ] Confirm the release note - [ ] Confirm test cases - [ ] Confirm document - [ ] Add branch pick label
…ving to unpartitioned (apache#68124) ### What problem does this PR solve? Issue Number: None Related PR: None Problem Summary: After an Iceberg table's default partition spec evolves to unpartitioned, split planning gated the per-file partition metadata on the current spec (`table.spec().isPartitioned()`), so data files written under an older identity spec stopped carrying their partition values. `path_partition_keys` is the union of all specs, so BE does not read those columns from the data file either, and an identity partition column whose value only exists in the file's partition metadata (e.g. a table migrated with `add_files`) was read as NULL, with both `enable_file_scanner_v2=true` and `false`. Gate on whether any spec of the table is partitioned instead. The values, spec id and partition data are already derived from the spec each data file was written with, which is what Iceberg's `PartitionUtil.constantsMap` does. ### Release note None ### Check List (For Author) - Test - [ ] Regression test - [x] 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. - [x] 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
## Problem `UNION ALL` could publish output-column equality that does not hold for every row. Downstream rules may then remove a required window ordering key and change `RANK()` results. Two forms reproduce the problem: 1. Regular children project columns in a different order from their internal output. With child filters proving `a = b`, a union that projects `(c, a, b)` can incorrectly map that equality to `(c, a)` and remove `a` from `ORDER BY c, a`. 2. A regular child proves `a = b`, but constant rows such as `(1, 2)` and `(2, 1)` do not. The union can still claim the output columns are equal and remove `b` from `ORDER BY a, b`. ## Root cause Logical and physical unions independently mapped child equality sets through `child.getOutput()` positions. The authoritative union ordinal mapping is `regularChildrenOutputs`, which can have a different order. The derivation also considered only regular children and ignored every constant row carried by the union. ## Reproduction Create rows `(1, 1, 10)`, `(2, 2, 10)`, and `(1, 1, 20)`, duplicate a filtered `(c, a, b)` child with `UNION ALL`, and compute `RANK() OVER (ORDER BY c, a)`. The two rows with `(c, a) = (10, 2)` must have rank 3. Separately, union filtered table rows satisfying `a = b` with constant rows `(1, 2)` and `(2, 1)`, then compute `RANK() OVER (ORDER BY a, b)`. The four ordered pairs must receive ranks 1, 2, 3, and 4. ## Fix - Share one equal-set derivation between logical and physical unions. - Validate and use each regular child's explicit union-output mapping. - Intersect child equality classes by per-ordinal class signatures, avoiding pairwise quadratic candidate generation. - Refine candidates against every constant row after SQL comparison coercion and constant folding. - Accept only a folded `TRUE`; `NULL`, unsupported coercion, non-foldable expressions, and malformed mappings conservatively provide no equality proof. - Build each surviving equivalence class with linear star edges.
IP functions did not consistently respect the explicit boundaries of
`ColumnString` values. IPv4 and IPv6 text conversions accepted an
otherwise valid address followed by an embedded NUL byte and trailing
data because unbounded parser overloads stopped at the first NUL. In
addition, `is_ipv4_compat` and `is_ipv4_mapped` discarded each binary
string's length and unconditionally read 16 bytes, so short values could
consume bytes from the following row and produce results that changed
with filtering, while oversized values were accepted based only on their
first 16 bytes. Root cause: both paths reduced length-aware string
values to raw pointers before parsing or inspection. This change uses
bounded parsers throughout, removes the unsafe null-terminated parser
overloads, maps parsed IPv4 values directly to IPv6, and requires binary
IPv6 inputs to be exactly 16 bytes before inspecting them. Unit coverage
includes throw, default, nullable, vector, constant, short, valid, and
oversized input paths.
### Release note
None
### Check List (For Author)
- Test <!-- At least one of them must be included. -->
- [ ] 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 <!-- Add your reason? -->
- Behavior changed:
- [ ] No.
- [ ] Yes. <!-- Explain the behavior change -->
- Does this need documentation?
- [ ] No.
- [ ] Yes. <!-- Add document PR link here. eg:
apache/doris-website#1214 -->
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label <!-- Add branch pick label that this PR
should merge into -->
### What problem does this PR solve?
Issue Number: N/A
Problem Summary: AES and SM4 encryption functions previously accepted non-constant mode columns even though execution paths resolve a stable encryption mode. Declare the mode argument as always constant for three-, four-, and five-argument signatures, add BE unit coverage for constant and dynamic modes, and update the GCM regression case to use literal modes.
### Release note
AES_ENCRYPT, AES_DECRYPT, SM4_ENCRYPT, and SM4_DECRYPT now require the mode argument to be constant.
### Check List (For Author)
- Test: Unit Test
- Focused function_string_test AES and SM4 encryption tests
- Behavior changed: Yes. Encryption mode expressions must now be constant.
- Does this need documentation: No.
Owner
Author
|
Closing this fork-local PR; the upstream PR will target apache/doris:master. |
Mryange
pushed a commit
that referenced
this pull request
Oct 22, 2026
…fresh exprId (apache#69111) ### What problem does this PR solve? Problem Summary: When ConstantPropagation replaces an aggregate output by a constant, it materializes the constant in a project above the aggregate, and the project item reused the exprId of the replaced output: LogicalProject ( projects=[..., 1 AS `id`#1, ...] ) +-- LogicalAggregate ( groupByExpr=[id#1], outputExpr=[id#1] ) So one exprId had two definitions, the aggregate output slot and the constant, whose nullable and data type may differ. Rules which compare exprIds only then take them as the same column. For RQG case 11000258898 EliminateUnnecessaryProject removed such a project after the aggregate had been rewritten into `Limit 1`, the plan above fell back to the nullable output slot of the set operation, and the last AdjustNullable pass reported AdjustNullable convert slot 2004-04-28#55 from not-nullable to nullable Fix: Give the constant a fresh exprId only when it really shadows a column, i.e. when the exprId is still produced by the plan below; otherwise keep it: * the constant gets a fresh exprId, and the references above are refreshed with ExprIdRewriter, when the aggregate still outputs the replaced column (its grouping key is kept because all grouping keys are constant) or when a project item re-defines a column which its child still outputs. That is the shadow the old code created, e.g. the RQG case 11000258898 of DORIS-28416. * the constant keeps the exprId when the aggregate removed the constant grouping key from its outputs: the project item is then the only definition of the column, nothing below references the exprId, and consumers which rely on the identity of the column, e.g. the materialized view matching, keep working. The plan of such a query is byte identical to the plan before this change, including the exprIds (verified with the query of `agg_optimize_when_uniform/mv2_0`, for the query side and for the MV side which is generated with constant propagation disabled). The sink also has to follow the fresh exprIds, otherwise it would reference a slot which its child does not output any more; only exprIds are remapped there, the name and the data type declared by the sink are kept (that is why the rule does not replace the slots of the sink by literals). A CTE is rewritten in separate subtree contexts (producer body and consumers) and the consumers, which map their slots to the producer outputs by exprId, are rewritten before the producer. The renamed exprIds are published per CTE (`StatementContext#producerExprIdRemap`), and `RewriteCteChildren` refreshes both maps of every consumer with the last exprId of the chain (`ExprIdRewriter#lastExprId`). Reproduction: ConstantPropagationFreshExprIdTest runs this rule alone, so the project above the aggregate is still visible in the plan, and asserts that it does not reuse the exprId of the aggregate output and that the plan above references the fresh exprIds. ConstantPropagationTest used to pin the reused exprIds in its constant project expectations; it now asserts fresh exprIds. Both fail before this change. ### Release note None ### Check List (For Author) - Test: Unit Test - ConstantPropagationFreshExprIdTest (new): fails before with "the constant project reuses the exprId of the aggregate output". - ConstantPropagationTest: expectations updated, fails before with "the constant project item must not reuse the exprId of the replaced output slot". - 31 related FE unit test classes (constant propagation, constant cte, set operation, column pruning, fd, uniform, sql plan suite, runtime filter, ...) rerun: 385 tests, 0 failures. - Behavior changed: Yes. A constant materialized above an aggregate has its own exprId and the plan above references it, so one exprId no longer describes two different columns. - Does this need documentation: No
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix Require constant mode arguments for encryption functions
What problem does this PR solve?
Issue Number: N/A
Problem Summary: AES and SM4 encryption functions resolve the encryption mode as function-level execution state, but previously accepted a non-constant mode column. This allowed rows in one function invocation to request different modes even though optimized execution paths assume one stable mode. Root cause: the encryption function implementations did not declare the mode argument through
get_arguments_that_are_always_constant(). This change marks argument 2 as constant for three-argument signatures and argument 3 for four- and five-argument signatures, adds BE unit coverage for valid constant combinations and rejected dynamic modes, and updates the GCM regression case to use literal modes while verifying that a mode column is rejected.Release note
AES_ENCRYPT, AES_DECRYPT, SM4_ENCRYPT, and SM4_DECRYPT now require the mode argument to be constant.
Check List (For Author)
Test
./run-be-ut.sh --run --filter='function_string_test.function_aes_encrypt_test:function_string_test.function_aes_decrypt_test:function_string_test.function_encryption_mode_must_be_constant_test:function_string_test.function_sm4_encrypt_test:function_string_test.function_sm4_decrypt_test' -j 48Behavior changed:
Does this need documentation?
Check List (For Reviewer who merge this PR)