You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polaris.apache.org by su...@apache.org on 2026/03/12 15:24:36 UTC
(polaris) branch main updated: core: Standardize Path Lookup Key for `PolarisResolutionManifest.getResolvedPath` (#3940)
This is an automated email from the ASF dual-hosted git repository.
sungwy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/main by this push:
new 6749238667 core: Standardize Path Lookup Key for `PolarisResolutionManifest.getResolvedPath` (#3940)
6749238667 is described below
commit 6749238667aa4b1967ee024948d73cccacdc43b1
Author: Sung Yun <10...@users.noreply.github.com>
AuthorDate: Thu Mar 12 11:24:28 2026 -0400
core: Standardize Path Lookup Key for `PolarisResolutionManifest.getResolvedPath` (#3940)
* use standardized path key in PolarisResolutionManifest
* comment
* adopt feedback
* Rename PolarisResolutionManifestLookUpKeyTest.java to PolarisResolutionManifestLookupKeyTest.java
* adopt nits. thanks alex and dmitri!
* more nits
---
.../resolver/PolarisResolutionManifest.java | 108 +++++-----------
.../PolarisResolutionManifestCatalogView.java | 10 +-
.../core/persistence/resolver/ResolvedPathKey.java | 60 +++++++++
.../core/persistence/resolver/ResolverPath.java | 40 ++++--
.../PolarisResolutionManifestLookupKeyTest.java | 139 +++++++++++++++++++++
.../polaris/service/admin/PolarisAdminService.java | 88 +++++++------
.../service/catalog/common/CatalogHandler.java | 62 ++++-----
.../service/catalog/common/CatalogUtils.java | 7 +-
.../generic/PolarisGenericTableCatalog.java | 13 +-
.../service/catalog/iceberg/IcebergCatalog.java | 105 ++++++++++------
.../catalog/iceberg/IcebergCatalogHandler.java | 9 +-
.../service/catalog/policy/PolicyCatalog.java | 18 ++-
.../catalog/policy/PolicyCatalogHandler.java | 20 +--
.../service/catalog/policy/PolicyCatalogUtils.java | 7 +-
.../service/admin/PolarisAdminServiceTest.java | 130 ++++++++++++++-----
.../catalog/PolarisPassthroughResolutionView.java | 108 +++++-----------
16 files changed, 578 insertions(+), 346 deletions(-)
diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/PolarisResolutionManifest.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/PolarisResolutionManifest.java
index 4954cdd482..be9e755ff7 100644
--- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/PolarisResolutionManifest.java
+++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/PolarisResolutionManifest.java
@@ -57,11 +57,11 @@ public class PolarisResolutionManifest implements PolarisResolutionManifestCatal
private final Resolver primaryResolver;
private final PolarisDiagnostics diagnostics;
- private final Map<Object, Integer> pathLookup = new HashMap<>();
+ private final Map<ResolvedPathKey, Integer> pathLookup = new HashMap<>();
private final List<ResolverPath> addedPaths = new ArrayList<>();
private final Multimap<String, PolarisEntityType> addedTopLevelNames = HashMultimap.create();
- private final Map<Object, ResolverPath> passthroughPaths = new HashMap<>();
+ private final Map<ResolvedPathKey, ResolverPath> passthroughPaths = new HashMap<>();
private int currentPathIndex = 0;
@@ -112,29 +112,20 @@ public class PolarisResolutionManifest implements PolarisResolutionManifestCatal
}
}
- /**
- * Adds a path that will be statically resolved with the primary Resolver when resolveAll() is
- * called, and which contributes to the resolution status of whether all paths have successfully
- * resolved.
- *
- * @param key the friendly lookup key for retrieving resolvedPaths after resolveAll(); typically
- * might be a Namespace or TableIdentifier object.
- */
- public void addPath(ResolverPath path, Object key) {
+ /** Adds a statically resolved path using canonical registration semantics only. */
+ public void addPath(ResolverPath path) {
primaryResolver.addPath(path);
- pathLookup.put(key, currentPathIndex);
+ // Preserve prior manifest lookup behavior: re-registering the same lookup key overwrites the
+ // previous mapping (last-write-wins).
+ pathLookup.put(ResolvedPathKey.of(path), currentPathIndex);
addedPaths.add(path);
++currentPathIndex;
}
- /**
- * Adds a path that is allowed to be dynamically resolved with a new Resolver when
- * getPassthroughResolvedPath is called. These paths are also included in the primary static
- * resolution set resolved during resolveAll().
- */
- public void addPassthroughPath(ResolverPath path, Object key) {
- addPath(path, key);
- passthroughPaths.put(key, path);
+ /** Adds a passthrough path using canonical registration semantics only. */
+ public void addPassthroughPath(ResolverPath path) {
+ addPath(path);
+ passthroughPaths.put(ResolvedPathKey.of(path), path);
}
public ResolverStatus resolveAll() {
@@ -174,40 +165,26 @@ public class PolarisResolutionManifest implements PolarisResolutionManifestCatal
return getResolvedReferenceCatalogEntity(false);
}
- /**
- * @param key the key associated with the path to retrieve that was specified in addPath
- * @return null if the path resolved for {@code key} isn't fully-resolved when specified as
- * "optional"
- */
@Override
- public PolarisResolvedPathWrapper getResolvedPath(Object key) {
+ public PolarisResolvedPathWrapper getResolvedPath(ResolvedPathKey key) {
return getResolvedPath(key, false);
}
- /**
- * @return null if the path resolved for {@code key} isn't fully-resolved when specified as
- * "optional", or if it was resolved but the subType doesn't match the specified subType.
- */
@Override
public PolarisResolvedPathWrapper getResolvedPath(
- Object key, PolarisEntityType entityType, PolarisEntitySubType subType) {
- return getResolvedPath(key, entityType, subType, false);
+ ResolvedPathKey key, PolarisEntitySubType subType) {
+ return getResolvedPath(key, subType, false);
}
- /**
- * @param key the key associated with the path to retrieve that was specified in addPath
- * @return null if the path resolved for {@code key} isn't fully-resolved when specified as
- * "optional"
- */
@Override
- public PolarisResolvedPathWrapper getPassthroughResolvedPath(Object key) {
+ public PolarisResolvedPathWrapper getPassthroughResolvedPath(ResolvedPathKey key) {
+ ResolverPath requestedPath = passthroughPaths.get(key);
diagnostics.check(
- passthroughPaths.containsKey(key),
- "invalid_key_for_passthrough_resolved_path",
+ requestedPath != null,
+ "invalid_path_key_for_passthrough_resolved_path",
"key={} passthroughPaths={}",
key,
passthroughPaths);
- ResolverPath requestedPath = passthroughPaths.get(key);
// Run a single-use Resolver for this path.
Resolver passthroughResolver = resolverFactory.createResolver(principal, catalogName);
@@ -215,22 +192,19 @@ public class PolarisResolutionManifest implements PolarisResolutionManifestCatal
ResolverStatus status = passthroughResolver.resolveAll();
if (status.getStatus() != ResolverStatus.StatusEnum.SUCCESS) {
- LOGGER.debug("Returning null for key {} due to resolver status {}", key, status.getStatus());
+ LOGGER.debug(
+ "Returning null for path {} due to resolver status {}",
+ requestedPath,
+ status.getStatus());
return null;
}
List<ResolvedPolarisEntity> resolvedPath = passthroughResolver.getResolvedPath();
- // If the catalog is a passthrough facade, we can go ahead and just return only as much of
- // the parent path as was successfully found.
- // TODO: For passthrough facade semantics, consider whether this should be where we generate
- // the JIT-created entities that would get committed after we find them in the remote
- // catalog.
if (requestedPath.optional() && !getIsPassthroughFacade()) {
if (resolvedPath.size() != requestedPath.entityNames().size()) {
LOGGER.debug(
- "Returning null for key {} due to size mismatch from getPassthroughResolvedPath "
+ "Returning null due to size mismatch from getPassthroughResolvedPath "
+ "resolvedPath: {}, requestedPath.getEntityNames(): {}",
- key,
resolvedPath,
requestedPath.entityNames());
return null;
@@ -245,13 +219,9 @@ public class PolarisResolutionManifest implements PolarisResolutionManifestCatal
return new PolarisResolvedPathWrapper(resolvedEntities);
}
- /**
- * @return null if the path resolved for {@code key} isn't fully-resolved when specified as
- * "optional", or if it was resolved but the subType doesn't match the specified subType.
- */
@Override
public PolarisResolvedPathWrapper getPassthroughResolvedPath(
- Object key, PolarisEntityType entityType, PolarisEntitySubType subType) {
+ ResolvedPathKey key, PolarisEntitySubType subType) {
PolarisResolvedPathWrapper resolvedPath = getPassthroughResolvedPath(key);
if (resolvedPath == null) {
return null;
@@ -327,7 +297,7 @@ public class PolarisResolutionManifest implements PolarisResolutionManifestCatal
}
}
- public PolarisEntitySubType getLeafSubType(Object key) {
+ public PolarisEntitySubType getLeafSubType(ResolvedPathKey key) {
diagnostics.check(
pathLookup.containsKey(key),
"never_registered_key_for_resolved_path",
@@ -342,25 +312,19 @@ public class PolarisResolutionManifest implements PolarisResolutionManifestCatal
return resolved.get(resolved.size() - 1).getEntity().getSubType();
}
- /**
- * @param key the key associated with the path to retrieve that was specified in addPath
- * @param prependRootContainer if true, also includes the rootContainer as the first element of
- * the path; otherwise, the first element begins with the referenceCatalog.
- * @return null if the path resolved for {@code key} isn't fully-resolved when specified as
- * "optional"
- */
- public PolarisResolvedPathWrapper getResolvedPath(Object key, boolean prependRootContainer) {
+ /** Resolves a registered path using a canonical lookup key. */
+ public PolarisResolvedPathWrapper getResolvedPath(
+ ResolvedPathKey key, boolean prependRootContainer) {
diagnostics.check(
pathLookup.containsKey(key),
"never_registered_key_for_resolved_path",
"key={} pathLookup={}",
key,
pathLookup);
-
+ int index = pathLookup.get(key);
if (!isResolveAllSucceeded()) {
return null;
}
- int index = pathLookup.get(key);
// Return null for a partially-resolved "optional" path.
ResolverPath requestedPath = addedPaths.get(index);
@@ -385,24 +349,12 @@ public class PolarisResolutionManifest implements PolarisResolutionManifestCatal
return new PolarisResolvedPathWrapper(resolvedEntities);
}
- /**
- * @return null if the path resolved for {@code key} isn't fully-resolved when specified as
- * "optional", or if it was resolved but the subType doesn't match the specified subType.
- */
public PolarisResolvedPathWrapper getResolvedPath(
- Object key,
- PolarisEntityType entityType,
- PolarisEntitySubType subType,
- boolean prependRootContainer) {
+ ResolvedPathKey key, PolarisEntitySubType subType, boolean prependRootContainer) {
PolarisResolvedPathWrapper resolvedPath = getResolvedPath(key, prependRootContainer);
if (resolvedPath == null) {
return null;
}
- // In the case of a passthrough facade, we may have only resolved part of the parent path
- // in which case the subtype wouldn't match; return the path anyways in this case.
- //
- // TODO: Reconcile how we'll handle "TABLE_NOT_FOUND" or "VIEW_NOT_FOUND" semantics
- // against the remote catalog.
if (!getIsPassthroughFacade()
&& resolvedPath.getRawLeafEntity() != null
&& subType != PolarisEntitySubType.ANY_SUBTYPE
diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/PolarisResolutionManifestCatalogView.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/PolarisResolutionManifestCatalogView.java
index 5a8855925e..f4cc21ae89 100644
--- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/PolarisResolutionManifestCatalogView.java
+++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/PolarisResolutionManifestCatalogView.java
@@ -22,7 +22,6 @@ import jakarta.annotation.Nullable;
import java.util.Optional;
import org.apache.polaris.core.entity.CatalogEntity;
import org.apache.polaris.core.entity.PolarisEntitySubType;
-import org.apache.polaris.core.entity.PolarisEntityType;
import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
/**
@@ -39,13 +38,12 @@ public interface PolarisResolutionManifestCatalogView {
.orElse(null);
}
- PolarisResolvedPathWrapper getResolvedPath(Object key);
+ PolarisResolvedPathWrapper getResolvedPath(ResolvedPathKey key);
- PolarisResolvedPathWrapper getResolvedPath(
- Object key, PolarisEntityType entityType, PolarisEntitySubType subType);
+ PolarisResolvedPathWrapper getResolvedPath(ResolvedPathKey key, PolarisEntitySubType subType);
- PolarisResolvedPathWrapper getPassthroughResolvedPath(Object key);
+ PolarisResolvedPathWrapper getPassthroughResolvedPath(ResolvedPathKey key);
PolarisResolvedPathWrapper getPassthroughResolvedPath(
- Object key, PolarisEntityType entityType, PolarisEntitySubType subType);
+ ResolvedPathKey key, PolarisEntitySubType subType);
}
diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/ResolvedPathKey.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/ResolvedPathKey.java
new file mode 100644
index 0000000000..d1acfc2ca4
--- /dev/null
+++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/ResolvedPathKey.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.core.persistence.resolver;
+
+import java.util.Arrays;
+import java.util.List;
+import org.apache.iceberg.catalog.Namespace;
+import org.apache.iceberg.catalog.TableIdentifier;
+import org.apache.polaris.core.catalog.PolarisCatalogHelpers;
+import org.apache.polaris.core.entity.PolarisEntityType;
+
+/** Canonical lookup key for resolved paths in a {@link PolarisResolutionManifest}. */
+public record ResolvedPathKey(List<String> entityNames, PolarisEntityType entityType) {
+
+ public ResolvedPathKey {
+ entityNames = List.copyOf(entityNames);
+ }
+
+ public static ResolvedPathKey of(List<String> entityNames, PolarisEntityType entityType) {
+ return new ResolvedPathKey(entityNames, entityType);
+ }
+
+ public static ResolvedPathKey of(ResolverPath path) {
+ return path.key();
+ }
+
+ public static ResolvedPathKey ofNamespace(Namespace namespace) {
+ return new ResolvedPathKey(Arrays.asList(namespace.levels()), PolarisEntityType.NAMESPACE);
+ }
+
+ public static ResolvedPathKey ofTableLike(TableIdentifier identifier) {
+ return new ResolvedPathKey(
+ PolarisCatalogHelpers.tableIdentifierToList(identifier), PolarisEntityType.TABLE_LIKE);
+ }
+
+ public static ResolvedPathKey ofPolicy(Namespace namespace, String name) {
+ return new ResolvedPathKey(
+ PolarisCatalogHelpers.identifierToList(namespace, name), PolarisEntityType.POLICY);
+ }
+
+ public static ResolvedPathKey ofCatalogRole(String roleName) {
+ return new ResolvedPathKey(List.of(roleName), PolarisEntityType.CATALOG_ROLE);
+ }
+}
diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/ResolverPath.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/ResolverPath.java
index c76bf04d07..43cca6e0bb 100644
--- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/ResolverPath.java
+++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/resolver/ResolverPath.java
@@ -24,14 +24,18 @@ import org.apache.polaris.core.entity.PolarisEntityType;
/**
* Simple class to represent a path within a catalog
*
- * @param entityNames name of the entities in that path. The parent of the first named entity is the
- * path is the catalog
- * @param lastEntityType all entities in a path are namespaces except the last one which can be a
- * table_like entity versus a namespace
+ * @param key canonical path key (entity names + terminal entity type)
* @param optional true if this path is optional, i.e. failing to fully resolve it is not an error
*/
-public record ResolverPath(
- List<String> entityNames, PolarisEntityType lastEntityType, boolean optional) {
+public record ResolverPath(ResolvedPathKey key, boolean optional) {
+ /**
+ * Constructor for a non-optional path from a pre-built canonical key.
+ *
+ * @param key canonical path key (entity names + terminal entity type)
+ */
+ public ResolverPath(ResolvedPathKey key) {
+ this(key, false);
+ }
/**
* Constructor for a non-optional path.
@@ -40,6 +44,28 @@ public record ResolverPath(
* @param lastEntityType type of the last entity
*/
public ResolverPath(List<String> entityNames, PolarisEntityType lastEntityType) {
- this(entityNames, lastEntityType, false);
+ this(new ResolvedPathKey(entityNames, lastEntityType), false);
+ }
+
+ /**
+ * Constructor for a path from entity names + terminal type.
+ *
+ * @param entityNames set of entity names, all are namespaces except the last one
+ * @param lastEntityType type of the last entity
+ * @param optional true if this path is optional, i.e. failing to fully resolve it is not an error
+ */
+ public ResolverPath(
+ List<String> entityNames, PolarisEntityType lastEntityType, boolean optional) {
+ this(new ResolvedPathKey(entityNames, lastEntityType), optional);
+ }
+
+ /** Compatibility accessor for existing call sites. */
+ public List<String> entityNames() {
+ return key.entityNames();
+ }
+
+ /** Compatibility accessor for existing call sites. */
+ public PolarisEntityType lastEntityType() {
+ return key.entityType();
}
}
diff --git a/polaris-core/src/test/java/org/apache/polaris/core/persistence/PolarisResolutionManifestLookupKeyTest.java b/polaris-core/src/test/java/org/apache/polaris/core/persistence/PolarisResolutionManifestLookupKeyTest.java
new file mode 100644
index 0000000000..c880d9e4df
--- /dev/null
+++ b/polaris-core/src/test/java/org/apache/polaris/core/persistence/PolarisResolutionManifestLookupKeyTest.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.core.persistence;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.polaris.core.PolarisDefaultDiagServiceImpl;
+import org.apache.polaris.core.auth.PolarisPrincipal;
+import org.apache.polaris.core.context.RealmContext;
+import org.apache.polaris.core.entity.PolarisEntityType;
+import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifest;
+import org.apache.polaris.core.persistence.resolver.ResolvedPathKey;
+import org.apache.polaris.core.persistence.resolver.Resolver;
+import org.apache.polaris.core.persistence.resolver.ResolverFactory;
+import org.apache.polaris.core.persistence.resolver.ResolverPath;
+import org.apache.polaris.core.persistence.resolver.ResolverStatus;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+public class PolarisResolutionManifestLookupKeyTest {
+
+ @Test
+ void pathKeyLookupResolvesRegisteredPath() {
+ Resolver resolver = Mockito.mock(Resolver.class);
+ ResolverFactory resolverFactory = Mockito.mock(ResolverFactory.class);
+ RealmContext realmContext = Mockito.mock(RealmContext.class);
+ when(resolverFactory.createResolver(any(), anyString())).thenReturn(resolver);
+ when(resolver.resolveAll()).thenReturn(new ResolverStatus(ResolverStatus.StatusEnum.SUCCESS));
+ when(resolver.getIsPassthroughFacade()).thenReturn(false);
+
+ ResolvedPolarisEntity referenceCatalog = Mockito.mock(ResolvedPolarisEntity.class);
+ ResolvedPolarisEntity resolvedLeaf = Mockito.mock(ResolvedPolarisEntity.class);
+ when(resolver.getResolvedReferenceCatalog()).thenReturn(referenceCatalog);
+ when(resolver.getResolvedPaths()).thenReturn(List.of(List.of(resolvedLeaf)));
+
+ PolarisResolutionManifest manifest =
+ new PolarisResolutionManifest(
+ new PolarisDefaultDiagServiceImpl(),
+ realmContext,
+ resolverFactory,
+ PolarisPrincipal.of("p", Map.of(), Set.of()),
+ "catalog");
+
+ ResolverPath tablePath = new ResolverPath(List.of("ns1", "tbl1"), PolarisEntityType.TABLE_LIKE);
+ manifest.addPath(tablePath);
+ manifest.resolveAll();
+
+ var byKey = manifest.getResolvedPath(ResolvedPathKey.of(tablePath), false);
+ assertThat(byKey.getResolvedFullPath()).containsExactly(referenceCatalog, resolvedLeaf);
+ }
+
+ @Test
+ void pathKeyLookupFailsForUnregisteredPath() {
+ Resolver resolver = Mockito.mock(Resolver.class);
+ ResolverFactory resolverFactory = Mockito.mock(ResolverFactory.class);
+ RealmContext realmContext = Mockito.mock(RealmContext.class);
+ when(resolverFactory.createResolver(any(), anyString())).thenReturn(resolver);
+ when(resolver.resolveAll()).thenReturn(new ResolverStatus(ResolverStatus.StatusEnum.SUCCESS));
+ when(resolver.getIsPassthroughFacade()).thenReturn(false);
+ when(resolver.getResolvedReferenceCatalog())
+ .thenReturn(Mockito.mock(ResolvedPolarisEntity.class));
+ when(resolver.getResolvedPaths()).thenReturn(List.of());
+
+ PolarisResolutionManifest manifest =
+ new PolarisResolutionManifest(
+ new PolarisDefaultDiagServiceImpl(),
+ realmContext,
+ resolverFactory,
+ PolarisPrincipal.of("p", Map.of(), Set.of()),
+ "catalog");
+ manifest.resolveAll();
+
+ assertThatThrownBy(
+ () ->
+ manifest.getResolvedPath(
+ ResolvedPathKey.of(List.of("does_not_exist"), PolarisEntityType.NAMESPACE),
+ false))
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessageContaining("never_registered_key_for_resolved_path");
+ }
+
+ @Test
+ void pathKeyLookupUsesLastRegistrationForDuplicateCanonicalPath() {
+ Resolver resolver = Mockito.mock(Resolver.class);
+ ResolverFactory resolverFactory = Mockito.mock(ResolverFactory.class);
+ RealmContext realmContext = Mockito.mock(RealmContext.class);
+ when(resolverFactory.createResolver(any(), anyString())).thenReturn(resolver);
+ when(resolver.resolveAll()).thenReturn(new ResolverStatus(ResolverStatus.StatusEnum.SUCCESS));
+ when(resolver.getIsPassthroughFacade()).thenReturn(false);
+
+ ResolvedPolarisEntity resolvedLeaf = Mockito.mock(ResolvedPolarisEntity.class);
+ when(resolver.getResolvedReferenceCatalog())
+ .thenReturn(Mockito.mock(ResolvedPolarisEntity.class));
+ when(resolver.getResolvedPaths())
+ .thenReturn(List.of(List.of(resolvedLeaf), List.of(resolvedLeaf)));
+
+ PolarisResolutionManifest manifest =
+ new PolarisResolutionManifest(
+ new PolarisDefaultDiagServiceImpl(),
+ realmContext,
+ resolverFactory,
+ PolarisPrincipal.of("p", Map.of(), Set.of()),
+ "catalog");
+
+ ResolverPath nonOptionalPath =
+ new ResolverPath(List.of("ns1", "tbl1"), PolarisEntityType.TABLE_LIKE, false);
+ ResolverPath optionalPath =
+ new ResolverPath(List.of("ns1", "tbl1"), PolarisEntityType.TABLE_LIKE, true);
+
+ manifest.addPath(nonOptionalPath);
+ manifest.addPath(optionalPath);
+ manifest.resolveAll();
+
+ assertThat(manifest.getResolvedPath(ResolvedPathKey.of(optionalPath), false)).isNull();
+ }
+}
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java b/runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java
index b47f4790a8..ddc9b8f2fb 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/admin/PolarisAdminService.java
@@ -112,6 +112,7 @@ import org.apache.polaris.core.persistence.dao.entity.LoadGrantsResult;
import org.apache.polaris.core.persistence.dao.entity.PrivilegeResult;
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifest;
import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
+import org.apache.polaris.core.persistence.resolver.ResolvedPathKey;
import org.apache.polaris.core.persistence.resolver.ResolverPath;
import org.apache.polaris.core.persistence.resolver.ResolverStatus;
import org.apache.polaris.core.policy.PolicyEntity;
@@ -217,7 +218,8 @@ public class PolarisAdminService {
private static CatalogRoleEntity getCatalogRoleByName(
PolarisResolutionManifest resolutionManifest, String catalogRoleName) {
- return Optional.ofNullable(resolutionManifest.getResolvedPath(catalogRoleName))
+ return Optional.ofNullable(
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofCatalogRole(catalogRoleName)))
.map(PolarisResolvedPathWrapper::getRawLeafEntity)
.map(CatalogRoleEntity::of)
.orElseThrow(() -> new NotFoundException("CatalogRole %s not found", catalogRoleName));
@@ -302,11 +304,10 @@ public class PolarisAdminService {
private PolarisResolutionManifest authorizeBasicCatalogRoleOperationOrThrow(
PolarisAuthorizableOperation op, String catalogName, String catalogRoleName) {
PolarisResolutionManifest resolutionManifest = newResolutionManifest(catalogName);
- resolutionManifest.addPath(
- new ResolverPath(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE),
- catalogRoleName);
+ resolutionManifest.addPath(new ResolverPath(ResolvedPathKey.ofCatalogRole(catalogRoleName)));
resolutionManifest.resolveAll();
- PolarisResolvedPathWrapper target = resolutionManifest.getResolvedPath(catalogRoleName, true);
+ PolarisResolvedPathWrapper target =
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofCatalogRole(catalogRoleName), true);
if (target == null) {
throw new NotFoundException("CatalogRole does not exist: %s", catalogRoleName);
}
@@ -383,9 +384,7 @@ public class PolarisAdminService {
String catalogRoleName,
String principalRoleName) {
PolarisResolutionManifest resolutionManifest = newResolutionManifest(catalogName);
- resolutionManifest.addPath(
- new ResolverPath(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE),
- catalogRoleName);
+ resolutionManifest.addPath(new ResolverPath(ResolvedPathKey.ofCatalogRole(catalogRoleName)));
resolutionManifest.addTopLevelName(
principalRoleName, PolarisEntityType.PRINCIPAL_ROLE, false /* isOptional */);
ResolverStatus status = resolutionManifest.resolveAll();
@@ -404,7 +403,7 @@ public class PolarisAdminService {
resolutionManifest.getResolvedTopLevelEntity(
principalRoleName, PolarisEntityType.PRINCIPAL_ROLE);
PolarisResolvedPathWrapper catalogRoleWrapper =
- resolutionManifest.getResolvedPath(catalogRoleName, true);
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofCatalogRole(catalogRoleName), true);
authorizer.authorizeOrThrow(
polarisPrincipal,
@@ -420,9 +419,7 @@ public class PolarisAdminService {
PolarisResolutionManifest resolutionManifest = newResolutionManifest(catalogName);
resolutionManifest.addTopLevelName(
catalogName, PolarisEntityType.CATALOG, false /* isOptional */);
- resolutionManifest.addPath(
- new ResolverPath(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE),
- catalogRoleName);
+ resolutionManifest.addPath(new ResolverPath(ResolvedPathKey.ofCatalogRole(catalogRoleName)));
ResolverStatus status = resolutionManifest.resolveAll();
if (status.getStatus() == ResolverStatus.StatusEnum.ENTITY_COULD_NOT_BE_RESOLVED) {
@@ -434,7 +431,7 @@ public class PolarisAdminService {
PolarisResolvedPathWrapper catalogWrapper =
resolutionManifest.getResolvedTopLevelEntity(catalogName, PolarisEntityType.CATALOG);
PolarisResolvedPathWrapper catalogRoleWrapper =
- resolutionManifest.getResolvedPath(catalogRoleName, true);
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofCatalogRole(catalogRoleName), true);
authorizer.authorizeOrThrow(
polarisPrincipal,
resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(),
@@ -451,11 +448,8 @@ public class PolarisAdminService {
String catalogRoleName) {
PolarisResolutionManifest resolutionManifest = newResolutionManifest(catalogName);
resolutionManifest.addPassthroughPath(
- new ResolverPath(Arrays.asList(namespace.levels()), PolarisEntityType.NAMESPACE),
- namespace);
- resolutionManifest.addPath(
- new ResolverPath(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE),
- catalogRoleName);
+ new ResolverPath(Arrays.asList(namespace.levels()), PolarisEntityType.NAMESPACE));
+ resolutionManifest.addPath(new ResolverPath(ResolvedPathKey.ofCatalogRole(catalogRoleName)));
ResolverStatus status = resolutionManifest.resolveAll();
if (status.getStatus() == ResolverStatus.StatusEnum.ENTITY_COULD_NOT_BE_RESOLVED) {
@@ -470,9 +464,9 @@ public class PolarisAdminService {
}
PolarisResolvedPathWrapper namespaceWrapper =
- resolutionManifest.getResolvedPath(namespace, true);
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofNamespace(namespace), true);
PolarisResolvedPathWrapper catalogRoleWrapper =
- resolutionManifest.getResolvedPath(catalogRoleName, true);
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofCatalogRole(catalogRoleName), true);
authorizer.authorizeOrThrow(
polarisPrincipal,
@@ -492,15 +486,11 @@ public class PolarisAdminService {
PolarisResolutionManifest resolutionManifest = newResolutionManifest(catalogName);
resolutionManifest.addPassthroughPath(
new ResolverPath(
- Arrays.asList(identifier.namespace().levels()), PolarisEntityType.NAMESPACE),
- identifier.namespace());
+ Arrays.asList(identifier.namespace().levels()), PolarisEntityType.NAMESPACE));
resolutionManifest.addPassthroughPath(
new ResolverPath(
- PolarisCatalogHelpers.tableIdentifierToList(identifier), PolarisEntityType.TABLE_LIKE),
- identifier);
- resolutionManifest.addPath(
- new ResolverPath(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE),
- catalogRoleName);
+ PolarisCatalogHelpers.tableIdentifierToList(identifier), PolarisEntityType.TABLE_LIKE));
+ resolutionManifest.addPath(new ResolverPath(ResolvedPathKey.ofCatalogRole(catalogRoleName)));
ResolverStatus status = resolutionManifest.resolveAll();
if (status.getStatus() == ResolverStatus.StatusEnum.ENTITY_COULD_NOT_BE_RESOLVED) {
@@ -516,7 +506,7 @@ public class PolarisAdminService {
CatalogEntity catalogEntity = getCatalogByName(resolutionManifest, catalogName);
PolarisResolvedPathWrapper tableLikeWrapper =
resolutionManifest.getResolvedPath(
- identifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ANY_SUBTYPE, true);
+ ResolvedPathKey.ofTableLike(identifier), PolarisEntitySubType.ANY_SUBTYPE, true);
boolean rbacForFederatedCatalogsEnabled =
realmConfig.getConfig(
FeatureConfiguration.ENABLE_SUB_CATALOG_RBAC_FOR_FEDERATED_CATALOGS, catalogEntity);
@@ -526,7 +516,7 @@ public class PolarisAdminService {
}
PolarisResolvedPathWrapper catalogRoleWrapper =
- resolutionManifest.getResolvedPath(catalogRoleName, true);
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofCatalogRole(catalogRoleName), true);
authorizer.authorizeOrThrow(
polarisPrincipal,
@@ -546,11 +536,8 @@ public class PolarisAdminService {
resolutionManifest.addPath(
new ResolverPath(
PolarisCatalogHelpers.identifierToList(identifier.namespace(), identifier.name()),
- PolarisEntityType.POLICY),
- identifier);
- resolutionManifest.addPath(
- new ResolverPath(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE),
- catalogRoleName);
+ PolarisEntityType.POLICY));
+ resolutionManifest.addPath(new ResolverPath(ResolvedPathKey.ofCatalogRole(catalogRoleName)));
ResolverStatus status = resolutionManifest.resolveAll();
if (status.getStatus() == ResolverStatus.StatusEnum.ENTITY_COULD_NOT_BE_RESOLVED) {
throw new NotFoundException("Catalog not found: %s", catalogName);
@@ -562,9 +549,11 @@ public class PolarisAdminService {
}
}
- PolarisResolvedPathWrapper policyWrapper = resolutionManifest.getResolvedPath(identifier, true);
+ PolarisResolvedPathWrapper policyWrapper =
+ resolutionManifest.getResolvedPath(
+ ResolvedPathKey.ofPolicy(identifier.namespace(), identifier.name()), true);
PolarisResolvedPathWrapper catalogRoleWrapper =
- resolutionManifest.getResolvedPath(catalogRoleName, true);
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofCatalogRole(catalogRoleName), true);
authorizer.authorizeOrThrow(
polarisPrincipal,
@@ -1363,7 +1352,8 @@ public class PolarisAdminService {
PolarisResolutionManifest resolutionManifest =
authorizeBasicCatalogRoleOperationOrThrow(op, catalogName, name);
- PolarisResolvedPathWrapper resolvedCatalogRoleEntity = resolutionManifest.getResolvedPath(name);
+ PolarisResolvedPathWrapper resolvedCatalogRoleEntity =
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofCatalogRole(name));
if (resolvedCatalogRoleEntity == null) {
throw new NotFoundException("CatalogRole %s not found in catalog %s", name, catalogName);
}
@@ -1692,7 +1682,8 @@ public class PolarisAdminService {
CatalogEntity catalogEntity = getCatalogByName(resolutionManifest, catalogName);
CatalogRoleEntity catalogRoleEntity = getCatalogRoleByName(resolutionManifest, catalogRoleName);
- PolarisResolvedPathWrapper resolvedPathWrapper = resolutionManifest.getResolvedPath(namespace);
+ PolarisResolvedPathWrapper resolvedPathWrapper =
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofNamespace(namespace));
if (resolvedPathWrapper == null
|| !resolvedPathWrapper.isFullyResolvedNamespace(catalogName, namespace)) {
boolean rbacForFederatedCatalogsEnabled =
@@ -1735,7 +1726,8 @@ public class PolarisAdminService {
CatalogRoleEntity catalogRoleEntity = getCatalogRoleByName(resolutionManifest, catalogRoleName);
- PolarisResolvedPathWrapper resolvedPathWrapper = resolutionManifest.getResolvedPath(namespace);
+ PolarisResolvedPathWrapper resolvedPathWrapper =
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofNamespace(namespace));
if (resolvedPathWrapper == null
|| !resolvedPathWrapper.isFullyResolvedNamespace(catalogName, namespace)) {
throw new NotFoundException("Namespace %s not found", namespace);
@@ -1808,7 +1800,7 @@ public class PolarisAdminService {
syntheticNamespace = PolarisEntity.of(result.getEntity());
} else if (result.getReturnStatus() == BaseResult.ReturnStatus.ENTITY_ALREADY_EXISTS) {
PolarisResolvedPathWrapper partialPath =
- resolutionManifest.getPassthroughResolvedPath(namespace);
+ resolutionManifest.getPassthroughResolvedPath(ResolvedPathKey.ofNamespace(namespace));
PolarisEntity partialLeafEntity =
partialPath != null ? partialPath.getRawLeafEntity() : null;
if (partialLeafEntity == null
@@ -1830,7 +1822,7 @@ public class PolarisAdminService {
currentParent = syntheticNamespace;
}
PolarisResolvedPathWrapper resolvedPathWrapper =
- resolutionManifest.getPassthroughResolvedPath(namespace);
+ resolutionManifest.getPassthroughResolvedPath(ResolvedPathKey.ofNamespace(namespace));
return resolvedPathWrapper;
}
@@ -2131,7 +2123,7 @@ public class PolarisAdminService {
PolarisResolvedPathWrapper resolvedPathWrapper =
resolutionManifest.getResolvedPath(
- identifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ANY_SUBTYPE);
+ ResolvedPathKey.ofTableLike(identifier), PolarisEntitySubType.ANY_SUBTYPE);
if (resolvedPathWrapper == null
|| !subTypes.contains(resolvedPathWrapper.getRawLeafEntity().getSubType())) {
boolean rbacForFederatedCatalogsEnabled =
@@ -2221,7 +2213,7 @@ public class PolarisAdminService {
syntheticTableEntity);
PolarisResolvedPathWrapper completePathWrapper =
- resolutionManifest.getPassthroughResolvedPath(identifier);
+ resolutionManifest.getPassthroughResolvedPath(ResolvedPathKey.ofTableLike(identifier));
PolarisEntity leafEntity =
completePathWrapper != null ? completePathWrapper.getRawLeafEntity() : null;
if (completePathWrapper == null
@@ -2252,7 +2244,7 @@ public class PolarisAdminService {
PolarisResolvedPathWrapper resolvedPathWrapper =
resolutionManifest.getResolvedPath(
- identifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ANY_SUBTYPE);
+ ResolvedPathKey.ofTableLike(identifier), PolarisEntitySubType.ANY_SUBTYPE);
if (resolvedPathWrapper == null
|| !subTypes.contains(resolvedPathWrapper.getRawLeafEntity().getSubType())) {
throw notFoundExceptionForTableLikeEntity(identifier, subTypes);
@@ -2276,7 +2268,9 @@ public class PolarisAdminService {
CatalogEntity catalogEntity = getCatalogByName(resolutionManifest, catalogName);
CatalogRoleEntity catalogRoleEntity = getCatalogRoleByName(resolutionManifest, catalogRoleName);
- PolarisResolvedPathWrapper resolvedPathWrapper = resolutionManifest.getResolvedPath(identifier);
+ PolarisResolvedPathWrapper resolvedPathWrapper =
+ resolutionManifest.getResolvedPath(
+ ResolvedPathKey.ofPolicy(identifier.namespace(), identifier.name()));
if (resolvedPathWrapper == null) {
throw new NoSuchPolicyException(String.format("Policy not exists: %s", identifier));
}
@@ -2300,7 +2294,9 @@ public class PolarisAdminService {
CatalogEntity catalogEntity = getCatalogByName(resolutionManifest, catalogName);
CatalogRoleEntity catalogRoleEntity = getCatalogRoleByName(resolutionManifest, catalogRoleName);
- PolarisResolvedPathWrapper resolvedPathWrapper = resolutionManifest.getResolvedPath(identifier);
+ PolarisResolvedPathWrapper resolvedPathWrapper =
+ resolutionManifest.getResolvedPath(
+ ResolvedPathKey.ofPolicy(identifier.namespace(), identifier.name()));
if (resolvedPathWrapper == null) {
throw new NoSuchPolicyException(String.format("Policy not exists: %s", identifier));
}
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java
index b6fba5c853..5605cab033 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java
@@ -42,6 +42,7 @@ import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifest;
import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
+import org.apache.polaris.core.persistence.resolver.ResolvedPathKey;
import org.apache.polaris.core.persistence.resolver.ResolverPath;
import org.apache.polaris.core.persistence.resolver.ResolverStatus;
import org.apache.polaris.service.types.PolicyIdentifier;
@@ -100,15 +101,13 @@ public abstract class CatalogHandler {
List<PolicyIdentifier> extraPassThroughPolicies) {
resolutionManifest = newResolutionManifest();
resolutionManifest.addPath(
- new ResolverPath(Arrays.asList(namespace.levels()), PolarisEntityType.NAMESPACE),
- namespace);
+ new ResolverPath(Arrays.asList(namespace.levels()), PolarisEntityType.NAMESPACE));
if (extraPassthroughNamespaces != null) {
for (Namespace ns : extraPassthroughNamespaces) {
resolutionManifest.addPassthroughPath(
new ResolverPath(
- Arrays.asList(ns.levels()), PolarisEntityType.NAMESPACE, true /* optional */),
- ns);
+ Arrays.asList(ns.levels()), PolarisEntityType.NAMESPACE, true /* optional */));
}
}
if (extraPassthroughTableLikes != null) {
@@ -117,8 +116,7 @@ public abstract class CatalogHandler {
new ResolverPath(
PolarisCatalogHelpers.tableIdentifierToList(id),
PolarisEntityType.TABLE_LIKE,
- true /* optional */),
- id);
+ true /* optional */));
}
}
@@ -128,13 +126,13 @@ public abstract class CatalogHandler {
new ResolverPath(
PolarisCatalogHelpers.identifierToList(id.namespace(), id.name()),
PolarisEntityType.POLICY,
- true /* optional */),
- id);
+ true /* optional */));
}
}
resolutionManifest.resolveAll();
- PolarisResolvedPathWrapper target = resolutionManifest.getResolvedPath(namespace, true);
+ PolarisResolvedPathWrapper target =
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofNamespace(namespace), true);
if (target == null) {
throw noSuchNamespaceException(namespace);
}
@@ -155,8 +153,7 @@ public abstract class CatalogHandler {
Namespace parentNamespace = PolarisCatalogHelpers.getParentNamespace(namespace);
resolutionManifest.addPath(
- new ResolverPath(Arrays.asList(parentNamespace.levels()), PolarisEntityType.NAMESPACE),
- parentNamespace);
+ new ResolverPath(Arrays.asList(parentNamespace.levels()), PolarisEntityType.NAMESPACE));
// When creating an entity under a namespace, the authz target is the parentNamespace, but we
// must also add the actual path that will be created as an "optional" passthrough resolution
@@ -164,10 +161,10 @@ public abstract class CatalogHandler {
// a conflicting entity.
resolutionManifest.addPassthroughPath(
new ResolverPath(
- Arrays.asList(namespace.levels()), PolarisEntityType.NAMESPACE, true /* optional */),
- namespace);
+ Arrays.asList(namespace.levels()), PolarisEntityType.NAMESPACE, true /* optional */));
resolutionManifest.resolveAll();
- PolarisResolvedPathWrapper target = resolutionManifest.getResolvedPath(parentNamespace, true);
+ PolarisResolvedPathWrapper target =
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofNamespace(parentNamespace), true);
if (target == null) {
throw noSuchNamespaceException(parentNamespace);
}
@@ -188,8 +185,7 @@ public abstract class CatalogHandler {
resolutionManifest = newResolutionManifest();
resolutionManifest.addPath(
- new ResolverPath(Arrays.asList(namespace.levels()), PolarisEntityType.NAMESPACE),
- namespace);
+ new ResolverPath(Arrays.asList(namespace.levels()), PolarisEntityType.NAMESPACE));
// When creating an entity under a namespace, the authz target is the namespace, but we must
// also
@@ -201,10 +197,10 @@ public abstract class CatalogHandler {
new ResolverPath(
PolarisCatalogHelpers.tableIdentifierToList(identifier),
PolarisEntityType.TABLE_LIKE,
- true /* optional */),
- identifier);
+ true /* optional */));
resolutionManifest.resolveAll();
- PolarisResolvedPathWrapper target = resolutionManifest.getResolvedPath(namespace, true);
+ PolarisResolvedPathWrapper target =
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofNamespace(namespace), true);
if (target == null) {
throw noSuchNamespaceException(namespace);
}
@@ -233,8 +229,7 @@ public abstract class CatalogHandler {
new ResolverPath(
PolarisCatalogHelpers.tableIdentifierToList(identifier),
PolarisEntityType.TABLE_LIKE,
- true /* optional */),
- identifier);
+ true /* optional */));
resolutionManifest.resolveAll();
}
}
@@ -250,7 +245,7 @@ public abstract class CatalogHandler {
TableIdentifier identifier) {
ensureResolutionManifestForTable(identifier);
PolarisResolvedPathWrapper target =
- resolutionManifest.getResolvedPath(identifier, PolarisEntityType.TABLE_LIKE, subType, true);
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofTableLike(identifier), subType, true);
if (target == null) {
throw notFoundExceptionForTableLikeEntity(identifier, subType);
}
@@ -278,8 +273,7 @@ public abstract class CatalogHandler {
resolutionManifest.addPassthroughPath(
new ResolverPath(
PolarisCatalogHelpers.tableIdentifierToList(identifier),
- PolarisEntityType.TABLE_LIKE),
- identifier));
+ PolarisEntityType.TABLE_LIKE)));
ResolverStatus status = resolutionManifest.resolveAll();
@@ -298,7 +292,7 @@ public abstract class CatalogHandler {
identifier ->
Optional.ofNullable(
resolutionManifest.getResolvedPath(
- identifier, PolarisEntityType.TABLE_LIKE, subType, true))
+ ResolvedPathKey.ofTableLike(identifier), subType, true))
.orElseThrow(
() -> notFoundExceptionForTableLikeEntity(identifier, subType)))
.toList();
@@ -322,22 +316,19 @@ public abstract class CatalogHandler {
// Add src, dstParent, and dst(optional)
resolutionManifest.addPath(
new ResolverPath(
- PolarisCatalogHelpers.tableIdentifierToList(src), PolarisEntityType.TABLE_LIKE),
- src);
+ PolarisCatalogHelpers.tableIdentifierToList(src), PolarisEntityType.TABLE_LIKE));
resolutionManifest.addPath(
- new ResolverPath(Arrays.asList(dst.namespace().levels()), PolarisEntityType.NAMESPACE),
- dst.namespace());
+ new ResolverPath(Arrays.asList(dst.namespace().levels()), PolarisEntityType.NAMESPACE));
resolutionManifest.addPath(
new ResolverPath(
PolarisCatalogHelpers.tableIdentifierToList(dst),
PolarisEntityType.TABLE_LIKE,
- true /* optional */),
- dst);
+ true /* optional */));
ResolverStatus status = resolutionManifest.resolveAll();
if (status.getStatus() == ResolverStatus.StatusEnum.PATH_COULD_NOT_BE_FULLY_RESOLVED
&& status.getFailedToResolvePath().lastEntityType() == PolarisEntityType.NAMESPACE) {
throw noSuchNamespaceException(dst.namespace());
- } else if (resolutionManifest.getResolvedPath(src, PolarisEntityType.TABLE_LIKE, subType)
+ } else if (resolutionManifest.getResolvedPath(ResolvedPathKey.ofTableLike(src), subType)
== null) {
throw notFoundExceptionForTableLikeEntity(dst, subType);
}
@@ -349,7 +340,8 @@ public abstract class CatalogHandler {
// type.
// TODO: Possibly modify the exception thrown depending on whether the caller has privileges
// on the parent namespace.
- PolarisEntitySubType dstLeafSubType = resolutionManifest.getLeafSubType(dst);
+ PolarisEntitySubType dstLeafSubType =
+ resolutionManifest.getLeafSubType(ResolvedPathKey.ofTableLike(dst));
switch (dstLeafSubType) {
case ICEBERG_TABLE:
@@ -364,9 +356,9 @@ public abstract class CatalogHandler {
}
PolarisResolvedPathWrapper target =
- resolutionManifest.getResolvedPath(src, PolarisEntityType.TABLE_LIKE, subType, true);
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofTableLike(src), subType, true);
PolarisResolvedPathWrapper secondary =
- resolutionManifest.getResolvedPath(dst.namespace(), true);
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofNamespace(dst.namespace()), true);
authorizer()
.authorizeOrThrow(
polarisPrincipal(),
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogUtils.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogUtils.java
index ae76e1490c..0dcb1ba2b8 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogUtils.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogUtils.java
@@ -33,9 +33,9 @@ import org.apache.polaris.core.admin.model.StorageConfigInfo;
import org.apache.polaris.core.config.FeatureConfiguration;
import org.apache.polaris.core.config.RealmConfig;
import org.apache.polaris.core.entity.PolarisEntitySubType;
-import org.apache.polaris.core.entity.PolarisEntityType;
import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifestCatalogView;
+import org.apache.polaris.core.persistence.resolver.ResolvedPathKey;
import org.apache.polaris.core.storage.PolarisStorageConfigurationInfo;
/** Utility methods for working with Polaris catalog entities. */
@@ -52,11 +52,12 @@ public class CatalogUtils {
PolarisResolutionManifestCatalogView resolvedEntityView, TableIdentifier tableIdentifier) {
PolarisResolvedPathWrapper resolvedTableEntities =
resolvedEntityView.getResolvedPath(
- tableIdentifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ICEBERG_TABLE);
+ ResolvedPathKey.ofTableLike(tableIdentifier), PolarisEntitySubType.ICEBERG_TABLE);
if (resolvedTableEntities != null) {
return resolvedTableEntities;
}
- return resolvedEntityView.getResolvedPath(tableIdentifier.namespace());
+ return resolvedEntityView.getResolvedPath(
+ ResolvedPathKey.ofNamespace(tableIdentifier.namespace()));
}
/**
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalog.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalog.java
index a1c6078f43..b232f0e3a4 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalog.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/generic/PolarisGenericTableCatalog.java
@@ -41,6 +41,7 @@ import org.apache.polaris.core.persistence.dao.entity.DropEntityResult;
import org.apache.polaris.core.persistence.dao.entity.EntityResult;
import org.apache.polaris.core.persistence.pagination.PageToken;
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifestCatalogView;
+import org.apache.polaris.core.persistence.resolver.ResolvedPathKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -79,7 +80,8 @@ public class PolarisGenericTableCatalog implements GenericTableCatalog {
String doc,
Map<String, String> properties) {
PolarisResolvedPathWrapper resolvedParent =
- resolvedEntityView.getResolvedPath(tableIdentifier.namespace());
+ resolvedEntityView.getResolvedPath(
+ ResolvedPathKey.ofNamespace(tableIdentifier.namespace()));
if (resolvedParent == null) {
// Illegal state because the namespace should've already been in the static resolution set.
throw new IllegalStateException(
@@ -91,7 +93,7 @@ public class PolarisGenericTableCatalog implements GenericTableCatalog {
PolarisResolvedPathWrapper resolvedEntities =
resolvedEntityView.getPassthroughResolvedPath(
- tableIdentifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ANY_SUBTYPE);
+ ResolvedPathKey.ofTableLike(tableIdentifier), PolarisEntitySubType.ANY_SUBTYPE);
PolarisEntity entity = resolvedEntities == null ? null : resolvedEntities.getRawLeafEntity();
if (null == entity) {
entity =
@@ -137,7 +139,7 @@ public class PolarisGenericTableCatalog implements GenericTableCatalog {
public GenericTableEntity loadGenericTable(TableIdentifier tableIdentifier) {
PolarisResolvedPathWrapper resolvedEntities =
resolvedEntityView.getPassthroughResolvedPath(
- tableIdentifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.GENERIC_TABLE);
+ ResolvedPathKey.ofTableLike(tableIdentifier), PolarisEntitySubType.GENERIC_TABLE);
GenericTableEntity entity =
GenericTableEntity.of(
resolvedEntities == null ? null : resolvedEntities.getRawLeafEntity());
@@ -153,7 +155,7 @@ public class PolarisGenericTableCatalog implements GenericTableCatalog {
public boolean dropGenericTable(TableIdentifier tableIdentifier) {
PolarisResolvedPathWrapper resolvedEntities =
resolvedEntityView.getPassthroughResolvedPath(
- tableIdentifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.GENERIC_TABLE);
+ ResolvedPathKey.ofTableLike(tableIdentifier), PolarisEntitySubType.GENERIC_TABLE);
if (resolvedEntities == null) {
throw notFoundExceptionForTableLikeEntity(
@@ -176,7 +178,8 @@ public class PolarisGenericTableCatalog implements GenericTableCatalog {
@Override
public List<TableIdentifier> listGenericTables(Namespace namespace) {
- PolarisResolvedPathWrapper resolvedEntities = resolvedEntityView.getResolvedPath(namespace);
+ PolarisResolvedPathWrapper resolvedEntities =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(namespace));
if (resolvedEntities == null) {
throw noSuchNamespaceException(namespace);
}
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java
index 776a0a8b4a..5cd5490000 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java
@@ -123,6 +123,7 @@ import org.apache.polaris.core.persistence.pagination.Page;
import org.apache.polaris.core.persistence.pagination.PageToken;
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifest;
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifestCatalogView;
+import org.apache.polaris.core.persistence.resolver.ResolvedPathKey;
import org.apache.polaris.core.persistence.resolver.ResolverFactory;
import org.apache.polaris.core.persistence.resolver.ResolverPath;
import org.apache.polaris.core.persistence.resolver.ResolverStatus;
@@ -315,7 +316,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
TableOperations ops = newTableOps(identifier);
PolarisResolvedPathWrapper resolvedParent =
- resolvedEntityView.getResolvedPath(identifier.namespace());
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(identifier.namespace()));
if (resolvedParent == null) {
// Illegal state because the namespace should've already been in the static resolution set.
throw new IllegalStateException(
@@ -368,7 +369,8 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
defaultNamespaceLocation(tableIdentifier.namespace()), tableIdentifier.name());
} else {
PolarisResolvedPathWrapper resolvedNamespace =
- resolvedEntityView.getResolvedPath(tableIdentifier.namespace());
+ resolvedEntityView.getResolvedPath(
+ ResolvedPathKey.ofNamespace(tableIdentifier.namespace()));
if (resolvedNamespace == null) {
throw noSuchNamespaceException(tableIdentifier.namespace());
}
@@ -496,7 +498,8 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
// TODO: These should really be helpers in core Iceberg Namespace.
Namespace parentNamespace = PolarisCatalogHelpers.getParentNamespace(namespace);
- PolarisResolvedPathWrapper resolvedParent = resolvedEntityView.getResolvedPath(parentNamespace);
+ PolarisResolvedPathWrapper resolvedParent =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(parentNamespace));
if (resolvedParent == null) {
throw new NoSuchNamespaceException(
"Cannot create namespace %s. Parent namespace does not exist.", namespace);
@@ -630,9 +633,11 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
private PolarisResolvedPathWrapper getResolvedParentNamespace(Namespace namespace) {
Namespace parentNamespace =
Namespace.of(Arrays.copyOf(namespace.levels(), namespace.length() - 1));
- PolarisResolvedPathWrapper resolvedParent = resolvedEntityView.getResolvedPath(parentNamespace);
+ PolarisResolvedPathWrapper resolvedParent =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(parentNamespace));
if (resolvedParent == null) {
- return resolvedEntityView.getPassthroughResolvedPath(parentNamespace);
+ return resolvedEntityView.getPassthroughResolvedPath(
+ ResolvedPathKey.ofNamespace(parentNamespace));
}
return resolvedParent;
}
@@ -641,7 +646,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
public boolean namespaceExists(Namespace namespace) {
return Optional.ofNullable(namespace)
.filter(ns -> !ns.isEmpty())
- .map(resolvedEntityView::getResolvedPath)
+ .map(ns -> resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(ns)))
.isPresent();
}
@@ -650,7 +655,8 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
if (namespace.isEmpty()) {
throw new IllegalArgumentException("Cannot drop root namespace");
}
- PolarisResolvedPathWrapper resolvedEntities = resolvedEntityView.getResolvedPath(namespace);
+ PolarisResolvedPathWrapper resolvedEntities =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(namespace));
if (resolvedEntities == null) {
return false;
}
@@ -692,7 +698,8 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
@Override
public boolean setProperties(Namespace namespace, Map<String, String> properties)
throws NoSuchNamespaceException {
- PolarisResolvedPathWrapper resolvedEntities = resolvedEntityView.getResolvedPath(namespace);
+ PolarisResolvedPathWrapper resolvedEntities =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(namespace));
if (resolvedEntities == null) {
throw noSuchNamespaceException(namespace);
}
@@ -738,7 +745,8 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
@Override
public boolean removeProperties(Namespace namespace, Set<String> properties)
throws NoSuchNamespaceException {
- PolarisResolvedPathWrapper resolvedEntities = resolvedEntityView.getResolvedPath(namespace);
+ PolarisResolvedPathWrapper resolvedEntities =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(namespace));
if (resolvedEntities == null) {
throw noSuchNamespaceException(namespace);
}
@@ -770,7 +778,8 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
@Override
public Map<String, String> loadNamespaceMetadata(Namespace namespace)
throws NoSuchNamespaceException {
- PolarisResolvedPathWrapper resolvedEntities = resolvedEntityView.getResolvedPath(namespace);
+ PolarisResolvedPathWrapper resolvedEntities =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(namespace));
if (resolvedEntities == null) {
throw noSuchNamespaceException(namespace);
}
@@ -796,7 +805,8 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
public Page<Namespace> listNamespaces(Namespace namespace, PageToken pageToken)
throws NoSuchNamespaceException {
- PolarisResolvedPathWrapper resolvedEntities = resolvedEntityView.getResolvedPath(namespace);
+ PolarisResolvedPathWrapper resolvedEntities =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(namespace));
if (resolvedEntities == null) {
throw noSuchNamespaceException(namespace);
}
@@ -1018,12 +1028,15 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
private void validateLocationForTableLike(TableIdentifier identifier, String location) {
PolarisResolvedPathWrapper resolvedStorageEntity =
resolvedEntityView.getResolvedPath(
- identifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ANY_SUBTYPE);
+ ResolvedPathKey.ofTableLike(identifier), PolarisEntitySubType.ANY_SUBTYPE);
if (resolvedStorageEntity == null) {
- resolvedStorageEntity = resolvedEntityView.getResolvedPath(identifier.namespace());
+ resolvedStorageEntity =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(identifier.namespace()));
}
if (resolvedStorageEntity == null) {
- resolvedStorageEntity = resolvedEntityView.getPassthroughResolvedPath(identifier.namespace());
+ resolvedStorageEntity =
+ resolvedEntityView.getPassthroughResolvedPath(
+ ResolvedPathKey.ofNamespace(identifier.namespace()));
}
validateLocationForTableLike(identifier, location, resolvedStorageEntity);
@@ -1248,12 +1261,12 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
tbl ->
resolutionManifest.addPath(
new ResolverPath(
- PolarisCatalogHelpers.tableIdentifierToList(tbl), PolarisEntityType.TABLE_LIKE),
- tbl));
+ PolarisCatalogHelpers.tableIdentifierToList(tbl),
+ PolarisEntityType.TABLE_LIKE)));
siblingNamespaces.forEach(
ns ->
resolutionManifest.addPath(
- new ResolverPath(Arrays.asList(ns.levels()), PolarisEntityType.NAMESPACE), ns));
+ new ResolverPath(Arrays.asList(ns.levels()), PolarisEntityType.NAMESPACE)));
ResolverStatus status = resolutionManifest.resolveAll();
if (!status.getStatus().equals(ResolverStatus.StatusEnum.SUCCESS)) {
String message =
@@ -1271,7 +1284,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
.map(
tbl -> {
PolarisResolvedPathWrapper resolveTablePath =
- resolutionManifest.getResolvedPath(tbl);
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofTableLike(tbl));
PolarisEntity tableEntity = resolveTablePath.getRawLeafEntity();
if (tableEntity.getSubType() == PolarisEntitySubType.GENERIC_TABLE) {
return GenericTableEntity.of(tableEntity).getBaseLocation();
@@ -1283,7 +1296,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
.map(
ns -> {
PolarisResolvedPathWrapper resolveNamespacePath =
- resolutionManifest.getResolvedPath(ns);
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofNamespace(ns));
return NamespaceEntity.of(resolveNamespacePath.getRawLeafEntity())
.getBaseLocation();
}))
@@ -1436,7 +1449,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
// table entity instead of the statically-resolved authz resolution set.
PolarisResolvedPathWrapper resolvedEntities =
resolvedEntityView.getPassthroughResolvedPath(
- tableIdentifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ICEBERG_TABLE);
+ ResolvedPathKey.ofTableLike(tableIdentifier), PolarisEntitySubType.ICEBERG_TABLE);
IcebergTableLikeEntity entity = null;
if (resolvedEntities != null) {
@@ -1506,14 +1519,15 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
PolarisResolvedPathWrapper resolvedTableEntities =
resolvedEntityView.getPassthroughResolvedPath(
- tableIdentifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ICEBERG_TABLE);
+ ResolvedPathKey.ofTableLike(tableIdentifier), PolarisEntitySubType.ICEBERG_TABLE);
// Fetch credentials for the resolved entity. The entity could be the table itself (if it has
// already been stored and credentials have been configured directly) or it could be the
// table's namespace or catalog.
PolarisResolvedPathWrapper resolvedStorageEntity =
resolvedTableEntities == null
- ? resolvedEntityView.getResolvedPath(tableIdentifier.namespace())
+ ? resolvedEntityView.getResolvedPath(
+ ResolvedPathKey.ofNamespace(tableIdentifier.namespace()))
: resolvedTableEntities;
// refresh credentials because we need to read the metadata file to validate its location
@@ -1530,7 +1544,9 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
List<PolarisEntity> resolvedNamespace =
resolvedTableEntities == null
- ? resolvedEntityView.getResolvedPath(tableIdentifier.namespace()).getRawFullPath()
+ ? resolvedEntityView
+ .getResolvedPath(ResolvedPathKey.ofNamespace(tableIdentifier.namespace()))
+ .getRawFullPath()
: resolvedTableEntities.getRawParentPath();
if (base == null
@@ -1572,7 +1588,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
// persistence-layer commit).
PolarisResolvedPathWrapper resolvedPath =
resolvedEntityView.getPassthroughResolvedPath(
- tableIdentifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ANY_SUBTYPE);
+ ResolvedPathKey.ofTableLike(tableIdentifier), PolarisEntitySubType.ANY_SUBTYPE);
if (resolvedPath != null && resolvedPath.getRawLeafEntity() != null) {
var subType = resolvedPath.getRawLeafEntity().getSubType();
if (subType != PolarisEntitySubType.ICEBERG_TABLE) {
@@ -1856,7 +1872,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
public void doRefresh() {
PolarisResolvedPathWrapper resolvedEntities =
resolvedEntityView.getPassthroughResolvedPath(
- identifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ICEBERG_VIEW);
+ ResolvedPathKey.ofTableLike(identifier), PolarisEntitySubType.ICEBERG_VIEW);
IcebergTableLikeEntity entity = null;
if (resolvedEntities != null) {
@@ -1928,7 +1944,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
PolarisResolvedPathWrapper resolvedTable =
resolvedEntityView.getPassthroughResolvedPath(
- identifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ICEBERG_TABLE);
+ ResolvedPathKey.ofTableLike(identifier), PolarisEntitySubType.ICEBERG_TABLE);
if (resolvedTable != null) {
throw alreadyExistsExceptionWithSameNameForTableLikeEntity(
identifier, PolarisEntitySubType.ICEBERG_TABLE);
@@ -1936,19 +1952,22 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
PolarisResolvedPathWrapper resolvedEntities =
resolvedEntityView.getPassthroughResolvedPath(
- identifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ICEBERG_VIEW);
+ ResolvedPathKey.ofTableLike(identifier), PolarisEntitySubType.ICEBERG_VIEW);
// Fetch credentials for the resolved entity. The entity could be the view itself (if it has
// already been stored and credentials have been configured directly) or it could be the
// table's namespace or catalog.
PolarisResolvedPathWrapper resolvedStorageEntity =
resolvedEntities == null
- ? resolvedEntityView.getResolvedPath(identifier.namespace())
+ ? resolvedEntityView.getResolvedPath(
+ ResolvedPathKey.ofNamespace(identifier.namespace()))
: resolvedEntities;
List<PolarisEntity> resolvedNamespace =
resolvedEntities == null
- ? resolvedEntityView.getResolvedPath(identifier.namespace()).getRawFullPath()
+ ? resolvedEntityView
+ .getResolvedPath(ResolvedPathKey.ofNamespace(identifier.namespace()))
+ .getRawFullPath()
: resolvedEntities.getRawParentPath();
if (base == null || !metadata.location().equals(base.location())) {
// If location is changing then we must validate that the requested location is valid
@@ -2208,7 +2227,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
PolarisEntitySubType subType, TableIdentifier from, TableIdentifier to) {
LOGGER.debug("Renaming tableLike from {} to {}", from, to);
PolarisResolvedPathWrapper resolvedEntities =
- resolvedEntityView.getResolvedPath(from, PolarisEntityType.TABLE_LIKE, subType);
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofTableLike(from), subType);
if (resolvedEntities == null) {
if (subType == PolarisEntitySubType.ICEBERG_VIEW) {
throw new NoSuchViewException("Cannot rename %s to %s. View does not exist", from, to);
@@ -2222,7 +2241,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
List<PolarisEntity> newCatalogPath = null;
if (!from.namespace().equals(to.namespace())) {
PolarisResolvedPathWrapper resolvedNewParentEntities =
- resolvedEntityView.getResolvedPath(to.namespace());
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(to.namespace()));
if (resolvedNewParentEntities == null) {
throw new NoSuchNamespaceException(
"Cannot rename %s to %s. Namespace does not exist: %s", from, to, to.namespace());
@@ -2315,7 +2334,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
*/
private void createTableLike(TableIdentifier identifier, PolarisEntity entity) {
PolarisResolvedPathWrapper resolvedParent =
- resolvedEntityView.getResolvedPath(identifier.namespace());
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(identifier.namespace()));
if (resolvedParent == null) {
// Illegal state because the namespace should've already been in the static resolution set.
throw new IllegalStateException(
@@ -2385,7 +2404,8 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
private void updateTableLike(TableIdentifier identifier, PolarisEntity entity) {
PolarisResolvedPathWrapper resolvedEntities =
- resolvedEntityView.getResolvedPath(identifier, entity.getType(), entity.getSubType());
+ resolvedEntityView.getResolvedPath(
+ ResolvedPathKey.ofTableLike(identifier), entity.getSubType());
if (resolvedEntities == null) {
// Illegal state because the identifier should've already been in the static resolution set.
throw new IllegalStateException(
@@ -2443,7 +2463,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
Map<String, String> storageProperties,
boolean purge) {
PolarisResolvedPathWrapper resolvedEntities =
- resolvedEntityView.getResolvedPath(identifier, PolarisEntityType.TABLE_LIKE, subType);
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofTableLike(identifier), subType);
if (resolvedEntities == null) {
// TODO: Error?
return new DropEntityResult(BaseResult.ReturnStatus.ENTITY_NOT_FOUND, null);
@@ -2482,7 +2502,7 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
"Handling notification request {} for tableIdentifier {}", request, tableIdentifier);
PolarisResolvedPathWrapper resolvedEntities =
resolvedEntityView.getPassthroughResolvedPath(
- tableIdentifier, PolarisEntityType.TABLE_LIKE, subType);
+ ResolvedPathKey.ofTableLike(tableIdentifier), subType);
NotificationType notificationType = request.getNotificationType();
@@ -2507,7 +2527,8 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
Arrays.stream(tableIdentifier.namespace().levels())
.limit(i)
.toArray(String[]::new));
- resolvedStorageEntity = resolvedEntityView.getResolvedPath(nsLevel);
+ resolvedStorageEntity =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(nsLevel));
if (resolvedStorageEntity != null) {
storageInfoEntity = FileIOUtil.findStorageInfoFromHierarchy(resolvedStorageEntity);
break;
@@ -2543,7 +2564,8 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
Namespace ns = tableIdentifier.namespace();
createNonExistingNamespaces(ns);
- PolarisResolvedPathWrapper resolvedParent = resolvedEntityView.getPassthroughResolvedPath(ns);
+ PolarisResolvedPathWrapper resolvedParent =
+ resolvedEntityView.getPassthroughResolvedPath(ResolvedPathKey.ofNamespace(ns));
IcebergTableLikeEntity entity =
IcebergTableLikeEntity.of(
@@ -2625,10 +2647,12 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
for (int i = 1; i <= namespace.length(); i++) {
Namespace nsLevel =
Namespace.of(Arrays.stream(namespace.levels()).limit(i).toArray(String[]::new));
- if (resolvedEntityView.getPassthroughResolvedPath(nsLevel) == null) {
+ if (resolvedEntityView.getPassthroughResolvedPath(ResolvedPathKey.ofNamespace(nsLevel))
+ == null) {
Namespace parentNamespace = PolarisCatalogHelpers.getParentNamespace(nsLevel);
PolarisResolvedPathWrapper resolvedParent =
- resolvedEntityView.getPassthroughResolvedPath(parentNamespace);
+ resolvedEntityView.getPassthroughResolvedPath(
+ ResolvedPathKey.ofNamespace(parentNamespace));
try {
createNamespaceInternal(nsLevel, Collections.emptyMap(), resolvedParent);
} catch (AlreadyExistsException aee) {
@@ -2652,7 +2676,8 @@ public class IcebergCatalog extends BaseMetastoreViewCatalog
private Page<TableIdentifier> listTableLike(
PolarisEntitySubType subType, Namespace namespace, PageToken pageToken) {
- PolarisResolvedPathWrapper resolvedEntities = resolvedEntityView.getResolvedPath(namespace);
+ PolarisResolvedPathWrapper resolvedEntities =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(namespace));
if (resolvedEntities == null) {
// Illegal state because the namespace should've already been in the static resolution set.
throw new IllegalStateException(
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
index 2d8664f204..dda26ff048 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalogHandler.java
@@ -106,6 +106,7 @@ import org.apache.polaris.core.persistence.dao.entity.EntitiesResult;
import org.apache.polaris.core.persistence.dao.entity.EntityWithPath;
import org.apache.polaris.core.persistence.pagination.Page;
import org.apache.polaris.core.persistence.pagination.PageToken;
+import org.apache.polaris.core.persistence.resolver.ResolvedPathKey;
import org.apache.polaris.core.persistence.resolver.Resolver;
import org.apache.polaris.core.persistence.resolver.ResolverFactory;
import org.apache.polaris.core.persistence.resolver.ResolverStatus;
@@ -327,7 +328,7 @@ public abstract class IcebergCatalogHandler extends CatalogHandler implements Au
reservedProperties()
.removeReservedProperties(
resolutionManifest
- .getPassthroughResolvedPath(namespace)
+ .getPassthroughResolvedPath(ResolvedPathKey.ofNamespace(namespace))
.getRawLeafEntity()
.getPropertiesAsMap());
return CreateNamespaceResponse.builder()
@@ -657,7 +658,8 @@ public abstract class IcebergCatalogHandler extends CatalogHandler implements Au
long catalogId = catalogEntity.getId();
// Get the table ID from the resolved path
- PolarisResolvedPathWrapper resolvedTable = resolutionManifest.getResolvedPath(identifier);
+ PolarisResolvedPathWrapper resolvedTable =
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofTableLike(identifier));
PolarisEntity tableEntity = resolvedTable.getRawLeafEntity();
long tableId = tableEntity.getId();
@@ -673,7 +675,8 @@ public abstract class IcebergCatalogHandler extends CatalogHandler implements Au
* @return the Polaris table entity for the table or null for external catalogs
*/
private @Nullable IcebergTableLikeEntity getTableEntity(TableIdentifier tableIdentifier) {
- PolarisResolvedPathWrapper target = resolutionManifest.getResolvedPath(tableIdentifier);
+ PolarisResolvedPathWrapper target =
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofTableLike(tableIdentifier));
PolarisEntity rawLeafEntity = target.getRawLeafEntity();
if (rawLeafEntity.getType() == PolarisEntityType.TABLE_LIKE) {
return IcebergTableLikeEntity.of(rawLeafEntity);
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalog.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalog.java
index 147f550510..fdd1496ce4 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalog.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalog.java
@@ -54,6 +54,7 @@ import org.apache.polaris.core.persistence.dao.entity.ListEntitiesResult;
import org.apache.polaris.core.persistence.dao.entity.LoadPolicyMappingsResult;
import org.apache.polaris.core.persistence.pagination.PageToken;
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifestCatalogView;
+import org.apache.polaris.core.persistence.resolver.ResolvedPathKey;
import org.apache.polaris.core.policy.PolicyEntity;
import org.apache.polaris.core.policy.PolicyType;
import org.apache.polaris.core.policy.exceptions.NoSuchPolicyException;
@@ -91,7 +92,8 @@ public class PolicyCatalog {
public Policy createPolicy(
PolicyIdentifier policyIdentifier, String type, String description, String content) {
PolarisResolvedPathWrapper resolvedParent =
- resolvedEntityView.getResolvedPath(policyIdentifier.namespace());
+ resolvedEntityView.getResolvedPath(
+ ResolvedPathKey.ofNamespace(policyIdentifier.namespace()));
if (resolvedParent == null) {
// Illegal state because the namespace should've already been in the static resolution set.
throw new IllegalStateException(
@@ -102,7 +104,8 @@ public class PolicyCatalog {
PolarisResolvedPathWrapper resolvedPolicyEntities =
resolvedEntityView.getPassthroughResolvedPath(
- policyIdentifier, PolarisEntityType.POLICY, PolarisEntitySubType.NULL_SUBTYPE);
+ ResolvedPathKey.ofPolicy(policyIdentifier.namespace(), policyIdentifier.name()),
+ PolarisEntitySubType.NULL_SUBTYPE);
PolicyEntity entity =
PolicyEntity.of(
@@ -155,7 +158,8 @@ public class PolicyCatalog {
}
public List<PolicyIdentifier> listPolicies(Namespace namespace, @Nullable PolicyType policyType) {
- PolarisResolvedPathWrapper resolvedEntities = resolvedEntityView.getResolvedPath(namespace);
+ PolarisResolvedPathWrapper resolvedEntities =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(namespace));
if (resolvedEntities == null) {
throw new IllegalStateException(
String.format("Failed to fetch resolved namespace '%s'", namespace));
@@ -446,7 +450,8 @@ public class PolicyCatalog {
return List.of(catalogEntity);
} else if (Strings.isNullOrEmpty(targetName)) {
// namespace
- var resolvedTargetEntity = resolvedEntityView.getResolvedPath(namespace);
+ var resolvedTargetEntity =
+ resolvedEntityView.getResolvedPath(ResolvedPathKey.ofNamespace(namespace));
if (resolvedTargetEntity == null) {
throw noSuchNamespaceException(namespace);
}
@@ -457,7 +462,7 @@ public class PolicyCatalog {
// only Iceberg tables are supported
var resolvedTableEntity =
resolvedEntityView.getResolvedPath(
- tableIdentifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ICEBERG_TABLE);
+ ResolvedPathKey.ofTableLike(tableIdentifier), PolarisEntitySubType.ICEBERG_TABLE);
if (resolvedTableEntity == null) {
throw notFoundExceptionForTableLikeEntity(
tableIdentifier, PolarisEntitySubType.ICEBERG_TABLE);
@@ -478,7 +483,8 @@ public class PolicyCatalog {
private PolarisResolvedPathWrapper getResolvedPathWrapper(PolicyIdentifier policyIdentifier) {
var resolvedEntities =
resolvedEntityView.getPassthroughResolvedPath(
- policyIdentifier, PolarisEntityType.POLICY, PolarisEntitySubType.NULL_SUBTYPE);
+ ResolvedPathKey.ofPolicy(policyIdentifier.namespace(), policyIdentifier.name()),
+ PolarisEntitySubType.NULL_SUBTYPE);
if (resolvedEntities == null || resolvedEntities.getResolvedLeafEntity() == null) {
throw new NoSuchPolicyException(String.format("Policy does not exist: %s", policyIdentifier));
}
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandler.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandler.java
index 1fe29ae414..a194e8e6c1 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandler.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogHandler.java
@@ -34,6 +34,7 @@ import org.apache.polaris.core.catalog.PolarisCatalogHelpers;
import org.apache.polaris.core.entity.PolarisEntitySubType;
import org.apache.polaris.core.entity.PolarisEntityType;
import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
+import org.apache.polaris.core.persistence.resolver.ResolvedPathKey;
import org.apache.polaris.core.persistence.resolver.ResolverPath;
import org.apache.polaris.core.persistence.resolver.ResolverStatus;
import org.apache.polaris.core.policy.PolicyType;
@@ -142,11 +143,12 @@ public abstract class PolicyCatalogHandler extends CatalogHandler {
new ResolverPath(
PolarisCatalogHelpers.identifierToList(identifier.namespace(), identifier.name()),
PolarisEntityType.POLICY,
- true /* optional */),
- identifier);
+ true /* optional */));
resolutionManifest.resolveAll();
- PolarisResolvedPathWrapper target = resolutionManifest.getResolvedPath(identifier, true);
+ PolarisResolvedPathWrapper target =
+ resolutionManifest.getResolvedPath(
+ ResolvedPathKey.ofPolicy(identifier.namespace(), identifier.name()), true);
if (target == null) {
throw new NoSuchPolicyException(String.format("Policy does not exist: %s", identifier));
}
@@ -212,16 +214,14 @@ public abstract class PolicyCatalogHandler extends CatalogHandler {
new ResolverPath(
PolarisCatalogHelpers.identifierToList(identifier.namespace(), identifier.name()),
PolarisEntityType.POLICY,
- true /* optional */),
- identifier);
+ true /* optional */));
switch (target.getType()) {
case CATALOG -> {}
case NAMESPACE -> {
Namespace targetNamespace = Namespace.of(target.getPath().toArray(new String[0]));
resolutionManifest.addPath(
- new ResolverPath(Arrays.asList(targetNamespace.levels()), PolarisEntityType.NAMESPACE),
- targetNamespace);
+ new ResolverPath(Arrays.asList(targetNamespace.levels()), PolarisEntityType.NAMESPACE));
}
case TABLE_LIKE -> {
TableIdentifier targetIdentifier =
@@ -229,8 +229,7 @@ public abstract class PolicyCatalogHandler extends CatalogHandler {
resolutionManifest.addPath(
new ResolverPath(
PolarisCatalogHelpers.tableIdentifierToList(targetIdentifier),
- PolarisEntityType.TABLE_LIKE),
- targetIdentifier);
+ PolarisEntityType.TABLE_LIKE));
}
default -> throw new IllegalArgumentException("Unsupported target type: " + target.getType());
}
@@ -241,7 +240,8 @@ public abstract class PolicyCatalogHandler extends CatalogHandler {
PolarisResolvedPathWrapper policyWrapper =
resolutionManifest.getPassthroughResolvedPath(
- identifier, PolarisEntityType.POLICY, PolarisEntitySubType.NULL_SUBTYPE);
+ ResolvedPathKey.ofPolicy(identifier.namespace(), identifier.name()),
+ PolarisEntitySubType.NULL_SUBTYPE);
if (policyWrapper == null) {
throw new NoSuchPolicyException(String.format("Policy does not exist: %s", identifier));
}
diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogUtils.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogUtils.java
index ede8f864b0..705f2ead13 100644
--- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogUtils.java
+++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/policy/PolicyCatalogUtils.java
@@ -25,9 +25,9 @@ import jakarta.annotation.Nonnull;
import org.apache.iceberg.catalog.Namespace;
import org.apache.iceberg.catalog.TableIdentifier;
import org.apache.polaris.core.entity.PolarisEntitySubType;
-import org.apache.polaris.core.entity.PolarisEntityType;
import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifestCatalogView;
+import org.apache.polaris.core.persistence.resolver.ResolvedPathKey;
import org.apache.polaris.service.types.PolicyAttachmentTarget;
public class PolicyCatalogUtils {
@@ -40,7 +40,8 @@ public class PolicyCatalogUtils {
case CATALOG -> resolutionManifest.getResolvedReferenceCatalogEntity();
case NAMESPACE -> {
var namespace = Namespace.of(target.getPath().toArray(new String[0]));
- var resolvedTargetEntity = resolutionManifest.getResolvedPath(namespace);
+ var resolvedTargetEntity =
+ resolutionManifest.getResolvedPath(ResolvedPathKey.ofNamespace(namespace));
if (resolvedTargetEntity == null) {
throw noSuchNamespaceException(namespace);
}
@@ -51,7 +52,7 @@ public class PolicyCatalogUtils {
// only Iceberg tables are supported
var resolvedTableEntity =
resolutionManifest.getResolvedPath(
- tableIdentifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ICEBERG_TABLE);
+ ResolvedPathKey.ofTableLike(tableIdentifier), PolarisEntitySubType.ICEBERG_TABLE);
if (resolvedTableEntity == null) {
throw notFoundExceptionForTableLikeEntity(
tableIdentifier, PolarisEntitySubType.ICEBERG_TABLE);
diff --git a/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAdminServiceTest.java b/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAdminServiceTest.java
index 276315fb15..e2b7936de9 100644
--- a/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAdminServiceTest.java
+++ b/runtime/service/src/test/java/org/apache/polaris/service/admin/PolarisAdminServiceTest.java
@@ -34,6 +34,7 @@ import org.apache.iceberg.exceptions.NotFoundException;
import org.apache.polaris.core.PolarisCallContext;
import org.apache.polaris.core.auth.PolarisAuthorizer;
import org.apache.polaris.core.auth.PolarisPrincipal;
+import org.apache.polaris.core.catalog.PolarisCatalogHelpers;
import org.apache.polaris.core.config.FeatureConfiguration;
import org.apache.polaris.core.config.RealmConfig;
import org.apache.polaris.core.context.CallContext;
@@ -53,6 +54,7 @@ import org.apache.polaris.core.persistence.dao.entity.GenerateEntityIdResult;
import org.apache.polaris.core.persistence.dao.entity.PrivilegeResult;
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifest;
import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
+import org.apache.polaris.core.persistence.resolver.ResolvedPathKey;
import org.apache.polaris.core.persistence.resolver.ResolverStatus;
import org.apache.polaris.core.secrets.UserSecretsManager;
import org.apache.polaris.service.config.ReservedProperties;
@@ -153,9 +155,13 @@ public class PolarisAdminServiceTest {
PolarisEntity catalogRoleEntity =
createEntity(catalogRoleName, PolarisEntityType.CATALOG_ROLE, 2L);
when(catalogRoleWrapper.getRawLeafEntity()).thenReturn(catalogRoleEntity);
- when(resolutionManifest.getResolvedPath(eq(catalogRoleName))).thenReturn(catalogRoleWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE))))
+ .thenReturn(catalogRoleWrapper);
- when(resolutionManifest.getResolvedPath(eq(namespace))).thenReturn(null);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(namespace.levels()), PolarisEntityType.NAMESPACE))))
+ .thenReturn(null);
assertThatThrownBy(
() ->
@@ -184,9 +190,13 @@ public class PolarisAdminServiceTest {
PolarisEntity catalogRoleEntity =
createEntity(catalogRoleName, PolarisEntityType.CATALOG_ROLE, 2L);
when(catalogRoleWrapper.getRawLeafEntity()).thenReturn(catalogRoleEntity);
- when(resolutionManifest.getResolvedPath(eq(catalogRoleName))).thenReturn(catalogRoleWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE))))
+ .thenReturn(catalogRoleWrapper);
- when(resolutionManifest.getResolvedPath(eq(namespace))).thenReturn(resolvedPathWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(namespace.levels()), PolarisEntityType.NAMESPACE))))
+ .thenReturn(resolvedPathWrapper);
when(resolvedPathWrapper.getRawFullPath())
.thenReturn(
List.of(
@@ -239,9 +249,13 @@ public class PolarisAdminServiceTest {
PolarisEntity catalogRoleEntity =
createEntity(catalogRoleName, PolarisEntityType.CATALOG_ROLE, 2L);
when(catalogRoleWrapper.getRawLeafEntity()).thenReturn(catalogRoleEntity);
- when(resolutionManifest.getResolvedPath(eq(catalogRoleName))).thenReturn(catalogRoleWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE))))
+ .thenReturn(catalogRoleWrapper);
- when(resolutionManifest.getResolvedPath(eq(namespace))).thenReturn(null);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(namespace.levels()), PolarisEntityType.NAMESPACE))))
+ .thenReturn(null);
assertThatThrownBy(
() ->
@@ -267,9 +281,13 @@ public class PolarisAdminServiceTest {
PolarisEntity catalogRoleEntity =
createEntity(catalogRoleName, PolarisEntityType.CATALOG_ROLE, 2L);
when(catalogRoleWrapper.getRawLeafEntity()).thenReturn(catalogRoleEntity);
- when(resolutionManifest.getResolvedPath(eq(catalogRoleName))).thenReturn(catalogRoleWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE))))
+ .thenReturn(catalogRoleWrapper);
- when(resolutionManifest.getResolvedPath(eq(namespace))).thenReturn(resolvedPathWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(namespace.levels()), PolarisEntityType.NAMESPACE))))
+ .thenReturn(resolvedPathWrapper);
when(resolvedPathWrapper.getRawFullPath())
.thenReturn(List.of(createEntity("wrong-catalog", PolarisEntityType.CATALOG)));
when(resolvedPathWrapper.isFullyResolvedNamespace(eq(catalogName), eq(namespace)))
@@ -297,10 +315,14 @@ public class PolarisAdminServiceTest {
PolarisEntity catalogRoleEntity =
createEntity(catalogRoleName, PolarisEntityType.CATALOG_ROLE, 2L);
when(catalogRoleWrapper.getRawLeafEntity()).thenReturn(catalogRoleEntity);
- when(resolutionManifest.getResolvedPath(eq(catalogRoleName))).thenReturn(catalogRoleWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE))))
+ .thenReturn(catalogRoleWrapper);
PolarisEntity orgNsEntity = createNamespaceEntity(Namespace.of("org-ns"), 3L, 1L);
- when(resolutionManifest.getResolvedPath(eq(namespace))).thenReturn(resolvedPathWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(namespace.levels()), PolarisEntityType.NAMESPACE))))
+ .thenReturn(resolvedPathWrapper);
when(resolvedPathWrapper.getRawFullPath()).thenReturn(List.of(catalogEntity, orgNsEntity));
when(resolvedPathWrapper.getRawLeafEntity()).thenReturn(orgNsEntity);
@@ -328,7 +350,9 @@ public class PolarisAdminServiceTest {
// Mock successful synthetic namespace resolution.
PolarisResolvedPathWrapper syntheticPathWrapper = mock(PolarisResolvedPathWrapper.class);
- when(resolutionManifest.getResolvedPath(eq(namespace))).thenReturn(syntheticPathWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(namespace.levels()), PolarisEntityType.NAMESPACE))))
+ .thenReturn(syntheticPathWrapper);
when(syntheticPathWrapper.isFullyResolvedNamespace(eq(catalogName), eq(namespace)))
.thenReturn(true);
@@ -365,13 +389,17 @@ public class PolarisAdminServiceTest {
PolarisEntity catalogRoleEntity =
createEntity(catalogRoleName, PolarisEntityType.CATALOG_ROLE, 2L);
when(catalogRoleWrapper.getRawLeafEntity()).thenReturn(catalogRoleEntity);
- when(resolutionManifest.getResolvedPath(eq(catalogRoleName))).thenReturn(catalogRoleWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE))))
+ .thenReturn(catalogRoleWrapper);
// Create a mock resolved path that returns null initially and is not fully resolved
PolarisResolvedPathWrapper unresolvedWrapper = mock(PolarisResolvedPathWrapper.class);
when(unresolvedWrapper.isFullyResolvedNamespace(eq(catalogName), eq(namespace)))
.thenReturn(false);
- when(resolutionManifest.getResolvedPath(eq(namespace))).thenReturn(unresolvedWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(namespace.levels()), PolarisEntityType.NAMESPACE))))
+ .thenReturn(unresolvedWrapper);
// Should throw NotFoundException because feature is disabled and it's passthrough facade
assertThatThrownBy(
@@ -400,10 +428,14 @@ public class PolarisAdminServiceTest {
PolarisEntity catalogRoleEntity =
createEntity(catalogRoleName, PolarisEntityType.CATALOG_ROLE, 2L);
when(catalogRoleWrapper.getRawLeafEntity()).thenReturn(catalogRoleEntity);
- when(resolutionManifest.getResolvedPath(eq(catalogRoleName))).thenReturn(catalogRoleWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE))))
+ .thenReturn(catalogRoleWrapper);
PolarisEntity orgNsEntity = createNamespaceEntity(Namespace.of("org-ns"), 3L, 1L);
- when(resolutionManifest.getResolvedPath(eq(namespace))).thenReturn(resolvedPathWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(namespace.levels()), PolarisEntityType.NAMESPACE))))
+ .thenReturn(resolvedPathWrapper);
when(resolvedPathWrapper.getRawFullPath()).thenReturn(List.of(catalogEntity, orgNsEntity));
when(resolvedPathWrapper.getRawLeafEntity()).thenReturn(orgNsEntity);
@@ -420,7 +452,8 @@ public class PolarisAdminServiceTest {
// Mock getResolvedPath to return null for partial namespace
PolarisResolvedPathWrapper partialPathWrapper = mock(PolarisResolvedPathWrapper.class);
when(partialPathWrapper.getRawLeafEntity()).thenReturn(orgNsEntity);
- when(resolutionManifest.getResolvedPath(eq(Namespace.of("org-ns", "team-ns"))))
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of("org-ns", "team-ns"), PolarisEntityType.NAMESPACE))))
.thenReturn(partialPathWrapper);
assertThatThrownBy(
@@ -447,7 +480,9 @@ public class PolarisAdminServiceTest {
PolarisResolvedPathWrapper catalogRoleWrapper = mock(PolarisResolvedPathWrapper.class);
PolarisEntity catalogRoleEntity = createEntity(catalogRoleName, PolarisEntityType.CATALOG_ROLE);
when(catalogRoleWrapper.getRawLeafEntity()).thenReturn(catalogRoleEntity);
- when(resolutionManifest.getResolvedPath(eq(catalogRoleName))).thenReturn(catalogRoleWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE))))
+ .thenReturn(catalogRoleWrapper);
PolarisEntity orgNsEntity = createNamespaceEntity(Namespace.of("org-ns"), 3L, 1L);
PolarisEntity teamNsEntity = createNamespaceEntity(Namespace.of("org-ns", "team-ns"), 4L, 3L);
@@ -457,7 +492,11 @@ public class PolarisAdminServiceTest {
.thenReturn(List.of(catalogEntity, orgNsEntity, teamNsEntity));
when(existingPathWrapper.getRawLeafEntity()).thenReturn(teamNsEntity);
when(resolutionManifest.getResolvedPath(
- identifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ANY_SUBTYPE))
+ eq(
+ ResolvedPathKey.of(
+ PolarisCatalogHelpers.tableIdentifierToList(identifier),
+ PolarisEntityType.TABLE_LIKE)),
+ eq(PolarisEntitySubType.ANY_SUBTYPE)))
.thenReturn(existingPathWrapper);
when(existingPathWrapper.getRawLeafEntity()).thenReturn(teamNsEntity);
@@ -475,7 +514,9 @@ public class PolarisAdminServiceTest {
PolarisResolvedPathWrapper syntheticPathWrapper = mock(PolarisResolvedPathWrapper.class);
when(syntheticPathWrapper.getRawFullPath())
.thenReturn(List.of(catalogEntity, orgNsEntity, teamNsEntity, projectNsEntity));
- when(resolutionManifest.getResolvedPath(eq(namespace))).thenReturn(syntheticPathWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(namespace.levels()), PolarisEntityType.NAMESPACE))))
+ .thenReturn(syntheticPathWrapper);
when(syntheticPathWrapper.isFullyResolvedNamespace(eq(catalogName), eq(namespace)))
.thenReturn(true);
when(syntheticPathWrapper.getRawLeafEntity()).thenReturn(projectNsEntity);
@@ -492,7 +533,11 @@ public class PolarisAdminServiceTest {
PolarisResolvedPathWrapper tablePathWrapper = mock(PolarisResolvedPathWrapper.class);
when(tablePathWrapper.getRawLeafEntity()).thenReturn(tableEntity);
when(resolutionManifest.getResolvedPath(
- identifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ANY_SUBTYPE))
+ eq(
+ ResolvedPathKey.of(
+ PolarisCatalogHelpers.tableIdentifierToList(identifier),
+ PolarisEntityType.TABLE_LIKE)),
+ eq(PolarisEntitySubType.ANY_SUBTYPE)))
.thenReturn(tablePathWrapper);
PrivilegeResult successResult = mock(PrivilegeResult.class);
@@ -530,7 +575,9 @@ public class PolarisAdminServiceTest {
PolarisEntity catalogRoleEntity =
createEntity(catalogRoleName, PolarisEntityType.CATALOG_ROLE, 2L);
when(catalogRoleWrapper.getRawLeafEntity()).thenReturn(catalogRoleEntity);
- when(resolutionManifest.getResolvedPath(eq(catalogRoleName))).thenReturn(catalogRoleWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE))))
+ .thenReturn(catalogRoleWrapper);
// Create a table entity for authorization but later it should not be found
PolarisEntity tableEntity =
@@ -540,15 +587,21 @@ public class PolarisAdminServiceTest {
// Mock authorization path with table
when(resolutionManifest.getResolvedPath(
- eq(identifier),
- eq(PolarisEntityType.TABLE_LIKE),
+ eq(
+ ResolvedPathKey.of(
+ PolarisCatalogHelpers.tableIdentifierToList(identifier),
+ PolarisEntityType.TABLE_LIKE)),
eq(PolarisEntitySubType.ANY_SUBTYPE),
eq(true)))
.thenReturn(tableWrapper);
// Mock the main resolution to return null (table not found in main logic)
when(resolutionManifest.getResolvedPath(
- eq(identifier), eq(PolarisEntityType.TABLE_LIKE), eq(PolarisEntitySubType.ANY_SUBTYPE)))
+ eq(
+ ResolvedPathKey.of(
+ PolarisCatalogHelpers.tableIdentifierToList(identifier),
+ PolarisEntityType.TABLE_LIKE)),
+ eq(PolarisEntitySubType.ANY_SUBTYPE)))
.thenReturn(null);
// Should throw NoSuchTableException because feature is disabled
@@ -574,12 +627,18 @@ public class PolarisAdminServiceTest {
PolarisResolvedPathWrapper catalogRoleWrapper = mock(PolarisResolvedPathWrapper.class);
PolarisEntity catalogRoleEntity = createEntity(catalogRoleName, PolarisEntityType.CATALOG_ROLE);
when(catalogRoleWrapper.getRawLeafEntity()).thenReturn(catalogRoleEntity);
- when(resolutionManifest.getResolvedPath(eq(catalogRoleName))).thenReturn(catalogRoleWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE))))
+ .thenReturn(catalogRoleWrapper);
PolarisResolvedPathWrapper existingPathWrapper = mock(PolarisResolvedPathWrapper.class);
when(existingPathWrapper.getRawFullPath()).thenReturn(List.of(catalogEntity));
when(resolutionManifest.getResolvedPath(
- identifier, PolarisEntityType.TABLE_LIKE, PolarisEntitySubType.ANY_SUBTYPE))
+ eq(
+ ResolvedPathKey.of(
+ PolarisCatalogHelpers.tableIdentifierToList(identifier),
+ PolarisEntityType.TABLE_LIKE)),
+ eq(PolarisEntitySubType.ANY_SUBTYPE)))
.thenReturn(existingPathWrapper);
when(existingPathWrapper.getRawLeafEntity()).thenReturn(catalogEntity);
@@ -591,7 +650,12 @@ public class PolarisAdminServiceTest {
.thenReturn(tableCreateResult);
when(tableCreateResult.isSuccess()).thenReturn(false);
- when(resolutionManifest.getResolvedPath(identifier)).thenReturn(existingPathWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(
+ ResolvedPathKey.of(
+ PolarisCatalogHelpers.tableIdentifierToList(identifier),
+ PolarisEntityType.TABLE_LIKE))))
+ .thenReturn(existingPathWrapper);
when(existingPathWrapper.getRawLeafEntity()).thenReturn(catalogEntity);
assertThatThrownBy(
@@ -677,7 +741,9 @@ public class PolarisAdminServiceTest {
when(resolutionManifestFactory.createResolutionManifest(any(), eq(catalogName)))
.thenReturn(resolutionManifest);
when(resolutionManifest.resolveAll()).thenReturn(createSuccessfulResolverStatus());
- when(resolutionManifest.getResolvedPath(eq(namespace))).thenReturn(resolvedPathWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(namespace.levels()), PolarisEntityType.NAMESPACE))))
+ .thenReturn(resolvedPathWrapper);
PolarisEntity catalogEntity = createEntity(catalogName, PolarisEntityType.CATALOG);
when(resolutionManifest.getResolvedCatalogEntity()).thenReturn(CatalogEntity.of(catalogEntity));
@@ -686,7 +752,9 @@ public class PolarisAdminServiceTest {
PolarisEntity catalogRoleEntity =
createEntity(catalogRoleName, PolarisEntityType.CATALOG_ROLE, 2L);
when(catalogRoleWrapper.getRawLeafEntity()).thenReturn(catalogRoleEntity);
- when(resolutionManifest.getResolvedPath(eq(catalogRoleName))).thenReturn(catalogRoleWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(catalogRoleName), PolarisEntityType.CATALOG_ROLE))))
+ .thenReturn(catalogRoleWrapper);
PolarisEntity namespaceEntity =
createNamespaceEntity(Namespace.of(namespace.levels()[0]), 3L, 1L);
@@ -696,6 +764,8 @@ public class PolarisAdminServiceTest {
when(resolvedPathWrapper.getRawLeafEntity()).thenReturn(namespaceEntity);
when(resolvedPathWrapper.isFullyResolvedNamespace(eq(catalogName), eq(namespace)))
.thenReturn(true);
- when(resolutionManifest.getResolvedPath(eq(namespace))).thenReturn(resolvedPathWrapper);
+ when(resolutionManifest.getResolvedPath(
+ eq(ResolvedPathKey.of(List.of(namespace.levels()), PolarisEntityType.NAMESPACE))))
+ .thenReturn(resolvedPathWrapper);
}
}
diff --git a/runtime/service/src/testFixtures/java/org/apache/polaris/service/catalog/PolarisPassthroughResolutionView.java b/runtime/service/src/testFixtures/java/org/apache/polaris/service/catalog/PolarisPassthroughResolutionView.java
index f25255d703..d71bcfaf7e 100644
--- a/runtime/service/src/testFixtures/java/org/apache/polaris/service/catalog/PolarisPassthroughResolutionView.java
+++ b/runtime/service/src/testFixtures/java/org/apache/polaris/service/catalog/PolarisPassthroughResolutionView.java
@@ -18,19 +18,16 @@
*/
package org.apache.polaris.service.catalog;
-import java.util.Arrays;
-import org.apache.iceberg.catalog.Namespace;
-import org.apache.iceberg.catalog.TableIdentifier;
+import com.google.common.base.Preconditions;
import org.apache.polaris.core.auth.PolarisPrincipal;
-import org.apache.polaris.core.catalog.PolarisCatalogHelpers;
import org.apache.polaris.core.entity.PolarisEntitySubType;
import org.apache.polaris.core.entity.PolarisEntityType;
import org.apache.polaris.core.persistence.PolarisResolvedPathWrapper;
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifest;
import org.apache.polaris.core.persistence.resolver.PolarisResolutionManifestCatalogView;
import org.apache.polaris.core.persistence.resolver.ResolutionManifestFactory;
+import org.apache.polaris.core.persistence.resolver.ResolvedPathKey;
import org.apache.polaris.core.persistence.resolver.ResolverPath;
-import org.apache.polaris.service.types.PolicyIdentifier;
/**
* For test purposes or for elevated-privilege scenarios where entity resolution is allowed to
@@ -65,89 +62,52 @@ public class PolarisPassthroughResolutionView implements PolarisResolutionManife
}
@Override
- public PolarisResolvedPathWrapper getResolvedPath(Object key) {
+ public PolarisResolvedPathWrapper getResolvedPath(ResolvedPathKey key) {
+ Preconditions.checkState(
+ key.entityType() == PolarisEntityType.NAMESPACE,
+ "Trying to getResolvedPath(key) for non-namespace key %s",
+ key);
PolarisResolutionManifest manifest = newResolutionManifest();
-
- if (key instanceof Namespace namespace) {
- manifest.addPath(
- new ResolverPath(Arrays.asList(namespace.levels()), PolarisEntityType.NAMESPACE),
- namespace);
- manifest.resolveAll();
- return manifest.getResolvedPath(namespace);
- } else {
- throw new IllegalStateException(
- String.format(
- "Trying to getResolvedPath(key) for %s with class %s", key, key.getClass()));
- }
+ manifest.addPath(new ResolverPath(key.entityNames(), key.entityType()));
+ manifest.resolveAll();
+ return manifest.getResolvedPath(key);
}
@Override
public PolarisResolvedPathWrapper getResolvedPath(
- Object key, PolarisEntityType entityType, PolarisEntitySubType subType) {
+ ResolvedPathKey key, PolarisEntitySubType subType) {
+ Preconditions.checkState(
+ key.entityType() == PolarisEntityType.TABLE_LIKE
+ || key.entityType() == PolarisEntityType.POLICY,
+ "Trying to getResolvedPath(key, subType) for unsupported key %s",
+ key);
PolarisResolutionManifest manifest = newResolutionManifest();
-
- if (key instanceof TableIdentifier identifier) {
- manifest.addPath(
- new ResolverPath(PolarisCatalogHelpers.tableIdentifierToList(identifier), entityType),
- identifier);
- manifest.resolveAll();
- return manifest.getResolvedPath(identifier, entityType, subType);
- } else if (key instanceof PolicyIdentifier policyIdentifier) {
- manifest.addPath(
- new ResolverPath(
- PolarisCatalogHelpers.identifierToList(
- policyIdentifier.namespace(), policyIdentifier.name()),
- entityType),
- policyIdentifier);
- manifest.resolveAll();
- return manifest.getResolvedPath(policyIdentifier, entityType, subType);
- } else {
- throw new IllegalStateException(
- String.format(
- "Trying to getResolvedPath(key, subType) for %s with class %s and type %s / %s",
- key, key.getClass(), entityType, subType));
- }
+ manifest.addPath(new ResolverPath(key.entityNames(), key.entityType()));
+ manifest.resolveAll();
+ return manifest.getResolvedPath(key, subType);
}
@Override
- public PolarisResolvedPathWrapper getPassthroughResolvedPath(Object key) {
+ public PolarisResolvedPathWrapper getPassthroughResolvedPath(ResolvedPathKey key) {
+ Preconditions.checkState(
+ key.entityType() == PolarisEntityType.NAMESPACE,
+ "Trying to getPassthroughResolvedPath(key) for non-namespace key %s",
+ key);
PolarisResolutionManifest manifest = newResolutionManifest();
-
- if (key instanceof Namespace namespace) {
- manifest.addPassthroughPath(
- new ResolverPath(Arrays.asList(namespace.levels()), PolarisEntityType.NAMESPACE),
- namespace);
- return manifest.getPassthroughResolvedPath(namespace);
- } else {
- throw new IllegalStateException(
- String.format(
- "Trying to getResolvedPath(key) for %s with class %s", key, key.getClass()));
- }
+ manifest.addPassthroughPath(new ResolverPath(key.entityNames(), key.entityType()));
+ return manifest.getPassthroughResolvedPath(key);
}
@Override
public PolarisResolvedPathWrapper getPassthroughResolvedPath(
- Object key, PolarisEntityType entityType, PolarisEntitySubType subType) {
+ ResolvedPathKey key, PolarisEntitySubType subType) {
+ Preconditions.checkState(
+ key.entityType() == PolarisEntityType.TABLE_LIKE
+ || key.entityType() == PolarisEntityType.POLICY,
+ "Trying to getPassthroughResolvedPath(key, subType) for unsupported key %s",
+ key);
PolarisResolutionManifest manifest = newResolutionManifest();
-
- if (key instanceof TableIdentifier identifier) {
- manifest.addPassthroughPath(
- new ResolverPath(PolarisCatalogHelpers.tableIdentifierToList(identifier), entityType),
- identifier);
- return manifest.getPassthroughResolvedPath(identifier, entityType, subType);
- } else if (key instanceof PolicyIdentifier policyIdentifier) {
- manifest.addPassthroughPath(
- new ResolverPath(
- PolarisCatalogHelpers.identifierToList(
- policyIdentifier.namespace(), policyIdentifier.name()),
- entityType),
- policyIdentifier);
- return manifest.getPassthroughResolvedPath(policyIdentifier, entityType, subType);
- } else {
- throw new IllegalStateException(
- String.format(
- "Trying to getResolvedPath(key, subType) for %s with class %s and subType %s",
- key, key.getClass(), subType));
- }
+ manifest.addPassthroughPath(new ResolverPath(key.entityNames(), key.entityType()));
+ return manifest.getPassthroughResolvedPath(key, subType);
}
}