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

pfzhan pushed a commit to branch kylin5
in repository https://gitbox.apache.org/repos/asf/kylin.git


The following commit(s) were added to refs/heads/kylin5 by this push:
     new 9db7d8de0a KYLIN-6031 Add OpenAPI to show internalTable info (#2280)
9db7d8de0a is described below

commit 9db7d8de0a6743077fcb1bb11d75e081b89e8c34
Author: Guoliang Sun <guoliang....@kyligence.io>
AuthorDate: Tue Feb 25 14:36:38 2025 +0800

    KYLIN-6031 Add OpenAPI to show internalTable info (#2280)
    
    Co-authored-by: Yan Xin <206577...@qq.com>
---
 .../org/apache/kylin/common/msg/CnMessage.java     |  30 ++++
 .../java/org/apache/kylin/common/msg/Message.java  |  24 +++
 .../rest/service/InternalTableServiceTest.java     | 162 ++++++++++++++++++---
 .../job/service/InternalTableLoadingService.java   |   4 +-
 .../rest/response/InternalTableDescResponse.java   |  32 ++++
 .../kylin/rest/service/InternalTableService.java   |  55 +++----
 .../apache/kylin/query/QueryGroupingSetsTest.java  |   3 +
 .../rest/controller/InternalTableController.java   |  43 ++++--
 .../open/OpenInternalTableController.java          |  26 ++--
 9 files changed, 303 insertions(+), 76 deletions(-)

diff --git 
a/src/core-common/src/main/java/org/apache/kylin/common/msg/CnMessage.java 
b/src/core-common/src/main/java/org/apache/kylin/common/msg/CnMessage.java
index 0da315c13d..4616c3e352 100644
--- a/src/core-common/src/main/java/org/apache/kylin/common/msg/CnMessage.java
+++ b/src/core-common/src/main/java/org/apache/kylin/common/msg/CnMessage.java
@@ -940,6 +940,36 @@ public class CnMessage extends Message {
         return "无法找到内表 \"%s\"。 请检查后重试。";
     }
 
+    @Override
+    public String getInternalTableEmpty() {
+        return "无法更新非空内表 \"%s\"。 请检查后重试。";
+    }
+
+    @Override
+    public String getSameInternalTableNameExist() {
+        return "表:\"%s\" 已经存在,请检查后重试。";
+    }
+
+    @Override
+    public String getInternalTablePath() {
+        return "创建内表路径失败,请检查后重试。";
+    }
+
+    @Override
+    public String getInternalTableUnpartitioned() {
+        return "不支持增量构建为分区内表,请检查后重试。";
+    }
+
+    @Override
+    public String getInternalTableNullPartitionFormat() {
+        return "日期分区格式不能为空, 请检查后重试。";
+    }
+
+    @Override
+    public String getInternalTableNoDataCol() {
+        return "在分区列中无法找到日期列,请检查后重试。";
+    }
+
     @Override
     public String getTimeExceedPartitionRange() {
         return "刷新时间超出已加载范围 :\"%s\" ~ \"%s\",请检查后重试。 ";
diff --git 
a/src/core-common/src/main/java/org/apache/kylin/common/msg/Message.java 
b/src/core-common/src/main/java/org/apache/kylin/common/msg/Message.java
index 230cffe1d3..7091589691 100644
--- a/src/core-common/src/main/java/org/apache/kylin/common/msg/Message.java
+++ b/src/core-common/src/main/java/org/apache/kylin/common/msg/Message.java
@@ -446,6 +446,30 @@ public class Message {
         return "Can’t find internal table \"%s\". Please check and try again.";
     }
 
+    public String getInternalTableEmpty() {
+        return "Can't update non empty internal table \"%s\", Please check and 
try again.";
+    }
+
+    public String getSameInternalTableNameExist() {
+        return "Internal table %s already exists, please choose a different 
name.";
+    }
+
+    public String getInternalTablePath() {
+        return "Failed to create internal table location.";
+    }
+
+    public String getInternalTableUnpartitioned() {
+        return "Incremental build is not supported for unPartitioned table.";
+    }
+
+    public String getInternalTableNullPartitionFormat() {
+        return "date_partition_format can not be null, please check again.";
+    }
+
+    public String getInternalTableNoDataCol() {
+        return "couldn't find date_col present in partition_cols, please check 
again. ";
+    }
+
     public String getTimeExceedPartitionRange() {
         return "Refresh time exceed loaded range :\"%s\" ~ \"%s\", Please 
check and try again. ";
     }
diff --git 
a/src/data-loading-service/src/test/java/org/apache/kylin/rest/service/InternalTableServiceTest.java
 
b/src/data-loading-service/src/test/java/org/apache/kylin/rest/service/InternalTableServiceTest.java
index 4d3f5db4da..c81b251c93 100644
--- 
a/src/data-loading-service/src/test/java/org/apache/kylin/rest/service/InternalTableServiceTest.java
+++ 
b/src/data-loading-service/src/test/java/org/apache/kylin/rest/service/InternalTableServiceTest.java
@@ -51,7 +51,9 @@ import 
org.apache.kylin.engine.spark.utils.SparkJobFactoryUtils;
 import org.apache.kylin.job.execution.ExecutableManager;
 import org.apache.kylin.job.execution.ExecutableState;
 import org.apache.kylin.job.service.InternalTableLoadingService;
+import org.apache.kylin.job.util.JobContextUtil;
 import org.apache.kylin.junit.annotation.MetadataInfo;
+import org.apache.kylin.metadata.model.ColumnDesc;
 import org.apache.kylin.metadata.model.NTableMetadataManager;
 import org.apache.kylin.metadata.model.TableDesc;
 import org.apache.kylin.metadata.table.InternalTableDesc;
@@ -111,6 +113,7 @@ public class InternalTableServiceTest extends 
AbstractTestCase {
 
     @BeforeEach
     void setUp() throws Exception {
+        JobContextUtil.cleanUp();
         MockitoAnnotations.openMocks(this);
         SecurityContextHolder.getContext()
                 .setAuthentication(new TestingAuthenticationToken("ADMIN", 
"ADMIN", Constant.ROLE_ADMIN));
@@ -279,7 +282,7 @@ public class InternalTableServiceTest extends 
AbstractTestCase {
                 partitionCols, dateFormat, tblProperties, 
InternalTableDesc.StorageType.PARQUET.name());
 
         // check internal table metadata
-        List<InternalTableDescResponse> internalTables = 
internalTableService.getTableList(PROJECT);
+        List<InternalTableDescResponse> internalTables = 
internalTableService.getTableList(PROJECT, false, false, "");
         Assertions.assertEquals(1, internalTables.size());
         InternalTableDescResponse response = internalTables.get(0);
         Assertions.assertEquals(DATE_COL, response.getTimePartitionCol());
@@ -577,7 +580,7 @@ public class InternalTableServiceTest extends 
AbstractTestCase {
         internalTableService.createInternalTable(PROJECT, table.getName(), 
table.getDatabase(), null, null,
                 new HashMap<>(), InternalTableDesc.StorageType.PARQUET.name());
 
-        List<InternalTableDescResponse> tables = 
internalTableService.getTableList(PROJECT);
+        List<InternalTableDescResponse> tables = 
internalTableService.getTableList(PROJECT, false, false, "");
         Assertions.assertEquals(1, tables.size());
         Assertions.assertNull(tables.get(0).getTimePartitionCol());
 
@@ -587,7 +590,7 @@ public class InternalTableServiceTest extends 
AbstractTestCase {
         internalTableService.updateInternalTable(PROJECT, 
tables.get(0).getTableName(), tables.get(0).getDatabaseName(),
                 new String[] { DATE_COL }, "yyyy-MM-dd", new HashMap<>(), 
InternalTableDesc.StorageType.PARQUET.name());
 
-        tables = internalTableService.getTableList(PROJECT);
+        tables = internalTableService.getTableList(PROJECT, false, false, "");
         Assertions.assertEquals(1, tables.size());
         Assertions.assertEquals(DATE_COL, tables.get(0).getTimePartitionCol());
 
@@ -669,10 +672,9 @@ public class InternalTableServiceTest extends 
AbstractTestCase {
         TransactionException exception = 
Assertions.assertThrows(TransactionException.class,
                 () -> internalTableService.createInternalTable(PROJECT, 
table.getName(), table.getDatabase(),
                         partitionCols, "yyyy-MM-dd", tblProperties, 
InternalTableDesc.StorageType.PARQUET.name()));
-
-        Assertions.assertEquals("KE-010007011(Internal Table Operation Failed) 
\n"
-                + "org.apache.kylin.common.exception.KylinException: 
KE-010007011(Internal Table Operation Failed):Table is already an internal 
table",
-                exception.getCause().toString());
+        Assertions.assertEquals(String.format(Locale.ROOT, 
MsgPicker.getMsg().getSameInternalTableNameExist(),
+                        table.getName()),
+                exception.getCause().getMessage());
         if (!internalTableFolder.delete()) {
             Assertions.fail();
         }
@@ -712,25 +714,23 @@ public class InternalTableServiceTest extends 
AbstractTestCase {
                 () -> internalTableService.updateInternalTable(PROJECT, 
tableName, db, partitionCols, dateFormat,
                         tblProperties, 
InternalTableDesc.StorageType.PARQUET.name()));
 
-        Assertions.assertEquals("KE-010007011(Internal Table Operation Failed) 
\n"
-                + "org.apache.kylin.common.exception.KylinException: 
KE-010007011(Internal Table Operation Failed):Non-empty internal table can not 
be updated",
-                exception.getCause().toString());
+        Assertions.assertEquals(String.format(Locale.ROOT, 
MsgPicker.getMsg().getInternalTableEmpty(),
+                table.getDatabase() + "." + table.getName()), 
exception.getCause().getMessage());
     }
 
     @Test
     void testCreateInternalPathFailedErrorCode() throws Exception {
         when(tableService.getPartitionColumnFormat(any(), any(), any(), 
any())).thenReturn("yyyy-MM-dd");
-        FileSystem mockFileSystem = Mockito.mock(FileSystem.class);
+        FileSystem mockFileSystem = mock(FileSystem.class);
         try (MockedStatic<HadoopUtil> mockedHadoopUtil = 
Mockito.mockStatic(HadoopUtil.class)) {
             
mockedHadoopUtil.when(HadoopUtil::getWorkingFileSystem).thenReturn(mockFileSystem);
-            Mockito.doThrow(new IOException("Simulated IO 
error")).when(mockFileSystem).mkdirs(Mockito.any(Path.class));
+            doThrow(new IOException("Simulated IO 
error")).when(mockFileSystem).mkdirs(any(Path.class));
             KylinException exception = 
Assertions.assertThrows(KylinException.class, () -> {
                 String path = "mocked/path/to/internal_table";
                 internalTableService.createInternalTablePath(path);
             });
-            Assertions.assertEquals("KE-010007011(Internal Table Operation 
Failed) \n"
-                    + "org.apache.kylin.common.exception.KylinException: 
KE-010007011(Internal Table Operation Failed):Failed to create internal table 
location",
-                    exception.toString());
+            Assertions.assertEquals(String.format(Locale.ROOT, 
MsgPicker.getMsg().getInternalTablePath()),
+                    exception.getMessage());
         }
     }
 
@@ -745,9 +745,8 @@ public class InternalTableServiceTest extends 
AbstractTestCase {
         TransactionException exception = 
Assertions.assertThrows(TransactionException.class,
                 () -> internalTableService.loadIntoInternalTable(PROJECT, 
table.getName(), table.getDatabase(), true,
                         false, startDate, endDate, null));
-        Assertions.assertEquals("KE-010007011(Internal Table Operation Failed) 
\n"
-                + "org.apache.kylin.common.exception.KylinException: 
KE-010007011(Internal Table Operation Failed):Incremental build is not 
supported for unPartitioned table",
-                exception.getCause().toString());
+        Assertions.assertEquals(String.format(Locale.ROOT, 
MsgPicker.getMsg().getInternalTableUnpartitioned()),
+                exception.getCause().getMessage());
     }
 
     @Test
@@ -758,9 +757,9 @@ public class InternalTableServiceTest extends 
AbstractTestCase {
         when(tableService.getPartitionColumnFormat(any(), any(), any(), 
any())).thenReturn("yyyy-MM-dd");
         KylinException exception = 
Assertions.assertThrows(KylinException.class,
                 () -> internalTableService.checkParameters(null, table, 
"yyyy-MM-dd"));
-        Assertions.assertEquals("KE-010007013(Internal Table Parameter 
Invalid) \n"
-                + "org.apache.kylin.common.exception.KylinException: 
KE-010007013(Internal Table Parameter Invalid):Can’t find the partition column. 
Please check and try again.",
-                exception.toString());
+        Assertions.assertEquals(
+                String.format(Locale.ROOT, 
MsgPicker.getMsg().getPartitionColumnNotExist(), table.getIdentity()),
+                exception.getMessage());
     }
 
     @Test
@@ -771,8 +770,123 @@ public class InternalTableServiceTest extends 
AbstractTestCase {
         when(tableService.getPartitionColumnFormat(any(), any(), any(), 
any())).thenReturn("yyyy-MM-dd");
         KylinException exception = 
Assertions.assertThrows(KylinException.class,
                 () -> internalTableService.checkParameters(new String[] { 
"TRANS_ID", "CAL_DT" }, table, "yyyy-MM"));
-        Assertions.assertEquals("KE-010007013(Internal Table Parameter 
Invalid) \n"
-                + "org.apache.kylin.common.exception.KylinException: 
KE-010007013(Internal Table Parameter Invalid):Date partition format 
\"yyyy-MM\" is not correct.",
-                exception.toString());
+        Assertions.assertEquals(String.format(Locale.ROOT, 
MsgPicker.getMsg().getIncorrectDateformat(), "yyyy-MM"),
+                exception.getMessage());
+    }
+
+    @Test
+    void testInternalTableShowDetailsFuzzy() throws Exception {
+        KylinConfig config = KylinConfig.getInstanceFromEnv();
+        NTableMetadataManager tManager = 
NTableMetadataManager.getInstance(config, PROJECT);
+        InternalTableManager internalTableManager = 
InternalTableManager.getInstance(config, PROJECT);
+        TableDesc table = tManager.getTableDesc(TABLE_INDENTITY);
+        String[] partitionCols = new String[] { DATE_COL };
+        Map<String, String> tblProperties = new HashMap<>();
+        String tableIdentity = table.getDatabase() + "." + table.getName();
+        boolean isFuzzy = true;
+        boolean needDetails = true;
+        when(tableService.getPartitionColumnFormat(any(), any(), any(), 
any())).thenReturn("yyyy-MM-dd");
+
+        internalTableService.createInternalTable(PROJECT, table.getName(), 
table.getDatabase(), partitionCols,
+                "yyyy-MM-dd", tblProperties, 
InternalTableDesc.StorageType.PARQUET.name());
+        InternalTableDesc internalTable = 
internalTableManager.getInternalTableDesc(TABLE_INDENTITY);
+        Assertions.assertNotNull(internalTable);
+        String workingDir = 
config.getHdfsWorkingDirectory().replace("file://", "");
+        File internalTableFolder = new File(workingDir, INTERNAL_DIR);
+        Assertions.assertTrue(internalTableFolder.exists() && 
internalTableFolder.isDirectory());
+
+        List<InternalTableDescResponse> tables = 
internalTableService.getTableList(PROJECT, isFuzzy, needDetails,
+                tableIdentity);
+        Assertions.assertEquals(tables.get(0).getTableName(), table.getName());
+        Assertions.assertEquals(DATE_COL, tables.get(0).getTimePartitionCol());
+        List<ColumnDesc> tableColumn = tables.get(0).getColumns();
+        ColumnDesc[] columns = internalTable.getColumns();
+        Assertions.assertEquals(tableColumn.size(), columns.length);
+        for (int i = 0; i < columns.length; i++) {
+            ColumnDesc columninfo = tableColumn.get(i);
+            Assertions.assertEquals(columns[i].getName(), 
columninfo.getName());
+            Assertions.assertEquals(columns[i].getId(), columninfo.getId());
+            Assertions.assertEquals(columns[i].getDatatype(), 
columninfo.getDatatype());
+        }
+
+        tableIdentity = "E.S";
+        tables.clear();
+        tables = internalTableService.getTableList(PROJECT, isFuzzy, 
needDetails, tableIdentity);
+        Assertions.assertEquals(tables.get(0).getTableName(), table.getName());
+        Assertions.assertEquals(DATE_COL, tables.get(0).getTimePartitionCol());
+        tableColumn = tables.get(0).getColumns();
+        Assertions.assertEquals(tableColumn.size(), columns.length);
+
+        tableIdentity = "DEFAULT2.DUMMY";
+        KylinException notExistException = null;
+        tables.clear();
+        try {
+            tables = internalTableService.getTableList(PROJECT, isFuzzy, 
needDetails, tableIdentity);
+        } catch (KylinException e) {
+            notExistException = e;
+        }
+        Assertions.assertTrue(tables.isEmpty());
+        Assertions.assertTrue(
+                null != notExistException && 
notExistException.getErrorCode().getCodeString().equals("KE-010007014"));
+
+        //Illegal string
+        tableIdentity = "DEFAULT.1";
+        notExistException = null;
+        try {
+            tables = internalTableService.getTableList(PROJECT, isFuzzy, 
needDetails, tableIdentity);
+        } catch (KylinException e) {
+            notExistException = e;
+        }
+        Assertions.assertTrue(tables.isEmpty());
+        Assertions.assertTrue(
+                null != notExistException && 
notExistException.getErrorCode().getCodeString().equals("KE-010007014"));
+    }
+
+    @Test
+    void testInternalTableShowDetails() throws Exception {
+        KylinConfig config = KylinConfig.getInstanceFromEnv();
+        NTableMetadataManager tManager = 
NTableMetadataManager.getInstance(config, PROJECT);
+        InternalTableManager internalTableManager = 
InternalTableManager.getInstance(config, PROJECT);
+        TableDesc table = tManager.getTableDesc(TABLE_INDENTITY);
+        String[] partitionCols = new String[] { DATE_COL };
+        Map<String, String> tblProperties = new HashMap<>();
+        String tableIdentity = table.getDatabase() + "." + table.getName();
+        boolean isFuzzy = false;
+        boolean needDetails = true;
+        when(tableService.getPartitionColumnFormat(any(), any(), any(), 
any())).thenReturn("yyyy-MM-dd");
+
+        internalTableService.createInternalTable(PROJECT, table.getName(), 
table.getDatabase(), partitionCols,
+                "yyyy-MM-dd", tblProperties, 
InternalTableDesc.StorageType.PARQUET.name());
+        InternalTableDesc internalTable = 
internalTableManager.getInternalTableDesc(TABLE_INDENTITY);
+        Assertions.assertNotNull(internalTable);
+        String workingDir = 
config.getHdfsWorkingDirectory().replace("file://", "");
+        File internalTableFolder = new File(workingDir, INTERNAL_DIR);
+        Assertions.assertTrue(internalTableFolder.exists() && 
internalTableFolder.isDirectory());
+
+        List<InternalTableDescResponse> tables = 
internalTableService.getTableList(PROJECT, isFuzzy, needDetails,
+                tableIdentity);
+        Assertions.assertEquals(tables.get(0).getTableName(), table.getName());
+        Assertions.assertEquals(DATE_COL, tables.get(0).getTimePartitionCol());
+        List<ColumnDesc> tableColumn = tables.get(0).getColumns();
+        ColumnDesc[] columns = internalTable.getColumns();
+        Assertions.assertEquals(tableColumn.size(), columns.length);
+        for (int i = 0; i < columns.length; i++) {
+            ColumnDesc columninfo = tableColumn.get(i);
+            Assertions.assertEquals(columns[i].getName(), 
columninfo.getName());
+            Assertions.assertEquals(columns[i].getId(), columninfo.getId());
+            Assertions.assertEquals(columns[i].getDatatype(), 
columninfo.getDatatype());
+        }
+
+        tableIdentity = "DEFAULT.T";
+        KylinException notExistException = null;
+        tables.clear();
+        try {
+            tables = internalTableService.getTableList(PROJECT, isFuzzy, 
needDetails, tableIdentity);
+        } catch (KylinException e) {
+            notExistException = e;
+        }
+        Assertions.assertTrue(tables.isEmpty());
+        Assertions.assertTrue(
+                null != notExistException && 
notExistException.getErrorCode().getCodeString().equals("KE-010007014"));
     }
 }
diff --git 
a/src/datasource-service/src/main/java/org/apache/kylin/job/service/InternalTableLoadingService.java
 
b/src/datasource-service/src/main/java/org/apache/kylin/job/service/InternalTableLoadingService.java
index 354d186fdd..8d10c4b3a6 100644
--- 
a/src/datasource-service/src/main/java/org/apache/kylin/job/service/InternalTableLoadingService.java
+++ 
b/src/datasource-service/src/main/java/org/apache/kylin/job/service/InternalTableLoadingService.java
@@ -77,8 +77,8 @@ public class InternalTableLoadingService extends BasicService 
{
             if (isIncremental && 
(Objects.isNull(internalTable.getTablePartition())
                     || 
Objects.isNull(internalTable.getTablePartition().getPartitionColumns())
                     || 
internalTable.getTablePartition().getPartitionColumns().length == 0)) {
-                throw new KylinException(INTERNAL_TABLE_ERROR,
-                        "Incremental build is not supported for unPartitioned 
table");
+                String errorMsg = String.format(Locale.ROOT, 
MsgPicker.getMsg().getInternalTableUnpartitioned());
+                throw new KylinException(INTERNAL_TABLE_ERROR, errorMsg);
             }
             // check refresh time exceed loaded range
             InternalTablePartition tablePartition = 
internalTable.getTablePartition();
diff --git 
a/src/datasource-service/src/main/java/org/apache/kylin/rest/response/InternalTableDescResponse.java
 
b/src/datasource-service/src/main/java/org/apache/kylin/rest/response/InternalTableDescResponse.java
index b4e9c4fe8b..e26bcab665 100644
--- 
a/src/datasource-service/src/main/java/org/apache/kylin/rest/response/InternalTableDescResponse.java
+++ 
b/src/datasource-service/src/main/java/org/apache/kylin/rest/response/InternalTableDescResponse.java
@@ -18,8 +18,14 @@
 
 package org.apache.kylin.rest.response;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.kylin.metadata.model.ColumnDesc;
+import org.apache.kylin.metadata.table.InternalTableDesc;
+
 import com.fasterxml.jackson.annotation.JsonProperty;
 
 import lombok.Data;
@@ -57,4 +63,30 @@ public class InternalTableDescResponse {
     @JsonProperty("tbl_properties")
     private Map<String, String> tblProperties;
 
+    @JsonProperty("columns_info")
+    private List<ColumnDesc> columns;
+
+    public static InternalTableDescResponse 
convertToResponse(InternalTableDesc internalTableDesc,
+            boolean needDetails) {
+        InternalTableDescResponse response = new InternalTableDescResponse();
+        response.setTableName(internalTableDesc.getName());
+        response.setUuid(internalTableDesc.getUuid());
+        response.setDatabaseName(internalTableDesc.getDatabase());
+        response.setRowCount(internalTableDesc.getRowCount());
+        response.setStorageSize(internalTableDesc.getStorageSize());
+        response.setHitCount(internalTableDesc.getHitCount());
+
+        String[] partitionColumns = internalTableDesc.getPartitionColumns();
+        String partitionColumn = ArrayUtils.isNotEmpty(partitionColumns) ? 
partitionColumns[0] : null;
+        response.setTimePartitionCol(partitionColumn);
+
+        response.setUpdateTime(internalTableDesc.getLastModified());
+        
response.setDatePartitionFormat(internalTableDesc.getDatePartitionFormat());
+        response.setTblProperties(internalTableDesc.getTblProperties());
+
+        if (needDetails) {
+            response.setColumns(Arrays.asList(internalTableDesc.getColumns()));
+        }
+        return response;
+    }
 }
diff --git 
a/src/datasource-service/src/main/java/org/apache/kylin/rest/service/InternalTableService.java
 
b/src/datasource-service/src/main/java/org/apache/kylin/rest/service/InternalTableService.java
index ea81cc175d..cc6913b8c3 100644
--- 
a/src/datasource-service/src/main/java/org/apache/kylin/rest/service/InternalTableService.java
+++ 
b/src/datasource-service/src/main/java/org/apache/kylin/rest/service/InternalTableService.java
@@ -116,7 +116,9 @@ public class InternalTableService extends BasicService {
                 throw new KylinException(TABLE_NOT_EXIST, errorMsg);
             }
             if (originTable.isHasInternal()) {
-                throw new KylinException(INTERNAL_TABLE_ERROR, "Table is 
already an internal table");
+                String errorMsg = String.format(Locale.ROOT, 
MsgPicker.getMsg().getSameInternalTableNameExist(),
+                        originTable.getName());
+                throw new KylinException(INTERNAL_TABLE_ERROR, errorMsg);
             }
             checkParameters(partitionCols, originTable, datePartitionFormat);
             InternalTableDesc internalTable = new 
InternalTableDesc(originTable);
@@ -155,11 +157,11 @@ public class InternalTableService extends BasicService {
             Optional<ColumnDesc> dateCol = 
partitionColList.stream().filter(col -> col.getTypeName().equals("date"))
                     .findFirst();
             if (StringUtils.isEmpty(datePartitionFormat) && 
dateCol.isPresent()) {
-                throw new KylinException(EMPTY_PARAMETER, 
"date_partition_format can not be null, please check again");
+                throw new KylinException(EMPTY_PARAMETER,
+                        String.format(Locale.ROOT, 
MsgPicker.getMsg().getInternalTableNullPartitionFormat()));
             }
             if (!StringUtils.isEmpty(datePartitionFormat) && 
!dateCol.isPresent()) {
-                throw new KylinException(EMPTY_PARAMETER,
-                        "couldn't find date_col present in partition_cols, 
please check again");
+                throw new KylinException(EMPTY_PARAMETER, 
MsgPicker.getMsg().getInternalTableNoDataCol());
             }
             checkIfFormatMatchCol(dateCol, originTable, datePartitionFormat);
         }
@@ -229,7 +231,8 @@ public class InternalTableService extends BasicService {
                 throw new KylinException(INTERNAL_TABLE_NOT_EXIST, errorMsg);
             }
             if (internalTable.getRowCount() > 0L) {
-                throw new KylinException(INTERNAL_TABLE_ERROR, "Non-empty 
internal table can not be updated");
+                String errorMsg = String.format(Locale.ROOT, 
MsgPicker.getMsg().getInternalTableEmpty(), dbTblName);
+                throw new KylinException(INTERNAL_TABLE_ERROR, errorMsg);
             }
             checkParameters(partitionCols, originTable, datePartitionFormat);
             if (partitionCols != null && partitionCols.length != 0) {
@@ -255,7 +258,8 @@ public class InternalTableService extends BasicService {
             Path location = new Path(path);
             fs.mkdirs(location);
         } catch (IOException e) {
-            throw new KylinException(INTERNAL_TABLE_ERROR, "Failed to create 
internal table location", e);
+            String errorMsg = String.format(Locale.ROOT, 
MsgPicker.getMsg().getInternalTablePath());
+            throw new KylinException(INTERNAL_TABLE_ERROR, errorMsg);
         }
     }
 
@@ -397,28 +401,27 @@ public class InternalTableService extends BasicService {
                 startDate, endDate, yarnQueue);
     }
 
-    public List<InternalTableDescResponse> getTableList(String project) {
+    public List<InternalTableDescResponse> getTableList(String project, 
boolean isFuzzy, boolean needDetails,
+            String fuzzyKey) {
         InternalTableManager internalTableManager = 
getManager(InternalTableManager.class, project);
         List<InternalTableDesc> tableList = 
internalTableManager.listAllTables();
-        List<InternalTableDescResponse> descList = Lists.newArrayList();
-        tableList.forEach(internalTableDesc -> {
-            InternalTableDescResponse internalTableDescResponse = new 
InternalTableDescResponse();
-            
internalTableDescResponse.setTableName(internalTableDesc.getName());
-            internalTableDescResponse.setUuid(internalTableDesc.getUuid());
-            
internalTableDescResponse.setDatabaseName(internalTableDesc.getDatabase());
-            
internalTableDescResponse.setRowCount(internalTableDesc.getRowCount());
-            
internalTableDescResponse.setStorageSize(internalTableDesc.getStorageSize());
-            
internalTableDescResponse.setHitCount(internalTableDesc.getHitCount());
-            String[] partitionColumns = 
internalTableDesc.getPartitionColumns();
-            String partitionColumn = (partitionColumns == null || 
partitionColumns.length == 0) ? null
-                    : internalTableDesc.getPartitionColumns()[0];
-            internalTableDescResponse.setTimePartitionCol(partitionColumn);
-            
internalTableDescResponse.setUpdateTime(internalTableDesc.getLastModified());
-            
internalTableDescResponse.setDatePartitionFormat(internalTableDesc.getDatePartitionFormat());
-            
internalTableDescResponse.setTblProperties(internalTableDesc.getTblProperties());
-            descList.add(internalTableDescResponse);
-        });
-        return descList;
+        if (StringUtils.isNotBlank(fuzzyKey)) {
+            if (isFuzzy) {
+                String regex = fuzzyKey.replace(".", ".*");
+                tableList = tableList.stream().filter(table -> 
table.getIdentity().matches("(?i).*" + regex + ".*"))
+                        .collect(Collectors.toList());
+            } else {
+                tableList = tableList.stream()
+                        .filter(table -> 
StringUtils.equalsIgnoreCase(table.getIdentity(), fuzzyKey))
+                        .collect(Collectors.toList());
+            }
+            if (tableList.isEmpty()) {
+                throw new KylinException(INTERNAL_TABLE_NOT_EXIST,
+                        String.format(Locale.ROOT, 
MsgPicker.getMsg().getInternalTableNotFound(), fuzzyKey));
+            }
+        }
+        return tableList.stream().map(table -> 
InternalTableDescResponse.convertToResponse(table, needDetails))
+                .collect(Collectors.toList());
     }
 
     public List<InternalTablePartitionDetail> getTableDetail(String project, 
String databaseName, String tableName) {
diff --git 
a/src/kylin-it/src/test/java/org/apache/kylin/query/QueryGroupingSetsTest.java 
b/src/kylin-it/src/test/java/org/apache/kylin/query/QueryGroupingSetsTest.java
index 402c4165fe..02c5dbdd2f 100644
--- 
a/src/kylin-it/src/test/java/org/apache/kylin/query/QueryGroupingSetsTest.java
+++ 
b/src/kylin-it/src/test/java/org/apache/kylin/query/QueryGroupingSetsTest.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 
 import org.apache.calcite.rel.RelNode;
 import org.apache.kylin.common.KylinConfig;
@@ -112,6 +113,8 @@ public class QueryGroupingSetsTest extends SemiAutoTestBase 
{
     @After
     public void teardown() throws Exception {
         queryHistoryDAO.deleteAllQueryHistory();
+        ReflectionTestUtils.invokeMethod(
+                
Objects.requireNonNull(ReflectionTestUtils.getField(queryService, 
"slowQueryDetector")), "interrupt");
         super.tearDown();
         QueryHistoryAccelerateScheduler.shutdown();
     }
diff --git 
a/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/InternalTableController.java
 
b/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/InternalTableController.java
index 6f9bbd25e0..d514bfc6e9 100644
--- 
a/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/InternalTableController.java
+++ 
b/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/InternalTableController.java
@@ -67,8 +67,8 @@ public class InternalTableController extends NBasicController 
{
     public EnvelopeResponse<String> createInternalTable(@RequestParam(value = 
"project") String project,
             @PathVariable(value = "database") String database, //
             @PathVariable(value = "table") String table, @RequestBody 
InternalTableRequest request) throws Exception {
-        checkProjectName(project);
-        if (StringUtils.isEmpty(table) || StringUtils.isEmpty(database)) {
+        project = checkProjectName(project);
+        if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) {
             throw new KylinException(EMPTY_PARAMETER, "Table or database can 
not be null, please check again.");
         }
         internalTableService.createInternalTable(project, table, database, 
request.getPartitionCols(),
@@ -82,7 +82,7 @@ public class InternalTableController extends NBasicController 
{
     public EnvelopeResponse<String> dropInternalTable(@RequestParam(value = 
"project") String project,
             @PathVariable(value = "database") String database, //
             @PathVariable(value = "table") String table) throws Exception {
-        checkProjectName(project);
+        project = checkProjectName(project);
         String dbTblName = database + "." + table;
         internalTableService.dropInternalTable(project, dbTblName);
         return new EnvelopeResponse<>(KylinException.CODE_SUCCESS, "", "");
@@ -94,8 +94,8 @@ public class InternalTableController extends NBasicController 
{
     public EnvelopeResponse<String> truncateInternalTable(@RequestParam(value 
= "project") String project,
             @RequestParam(value = "database") String database, 
@RequestParam(value = "table") String table)
             throws Exception {
-        checkProjectName(project);
-        if (StringUtils.isEmpty(StringUtils.trim(table)) || 
StringUtils.isEmpty(StringUtils.trim(database))) {
+        project = checkProjectName(project);
+        if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) {
             throw new KylinException(INVALID_TABLE_NAME, 
MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty());
         }
         String tableIdentity = database + "." + table;
@@ -109,8 +109,8 @@ public class InternalTableController extends 
NBasicController {
     public EnvelopeResponse<String> dropPartitions(@RequestParam(value = 
"project") String project,
             @RequestParam(value = "database") String database, 
@RequestParam(value = "table") String table,
             @RequestParam(value = "partitions") String[] partitionValues) 
throws Exception {
-        checkProjectName(project);
-        if (StringUtils.isEmpty(StringUtils.trim(table)) || 
StringUtils.isEmpty(StringUtils.trim(database))) {
+        project = checkProjectName(project);
+        if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) {
             throw new KylinException(INVALID_TABLE_NAME, 
MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty());
         }
         // If partitionValues is null, all files will be cleared
@@ -127,8 +127,8 @@ public class InternalTableController extends 
NBasicController {
             @PathVariable(value = "project") String project, 
@PathVariable(value = "database") String database, //
             @PathVariable(value = "table") String table, @RequestBody 
InternalTableBuildRequest request)
             throws Exception {
-        checkProjectName(project);
-        if (StringUtils.isEmpty(table) || StringUtils.isEmpty(database)) {
+        project = checkProjectName(project);
+        if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) {
             throw new KylinException(INVALID_TABLE_NAME, 
MsgPicker.getMsg().getTableNameCannotEmpty());
         }
         InternalTableLoadingJobResponse response = 
internalTableService.loadIntoInternalTable(project, table, database,
@@ -143,8 +143,8 @@ public class InternalTableController extends 
NBasicController {
     public EnvelopeResponse<String> updateTable(@RequestParam(value = 
"project") String project,
             @PathVariable(value = "database") String database, //
             @PathVariable(value = "table") String table, @RequestBody 
InternalTableRequest request) throws Exception {
-        checkProjectName(project);
-        if (StringUtils.isEmpty(table) || StringUtils.isEmpty(database)) {
+        project = checkProjectName(project);
+        if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) {
             throw new KylinException(EMPTY_PARAMETER, "Table or database can 
not be null, please check again.");
         }
         if (table.isEmpty()) {
@@ -160,10 +160,24 @@ public class InternalTableController extends 
NBasicController {
     @ResponseBody
     public EnvelopeResponse<DataResult<List<InternalTableDescResponse>>> 
getTableList(
             @RequestParam(value = "project") String project,
+            @RequestParam(value = "need_details", required = false, 
defaultValue = "false") boolean needDetails,
+            @RequestParam(value = "is_fuzzy", required = false, defaultValue = 
"false") boolean isFuzzy,
+            @RequestParam(value = "database", required = false) String 
database,
+            @RequestParam(value = "table", required = false) String table,
             @RequestParam(value = "page_offset", required = false, 
defaultValue = "0") Integer offset,
             @RequestParam(value = "page_size", required = false, defaultValue 
= "10") Integer limit) {
-        checkProjectName(project);
-        val rep = internalTableService.getTableList(project);
+        project = checkProjectName(project);
+
+        String fuzzyKey = "";
+        if (StringUtils.isNotBlank(database) && StringUtils.isNotBlank(table)) 
{
+            fuzzyKey = StringUtils.trim(database) + "." + 
StringUtils.trim(table);
+        } else if (StringUtils.isBlank(database)) {
+            fuzzyKey = StringUtils.trim(table);
+        } else if (StringUtils.isBlank(table)) {
+            fuzzyKey = StringUtils.trim(database);
+        }
+
+        val rep = internalTableService.getTableList(project, isFuzzy, 
needDetails, fuzzyKey);
         return new EnvelopeResponse<>(KylinException.CODE_SUCCESS, 
DataResult.get(rep, offset, limit), "");
     }
 
@@ -175,8 +189,9 @@ public class InternalTableController extends 
NBasicController {
             @PathVariable(value = "table") String table,
             @RequestParam(value = "page_offset", required = false, 
defaultValue = "0") Integer offset,
             @RequestParam(value = "page_size", required = false, defaultValue 
= "10") Integer limit) {
-        checkProjectName(project);
+        project = checkProjectName(project);
         val rep = internalTableService.getTableDetail(project, database, 
table);
         return new EnvelopeResponse<>(KylinException.CODE_SUCCESS, 
DataResult.get(rep, offset, limit), "");
     }
+
 }
diff --git 
a/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/open/OpenInternalTableController.java
 
b/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/open/OpenInternalTableController.java
index 20c0927381..c54d7ed853 100644
--- 
a/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/open/OpenInternalTableController.java
+++ 
b/src/metadata-server/src/main/java/org/apache/kylin/rest/controller/open/OpenInternalTableController.java
@@ -67,7 +67,7 @@ public class OpenInternalTableController extends 
NBasicController {
             @PathVariable(value = "database") String database, //
             @PathVariable(value = "table") String table, @RequestBody 
InternalTableRequest request) throws Exception {
         String projectName = checkProjectName(project);
-        if (StringUtils.isEmpty(StringUtils.trim(table)) || 
StringUtils.isEmpty(StringUtils.trim(database))) {
+        if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) {
             throw new KylinException(EMPTY_PARAMETER, 
MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty());
         }
         return internalTableController.createInternalTable(projectName, 
database, table, request);
@@ -78,6 +78,10 @@ public class OpenInternalTableController extends 
NBasicController {
     @ResponseBody
     public EnvelopeResponse<DataResult<List<InternalTableDescResponse>>> 
getTableList(
             @RequestParam(value = "project") String project,
+            @RequestParam(value = "need_details", required = false, 
defaultValue = "false") boolean needDetails,
+            @RequestParam(value = "is_fuzzy", required = false, defaultValue = 
"false") boolean isFuzzy,
+            @RequestParam(value = "database", required = false) String 
database,
+            @RequestParam(value = "table", required = false) String table,
             @RequestParam(value = "page_offset", required = false, 
defaultValue = "0") Integer offset,
             @RequestParam(value = "page_size", required = false, defaultValue 
= "10") Integer limit) {
         String projectName = checkProjectName(project);
@@ -85,10 +89,12 @@ public class OpenInternalTableController extends 
NBasicController {
             checkNonNegativeIntegerArg("page_offset", offset);
         }
         if (null != limit) {
-            checkNonNegativeIntegerArg("page_offset", limit);
+            checkNonNegativeIntegerArg("page_size", limit);
+        }
+        if (StringUtils.isBlank(table) && StringUtils.isBlank(database) && 
isFuzzy) {
+            throw new KylinException(EMPTY_PARAMETER, 
MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty());
         }
-        checkNonNegativeIntegerArg("page_size", limit);
-        return internalTableController.getTableList(projectName, offset, 
limit);
+        return internalTableController.getTableList(projectName, isFuzzy, 
needDetails, database, table, offset, limit);
     }
 
     @ApiOperation(value = "get_table_detail", tags = { "AI" })
@@ -100,7 +106,7 @@ public class OpenInternalTableController extends 
NBasicController {
             @RequestParam(value = "page_offset", required = false, 
defaultValue = "0") Integer offset,
             @RequestParam(value = "page_size", required = false, defaultValue 
= "10") Integer limit) {
         String projectName = checkProjectName(project);
-        if (StringUtils.isEmpty(StringUtils.trim(table)) || 
StringUtils.isEmpty(StringUtils.trim(database))) {
+        if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) {
             throw new KylinException(EMPTY_PARAMETER, 
MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty());
         }
         if (null != offset) {
@@ -119,7 +125,7 @@ public class OpenInternalTableController extends 
NBasicController {
             @PathVariable(value = "database") String database, //
             @PathVariable(value = "table") String table, @RequestBody 
InternalTableRequest request) throws Exception {
         String projectName = checkProjectName(project);
-        if (StringUtils.isEmpty(StringUtils.trim(table)) || 
StringUtils.isEmpty(StringUtils.trim(database))) {
+        if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) {
             throw new KylinException(EMPTY_PARAMETER, 
MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty());
         }
         return internalTableController.updateTable(projectName, database, 
table, request);
@@ -133,7 +139,7 @@ public class OpenInternalTableController extends 
NBasicController {
             @PathVariable(value = "table") String table, @RequestBody 
InternalTableBuildRequest request)
             throws Exception {
         String projectName = checkProjectName(project);
-        if (StringUtils.isEmpty(StringUtils.trim(table)) || 
StringUtils.isEmpty(StringUtils.trim(database))) {
+        if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) {
             throw new KylinException(EMPTY_PARAMETER, 
MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty());
         }
         return internalTableController.loadIntoInternalTable(projectName, 
database, table, request);
@@ -146,7 +152,7 @@ public class OpenInternalTableController extends 
NBasicController {
             @RequestParam(value = "project") String project, 
@RequestParam(value = "database") String database,
             @RequestParam(value = "table") String table) throws Exception {
         String projectName = checkProjectName(project);
-        if (StringUtils.isEmpty(StringUtils.trim(table)) || 
StringUtils.isEmpty(StringUtils.trim(database))) {
+        if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) {
             throw new KylinException(INVALID_TABLE_NAME, 
MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty());
         }
         return internalTableController.truncateInternalTable(projectName, 
database, table);
@@ -160,7 +166,7 @@ public class OpenInternalTableController extends 
NBasicController {
             @RequestParam(value = "table") String table, @RequestParam(value = 
"partitions") String[] partitionValues)
             throws Exception {
         String projectName = checkProjectName(project);
-        if (StringUtils.isEmpty(StringUtils.trim(table)) || 
StringUtils.isEmpty(StringUtils.trim(database))) {
+        if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) {
             throw new KylinException(INVALID_TABLE_NAME, 
MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty());
         }
         if (null == partitionValues || partitionValues.length == 0) {
@@ -177,7 +183,7 @@ public class OpenInternalTableController extends 
NBasicController {
             @PathVariable(value = "database") String database, //
             @PathVariable(value = "table") String table) throws Exception {
         String projectName = checkProjectName(project);
-        if (StringUtils.isEmpty(StringUtils.trim(table)) || 
StringUtils.isEmpty(StringUtils.trim(database))) {
+        if (StringUtils.isBlank(table) || StringUtils.isBlank(database)) {
             throw new KylinException(INVALID_TABLE_NAME, 
MsgPicker.getMsg().getTableOrDatabaseNameCannotEmpty());
         }
         return internalTableController.dropInternalTable(projectName, 
database, table);


Reply via email to