This is an automated email from the ASF dual-hosted git repository.

yashmayya pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 6950c850cd GET /logicalTables API to return database specific tables. 
(#15944)
6950c850cd is described below

commit 6950c850cd7ce14af7cf667da8f09c4824bb96fd
Author: Abhishek Bafna <aba...@startree.ai>
AuthorDate: Fri May 30 20:07:39 2025 +0530

    GET /logicalTables API to return database specific tables. (#15944)
---
 .../api/resources/PinotLogicalTableResource.java   |  3 +-
 .../helix/core/PinotHelixResourceManager.java      | 15 +++++
 .../resources/PinotLogicalTableResourceTest.java   | 66 +++++++++++++++++++---
 3 files changed, 76 insertions(+), 8 deletions(-)

diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResource.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResource.java
index 73265bd832..56a9f02edd 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResource.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResource.java
@@ -93,7 +93,8 @@ public class PinotLogicalTableResource {
   @Authorize(targetType = TargetType.CLUSTER, paramName = "tableName", action 
= Actions.Cluster.GET_TABLE)
   @ApiOperation(value = "List all logical table names", notes = "Lists all 
logical table names")
   public List<String> listLogicalTableNames(@Context HttpHeaders headers) {
-    return _pinotHelixResourceManager.getAllLogicalTableNames();
+    String databaseName = 
DatabaseUtils.extractDatabaseFromHttpHeaders(headers);
+    return _pinotHelixResourceManager.getAllLogicalTableNames(databaseName);
   }
 
   @GET
diff --git 
a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/PinotHelixResourceManager.java
 
b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/PinotHelixResourceManager.java
index ef823d55bf..93ece7c42e 100644
--- 
a/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/PinotHelixResourceManager.java
+++ 
b/pinot-controller/src/main/java/org/apache/pinot/controller/helix/core/PinotHelixResourceManager.java
@@ -2378,6 +2378,10 @@ public class PinotHelixResourceManager {
     return ZKMetadataProvider.getLogicalTableConfig(_propertyStore, tableName);
   }
 
+  /**
+   * Returns all logical table names in the cluster regardless of their 
database name.
+   * @return List of logical table names
+   */
   public List<String> getAllLogicalTableNames() {
     List<String> logicalTableNames = _propertyStore.getChildNames(
         
PinotHelixPropertyStoreZnRecordProvider.forLogicalTable(_propertyStore).getRelativePath(),
@@ -2385,6 +2389,17 @@ public class PinotHelixResourceManager {
     return logicalTableNames != null ? logicalTableNames : 
Collections.emptyList();
   }
 
+  /**
+   * Returns all logical table names in the cluster that belong to the given 
database.
+   * @param databaseName The name of the database
+   * @return List of logical table names that belong to the given database
+   */
+  public List<String> getAllLogicalTableNames(String databaseName) {
+    return getAllLogicalTableNames().stream()
+        .filter(tableName -> DatabaseUtils.isPartOfDatabase(tableName, 
databaseName))
+        .collect(Collectors.toList());
+  }
+
   /**
    * Returns the ZK metdata for the given jobId and jobType
    * @param jobId the id of the job
diff --git 
a/pinot-controller/src/test/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResourceTest.java
 
b/pinot-controller/src/test/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResourceTest.java
index 3458777e8d..50a29e2e55 100644
--- 
a/pinot-controller/src/test/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResourceTest.java
+++ 
b/pinot-controller/src/test/java/org/apache/pinot/controller/api/resources/PinotLogicalTableResourceTest.java
@@ -20,6 +20,7 @@ package org.apache.pinot.controller.api.resources;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -32,6 +33,7 @@ import org.apache.pinot.spi.config.table.TableConfig;
 import org.apache.pinot.spi.config.table.TableType;
 import org.apache.pinot.spi.data.LogicalTableConfig;
 import org.apache.pinot.spi.data.TimeBoundaryConfig;
+import org.apache.pinot.spi.utils.CommonConstants;
 import org.apache.pinot.spi.utils.builder.ControllerRequestURLBuilder;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.AfterMethod;
@@ -334,9 +336,11 @@ public class PinotLogicalTableResourceTest extends 
ControllerTest {
         throwable.getMessage());
   }
 
+  @Test
   public void testLogicalTableTimeBoundaryConfigValidation()
       throws IOException {
     // Test logical table time boundary strategy validation
+    addDummySchema(LOGICAL_TABLE_NAME);
     List<String> physicalTableNamesWithType = 
createHybridTables(List.of("test_table_8"));
     LogicalTableConfig logicalTableConfig =
         getDummyLogicalTableConfig(LOGICAL_TABLE_NAME, 
physicalTableNamesWithType, BROKER_TENANT);
@@ -356,7 +360,7 @@ public class PinotLogicalTableResourceTest extends 
ControllerTest {
       ControllerTest.sendPostRequest(_addLogicalTableUrl, 
logicalTableConfig.toSingleLineJsonString(), getHeaders());
     });
     assertTrue(throwable.getMessage()
-            .contains("Reason: 'timeBoundaryConfig.strategy' should not be 
null or empty for hybrid logical tables"),
+            .contains("Reason: 'timeBoundaryConfig.boundaryStrategy' should 
not be null or empty"),
         throwable.getMessage());
 
     // Test logical table with time boundary config but empty strategy
@@ -365,7 +369,7 @@ public class PinotLogicalTableResourceTest extends 
ControllerTest {
       ControllerTest.sendPostRequest(_addLogicalTableUrl, 
logicalTableConfig.toSingleLineJsonString(), getHeaders());
     });
     assertTrue(throwable.getMessage()
-            .contains("Reason: 'timeBoundaryConfig.strategy' should not be 
null or empty for hybrid logical tables"),
+            .contains("Reason: 'timeBoundaryConfig.boundaryStrategy' should 
not be null or empty"),
         throwable.getMessage());
 
     // Test logical table with time boundary config but null parameters
@@ -374,7 +378,7 @@ public class PinotLogicalTableResourceTest extends 
ControllerTest {
       ControllerTest.sendPostRequest(_addLogicalTableUrl, 
logicalTableConfig.toSingleLineJsonString(), getHeaders());
     });
     assertTrue(throwable.getMessage()
-            .contains("Reason: 'timeBoundaryConfig.parameters' should not be 
null or empty for hybrid logical tables"),
+            .contains("Reason: 'timeBoundaryConfig.parameters' should not be 
null or empty"),
         throwable.getMessage());
 
     // Test logical table with time boundary config but empty parameters
@@ -383,7 +387,7 @@ public class PinotLogicalTableResourceTest extends 
ControllerTest {
       ControllerTest.sendPostRequest(_addLogicalTableUrl, 
logicalTableConfig.toSingleLineJsonString(), getHeaders());
     });
     assertTrue(throwable.getMessage()
-            .contains("Reason: 'timeBoundaryConfig.parameters' should not be 
null or empty for hybrid logical tables"),
+            .contains("Reason: 'timeBoundaryConfig.parameters' should not be 
null or empty"),
         throwable.getMessage());
   }
 
@@ -447,7 +451,8 @@ public class PinotLogicalTableResourceTest extends 
ControllerTest {
     assertEquals(response, objectMapper.writeValueAsString(List.of()));
 
     // setup physical tables and logical tables
-    List<String> logicalTableNames = List.of("db.test_logical_table_1", 
"test_logical_table_2", "test_logical_table_3");
+    List<String> logicalTableNames =
+        List.of("db.test_logical_table_1", "default.test_logical_table_2", 
"test_logical_table_3");
     List<String> physicalTableNames = List.of("test_table_1", "test_table_2", 
"db.test_table_3");
     List<String> physicalTableNamesWithType = 
createHybridTables(physicalTableNames);
 
@@ -459,9 +464,56 @@ public class PinotLogicalTableResourceTest extends 
ControllerTest {
       ControllerTest.sendPostRequest(_addLogicalTableUrl, 
logicalTableConfig.toSingleLineJsonString(), getHeaders());
     }
 
-    // verify logical table names
+    // verify logical table names without headers, should return tables 
without database prefix (or default database)
     String getLogicalTableNamesResponse = 
ControllerTest.sendGetRequest(getLogicalTableNamesUrl, getHeaders());
-    assertEquals(getLogicalTableNamesResponse, 
objectMapper.writeValueAsString(logicalTableNames));
+    assertEquals(getLogicalTableNamesResponse,
+        objectMapper.writeValueAsString(List.of("test_logical_table_2", 
"test_logical_table_3")));
+
+    // verify logical table names with headers, should return tables with 
database prefix
+    Map<String, String> headers = new HashMap<>(getHeaders());
+    headers.put(CommonConstants.DATABASE, "db");
+    getLogicalTableNamesResponse = 
ControllerTest.sendGetRequest(getLogicalTableNamesUrl, headers);
+    assertEquals(getLogicalTableNamesResponse,
+        objectMapper.writeValueAsString(List.of("db.test_logical_table_1")));
+  }
+
+  @Test
+  public void testLogicalTableDatabaseHeaderMismatchValidation()
+      throws IOException {
+    Map<String, String> headers = new HashMap<>(getHeaders());
+    headers.put(CommonConstants.DATABASE, "db1");
+    String logicalTableName = "db2.test_logical_table";
+    LogicalTableConfig logicalTableConfig = 
getDummyLogicalTableConfig(logicalTableName,
+        List.of("test_table_1_OFFLINE", "test_table_2_REALTIME"), 
BROKER_TENANT);
+
+    // Test add logical table with database header mismatch
+    String msg = expectThrows(IOException.class,
+        () -> ControllerTest.sendPostRequest(_addLogicalTableUrl, 
logicalTableConfig.toSingleLineJsonString(),
+            headers)).getMessage();
+    assertTrue(msg.contains("Database name 'db2' from table prefix does not 
match database name 'db1' from header"),
+        msg);
+
+    // Test get logical table with database header mismatch
+    String getLogicalTableUrl = 
_controllerRequestURLBuilder.forLogicalTableGet(logicalTableName);
+    msg = expectThrows(IOException.class,
+        () -> ControllerTest.sendGetRequest(getLogicalTableUrl, 
headers)).getMessage();
+    assertTrue(msg.contains("Database name 'db2' from table prefix does not 
match database name 'db1' from header"),
+        msg);
+
+    // Test update logical table with database header mismatch
+    String updateLogicalTableUrl = 
_controllerRequestURLBuilder.forLogicalTableUpdate(logicalTableName);
+    msg = expectThrows(IOException.class,
+        () -> ControllerTest.sendPutRequest(updateLogicalTableUrl, 
logicalTableConfig.toSingleLineJsonString(),
+            headers)).getMessage();
+    assertTrue(msg.contains("Database name 'db2' from table prefix does not 
match database name 'db1' from header"),
+        msg);
+
+    // Test delete logical table with database header mismatch
+    String deleteLogicalTableUrl = 
_controllerRequestURLBuilder.forLogicalTableDelete(logicalTableName);
+    msg = expectThrows(IOException.class,
+        () -> ControllerTest.sendDeleteRequest(deleteLogicalTableUrl, 
headers)).getMessage();
+    assertTrue(msg.contains("Database name 'db2' from table prefix does not 
match database name 'db1' from header"),
+        msg);
   }
 
   @Test


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org
For additional commands, e-mail: commits-h...@pinot.apache.org

Reply via email to