github-actions[bot] commented on code in PR #67725:
URL: https://github.com/apache/doris/pull/67725#discussion_r4226435242


##########
fe/fe-core/src/main/java/org/apache/doris/datasource/mvcc/PluginDrivenMvccExternalTable.java:
##########
@@ -714,11 +692,142 @@ static boolean schemaCacheDisabled(Connector connector) {
 
     @Override
     public Map<String, PartitionItem> 
getNameToPartitionItems(Optional<MvccSnapshot> snapshot) {
+        if (supportsConnectorPartitionPruning()) {
+            PluginDrivenMvccSnapshot pin = getOrMaterialize(snapshot);
+            if (pin.isPartitionViewMaterialized()) {
+                return pin.getNameToPartitionItem();
+            }
+            if (pin.isPartitionViewUnavailable()) {
+                return Collections.emptyMap();
+            }
+            Optional<ExternalTablePreloadInfo> sharedView = 
sharedLatestPreloadInfo(snapshot);
+            if (sharedView.isPresent() && 
sharedView.get().hasScanPartitionView()
+                    && sharedView.get().getScanPartitionView().isPresent()) {
+                return sharedView.get().getScanPartitionView().get();
+            }
+            // The latest Hive query pin intentionally carries no partition 
map so selective scans can send a
+            // predicate to HMS first. Consumers that explicitly ask for a 
partition map (MTMV alignment,
+            // no-filter scan finalization, and a connector-declined pruning 
fallback) require the real full
+            // view instead of treating that query-only pin as an empty table. 
An unavailable shared scan view
+            // is not an authoritative empty map either: checked MTMV 
consumers reject it in
+            // getAndCopyPartitionItems, while other explicit map consumers 
retain this fail-loud full-view path.
+            return super.getNameToPartitionItems(snapshot);
+        }
         return getOrMaterialize(snapshot).getNameToPartitionItem();
     }
 
     @Override
-    public Map<String, PartitionItem> 
getAndCopyPartitionItems(Optional<MvccSnapshot> snapshot) {
+    public Optional<Map<String, PartitionItem>> 
getNameToPartitionItemsForScan(Optional<MvccSnapshot> snapshot) {
+        if (snapshot.isPresent() && snapshot.get() instanceof 
PluginDrivenMvccSnapshot
+                && ((PluginDrivenMvccSnapshot) 
snapshot.get()).isPartitionViewUnavailable()) {
+            return Optional.empty();
+        }
+        if (supportsConnectorPartitionPruning()) {
+            PluginDrivenMvccSnapshot pin = getOrMaterialize(snapshot);
+            if (pin.isPartitionViewMaterialized()) {
+                // This statement's pin already carries a materialized view: 
reuse it instead of paying another
+                // connector round-trip that could observe a different remote 
generation.
+                return Optional.of(pin.getNameToPartitionItem());
+            }
+        }
+        return super.getNameToPartitionItemsForScan(snapshot);
+    }
+
+    @Override
+    public Optional<ConnectorFilteredPartitionView> 
applyPartitionFilterForScan(Optional<MvccSnapshot> snapshot,
+            ConnectorExpression partitionFilter) {
+        if (snapshot.isPresent() && snapshot.get() instanceof 
PluginDrivenMvccSnapshot
+                && ((PluginDrivenMvccSnapshot) 
snapshot.get()).isPartitionViewUnavailable()) {
+            return Optional.empty();
+        }
+        return super.applyPartitionFilterForScan(snapshot, partitionFilter);
+    }
+
+    /**
+     * Threads this statement's MVCC pin onto the handle the partition view is 
enumerated from, so a
+     * time-travel / {@code @options} query never prunes against the latest 
generation: the data scan reads the
+     * pinned snapshot, and a latest view can be missing (or contain) 
partitions it will never read.
+     */
+    @Override
+    protected ConnectorTableHandle pinPartitionViewHandle(ConnectorTableHandle 
handle,
+            ConnectorMetadata metadata, ConnectorSession session, 
Optional<MvccSnapshot> snapshot) {
+        if (snapshot.isPresent() && snapshot.get() instanceof 
PluginDrivenMvccSnapshot) {
+            return metadata.applySnapshot(session, handle,
+                    ((PluginDrivenMvccSnapshot) 
snapshot.get()).getConnectorSnapshot());
+        }
+        return handle;
+    }
+
+    /**
+     * Materializes the complete partition view for an MTMV refresh before it 
acquires base-table locks.
+     * The lightweight Hive query pin keeps the connector snapshot/freshness 
kind but deliberately omits the
+     * partition map; MTMV alignment needs that map and must not load it while 
holding internal table locks.
+     */
+    public MvccSnapshot materializePartitionViewForMtmv(MvccSnapshot snapshot) 
{
+        if (!supportsConnectorPartitionPruning() || !(snapshot instanceof 
PluginDrivenMvccSnapshot)) {
+            return snapshot;
+        }
+        PluginDrivenMvccSnapshot pin = (PluginDrivenMvccSnapshot) snapshot;
+        if (!pin.isPartitionViewDeferred()) {
+            return pin;
+        }
+        Map<String, PartitionItem> partitionItems = 
super.getNameToPartitionItems(Optional.of(pin));
+        Map<String, Long> partitionLastModified = new HashMap<>();
+        for (String partitionName : partitionItems.keySet()) {
+            partitionLastModified.put(partitionName, 
ConnectorPartitionInfo.UNKNOWN);
+        }
+        return new PluginDrivenMvccSnapshot(pin.getConnectorSnapshot(), 
partitionItems, partitionLastModified,
+                null);
+    }
+
+    /**
+     * Returns the latest-view preload record materialized by the statement 
before internal table locks were
+     * acquired, or empty when this request does not refer to that latest view.
+     *
+     * <p>The record, rather than only its map, preserves the intentionally 
unwarmed filtered-latest state, an
+     * unavailable scan view, and a materialized map. Query-time async-MV 
validation and union compensation ask
+     * for partition metadata while the planner holds internal read locks. 
Reusing the materialized pre-lock
+     * generation avoids a full HMS listing under those locks; preserving the 
other two states lets the checked
+     * MTMV path reject the candidate instead of listing partitions under the 
locks or converting "scan every
+     * partition" into an authoritative empty universe. A
+     * supplied pin is accepted only when it is the statement's own latest 
pin; historical/time-travel pins and
+     * calls without a statement context keep their existing snapshot 
semantics.</p>
+     */
+    private Optional<ExternalTablePreloadInfo> 
sharedLatestPreloadInfo(Optional<MvccSnapshot> snapshot) {
+        ConnectContext connectContext = ConnectContext.get();
+        StatementContext statementContext = connectContext == null ? null : 
connectContext.getStatementContext();
+        if (statementContext == null) {
+            return Optional.empty();
+        }
+        Optional<ExternalTablePreloadInfo> preloadInfo = 
statementContext.getExternalTablePreloadInfo(getId());
+        if (!preloadInfo.isPresent() || 
!preloadInfo.get().hasLatestOnlyRelation()) {
+            return Optional.empty();
+        }
+        Optional<MvccSnapshot> latestSnapshot = 
statementContext.getSnapshot(this);
+        boolean isLatestRequest = !snapshot.isPresent()
+                || (latestSnapshot.isPresent() && latestSnapshot.get() == 
snapshot.get());
+        return isLatestRequest ? preloadInfo : Optional.empty();
+    }
+
+    @Override

Review Comment:
   [P2] Keep a full partition view available for filtered async-MV mapping. For 
the reduced plan Filter(h.p = 2) -> Hive h, CollectRelation marks h filtered, 
so the pre-lock full-view warmup leaves scanPartitionView unset. During 
partitioned async-MV union compensation, MTMV.calculatePartitionMappings asks 
this method for the related-table items and reaches this new exception; 
AbstractMaterializedViewRule catches it and skips the otherwise eligible MV 
candidate. The query then scans the base table even though the rewrite was 
previously available. Supply a consistent view before MV mapping and cover a 
filtered query requiring union compensation.



##########
fe/fe-connector/fe-connector-hive/src/main/java/org/apache/doris/connector/hive/HiveConnectorMetadata.java:
##########
@@ -1289,6 +1281,106 @@ private List<ConnectorPartitionInfo> 
listPartitionsUncached(HiveTableHandle hive
         return result;
     }
 
+    private PartitionPruningResult prunePartitions(ConnectorSession session, 
HiveTableHandle hiveHandle,
+            ConnectorExpression expression) {
+        List<String> partKeyNames = hiveHandle.getPartitionKeyNames();
+        Map<String, List<String>> partitionPredicates = 
extractPartitionPredicates(expression, partKeyNames);
+        if (partitionPredicates.isEmpty()) {
+            return null;
+        }
+
+        String hmsFilter = buildHmsPartitionFilter(partKeyNames, 
hiveHandle.getPartitionKeyTypes(),
+                hiveHandle.getPartitionKeyHiveTypes(), partitionPredicates);
+        if (hmsFilter != null) {
+            int predicateValueCount = 
partitionPredicates.values().stream().mapToInt(List::size).sum();
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("HMS partition filter request for {}.{} 
predicateValues={} filter={}",
+                        hiveHandle.getDbName(), hiveHandle.getTableName(), 
predicateValueCount,
+                        summarizeHmsFilterForDebug(hmsFilter));

Review Comment:
   [P1] Do not trust successful integral JDO filtering as complete. With Hive 
metastore.integral.jdo.pushdown=true and direct SQL disabled or failing, a 
valid INT partition stored as p=01 is omitted from a successful HMS response to 
p = 1: [Hive documents this leading-zero 
limitation](https://github.com/apache/hive/blob/rel/release-3.1.3/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/conf/MetastoreConf.java#L3168-L3179),
 and its [JDO equality 
filter](https://github.com/apache/hive/blob/rel/release-3.1.3/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/parser/ExpressionTree.java#L2236-L2293)
 compares the rendered partition-name fragment as text. This return accepts the 
incomplete set as the logical and physical scan view, so the query misses 
matching rows; the local fallback cannot run because the RPC succeeded. Use 
full-name listing plus typed pruning for integral keys unless safe server 
semantics are known, and test p=01 alongside p=1 with JDO
  pushdown enabled.



-- 
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]

Reply via email to