You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polaris.apache.org by di...@apache.org on 2026/08/06 22:32:33 UTC
(polaris) branch main updated: NoSQL: Fix NPE when an entity that is not catalog content carries a location property (#5241)
This is an automated email from the ASF dual-hosted git repository.
dimas-b 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 ec65ed7258 NoSQL: Fix NPE when an entity that is not catalog content carries a location property (#5241)
ec65ed7258 is described below
commit ec65ed725870564d3e460e58a942ca1fc8beccb2
Author: Ayush Saxena <ay...@apache.org>
AuthorDate: Fri Aug 7 04:02:27 2026 +0530
NoSQL: Fix NPE when an entity that is not catalog content carries a location property (#5241)
---
.../nosql/metastore/mutation/MutationAttempt.java | 4 ++
.../BasePolarisMetaStoreManagerTest.java | 62 ++++++++++++++++++++++
2 files changed, 66 insertions(+)
diff --git a/persistence/nosql/persistence/metastore/src/main/java/org/apache/polaris/persistence/nosql/metastore/mutation/MutationAttempt.java b/persistence/nosql/persistence/metastore/src/main/java/org/apache/polaris/persistence/nosql/metastore/mutation/MutationAttempt.java
index 277db53a62..42d2fb5c5e 100644
--- a/persistence/nosql/persistence/metastore/src/main/java/org/apache/polaris/persistence/nosql/metastore/mutation/MutationAttempt.java
+++ b/persistence/nosql/persistence/metastore/src/main/java/org/apache/polaris/persistence/nosql/metastore/mutation/MutationAttempt.java
@@ -535,6 +535,10 @@ public record MutationAttempt(
public static void updateLocationsIndex(
UpdatableIndex<EntityIdSet> locations, ObjBase originalObj, ObjBase entityObj) {
+ if (locations == null) {
+ return;
+ }
+
var previousBaseLocation =
originalObj != null ? originalObj.properties().get(ENTITY_BASE_LOCATION) : null;
var entityBaseLocation =
diff --git a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BasePolarisMetaStoreManagerTest.java b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BasePolarisMetaStoreManagerTest.java
index d497714ba7..d18d7c45cd 100644
--- a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BasePolarisMetaStoreManagerTest.java
+++ b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BasePolarisMetaStoreManagerTest.java
@@ -38,6 +38,7 @@ import org.apache.polaris.core.PolarisCallContext;
import org.apache.polaris.core.entity.AsyncTaskType;
import org.apache.polaris.core.entity.PolarisBaseEntity;
import org.apache.polaris.core.entity.PolarisEntity;
+import org.apache.polaris.core.entity.PolarisEntityConstants;
import org.apache.polaris.core.entity.PolarisEntitySubType;
import org.apache.polaris.core.entity.PolarisEntityType;
import org.apache.polaris.core.entity.PolarisTaskConstants;
@@ -45,6 +46,8 @@ import org.apache.polaris.core.entity.PrincipalEntity;
import org.apache.polaris.core.entity.TaskEntity;
import org.apache.polaris.core.exceptions.AlreadyExistsException;
import org.apache.polaris.core.persistence.dao.entity.BaseResult;
+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.assertj.core.api.Assertions;
import org.assertj.core.api.InstanceOfAssertFactories;
@@ -559,4 +562,63 @@ public abstract class BasePolarisMetaStoreManagerTest {
callCtx, principalB.getId(), principalAClientId, null))
.isInstanceOf(AlreadyExistsException.class);
}
+
+ /**
+ * {@link PolarisEntityConstants#ENTITY_BASE_LOCATION} is an ordinary user-settable property, so
+ * entities that are not catalog content may carry it. Those entities are not location-tracked, so
+ * creating, updating and dropping them must all succeed regardless.
+ */
+ @Test
+ protected void testBaseLocationPropertyOnEntityThatIsNotCatalogContent() {
+ PolarisMetaStoreManager metaStoreManager = polarisTestMetaStoreManager.polarisMetaStoreManager;
+ PolarisCallContext callCtx = polarisTestMetaStoreManager.polarisCallContext;
+ Map<String, String> properties =
+ Map.of(PolarisEntityConstants.ENTITY_BASE_LOCATION, "s3://bucket/path/");
+
+ // creating a principal role that carries a base location must succeed
+ PolarisBaseEntity principalRole =
+ polarisTestMetaStoreManager.createEntity(
+ null,
+ PolarisEntityType.PRINCIPAL_ROLE,
+ PolarisEntitySubType.NULL_SUBTYPE,
+ "principalRoleWithLocation",
+ properties);
+ Assertions.assertThat(principalRole.getPropertiesAsMap())
+ .containsEntry(PolarisEntityConstants.ENTITY_BASE_LOCATION, "s3://bucket/path/");
+
+ // a catalog that carries one must remain updatable afterwards
+ PolarisBaseEntity catalog =
+ new PolarisBaseEntity.Builder()
+ .catalogId(PolarisEntityConstants.getNullId())
+ .id(metaStoreManager.generateNewEntityId(callCtx).getId())
+ .typeCode(PolarisEntityType.CATALOG.getCode())
+ .subTypeCode(PolarisEntitySubType.NULL_SUBTYPE.getCode())
+ .parentId(PolarisEntityConstants.getRootEntityId())
+ .name("catalogWithLocation")
+ .propertiesAsMap(properties)
+ .internalPropertiesAsMap(Map.of())
+ .build();
+ catalog = metaStoreManager.createCatalog(callCtx, catalog, List.of()).getCatalog();
+ Assertions.assertThat(catalog).isNotNull();
+ catalog =
+ metaStoreManager
+ .loadEntity(callCtx, catalog.getCatalogId(), catalog.getId(), catalog.getType())
+ .getEntity();
+
+ PolarisBaseEntity relocatedCatalog =
+ new PolarisBaseEntity.Builder(catalog)
+ .propertiesAsMap(
+ Map.of(PolarisEntityConstants.ENTITY_BASE_LOCATION, "s3://bucket/other/"))
+ .build();
+ EntityResult updated =
+ metaStoreManager.updateEntityPropertiesIfNotChanged(callCtx, null, relocatedCatalog);
+ Assertions.assertThat(updated.isSuccess()).isTrue();
+ Assertions.assertThat(updated.getEntity().getPropertiesAsMap())
+ .containsEntry(PolarisEntityConstants.ENTITY_BASE_LOCATION, "s3://bucket/other/");
+
+ // and dropping a location-carrying entity must succeed too
+ DropEntityResult dropped =
+ metaStoreManager.dropEntityIfExists(callCtx, null, principalRole, null, false);
+ Assertions.assertThat(dropped.isSuccess()).isTrue();
+ }
}