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();
+  }
 }