Skip to content

[feature](paimon) Add SQL and TVF ANN search with Paimon 2.1 - #69493

Open
pzhdfy wants to merge 28 commits into
apache:branch-4.2from
pzhdfy:branch-4.2-paimon-rust-ann
Open

pzhdfy wants to merge 28 commits into
apache:branch-4.2from
pzhdfy:branch-4.2-paimon-rust-ann

Conversation

@pzhdfy

@pzhdfy pzhdfy commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Related PRs: #66227, #69343, #70075

Upgrade branch-4.2 to Paimon Java 2.1.0 and paimon-rust 0.5.0-rc1, and add primary-key vector search through ordinary SQL and the shared vector_search TVF.

  • Align Java SDK compatibility with master: preserve nullable-key MERGE matched updates/deletes, reject unsupported latest-delta OPTIONS, and adapt removed APIs and SDK schema/timestamp behavior.
  • Push down ORDER BY l2_distance_approximate(...) ASC and inner_product_approximate(...) DESC LIMIT ... to eligible Paimon Rust scans. Preserve ordinary execution when the existing planner guards decline.
  • Dispatch the shared vector_search interface to Paimon while retaining Lance's provider. Support matching VECTOR<FLOAT> PK indexes with L2 and inner-product metrics.
  • Return squared L2 or negative inner product as TVF _distance, with one global TopN/offset after merging bucket candidates. Ordinary SQL distance functions retain their existing units.
  • Keep outer WHERE/default filter as postfilters; apply explicit prefilter=true before candidate selection. Normalize retained predicates and preserve their descriptor dependencies through column pruning.
  • Implement use_index=false with FULL mode in the serialized table schema and no ANN index sources in bucket payloads, preserving all planned data files and row ranges.
  • Reject catalog initialization when both legacy user.sys and privilege.sys markers exist. Run the checks and rejected-catalog cleanup in the authentication context; propagate metadata access errors instead of silently bypassing removed ACLs.
  • Preserve SQL distance validation by declining ANN pushdown for nullable vector fields, including historical schemas where the same field was nullable or absent. Use Paimon's actual schema constraints; Doris external-column nullability alone does not establish eligibility. The TVF retains its explicit search semantics.
  • Restore the shared regression comparator's original behavior. Normalize schema-declared binary leaves explicitly in the Paimon consistency suite, preserving hex-looking VARCHAR values and all byte values.
  • Use optional compatible Thrift fields; reserve the Paimon payload layout on master via merged [chore](paimon) Upgrade paimon-rust and reserve ANN Thrift fields #70075.

Example:

SELECT id, _distance
FROM vector_search(
    'table' = 'paimon_catalog.demo.items',
    'column' = 'embedding',
    'query_vector' = '[0.1, 0.2, 0.3]',
    'metric' = 'l2',
    'top_k' = '10'
)
ORDER BY _distance;

Validation

Current head: 211eab204f3.

Current functional fixes:

  • run-fe-ut.sh --coverage: FE main/test compilation and Checkstyle passed; 151 tests across PaimonCatalogCompatibilityTest, PaimonExternalMetaCacheTest, PushDownVectorTopNIntoPaimonScanTest and PaimonVectorSearchTableValuedFunctionTest passed with no failures/errors/skips.
  • Coverage includes ordinary and legacy ACL warehouses, wrappers, metadata/close failures, authentication context, SQL L2/IP nullable vectors, historical nullable/missing vector fields, and a non-nullable positive control independent of Doris external nullability.
  • Current regression framework rebuilt and packaged: 51 unit tests passed. New negative cases prevent plain or nested 0x41 and A from comparing equal, while actual byte arrays and explicitly encoded bytes remain comparable.
  • ANN and Spark/Doris consistency suites passed dry-run: 2 suites, 0 failures/fatal errors/skips. After completing the NULL fixture's deletion-vector options, its dry-run passed again (1 suite, 0 failures). External Doris/Spark end-to-end execution remains pending; dry-run does not execute those queries.
  • SDK 2.1 metadata probe successfully created nullable and NOT NULL VECTOR<FLOAT,16> primary-key tables with partial-update/deletion-vector options. The probe also enabled the PK-vector index options through ALTER. This checks schema/options acceptance, not Spark writes or index building.
  • Local Doris code-review skill review updated with individual conclusions for all 17 critical checkpoints. git diff --check passed for the current fixes.

Earlier complete validation at ada008c4ba5 (native/JNI sources are unchanged by the current fixes):

  • Full FE and all BE Java extensions built with JDK 17 and zero Checkstyle violations. Focused FE/JNI tests: 511 distinct cases in 23 classes passed across the initial run and targeted rerun.
  • Full Clang ASAN/UBSAN BE build, link, installation and CDC packaging passed using BUILD_TYPE=ASAN EXTRA_CXX_FLAGS='-Xclang -debug-info-kind=line-tables-only' DORIS_TOOLCHAIN=clang DISABLE_BE_JAVA_EXTENSIONS=ON ./build.sh --be -j 8. doris_be --version passed with the standard JNI/HDFS library paths.
  • build-support/check-format.sh passed for 4,899 C/C++ files with clang-format 16. BE reader and predicate-converter test sources passed syntax compilation with standard UT options; the full BE gtest binary has not been run.
  • Java 2.1 → Rust 0.5 wire probe decoded indexed and exact bucket payloads with indexed/unindexed files and row ranges, and rejected truncated payloads. This did not read physical files.
  • The ANN, SDK 2.1 compatibility and nullable-key MERGE suites passed dry-run (3 suites). SDK compatibility regression result files were imported from master [improvement](fe) Upgrade Paimon to 2.1.0 #69343.

Compatibility and remaining limitation

  • Mixed-version compatibility requires a query error instead of a process crash; query functionality during rolling upgrades is not guaranteed. The generic Rust-reader bit does not negotiate ANN separately: an older BE can reject the new ANN request with an empty-split error. Old-FE serialized privilege wrappers can fail in the upgraded JNI SDK with an explicit upgrade error. These error paths were inspected; a real mixed-version cluster has not been exercised locally.
  • Paimon 2.1 removes upstream legacy file-based privileges. Catalog initialization now rejects warehouses containing the old ACL metadata; authorization must be migrated before those warehouses can be used.
  • SQL ANN requires the vector field to be NOT NULL in the current and historical schemas. Otherwise ordinary execution preserves the distance function's NULL error behavior.
  • Rust vector eager materialization memory budgeting remains deferred from this functional work.

Release note

Upgrade Paimon Java to 2.1.0 and paimon-rust to 0.5.0-rc1. Add Paimon SQL ANN pushdown and vector_search TVF support, including exact searches with use_index=false. Fix matched MERGE updates/deletes for NULL primary keys and reject unsupported latest-delta OPTIONS.

Deployments using Paimon's removed legacy file-based privilege system must migrate authorization before upgrading; affected catalogs are explicitly rejected. SQL ANN pushdown preserves ordinary NULL validation by requiring NOT NULL vector schemas, including their history.

Check List (For Author)

  • Unit tests and regression coverage added or adapted
  • Local compilation and focused test verification complete (external end-to-end regression remains pending)
  • Local Doris code-review skill review complete (compatibility policy and deferred memory limitation described above)
  • Behavior changed: Yes; SDK upgrade and Paimon ANN/TVF search.
  • Documentation: interface and compatibility restrictions described above.

dengfangyuan and others added 8 commits October 22, 2026 16:29
…the FE off the removed privilege package

Paimon 2.1 removes the privilege package the Doris FE paimon path depended
on; this swaps the dependency to the 2.1-community-release line and ports
the FE references to the replacement API surface.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
…stack

Order-by-distance pushdown over the PK-vector index (l2 / inner_product
metrics), executed exclusively by the BE paimon-rust reader:

- FE: PushDownVectorTopNIntoPaimonScan rewrite (bounded TopN -> index-only
  scan with the __paimon_search_score_to_dis synthetic output column) and
  the AnnTopNInfo / vector payload plumbing down to the split.
- Rust eligibility gates: the vector capability bit is negotiated separately
  from the batch rust bit (a vector payload rides an empty paimon_split,
  which an older rust-capable BE would reject), the table/storage/backend
  gates are unified between the batch and vector paths, raw-convertible
  compacted splits skip the merge-reader gates, and the rewrite pre-flights
  the gate because a vector split has no JNI fallback.
- BE: the paimon-rust vector reader mode (bucket vector search split
  deserialization, score-to-distance transform, synthetic column fill).
- Housekeeping caught by the port: clang-format of the ANN reader files,
  FileSystemSchemaManager in the rust reader schema tests, the privilege
  references the 2.1 port missed, and a docs note that read.batch-size is
  currently a no-op on the PK-vector path.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

Conflicts:
	fe/fe-core/src/main/java/org/apache/doris/datasource/paimon/source/PaimonScanNode.java
	fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFileScan.java
…s and adapt the test suites

Finalization of the 2.1 stack switch:

- Pin the Paimon dependency to the released community 2.1.0 (identical
  content to the snapshot it replaces).
- Mirror the s3.* credentials into the catalog options: the 2.1 SDK's
  S3FileIO reads credentials from CatalogContext.options() where the
  previous version picked up the endpoint-scoped properties.
- Regression suites: a new end-to-end suite for the PK-vector ANN path
  (rust vs brute-force differential legs), adaptation of the write suites
  and fixtures to the 2.1 SDK / Spark behaviors, and the before-epoch
  timestamp-to-date expectation for 2.1.0.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
…review)

Addresses the P1/P2 review findings on PushDownVectorTopNIntoPaimonScan:

P1 - Keep residual filtering before the bounded vector top-N. The BE
paimon-rust predicate converter skips conjuncts it cannot represent
(and the synthetic distance column is outside its field registry), and
the engine re-applies those residuals on the returned block -- after the
top-K rows were already selected. With candidate distances 0, 2 and 3,
a `WHERE dis > 1 ORDER BY dis LIMIT 1` fetched only the distance-0 row
and returned nothing. The rewrite now fires with a Filter only when
every conjunct provably rides into the vector search: a comparison / IN /
null-check on a table column whose Doris type is in the converter's
supported set (mirrors PaimonRustPredicateConverter._is_supported_slot_type).
Anything else declines the rewrite and the query computes the distance
in Doris, which is always correct. Verified end to end: the differential
leg caught the empty result on the unfixed build and passes on the
fixed one.

P1 - Do not strip value-changing casts from the indexed vector. A legal
cast chain can change vector values (an ARRAY<FLOAT> -> ARRAY<INT> ->
ARRAY<FLOAT> round trip loses precision), so searching the original
vectors while the query means the casted ones changes the ranking. The
rewrite now accepts a direct indexed column slot only.

P1 - Preserve the relation's file-creation-time restriction on the
vector path. The ordinary path drops manifest entries older than the
bound, but the PK-vector search plans its own splits and never consults
the bound, so old files' nearest neighbors could leak into the result. A
scan carrying scan.file-creation-time-millis now declines the rewrite
(snapshot / tag / version selectors are resolved into the table before
the vector search and stay eligible).

P2 - Check the projection capabilities before committing the rewrite. A
PK-vector split has no JNI fallback, so a query whose projected columns
would set the projectedVariant bound (nested Variant) or an ORC table
with TIMESTAMP_LTZ in its schema -- both scan-node bounds with no
vector-path fallback -- would turn a supported query into an error.
Both are now pre-flighted and decline instead, keeping the query on an
ordinary supported path.

Tests: PushDownVectorTopNIntoPaimonScanTest grows from 20 to 27 cases
(distance-predicate / unsupported-type / expression filters decline, a
simple column filter still rides, file-creation-time declines while a
snapshot selector does not, lossy cast declines, Variant projection
declines; the two distance-predicate positives flip to the new sound
semantics). The ANN regression suite adds the requested differential
legs: a distance lower bound, an unconvertible ARRAY<FLOAT> predicate
and a file-creation-time bound, each compared against the rust-disabled
brute force.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Replace the 3.1.4-SNAPSHOT dependency with its release build. The 4.1.0
artifact is byte-identical to the snapshot it replaces (same class list
and file sizes, same shaded paimon 2.1.0 / hive 3.1.3, identical pom
dependency declarations), so this only pins the FE build to a stable
release version.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
…NN path

Static review of this PR surfaced twelve soundness and compatibility
gaps on the PK-vector (ANN) search path; every one was verified against
the pinned sources before the fix:

- Wire protocol: TPaimonFileDesc.vector_payload moves from field 20 to
  21 and TFileScanRangeParams.external_search_request from 41 to 42 --
  both IDs are already reserved on master (original_file_path,
  fluss_properties), and reusing them would make a mixed-version cluster
  drop the payload instead of decoding it. BE/FE must upgrade together.
- Vector capability negotiation: a new heartbeat bit
  supports_paimon_rust_vector_reader (TBackendInfo field 12, free on all
  branches) gates the one-way rewrite separately from the batch rust
  bit, so a rolling upgrade keeps ordinary rust reads working and only
  declines the vector rewrite against older BEs.
- Partitioned vector splits now carry the derived partition values
  (PaimonSplit.setPaimonPartitionValues), which setPaimonParams demands
  for any table with partition keys.
- The rewrite pre-flight now also declines: a query vector containing a
  NULL element (getDouble() would silently search a zero coordinate
  while the un-rewritten function raises); scan.creation-time-millis
  (resolves into the same internal file-creation bound the vector search
  never consults); a data predicate on a table without deletion vectors
  or with merge-on-read (paimon-rust rejects it AFTER the one-way
  rewrite); a table column named __paimon_search_score_to_dis (collides
  with the synthetic distance slot); and an expression over a complex
  column (nested pruning reduces the scan tuple while the vector reader
  projects only root names -- the struct SerDe then binds children by
  ordinal). The shape whitelist additionally rejects NullLiteral
  operands: the BE converter rejects a null literal and with it the
  whole predicate, leaving it in the post-fetch residual. The scan node
  keeps the nested-projection bound as a loud backstop for vector
  splits and logs the vector-capability reason.
- BE: _convert_score_to_distance maps zero and out-of-range scores to
  +inf instead of negative sentinels -- a zero score is reachable from a
  genuine huge distance (the search-mode=full exact fallback computes
  squared L2 in f32), and -2 sorted ahead of every finite distance,
  inverting the coordinator's TopN. _build_read_columns skips the
  synthetic distance name only in vector mode, so an ordinary scan of a
  real column with that name keeps reading it. The BE test include path
  is fixed (the file never compiled).
- Regression framework: the 0x-token decode pass only substitutes
  UTF-8-round-trippable bytes and keeps the lossless hex token otherwise
  -- replacement-character decoding made 0x80 and 0x81 compare equal.

Verified: FE UT 36/36 (rewrite) + 96/0 (scan node) + 22/22 (rust
compat) + 4/4 (capability); BE UT 30/30; the full ANN regression suite
including the four new differential legs (no-deletion-vector first-row
table, partitioned table, NULL query vector, IN with a NULL option).

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Six new findings, all verified and fixed:

- Branch identity: the pre-flight resolved the cached main table while the
  scan reads the relation's bound branch table, so a branch with a different
  index metric scored and reordered with the wrong metric. All four
  pre-flight sites now resolve the bound table (relation snapshot, or the
  options-applied table for t@options); time-travel relations benefit too.
- Historical scalar evolution: the vector path skipped the batch reader's
  per-file schema gate, so a TIMESTAMP(3)->(9) widening would NULL
  out-of-range values through Arrow's safe cast. The rewrite now declines
  any rust-incompatible schema history, and the scan node re-checks per
  split (loud backstop mirroring the pre-flight exactly).
- Generic mapping exception: FileQueryScanNode skipped the synthetic
  distance name for every external catalog, breaking real same-named Hive
  columns; the skip now applies only when the schema has no such column.
- Nonmovable projection: a NoneMovableFunction (assert_true) in the ANN
  project must keep evaluating below the TopN; any nonmovable expression
  outside the order-key alias now declines the rewrite.
- Pruned bare slot: a bare complex slot whose type was already reduced by
  nested pruning now declines (slot type must still equal the original
  column's), instead of tripping the desc-side guard loudly.
- IN beyond the converter cap: the whitelist mirrors the BE converter's
  16-bit child count, so a raised expr_children_limit no longer drops the
  predicate into the post-fetch residual.

Carried P1 threads closed at their narrowed edges: the pinned-empty
generation is fenced in getVectorSearchSplits exactly like the ordinary
path (a first commit after binding is no longer readable by vector
planning), and the pruned-bare-slot / IN-cap cases above.

The stored-NULL differential is kept as a documented limitation: a
nullability-based decline cannot ship until PaimonExternalTable.loadSchema
stops hardcoding isAllowNull=true (today every paimon column, even PK
columns, maps as nullable, so the gate would disable the rewrite for every
table). Follow-ups recorded in the review thread.

Tests: rewrite rule 36 -> 42 cases, PaimonScanNode +3 (fence twin, loud
per-file backstop, schemaId-matching encode); the ANN e2e suite stays
green with a new assert_true error-parity leg. BE untouched.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
- Paimon 2.1 turned SchemaManager into an interface; the connector test
  moves to the FileSystemSchemaManager default implementation.
- The LogicalFileScan conflict resolution missed a blank line between
  constructors (checkstyle).

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@pzhdfy
pzhdfy requested a review from yiguolei as a code owner October 23, 2026 02:35
@hello-stephen

Copy link
Copy Markdown
Contributor

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

Please clearly describe your PR:

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

@Gabriel39

Copy link
Copy Markdown
Contributor

/review

@Gabriel39

Copy link
Copy Markdown
Contributor

run buildall

Comment thread gensrc/thrift/HeartbeatService.thrift Resolved

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Static review of #69493 at 8fd3bec. Six verified P2 findings are inline: stored-NULL error suppression, missing TIMESTAMP_NS preflight, reserved materializer names, an overbroad nested-distance exemption, retained ORC/LTZ files, and loss of literal-string identity in the shared regression oracle.

Critical checkpoints:

  1. Goal and behavior: the SDK upgrade and PK-vector ANN path are connected from Nereids through split serialization to Rust. The six findings prevent full correctness/compatibility; new tests do not cover these inputs.
  2. Scope and clarity: changes span all 61 authoritative paths; the shared eligibility refactor is relevant. The regression helper affects comparisons beyond ANN and needs the inline correction.
  3. Concurrency: no new threads or lock order; Backend capability fields are volatile and heartbeat/replay updates were traced. Scan-local and split-local ownership examined; no additional concrete race found.
  4. Lifecycle/static initialization: C ABI setters copy inputs, filters transfer ownership, returned streams own required state, and RAII handles/Arrow callbacks cover examined error paths. No new cross-translation-unit static dependency identified.
  5. Configuration: existing Rust-reader and FileScannerV2 session switches gate the rewrite; no new dynamic configuration item.
  6. Compatibility: Java Paimon 1.4.2 -> 2.1.0 and Hive shade 3.1.3 -> 4.1.0 reviewed, including VECTOR/JNI physical layout, removed privilege wrapper, S3 options and retained schema/file compatibility. Inline findings cover remaining proven input-shape failures.
  7. Thrift: touched definitions compared with master and branch-4.2/4.1/4.0/3.1. Added IDs 12/21/6/42 avoid collisions, including master reservations 20/41. Required members are inside a new optional, capability-gated payload type; no old-sender required-field failure demonstrated.
  8. Parallel paths: batch Rust, vector Rust, JNI/native fallback, logical/physical/lazy scan copies, filesystem/HMS/JDBC and relevant REST/DLF paths reviewed. New vector plans have no fallback, which makes the reported preflight gaps observable failures.
  9. Conditions: predicate whitelists, NULL query elements, IN bounds, incremental/file-time exclusions, branch/snapshot identity and pinned-empty state traced. Canonical field casing is preserved; apparent lowercasing issues were dismissed from actual descriptor code.
  10. Tests: inspected FE/BE unit and differential regression additions; no builds or tests executed under the static-only contract. Missing cases are stated inline. Profile presence alone is not proof of vector execution.
  11. Expected results: inspected changed temporal/date, table-property and oversized-row expectations; no additional proven expectation defect. The new shared binary normalization can hide mismatches (inline).
  12. Observability: ANN explain fields, fallback reason logging and Rust timers are present. No additional critical logging/metrics defect established; large-K behavior was not benchmarked.
  13. Transactions/persistence: no changed write/commit/EditLog protocol. New heartbeat capability serialization and replay/default-false downgrade behavior checked.
  14. Data writes/crashes: production changes are read/planning paths; no new table mutation or transaction atomicity change. Reader cleanup/error propagation inspected statically.
  15. FE/BE state: AnnTopNInfo survives logical/physical copies and translation; query-wide request and per-bucket bytes reach the Rust reader. Old BEs are excluded by independently negotiated vector support.
  16. Performance/memory: source reads stream into bounded search heaps; selected TopK payloads are eagerly materialized and ignore ordinary batch-size controls. Static inspection does not establish a separate lifetime/tracker defect; runtime memory/cancellation and dependency-linkage validation remain outside this review.
  17. Other concerns: the whole PR and upstream/downstream special cases were checked beyond the first finding; candidate dispositions and risk coverage are recorded in the shared ledger.

User focus: no additional focus was supplied. Existing thread 4357063534 about reusing the heartbeat flag was reviewed as a duplicate fence and not reposted; no existing P0/P1 blocker was independently confirmed. Coverage limits: static source review only, with no build, test, external-service execution or performance measurements. No repository source changes or submodule initialization were performed.

Review converged after 2 round(s).

dengfangyuan and others added 3 commits October 23, 2026 16:39
Per review: drop the separate supports_paimon_rust_vector_reader field
and gate the PK-vector rewrite on supports_paimon_rust_reader alone. The
rust reader bit has not shipped in any release yet, and the PK-vector
protocol ships in the same release, so no deployed BE can ever report
the rust bit without the vector protocol — the separate negotiation
(and its mixed-version window) cannot occur in practice.

Removes the thrift field, the BE heartbeat report, the FE backend-state
plumbing, and the vectorEligible layer; the vector gates now reuse the
plain eligible() computation.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Per the static review round on 8fd3bec:

- Nanosecond pre-flight: a TIMESTAMP_NS column in the CURRENT schema (no
  evolution history) passed the pre-flight but tripped the scan node's
  nanosecond-reader gate, which a no-fallback vector split turns into a
  query error. The pre-flight now mirrors PaimonUtil.containsTimestampNs
  over the slots the Project and Filter reference.
- Reserved materializer names: a user column named __paimon_search_score
  or _PKEY_VECTOR_POSITION makes the rust table open fail after the
  one-way rewrite; both names join the synthetic-distance collision check.
- Distance exemption narrowed: only the call the rewrite actually
  replaces (the one equal to the order-key expression) may exempt its
  slots; a distinct distance call keeps its complex-slot whole-column
  guard instead of shipping a projection rust cannot materialize.
- ORC era detection: the orc-ltz pre-flight checked only the CURRENT file
  format, so a table written ORC with TIMESTAMP_LTZ and later switched
  to Parquet passed while setPaimonParams still detected the retained
  ORC files. Any schema era that declared ORC and carried LTZ columns
  (its own or the current schema's) now declines.

Tests: four new rewrite-rule cases (45 total, all green); the ANN e2e
suite stays green against the tighter pre-flight.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…ries

The 0x-token substitution ran as a substring replacement on every
normalized string, so a literal-text fragment shaped like a token could
collapse distinct values across engines (Spark "prefixA" vs Doris
"prefix0x41" comparing equal after the decode), and quoted strings and
map keys were equally exposed.

The token pattern now requires a value/element boundary (negative
lookbehind on alphanumerics, quotes and backslash), so only shapes Doris
can only have produced as a binary element ("[0x616C, ", "{0x41: ",
"ROW(0x61") decode; the quantifier also stops matching a bare "0x" with
zero byte pairs. A literal string whose whole value coincides with a
bare token remains the one documented ambiguity — distinguishing it
needs column types the comparison does not have.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@Gabriel39

Copy link
Copy Markdown
Contributor

/review

@Gabriel39

Copy link
Copy Markdown
Contributor

run buildall

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed #69493 at 199ad37. Request changes for two new P1 findings (regression-framework syntax and unaccounted eager vector materialization) and one P2 S3 credential-precedence regression.

Critical checkpoint conclusions:

  1. Goal and proof: the SDK upgrade and PK-vector ANN path are implemented across planner, split transport and BE; focused FE/BE tests and differential regression cases are present, but this static review does not prove runtime success.
  2. Scope: the production changes form a coherent feature/SDK migration; shared regression normalization expands the affected surface and contains the syntax finding.
  3. Concurrency and locks: query planning and scanner-local state introduce no new shared lock order; Rust executes through its Tokio runtime. Its unaccounted eager allocations are covered by the memory finding.
  4. Lifecycle: table reuse keys include schema/options/branch, split cleanup follows ownership order, and the pinned eager API returns an independently owned Arrow stream before local handles are freed. No additional lifetime defect established.
  5. Configuration: existing Rust-reader and FileScannerV2 session switches gate the feature; no new dynamic server configuration is introduced.
  6. Compatibility: VECTOR is consistently mapped to Doris ARRAY with the corresponding JNI physical accessor. Unsupported reader shapes mostly decline before the one-way rewrite; existing NULL-vector and retained-ORC concerns remain below.
  7. Thrift: touched definitions were compared on HEAD, branch-4.2, branch-4.1, branch-4.0, branch-3.1 and master. New parent fields do not reuse IDs; master's reserved fields20/41 are avoided. Required children belong to a wholly new optional payload, so old readers skip that payload.
  8. Parallel paths: normal batch/raw/JNI paths, Hudi/lazy scan copies and both metrics were checked. The shared filesystem/HMS/JDBC S3-option mirror overwrites explicit provider options, as reported inline; generated Hadoop defaults must preserve explicit catalog choices.
  9. Conditional checks: filter shapes/types/NULL literals/IN size, snapshot/branch/options/empty generation, nested projection, nanoseconds and reserved names were traced through callers and consumers. Downstream TopN analysis rejects limit overflow; runtime filters do not cross the retained TopN.
  10. Test coverage: positive and negative planner cases, wire/schema guards, score conversion, partition metadata, filter fallback, assertions and both metrics are represented. No eager-memory admission test covers the new resource defect.
  11. Changed expected results: timestamp/date, property-default and error-prefix changes were inspected; no golden result files were edited. Framework syntax must be repaired before these suites can run.
  12. Observability: existing reader open/read/Arrow timers cover execution, and fallback-reason logs explain dispatch without logging credential values. No additional observability blocker established.
  13. Transactions and persistence: production EditLog, commit and failover logic are unchanged; relation snapshot selection and pinned-empty fencing were traced.
  14. Writes and atomicity: production write/transaction paths are unchanged; the adjusted write-failure test still checks rows and snapshot state after failure.
  15. FE-BE variables: AnnTopNInfo survives logical/physical copies and translation; query-wide search parameters and per-split payload agree with BE consumption.
  16. Performance and memory: table-handle reuse and merge-free compacted batch reads are retained. Eager all-K payload collection/reordering bypasses adaptive batch sizing and tracked admission, as detailed inline.
  17. Other checks: source casing prevents the suspected ordinary score-name misrouting, and small f32 score/tie differences were not raised as a separate defect under the approximate ANN contract.

Existing review context was revalidated and not reposted. The stored-NULL-vector validation issue in discussion4357228424 still applies. Discussion4357228441 also remains applicable to per-level file formats: a Parquet default plus file.format.per.level='0:orc' can retain ORC/LTZ files that the preflight misses. Its original schema-history trigger is now guarded. Nanosecond projection (4357228428), reserved vector materializer names (4357228431), distinct distance-call exemptions (4357228435), and the redundant heartbeat capability (4357063534) are addressed. Generic string/binary normalization ambiguity remains covered by4357228447; the syntax failure reported here is distinct. No existing P0/P1 inline finding required carrying forward.

User focus: no additional focus points were supplied. All 55 authoritative changed paths and relevant upstream/downstream contracts received static coverage. Builds, tests, live query execution and SDK interoperability matrices were not run, as required by the review contract; no source files or submodules were modified.

Review converged after 3 round(s).

…Groovy

The lookbehind's escaped quote terminated the double-quoted string literal
mid-pattern, so the shared framework fails to compile and no suite can
start. The pattern moves to a slashy string literal, where neither the
backslash nor either quote character needs escaping.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 61.19% (454/742) 🎉
Increment coverage report
Complete coverage report

The mirrorHadoopS3OptionsToCatalogOptions loop set every fs.s3a.* entry
from the generated Hadoop configuration unconditionally, so for a catalog
with static s3 keys plus an explicit assumed-role credentials provider
the Hadoop side's SimpleAWSCredentialsProvider replaced the requested
provider in the catalog options — the warehouse then re-opened under the
base identity and failed with AccessDenied. The mirror now fills only
options the catalog has not already set: the user's explicit fs.s3a.*
entries keep precedence over the generated defaults. This affects the
filesystem, HMS and JDBC paimon catalog variants alike.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 61.14% (461/754) 🎉
Increment coverage report
Complete coverage report

@Gabriel39

Copy link
Copy Markdown
Contributor

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Request changes on exact head af5c7cc. Four new verified findings are inline: legacy Paimon authorization is silently removed, legacy serialized privilege tables break BE-first upgrades, vector scans bypass cross-storage file eligibility, and non-finite query vectors change supported queries into errors.

Existing blocking finding 4358943088 still applies: uncapped LIMIT+OFFSET reaches eager Rust materialization without tracked admission or a byte bound. It is carried in existing_blocking_comment_ids rather than reposted. The previous Groovy quoting P1 is fixed by the slashy literal; the explicit S3-provider overwrite is fixed by filling only absent options. Existing stored-NULL-vector, per-level ORC/LTZ eligibility and literal-comparator ambiguities remain covered by their existing threads and are not duplicated. Reserved-name, projected nanosecond timestamp and exact distance-call exemption guards are present.

Critical checkpoint conclusions:

  1. Goal and proof: the PR adds the complete Nereids -> Java bucket planning -> Rust ANN pipeline and focused tests, but the four findings prevent accepting its behavior as complete.
  2. Scope: the SDK, VECTOR/JNI mappings, credentials and plan plumbing changes were reviewed together across all 56 changed paths.
  3. Concurrency and locks: immutable ANN plan data is copied defensively; no new Doris thread entry or lock-order change was identified. Rust asynchronous work remains SDK-owned, including the already-reported untracked allocations.
  4. Lifecycle: split/table handles, early error cleanup, Arrow ownership, nullable score conversion and query-homogeneous split reuse were traced; no additional lifetime or static-initialization defect was verified.
  5. Configuration: existing reader/scanner session switches are reused; no new dynamic Doris configuration was introduced.
  6. Compatibility: both supported BE-first serialized-table compatibility and fully upgraded catalog authorization have new regressions, reported inline. The reverse-order v9 split concern was dismissed using the documented BE-before-FE upgrade order.
  7. Thrift/protobuf: touched Thrift definitions were compared with branch-3.1, branch-4.0, branch-4.1, branch-4.2 and master. New outer fields are optional and avoid master IDs 20/41; no conflicting ID reuse or required addition to an existing struct was found. No protobuf change.
  8. Parallel paths: ordinary native/JNI/Rust readers, vector readers, all scan-copy/translation paths, Hudi constructor adaptation and filesystem/HMS/JDBC catalog variants were covered.
  9. Conditional gates: unsupported filter shapes, NULL query literals, oversized IN, data predicates without the required DV mode, projection and schema-history guards were checked. Cross-storage files and non-finite queries are the new missing preflights.
  10. Tests: FE/BE unit tests and external regression suites were inspected for positive, negative, partition, snapshot, schema and metric cases; no builds or tests were executed.
  11. Expected results: changed expectations and error assertions were reviewed statically; no generated .out file was modified. This review does not certify runtime output.
  12. Observability: ANN explain fields and reader timers exist; fallback reasons are logged once per combination. The regression profile assertion only checks PaimonRustReader, which also exists for ordinary Rust scans and cannot alone prove ANN executed.
  13. Transaction/persistence: no Doris EditLog, transaction-commit or persistence-format modification was found; statement snapshot/branch/pinned-empty handling was traced.
  14. Writes/atomicity: direct changes are on read/planning paths; no new Doris data-write atomicity change was found. The dependency upgrade's authorization effect is reported rather than assumed safe.
  15. FE/BE propagation: vector column, f32 bytes, metric, retrieval K, synthetic output and per-bucket payload were traced through logical/physical copies, translation and decoding.
  16. Performance/memory: the existing eager-materialization P1 remains blocking. The relaxed ordinary compacted-file gate was checked against Java split guarantees and Rust dispatch; no additional losing-batch retention trigger was verified.
  17. Further recheck: predicate canonicalization, runtime-filter boundaries, branch/options identity, external file storage, legacy privilege metadata, Java serialization and ordinary score-named columns were rechecked; every candidate has an accepted, existing-thread or evidence-based dismissal disposition.

User focus: no additional focus was supplied; the complete PR was reviewed. Coverage limits: static analysis only, with no live query, build, test or benchmark validation. No unresolved review candidate or uncovered changed-file scope remains. Convergence describes review stability; the new authorization P1 and existing memory P1 still require changes.

Review converged after 2 round(s).

Existing P0/P1 findings confirmed for this head: #69493 (comment)

Comment thread fe/pom.xml Resolved
Comment thread fe/pom.xml Resolved
dengfangyuan and others added 3 commits October 26, 2026 14:07
…or scans

Per the static review round on af5c7cc (the legacy-privilege P1 is
deliberately deferred this round):

- Non-finite query-vector literals (CAST('infinity' AS FLOAT), NaN): the
  ordinary path answers these with an infinite-distance row, while
  paimon-rust's validate_query rejects non-finite coordinates and the
  one-way rewrite has no fallback. The pre-flight now declines any
  non-finite coordinate literal (both metrics).
- External-file data (data-file.external-paths behind a
  resolving-file-io catalog): Java dispatches each URI to its matching
  backend, but the rust reader opens the table through a single FileIO
  and rejects foreign schemes (an oss:// external path on an S3 table).
  The external-file gate now applies to the vector path too — the scan
  node checks the split's external files in the base rust gate (with the
  fallback reason now also reported for vector splits), and the rewrite
  pre-flight declines a catalog (or table option) that opts into the
  resolving-file-io layout.

Tests: non-finite coordinate × both metrics and the resolving-file-io
catalog case join the rewrite suite (47/47 green).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
A BE-first rolling upgrade against a legacy Paimon 1.4 warehouse can
receive objects the 2.1 connector can no longer decode: the old FE
serializes the table as a PrivilegedFileStoreTable (for example with
scan.manifest.parallelism=1) whose privilege classes were removed in
2.1, and the bare ClassNotFoundException from this classloader says
nothing about the upgrade. Deserialization failures that bottom out in
ClassNotFoundException now rethrow with the upgrade/migration cause and
remedy, so BE-first windows fail diagnosably instead of cryptically.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@pzhdfy
pzhdfy requested a review from Gabriel39 October 28, 2026 06:21
The 0.5.0-rc1 release delivers Java-compatible schema evolution for
native reads (timestamp narrowing/widening, decimal, BIGINT, local-zone
temporal, nested), full query authorization support (REST auth masks
and transformed filters), PK partial-update and aggregation reads with
deletion vectors, and the apache#914 ResourceContext memory reservation
foundation with its C ABI exposure (paimon_read_builder_with_resources,
paimon_resource_context_create/metrics/free) — all of our 38 used C
ABI symbols are preserved with identical signatures.

Verified: BE build clean (14589 targets, zero errors), full ASAN UT
13935 passed / 0 failed including PaimonRustTableReaderTest 30/30 and
PaimonRustPredicateConverterTest 27/27.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@Gabriel39

Copy link
Copy Markdown
Contributor

/review

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41397208004

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

Dispatch external vector search by catalog and bind Paimon PK-vector searches to the existing scan and Rust reader. Preserve ordinary SQL ANN pushdown and distance semantics while exposing Lance-compatible TVF distances, global bounds, and explicit prefilter handling.

Keep Lance row-ID materialization provider-specific and cover source snapshots, empty tables, filter serialization, parameter validation, and both SQL entry points.
@Gabriel39

Copy link
Copy Markdown
Contributor

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor

/review

@Gabriel39 Gabriel39 changed the title branch-4.2:[feat](paimon) port PK-vector ANN search and upgrade Paimon to 2.1 branch-4.2:[feat](paimon) upgrade to 2.1 and support SQL/TVF ANN search Nov 2, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Request changes on head 9544d3a.

Three new inline findings are verified: [P1] captured TVF prefilters bypass required comparison normalization; [P2] prefilter inputs can be removed by later column pruning while the request still references them; [P2] TPaimonFileDesc field 21 collides with branch-4.1 blob_files. The two prefilter findings concern different invariants: expression semantics and preservation of hidden scan dependencies.

Existing blocking findings independently confirmed on this head, without reposting:

  • 4358943088: eager vector materialization still bypasses Doris allocation admission/accounting and retains projected Top-K batches before returning. The TVF row-count cap does not bound projected bytes; ordinary SQL still forwards unrestricted LIMIT+OFFSET. Rust 0.5 has ordinary-reader resource APIs, but this vector path does not integrate them.
  • 4373642116: legacy warehouse authorization still applies: the 2.1 factory no longer supplies the legacy privilege wrapper, and the actual catalog initialization has no legacy-metadata migration/rejection guard.

The prior Groovy syntax P1 is fixed and is not carried. Existing threads already cover stored NULL-vector validation, old-FE privilege-wrapper deserialization during BE-first upgrades, and the remaining bare-token ambiguity in result normalization. Nonfinite query coordinates, explicit S3 provider precedence, reserved materializer names, distinct distance-call projection checks, nanosecond columns, retained ORC/LTZ eras and external-file eligibility now have the inspected guards; no duplicates are posted.

Critical checkpoint conclusions:

  • Goal and proof: SQL/TVF ANN, shared Rust eligibility and 2.1/0.5 adaptation are implemented, but the verified prefilter errors prevent accepting the behavior. Added FE/BE/regression tests were inspected; they omit the raw comparison and post-pruning cases above.
  • Scope and clarity: shared eligibility and typed ANN state keep the change coherent; the dependency upgrade also affects ordinary scans and authorization, which were included in coverage.
  • Concurrency and locking: Paimon range conversion is serial on this branch; no new Doris thread, shared lock, nested lock order or heavy operation inside a new lock was introduced. SDK runtime ownership was traced.
  • Lifecycle and static initialization: local FFI handles, cloned Rust read state, independent Arrow stream and split EOF/close paths were inspected; no new ownership cycle or cross-TU initialization issue was established. Hidden predicate dependency lifetime is the second inline finding.
  • Configuration: existing Rust-reader and FileScannerV2 switches gate ordinary rewrites; no new dynamic configuration was added. Explicit TVFs require the supported reader configuration.
  • Compatibility: the field-ID collision and existing authorization/serialization upgrade concerns remain. The two required members in the new optional payload also conflict with the shared-definition optional-field convention; this is noted with the protocol finding.
  • Thrift/proto: every touched definition was compared with live master and branches 4.2, 4.1, 4.0 and 3.1. Request field 6 and scan-params field 42 avoid the inspected allocations; payload field 21 does not. No proto changes.
  • Parallel paths: ordinary JNI/native/Rust, SQL ANN, Paimon/Lance TVFs, prepared rebinding, Hudi scan constructors, provider-specific row-ID materialization and filesystem/HMS/JDBC S3 initialization were inspected.
  • Special conditions: predicate conversion, partition/data separation, global offset, runtime-filter TopN barriers, snapshot/tag/branch identity, empty snapshots, nested projection, schema history, VARIANT and timestamp gates were traced. No unresolved risk-focus question remains.
  • Functional and negative testing: inspected positive/negative FE tests, BE conversion/protocol tests and Spark-produced external regression fixtures. No build, test, benchmark or end-to-end query was executed under the static-only contract.
  • Changed results: no golden .out file changed; regression expectations, error assertions and numerical comparisons were inspected. Their runtime correctness is not claimed.
  • Observability: ANN metric/limit explain output, distinct fallback reasons and existing open/read/convert timers supply routing context; allocation observability remains limited with the known memory P1.
  • Persistence and transactions: no Doris EditLog, publish-version or transaction-state modification; bound external snapshot/schema transport was inspected. No new failover/persistence defect was established.
  • Writes and crash behavior: production additions are read planning/materialization; write regression expectations changed. No new write-atomicity change was found; unaccounted eager allocations remain an existing process-memory risk.
  • FE/BE variables: query vector, metric, candidate count, provider options and split payload were traced through the logical/physical/Thrift/reader chain; hidden prefilter slot loss and protocol allocation are the reported boundary defects.
  • Performance: eager projected materialization remains blocking. Raw-split/merge dispatch, per-split state reuse and batch boundaries were inspected; no additional substantiated performance regression was found.
  • Further sweep and user focus: no additional user focus was supplied. Casing and fallback-log concurrency suspicions were dismissed with caller/descriptor evidence; every candidate and risk item has a disposition.

Convergence: converged after 2 rounds. All three reviewers returned NO_NEW_VALUABLE_FINDINGS in round 2; all 70 changed paths and assigned mechanisms were covered, and the main review independently verified and deduplicated every accepted candidate. No unresolved static-review candidate or uncovered assigned scope remains. Runtime interoperability, allocator behavior and test results remain unexecuted static-review limits, not claimed validation.

Review converged after 2 round(s).

Existing P0/P1 findings confirmed for this head: #69493 (comment), #69493 (comment)

Comment thread gensrc/thrift/PlanNodes.thrift Resolved
@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 36.16% (145/401) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 64.76% (30335/46844)
Line Coverage 49.63% (321111/647025)
Region Coverage 45.41% (258794/569866)
Branch Coverage 47.06% (122298/259875)

### What problem does this PR solve?

Issue Number: None

Related PR: apache#69493

Problem Summary: Paimon vector_search retained prefilters before planner normalization. An explicit id <=> 7 could become an IS NULL predicate in the Rust converter, while literal-left comparisons could fail conversion. Reuse the planner's comparison normalization rules in filter context before retaining and validating the prefilter. Keep explicit prefilters in the scan conjuncts so their input slots survive elimination of tautological filters and distance-only projection pruning.

The new vector payload used TPaimonFileDesc field 21, which is already allocated to blob_files on branch-4.1. Reserve fields 20-23 and use field 24 after checking master and release branches 3.1, 4.0, 4.1 and 4.2. Make the payload members optional and reject missing members explicitly in the BE reader before opening storage.

### Release note

Fix Paimon vector_search explicit prefilter comparison semantics and preserve prefilter input columns when only _distance is selected. Keep the new vector payload compatible with field allocations on other release branches.

### Check List (For Author)

- Test: Unit Test / Regression test dry-run / Style checks
    - FE: PaimonVectorSearchTableValuedFunctionTest, PaimonVectorPayloadTest, PaimonScanNodeTest and PushDownVectorTopNIntoPaimonScanTest (160 tests)
    - Regression: run-regression-test.sh --run -d external_table_p0/paimon -s test_paimon_pk_vector_ann -dryRun passed; external end-to-end queries were not executed
    - FE Checkstyle and clang-format 16 checks passed
    - BE payload validation cases added; run-be-ut.sh was stopped during prolonged Clucene dependency fetching, so BE runtime tests were not executed
- Behavior changed: Yes, explicit Paimon prefilters retain SQL comparison semantics and required scan descriptors
- Does this need documentation: No, correctness and protocol compatibility fixes for the existing PR interface
suxiaogang223 added a commit to suxiaogang223/doris that referenced this pull request Nov 3, 2026
### What problem does this PR solve?

Related PR: apache#69493

Problem Summary: Reserve the optional Paimon vector payload, search options
and scan request fields on master before the branch-4.2 vector-search work
lands. Use TPaimonFileDesc.24, TExternalSearchRequest.6 and
TFileScanRangeParams.42. Keep payload enum values 0/1 and all new struct
members optional. Document the branch-4.1 blob fields 21-23 and the shared
search request fields 2-5 so their identifiers cannot be reused.

### Release note

None

### Check List (For Author)

- Test: Local build, Thrift generation and unit tests not run, as requested.
  Reviewed the affected definitions on master and branches 3.1/4.0/4.1/4.2.
- Behavior changed: No; master producers do not populate the reserved fields.
- Does this need documentation: No
### What problem does this PR solve?

Related PR: apache#69493

Problem Summary: CI merges this PR with a newer branch-4.2 before compiling.
That baseline adds historical-schema tests that still use the Paimon privilege
classes removed in SDK 2.1. Bring branch-4.2 commit 914257a into this branch
so the SDK compatibility fixes can include those tests and all current callers.

### Release note

None

### Check List (For Author)

- Test: Local builds and tests not run, as requested. Automatic merge had no conflicts.
- Behavior changed: No additional behavior beyond the merged upstream changes.
- Does this need documentation: No
### What problem does this PR solve?

Related PR: apache#69493

Problem Summary: FE UT and COMPILE fail in testCompile after CI merges the
current branch-4.2 baseline because PaimonHistoricalSchemaOptionsTest imports
PrivilegeChecker and PrivilegedFileStoreTable, which were removed in Paimon
2.1. Spy on the selected SDK table and reject its batch-write entry point
instead. Retain the test's snapshot/tag schema, row-result and read-only
projection checks without depending on removed authorization classes.

### Release note

None

### Check List (For Author)

- Test: Local builds and tests not run, as requested. Matched the changes to
  the FE UT (1088646) and COMPILE (1088990) compiler diagnostics and reviewed
  the existing Paimon SDK spy pattern in PaimonRowCountTest.
- Behavior changed: No; test-only SDK compatibility change.
- Does this need documentation: No
yiguolei pushed a commit that referenced this pull request Nov 4, 2026
…0075)

### What problem does this PR solve?

Related PR: #69493

Problem Summary: Master still builds paimon-rust v0.4.0-rc1, while the
Paimon vector-search work in #69493 needs v0.5.0-rc1 and additional wire
fields. Upgrade the native dependency and reserve its Thrift layout on
master so later changes cannot reuse the same identifiers for different
meanings.

The dependency change updates the source URL, archive name, source
directory and MD5 checksum together. The schema change adds the
following optional fields and their Paimon payload/options types:

| Structure | Field | ID |
| --- | --- | --- |
| `TPaimonFileDesc` | `vector_payload` | 24 |
| `TExternalSearchRequest` | `paimon_options` | 6 |
| `TFileScanRangeParams` | `external_search_request` | 42 |

`TPaimonVectorPayloadType` keeps `BUCKET_SPLIT_BYTES=0` and
`MATERIALIZE_OPAQUE_BYTES=1`. Both payload members and all Paimon
search-option members are optional. Master does not emit these fields
yet; this PR reserves the protocol without enabling SQL/TVF ANN search
or upgrading the Paimon Java SDK.

Compatibility notes:

- `TPaimonFileDesc.20` remains `original_file_path`; comments reserve
branch-4.1's `blob_files=21`, `anchor_first_row_id=22` and
`anchor_row_count=23`. The vector payload uses 24 rather than the
conflicting 21 from the original #69493 diff.
- Comments reserve the existing branch-4.1/4.2 shared-search fields
`search_query=2`, `search_filter=3`, `vector_search_options=4` and
`prefilter=5`. Their query types can be introduced independently on
master.
- `TFileScanRangeParams.41` remains `fluss_properties`.
- The affected definitions were reviewed against current master and
branches 3.1, 4.0, 4.1 and 4.2. Existing field IDs and enum values
retain their meanings.

### Release note

Upgrade the native Paimon Rust reader dependency to v0.5.0-rc1.

### Check List (For Author)

- Test: No local build, Thrift generation or unit tests on master, as
requested; CI validation pending. During the preceding branch-4.2 work,
the archive checksum was verified and the v0.5.0-rc1 dependency was
built with Rust 1.94.0. This is not a completed master BE build or BE
unit-test run.
- Behavior changed: Yes; the bundled native Paimon dependency is
upgraded. The new Thrift fields are reserved and remain unset by master
producers.
- Does this need documentation: No
### What problem does this PR solve?

Related PR: apache#69343, apache#69493

Problem Summary: Bring the Paimon 2.1 upgrade on branch-4.2 in line with
master's compatibility handling. A nullable primary key cannot identify
whether a MERGE target row is present: MATCHED-only NULL-safe joins lost
valid updates/deletes, while outer joins need a separate presence marker.
Use the existing join shape and bind user expressions before exposing the
private marker. Reject latest-delta OPTIONS before snapshot pinning can
silently turn a delta read into a full read. Match master after removal
of the legacy privilege delegates and carry over SDK compatibility tests,
file-index snapshot coverage and generated regression results.

### Release note

Fix Paimon MERGE matched UPDATE/DELETE for nullable primary keys. Reject
scan.mode=latest-delta in OPTIONS with guidance to use explicit @incr ranges.

### Check List (For Author)

- Test: Added/adapted FE and JNI unit tests and master's external regression
  suites. Static self-review and whitespace checks completed (preserving generated
  result-file separators). No local build,
  Checkstyle, unit tests or regression execution, as requested. Result files
  are copied from master apache#69343 rather than generated locally.
- Behavior changed: Yes; preserve NULL-key MERGE matches and reject an
  unsupported delta mode instead of reading a full snapshot.
- Does this need documentation: No; the rejection provides the supported alternative.
### What problem does this PR solve?

Related PR: apache#69493

Problem Summary: Paimon vector_search(use_index=false) previously only sent
vector-index.search-mode=full as a query option. The pinned PK reader resolves
that mode from the table schema instead, and FULL still searches ANN segments
for indexed files. A FAST table with uncovered data files could therefore
omit the nearest rows even when the user requested an unindexed search.

Carry use_index through the existing shared search options. For flat searches,
copy the read table with FULL in its schema and omit ANN payload files from
the bucket splits while preserving their snapshot, data files and row ranges.
The existing Rust exact fallback then searches all planned active files.
Keep default/true and ordinary SQL ANN behavior unchanged.

### Release note

Make Paimon vector_search(use_index=false) bypass ANN index segments and
include uncovered data files in exact Top-K searches.

### Check List (For Author)

- Test: Added FE payload round-trip coverage for indexed/flat controls and an
  external regression with data written before index configuration. Static
  self-review and git diff --check completed. No local build, Checkstyle,
  unit tests or regression execution, as requested.
- Behavior changed: Yes; use_index=false performs exact search over every
  planned active data file instead of continuing to use ANN.
- Does this need documentation: No; implements the existing option's behavior.
@suxiaogang223 suxiaogang223 changed the title branch-4.2:[feat](paimon) upgrade to 2.1 and support SQL/TVF ANN search [feature](paimon) Add SQL and TVF ANN search with Paimon 2.1 Nov 4, 2026
@suxiaogang223

Copy link
Copy Markdown
Member

run buildall

@suxiaogang223

Copy link
Copy Markdown
Member

/review

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 76.44% (2005/2623)
Line Coverage 64.96% (36152/55652)
Region Coverage 52.90% (34579/65367)
Branch Coverage 55.77% (10776/19322)

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41788470352

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 70.77% (758/1071) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 37.25% (152/408) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 64.81% (30383/46882)
Line Coverage 49.70% (321860/647621)
Region Coverage 45.47% (259337/570381)
Branch Coverage 47.16% (122694/260181)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 36.00% (144/400) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 76.34% (34760/45533)
Line Coverage 61.19% (392963/642214)
Region Coverage 57.92% (330835/571236)
Branch Coverage 58.93% (153150/259869)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants