github-actions[bot] commented on code in PR #66187:
URL: https://github.com/apache/doris/pull/66187#discussion_r3670590359
##########
fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java:
##########
@@ -1508,6 +1508,42 @@ public Partition getPartition(String partitionName,
boolean isTempPartition) {
}
}
+ @Override
+ public Partition getMaxVisiblePartition() {
+ PartitionInfo partitionInfo = getPartitionInfo();
+ PartitionType type = partitionInfo.getType();
+ // LIST has no natural "latest"; UNPARTITIONED has a single partition.
+ // Neither participates in the range-max scan below.
+ if (type == PartitionType.LIST) {
+ // no meaningful "max" partition -> caller builds an empty query
+ return null;
+ }
+ if (type == PartitionType.UNPARTITIONED) {
+ for (Partition partition : nameToPartition.values()) {
+ if (partition.getVisibleVersion() >
Partition.PARTITION_INIT_VERSION) {
+ return partition;
+ }
+ }
+ return null;
+ }
+ Partition result = null;
+ PartitionKey maxUpperBound = null;
+ for (Partition partition : nameToPartition.values()) {
+ if (partition.getVisibleVersion() <=
Partition.PARTITION_INIT_VERSION) {
Review Comment:
[P1] Batch cloud version lookups before scanning partitions
On a cloud table, every iteration here dispatches through
`CloudPartition.getVisibleVersion()`. Once the cache entry has expired, that is
a synchronous `batchMode=false` meta-service RPC. Binding runs after
`StatementContext.lock()` and the planner releases that table read lock only
after planning, so a table with N expired partitions now incurs N sequential
network round trips while holding metadata locks. The existing
`Partition.getVisibleVersions()` / `CloudPartition.getSnapshotVisibleVersion()`
path already fetches an aligned version vector in one batch. Please use that
batch result to choose the greatest upper bound; otherwise the feature intended
to reduce planning overhead can instead scale with N RPC latencies and combine
observations from different instants.
##########
fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java:
##########
@@ -1508,6 +1508,42 @@ public Partition getPartition(String partitionName,
boolean isTempPartition) {
}
}
+ @Override
+ public Partition getMaxVisiblePartition() {
+ PartitionInfo partitionInfo = getPartitionInfo();
+ PartitionType type = partitionInfo.getType();
+ // LIST has no natural "latest"; UNPARTITIONED has a single partition.
+ // Neither participates in the range-max scan below.
+ if (type == PartitionType.LIST) {
+ // no meaningful "max" partition -> caller builds an empty query
+ return null;
+ }
+ if (type == PartitionType.UNPARTITIONED) {
+ for (Partition partition : nameToPartition.values()) {
+ if (partition.getVisibleVersion() >
Partition.PARTITION_INIT_VERSION) {
Review Comment:
[P1] Include current-transaction partitions in the max selection
This test only sees committed `visibleVersion`, but Doris's transaction-load
path intentionally treats partitions containing earlier subtransaction writes
as readable: `PruneEmptyPartition.selectNonEmptyPartitionIdsForTxnLoad()` adds
them through `TransactionEntry.getPartitionSubTxnIds()`. By selecting one
committed partition here—or returning null before that rewrite runs—the new
path removes the higher pending partition from the candidate set. For example,
after one insert-select subtransaction writes `p2`, a later `INSERT INTO dst
SELECT ... FROM src max_visible_partition()` in the same transaction scans
older `p1` (or an empty relation) instead of `p2`. Please merge
current-transaction partition evidence into the max ordering before deciding
the result is empty.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java:
##########
@@ -260,6 +261,15 @@ private LogicalPlan makeOlapScan(TableIf table,
UnboundRelation unboundRelation,
} else if (unboundRelation.getScanParams() != null) {
unboundRelation.getScanParams().validateOlapTable();
}
+ // max_visible_partition() with no visible partition -> empty result
instead of
+ // falling through to a full-table scan (empty partIds otherwise means
"all partitions")
+ if (unboundRelation.isMaxVisiblePartition() &&
CollectionUtils.isEmpty(partIds)) {
Review Comment:
[P1] Validate and shape all scan modifiers before returning empty
This return happens before direct-index lookup/compatibility, manual-tablet
marking, `PREAGGOPEN`/`@incr` compatibility, and `validateTimeTravel()`.
Consequently `empty_t INDEX missing max_visible_partition()` succeeds instead
of reporting the missing index, and unsupported or malformed time travel is
accepted only while the table is empty. For a valid non-base index, this
default scan also supplies the base-table output rather than
`getOutputByIndex()`; for `@incr` it drops the scan params used to shape the
row-binlog output. Please resolve and validate the complete requested scan
first, then derive the empty relation from that resolved output so analysis and
metadata do not depend on whether data currently exists.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java:
##########
@@ -1014,14 +1033,19 @@ private Plan parseAndAnalyzeView(TableIf view, String
ddlSql, CascadesContext pa
private List<Long> getPartitionIds(TableIf t, UnboundRelation
unboundRelation, List<String> qualifier) {
List<String> parts = unboundRelation.getPartNames();
- if (CollectionUtils.isEmpty(parts)) {
+ if (CollectionUtils.isEmpty(parts) &&
!unboundRelation.isMaxVisiblePartition()) {
return ImmutableList.of();
}
if (!t.isManagedTable()) {
throw new AnalysisException(String.format(
"Only OLAP table is support select by partition for now,"
+ "Table: %s is not OLAP table", t.getName()));
}
+ if (unboundRelation.isMaxVisiblePartition()) {
+ Partition partition = t.getMaxVisiblePartition();
Review Comment:
[P1] Resolve the maximum partition at the requested snapshot
The grammar permits `FOR VERSION/TIME AS OF` immediately before this clause,
but this call uses today's partition versions and only later does
`buildTimeTravelPlan()` apply `commit_tso <= targetTso` to the already
restricted scan. With `p1` first populated at TSO 100 and higher `p2` first
populated at TSO 200, `FROM t FOR VERSION AS OF 150 max_visible_partition()`
becomes:
`Filter(commit_tso <= 150) -> LogicalOlapScan(partitions=[p2])`
and returns empty instead of the rows from `p1`; the MOW union receives the
same wrong `partIds`. Please either reject this modifier combination or
determine non-emptiness/max ordering against the requested snapshot.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java:
##########
@@ -53,6 +53,7 @@ public class UnboundRelation extends LogicalRelation
implements Unbound, BlockFu
private final List<String> partNames;
private final List<Long> tabletIds;
private final boolean isTempPart;
+ private final boolean isMaxVisiblePartition;
Review Comment:
[P2] Include this scan modifier in the SQL digest
The new flag is preserved by the copy/equality paths, but
`UnboundRelation.toDigest()` never emits it. `LogicalPlanAdapter` captures that
digest and `AuditLogHelper` hashes it into `SqlDigest`, so `SELECT ... FROM t`
and `SELECT ... FROM t max_visible_partition()` are grouped as the same
statement despite radically different scan scope and performance. Other
semantic scan modifiers such as `INDEX`, `TABLET`, scan params, and snapshots
are represented there. Please append a stable `MAX_VISIBLE_PARTITION()` token
when this flag is set and add a digest assertion.
##########
fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java:
##########
@@ -1508,6 +1508,42 @@ public Partition getPartition(String partitionName,
boolean isTempPartition) {
}
}
+ @Override
+ public Partition getMaxVisiblePartition() {
+ PartitionInfo partitionInfo = getPartitionInfo();
+ PartitionType type = partitionInfo.getType();
+ // LIST has no natural "latest"; UNPARTITIONED has a single partition.
+ // Neither participates in the range-max scan below.
+ if (type == PartitionType.LIST) {
+ // no meaningful "max" partition -> caller builds an empty query
+ return null;
+ }
+ if (type == PartitionType.UNPARTITIONED) {
+ for (Partition partition : nameToPartition.values()) {
+ if (partition.getVisibleVersion() >
Partition.PARTITION_INIT_VERSION) {
+ return partition;
+ }
+ }
+ return null;
+ }
+ Partition result = null;
+ PartitionKey maxUpperBound = null;
+ for (Partition partition : nameToPartition.values()) {
+ if (partition.getVisibleVersion() <=
Partition.PARTITION_INIT_VERSION) {
+ continue;
+ }
+ // RANGE: pick the partition with the greatest range upper bound,
so it works for
+ // date/number partitions regardless of the partition name width
+ PartitionKey upper = ((RangePartitionItem)
partitionInfo.getItem(partition.getId()))
+ .getItems().upperEndpoint();
+ if (maxUpperBound == null || upper.compareTo(maxUpperBound) > 0) {
+ maxUpperBound = upper;
+ result = partition;
Review Comment:
[P1] Re-resolve the max partition before reusing a prepared point plan
The chosen ID is baked into `LogicalOlapScan`, and a qualifying point query
can then be cached as a server-prepared short-circuit `OlapScanNode`.
`ExecuteCommand` reuses that node when `ShortCircuitQueryContext.isReusable()`
succeeds, but that check covers only dropped state, schema version, table name,
and a session limit—not visible/table/partition versions. Prepare and execute
while `p1` is the maximum, commit data into higher `p2` without changing the
schema, then execute for a key in `p2`: the cached node remains pinned to `p1`
and returns the wrong result. Please disable short-circuit reuse for this
data-dependent modifier or include the selection/data version and force
rebinding when it changes.
##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java:
##########
@@ -751,6 +761,15 @@ private LogicalPlan getLogicalPlan(TableIf table,
UnboundRelation unboundRelatio
}
List<String> qualifierWithoutTableName = qualifiedTableName.subList(0,
qualifiedTableName.size() - 1);
+ // max_visible_partition() only works on OLAP-backed tables; reject
others explicitly
+ // so the flag is not silently ignored.
+ if (unboundRelation.isMaxVisiblePartition()) {
Review Comment:
[P1] Enforce this restriction before every relation early return
This guard is not reached for two parser-accepted targets. `WITH c AS (...)
SELECT * FROM c max_visible_partition()` returns a
`LogicalCTEConsumer`/recursive work-table reference after
`rejectScanParamsOnCte()` (which does not inspect this flag), so it scans all
CTE rows. Likewise a resolved external `$` system table returns from
`handleMetaTable()` above this check as a file/TVF relation. Both silently
discard semantics that ordinary external tables reject. Please invoke a shared
modifier validation before those early returns, or explicitly reject the flag
in each path, and add CTE plus native/TVF meta-table negatives.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]