This is an automated email from the ASF dual-hosted git repository. yiguolei pushed a commit to branch branch-2.1 in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-2.1 by this push: new ff68859546e branch-2.1: [improvement](http) improve table schema api for catalog table #45933 (#45982) ff68859546e is described below commit ff68859546eadde9e20d8120c953bfbc83edd8c7 Author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> AuthorDate: Fri Jan 3 16:40:12 2025 +0800 branch-2.1: [improvement](http) improve table schema api for catalog table #45933 (#45982) Cherry-picked from #45933 Co-authored-by: wudi <w...@selectdb.com> --- .../doris/httpv2/controller/BaseController.java | 10 +++- .../doris/httpv2/rest/RestBaseController.java | 1 + .../doris/httpv2/rest/TableSchemaAction.java | 39 ++++++++++---- .../http_rest_api/get/test_schema_api.groovy | 60 ++++++++++++++++++++++ 4 files changed, 98 insertions(+), 12 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/BaseController.java b/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/BaseController.java index 026b1f8bda3..60fc9258717 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/BaseController.java +++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/BaseController.java @@ -117,7 +117,7 @@ public class BaseController { } private ActionAuthorizationInfo checkCookie(HttpServletRequest request, HttpServletResponse response, - boolean checkAuth) { + boolean checkAuth) { List<String> sessionIds = getCookieValues(request, PALO_SESSION_ID, response); if (sessionIds.isEmpty()) { return null; @@ -218,8 +218,14 @@ public class BaseController { protected void checkTblAuth(UserIdentity currentUser, String db, String tbl, PrivPredicate predicate) throws UnauthorizedException { + checkTblAuth(currentUser, InternalCatalog.INTERNAL_CATALOG_NAME, db, tbl, predicate); + } + + protected void checkTblAuth(UserIdentity currentUser, String catalog, String db, String tbl, + PrivPredicate predicate) + throws UnauthorizedException { if (!Env.getCurrentEnv().getAccessManager() - .checkTblPriv(currentUser, InternalCatalog.INTERNAL_CATALOG_NAME, db, tbl, predicate)) { + .checkTblPriv(currentUser, catalog, db, tbl, predicate)) { throw new UnauthorizedException("Access denied; you need (at least one of) the " + predicate.getPrivs().toString() + " privilege(s) for this operation"); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/RestBaseController.java b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/RestBaseController.java index 5621ffaccde..bf07eda4f8d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/RestBaseController.java +++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/RestBaseController.java @@ -49,6 +49,7 @@ import javax.servlet.http.HttpServletResponse; public class RestBaseController extends BaseController { protected static final String NS_KEY = "ns"; + protected static final String CATALOG_KEY = "catalog"; protected static final String DB_KEY = "db"; protected static final String TABLE_KEY = "table"; protected static final String LABEL_KEY = "label"; diff --git a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/TableSchemaAction.java b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/TableSchemaAction.java index ae1b3956179..0f362b4aad8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/TableSchemaAction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/TableSchemaAction.java @@ -19,20 +19,26 @@ package org.apache.doris.httpv2.rest; import org.apache.doris.catalog.Column; import org.apache.doris.catalog.Database; +import org.apache.doris.catalog.DatabaseIf; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.OlapTable; import org.apache.doris.catalog.PrimitiveType; import org.apache.doris.catalog.ScalarType; import org.apache.doris.catalog.Table; +import org.apache.doris.catalog.TableIf; import org.apache.doris.catalog.Type; +import org.apache.doris.common.AnalysisException; import org.apache.doris.common.DorisHttpException; import org.apache.doris.common.MetaNotFoundException; +import org.apache.doris.datasource.CatalogIf; +import org.apache.doris.datasource.InternalCatalog; import org.apache.doris.httpv2.entity.ResponseEntityBuilder; import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.qe.ConnectContext; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; +import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -54,8 +60,10 @@ import javax.servlet.http.HttpServletResponse; @RestController public class TableSchemaAction extends RestBaseController { - @RequestMapping(path = "/api/{" + DB_KEY + "}/{" + TABLE_KEY + "}/_schema", method = RequestMethod.GET) + @RequestMapping(path = {"/api/{" + DB_KEY + "}/{" + TABLE_KEY + "}/_schema", + "/api/{" + CATALOG_KEY + "}/{" + DB_KEY + "}/{" + TABLE_KEY + "}/_schema"}, method = RequestMethod.GET) protected Object schema( + @PathVariable(value = CATALOG_KEY, required = false) String catalogName, @PathVariable(value = DB_KEY) final String dbName, @PathVariable(value = TABLE_KEY) final String tblName, HttpServletRequest request, HttpServletResponse response) { @@ -63,15 +71,22 @@ public class TableSchemaAction extends RestBaseController { // just allocate 2 slot for top holder map Map<String, Object> resultMap = new HashMap<>(2); + if (StringUtils.isBlank(catalogName)) { + catalogName = InternalCatalog.INTERNAL_CATALOG_NAME; + } + try { String fullDbName = getFullDbName(dbName); // check privilege for select, otherwise return 401 HTTP status - checkTblAuth(ConnectContext.get().getCurrentUserIdentity(), fullDbName, tblName, PrivPredicate.SELECT); - OlapTable table; + checkTblAuth(ConnectContext.get().getCurrentUserIdentity(), catalogName, fullDbName, tblName, + PrivPredicate.SELECT); + TableIf table; try { - Database db = Env.getCurrentInternalCatalog().getDbOrMetaException(fullDbName); - table = (OlapTable) db.getTableOrMetaException(tblName, Table.TableType.OLAP); - } catch (MetaNotFoundException e) { + CatalogIf catalog = StringUtils.isNotBlank(catalogName) ? Env.getCurrentEnv().getCatalogMgr() + .getCatalogOrAnalysisException(catalogName) : Env.getCurrentInternalCatalog(); + DatabaseIf db = catalog.getDbOrMetaException(fullDbName); + table = db.getTableOrMetaException(tblName); + } catch (MetaNotFoundException | AnalysisException e) { return ResponseEntityBuilder.okWithCommonError(e.getMessage()); } table.readLock(); @@ -97,7 +112,9 @@ public class TableSchemaAction extends RestBaseController { propList.add(baseInfo); } resultMap.put("status", 200); - resultMap.put("keysType", table.getKeysType().name()); + if (table instanceof OlapTable) { + resultMap.put("keysType", ((OlapTable) table).getKeysType().name()); + } resultMap.put("properties", propList); } catch (Exception e) { // Transform the general Exception to custom DorisHttpException @@ -115,6 +132,7 @@ public class TableSchemaAction extends RestBaseController { return ResponseEntityBuilder.ok(resultMap); } + private static class DDLRequestBody { public Boolean isDropColumn; public String columnName; @@ -128,7 +146,7 @@ public class TableSchemaAction extends RestBaseController { * } */ @RequestMapping(path = "/api/enable_light_schema_change/{" + DB_KEY - + "}/{" + TABLE_KEY + "}", method = { RequestMethod.GET }) + + "}/{" + TABLE_KEY + "}", method = {RequestMethod.GET}) public Object columnChangeCanSync( @PathVariable(value = DB_KEY) String dbName, @PathVariable(value = TABLE_KEY) String tableName, @@ -145,7 +163,8 @@ public class TableSchemaAction extends RestBaseController { if (!table.getEnableLightSchemaChange()) { return ResponseEntityBuilder.okWithCommonError("table " + tableName + " disable light schema change"); } - java.lang.reflect.Type type = new TypeToken<DDLRequestBody>() {}.getType(); + java.lang.reflect.Type type = new TypeToken<DDLRequestBody>() { + }.getType(); DDLRequestBody ddlRequestBody = new Gson().fromJson(body, type); if (ddlRequestBody.isDropColumn) { boolean enableLightSchemaChange = true; @@ -165,7 +184,7 @@ public class TableSchemaAction extends RestBaseController { } if (!enableLightSchemaChange) { return ResponseEntityBuilder.okWithCommonError("Column " + ddlRequestBody.columnName - + " is primary key in materializedIndex that can't do the light schema change"); + + " is primary key in materializedIndex that can't do the light schema change"); } } return ResponseEntityBuilder.ok(); diff --git a/regression-test/suites/http_rest_api/get/test_schema_api.groovy b/regression-test/suites/http_rest_api/get/test_schema_api.groovy new file mode 100644 index 00000000000..937b35d4832 --- /dev/null +++ b/regression-test/suites/http_rest_api/get/test_schema_api.groovy @@ -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. + +import org.apache.doris.regression.util.Http + +suite("test_schema_api") { + + def thisDb = sql """select database()"""; + thisDb = thisDb[0][0]; + logger.info("current database is ${thisDb}"); + + def tbName = "test_schema_api" + sql "DROP TABLE IF EXISTS ${tbName}" + sql """ + CREATE TABLE ${tbName} + ( + `id` LARGEINT NOT NULL COMMENT "id", + `c1` DECIMAL(10, 2) COMMENT "decimal columns", + `c2` date NOT NULL COMMENT "date columns", + `c3` VARCHAR(20) COMMENT "nullable columns", + `c4` VARCHAR COMMENT "varchar columns", + `c5` BIGINT DEFAULT "0" COMMENT "test columns" + ) + UNIQUE KEY(`id`) + DISTRIBUTED BY HASH(`id`) BUCKETS 8 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + + //exist table + def url = String.format("http://%s/api/%s/%s/_schema", context.config.feHttpAddress, thisDb, tbName) + def result = Http.GET(url, true) + assertTrue(result.code == 0) + assertEquals(result.msg, "success") + // parsing + def resultList = result.data.properties + assertTrue(resultList.size() == 6) + + // not exist catalog + def url2 = String.format("http://%s/api/%s/%s/%s/_schema", context.config.feHttpAddress, "notexistctl", thisDb, tbName) + def result2 = Http.GET(url2, true) + assertTrue(result2.code != 0) + assertTrue(result2.data.contains("Unknown catalog")) + +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org