Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@
package org.apache.doris.nereids.trees.plans.commands;

import org.apache.doris.analysis.SetType;
import org.apache.doris.catalog.AggregateFunction;
import org.apache.doris.catalog.AliasFunction;
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.FunctionRegistry;
import org.apache.doris.catalog.Function;
import org.apache.doris.catalog.FunctionUtil;
import org.apache.doris.catalog.ScalarFunction;
import org.apache.doris.catalog.ScalarType;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
Expand All @@ -33,7 +36,6 @@
import org.apache.doris.common.util.Util;
import org.apache.doris.datasource.InternalCatalog;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.nereids.trees.expressions.functions.FunctionBuilder;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import org.apache.doris.qe.ConnectContext;
Expand All @@ -45,13 +47,13 @@
import com.google.common.base.Strings;
import com.google.common.collect.Lists;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
* show functions command
Expand Down Expand Up @@ -97,21 +99,21 @@ public ShowFunctionsCommand(boolean isVerbose, String likeCondition, boolean isG
* get Info by nereids.
* To make the code in nereids more concise, all irrelevant information here will use an empty string.
*/
private List<Comparable> getInfo(boolean isVerbose, String funcName) {
private List<Comparable> getInfo(boolean isVerbose, Function function) {
List<Comparable> row = Lists.newArrayList();
if (isVerbose) {
// signature
row.add(funcName);
row.add(function.signatureString());
// return type
row.add("");
row.add(function.getReturnType().toString());
// function type
// intermediate type
row.add("");
row.add("");
row.add(buildFunctionType(function));
row.add(buildIntermediateType(function));
// property
row.add("");
row.add(buildProperties(function));
} else {
row.add(funcName);
row.add(function.functionName());
}
return row;
}
Expand All @@ -126,13 +128,13 @@ protected boolean like(String funcName, String likeCondition) {
* get resultRowSet
*/
@VisibleForTesting
protected List<List<String>> getResultRowSetByFunctions(List<String> functions) {
protected List<List<String>> getResultRowSetByFunctions(List<Function> functions) {
List<List<String>> resultRowSet = Lists.newArrayList();
List<List<Comparable>> rowSet = Lists.newArrayList();
for (String function : functions) {
for (Function function : functions) {
List<Comparable> row = getInfo(isVerbose, function);
// like predicate
if (likeCondition == null || like(function, likeCondition)) {
if (likeCondition == null || like(function.functionName(), likeCondition)) {
rowSet.add(row);
}
}
Expand Down Expand Up @@ -163,7 +165,7 @@ protected List<List<String>> getResultRowSetByFunctions(List<String> functions)
* get resultRowSet
*/
private List<List<String>> getResultRowSet(ConnectContext ctx) throws AnalysisException {
List<String> functions = getFunctions(ctx);
List<Function> functions = getFunctions(ctx);
return getResultRowSetByFunctions(functions);
}

Expand All @@ -172,23 +174,23 @@ private List<List<String>> getResultRowSet(ConnectContext ctx) throws AnalysisEx
* All functions including builtin and udf are registered in FunctionRegistry
*/
@VisibleForTesting
protected List<String> getFunctions(ConnectContext ctx) throws AnalysisException {
List<String> functions = Lists.newArrayList();
protected List<Function> getFunctions(ConnectContext ctx) throws AnalysisException {
List<Function> functions = Lists.newArrayList();
if (ctx == null || ctx.getEnv() == null || ctx.getEnv().getFunctionRegistry() == null) {
return functions;
}

FunctionRegistry functionRegistry = ctx.getEnv().getFunctionRegistry();
Map<String, Map<String, List<FunctionBuilder>>> udfFunctions = functionRegistry.getName2UdfBuilders();
if (!FunctionUtil.isGlobalFunction(type)) {
dbName = reAcquireDbName(ctx, dbName);
}

if (FunctionUtil.isGlobalFunction(type)) {
// handle show global functions
functions = new ArrayList<>(udfFunctions
.getOrDefault(functionRegistry.getGlobalFunctionDbName(), new HashMap<>()).keySet());
functions = Env.getCurrentEnv().getGlobalFunctionMgr().getFunctions();
} else {
Util.prohibitExternalCatalog(ctx.getDefaultCatalog(), this.getClass().getSimpleName());
DatabaseIf db = ctx.getCurrentCatalog().getDbOrAnalysisException(dbName);
if (db instanceof Database) {
functions = new ArrayList<>(udfFunctions.getOrDefault(dbName, new HashMap<>()).keySet());
functions = ((Database) db).getFunctions();
}
}
return functions;
Expand Down Expand Up @@ -244,4 +246,102 @@ public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
return visitor.visitShowFunctionsCommand(this, context);
}

private String buildFunctionType(Function function) {
if (function instanceof AggregateFunction) {
return "AGGREGATE/" + function.getBinaryType();
}
if (function.isUDTFunction()) {
return "UDTF/" + function.getBinaryType();
}
if (function instanceof AliasFunction) {
return "ALIAS/" + function.getBinaryType();
}
return "SCALAR/" + function.getBinaryType();
}

private String buildIntermediateType(Function function) {
if (function instanceof AggregateFunction) {
AggregateFunction aggregateFunction = (AggregateFunction) function;
return aggregateFunction.getIntermediateType() == null
? ""
: aggregateFunction.getIntermediateType().toString();
}
return "";
}

private String buildProperties(Function function) {
Map<String, String> properties = new LinkedHashMap<>();
if (function.getId() > 0) {
properties.put("ID", String.valueOf(function.getId()));
}
if (!Strings.isNullOrEmpty(function.getChecksum())) {
properties.put("CHECKSUM", function.getChecksum());
}
if (function.getLocation() != null) {
String locationKey = function.getBinaryType() == null
|| function.getBinaryType().name().startsWith("JAVA")
? "FILE"
: "OBJECT_FILE";
properties.put(locationKey, function.getLocation().toString());
}
properties.put("NULLABLE_MODE", function.getNullableMode().name());
if (function.isStaticLoad()) {
properties.put("STATIC_LOAD", String.valueOf(function.isStaticLoad()));
}
if (!Strings.isNullOrEmpty(function.getRuntimeVersion())) {
properties.put("RUNTIME_VERSION", function.getRuntimeVersion());
}

if (function instanceof ScalarFunction) {
ScalarFunction scalarFunction = (ScalarFunction) function;
properties.put("SYMBOL", Strings.nullToEmpty(scalarFunction.getSymbolName()));
if (scalarFunction.getPrepareFnSymbol() != null) {
properties.put("PREPARE_FN", scalarFunction.getPrepareFnSymbol());
}
if (scalarFunction.getCloseFnSymbol() != null) {
properties.put("CLOSE_FN", scalarFunction.getCloseFnSymbol());
}
}

if (function instanceof AggregateFunction) {
AggregateFunction aggregateFunction = (AggregateFunction) function;
properties.put("INIT_FN", Strings.nullToEmpty(aggregateFunction.getInitFnSymbol()));
properties.put("UPDATE_FN", Strings.nullToEmpty(aggregateFunction.getUpdateFnSymbol()));
properties.put("MERGE_FN", Strings.nullToEmpty(aggregateFunction.getMergeFnSymbol()));
if (aggregateFunction.getSerializeFnSymbol() != null) {
properties.put("SERIALIZE_FN", aggregateFunction.getSerializeFnSymbol());
}
if (aggregateFunction.getFinalizeFnSymbol() != null) {
properties.put("FINALIZE_FN", aggregateFunction.getFinalizeFnSymbol());
}
if (aggregateFunction.getGetValueFnSymbol() != null) {
properties.put("GET_VALUE_FN", aggregateFunction.getGetValueFnSymbol());
}
if (aggregateFunction.getRemoveFnSymbol() != null) {
properties.put("REMOVE_FN", aggregateFunction.getRemoveFnSymbol());
}
if (aggregateFunction.getSymbolName() != null) {
properties.put("SYMBOL", aggregateFunction.getSymbolName());
}
}

if (function instanceof AliasFunction) {
AliasFunction aliasFunction = (AliasFunction) function;
properties.put("ALIAS_OF", aliasFunction.getOriginFunction().toSqlWithoutTbl());
if (aliasFunction.getParameters() != null && !aliasFunction.getParameters().isEmpty()) {
properties.put("PARAMETERS", String.join(",", aliasFunction.getParameters()));
}
}

// inline python UDF/UDTF/UDAF code
if (function.getBinaryType() != null && function.getBinaryType().name().contains("PYTHON")
&& !Strings.isNullOrEmpty(function.getFunctionCode())) {
properties.put("INLINE_CODE", function.getFunctionCode());
}

return properties.entrySet().stream()
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(Collectors.joining(", "));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.apache.doris.catalog.AccessPrivilege;
import org.apache.doris.catalog.AccessPrivilegeWithCols;
import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.Function;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.UserException;
import org.apache.doris.mysql.privilege.Auth;
Expand Down Expand Up @@ -59,13 +60,13 @@ void testGetFunctions() throws AnalysisException {

// test for not builtin functions
sf = new ShowFunctionsCommand("test", false, null);
List<String> re2 = sf.getFunctions(connectContext);
List<Function> re2 = sf.getFunctions(connectContext);
Assertions.assertEquals(1, re2.size());
Assertions.assertEquals("test_for_create_function", re2.get(0));
Assertions.assertEquals("test_for_create_function", re2.get(0).functionName());

// test for full not builtin functions
sf = new ShowFunctionsCommand("test", true, null);
List<String> re4 = sf.getFunctions(connectContext);
List<Function> re4 = sf.getFunctions(connectContext);
Assertions.assertEquals(1, re4.size());
}

Expand All @@ -75,34 +76,32 @@ void testGetResultRowSetByFunctions() throws AnalysisException {
ShowFunctionsCommand sf;
connectContext.setDatabase("test");
sf = new ShowFunctionsCommand("test", false, null);
List<String> func2 = sf.getFunctions(connectContext);
List<Function> func2 = sf.getFunctions(connectContext);
List<List<String>> re2 = sf.getResultRowSetByFunctions(func2);
Assertions.assertEquals(1, re2.get(0).size());
Assertions.assertEquals("test_for_create_function", re2.get(0).get(0));

// test for full not builtin functions
connectContext.setDatabase("test");
sf = new ShowFunctionsCommand("test", true, null);
List<String> func4 = sf.getFunctions(connectContext);
List<Function> func4 = sf.getFunctions(connectContext);
List<List<String>> re4 = sf.getResultRowSetByFunctions(func4);
Assertions.assertEquals(5, re4.get(0).size());
Assertions.assertEquals("test_for_create_function", re4.get(0).get(0));
Assertions.assertEquals("", re4.get(0).get(1));
Assertions.assertEquals("", re4.get(0).get(2));
Assertions.assertEquals("", re4.get(0).get(3));
Assertions.assertEquals("", re4.get(0).get(4));
Assertions.assertTrue(re4.get(0).get(0).startsWith("test_for_create_function"));
Assertions.assertFalse(re4.get(0).get(1).isEmpty());
Assertions.assertFalse(re4.get(0).get(2).isEmpty());
Assertions.assertFalse(re4.get(0).get(4).isEmpty());

// test for full not builtin functions with where condition
String where = "test_for_create_function%";
sf = new ShowFunctionsCommand("test", true, where);
List<String> func5 = sf.getFunctions(connectContext);
List<Function> func5 = sf.getFunctions(connectContext);
List<List<String>> re5 = sf.getResultRowSetByFunctions(func5);
Assertions.assertEquals(5, re5.get(0).size());
Assertions.assertEquals("test_for_create_function", re5.get(0).get(0));
Assertions.assertEquals("", re5.get(0).get(1));
Assertions.assertEquals("", re5.get(0).get(2));
Assertions.assertEquals("", re5.get(0).get(3));
Assertions.assertEquals("", re5.get(0).get(4));
Assertions.assertTrue(re5.get(0).get(0).startsWith("test_for_create_function"));
Assertions.assertFalse(re5.get(0).get(1).isEmpty());
Assertions.assertFalse(re5.get(0).get(2).isEmpty());
Assertions.assertFalse(re5.get(0).get(4).isEmpty());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.apache.doris.nereids.trees.plans.commands;

import org.apache.doris.catalog.Function;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.utframe.TestWithFeService;

Expand All @@ -39,59 +40,59 @@ protected void runBeforeAll() throws Exception {
void testGetFunctions() throws AnalysisException {
// test for not global
ShowFunctionsCommand sf = new ShowFunctionsCommand(false, null, false);
ShowFunctionsCommand finalSf = sf;
Assertions.assertThrows(AnalysisException.class, () -> finalSf.getFunctions(connectContext));
List<Function> nonGlobal = sf.getFunctions(connectContext);
Assertions.assertTrue(nonGlobal.isEmpty());

// test for verbose
connectContext.setDatabase("test");
sf = new ShowFunctionsCommand(true, null, true);
List<String> re1 = sf.getFunctions(connectContext);
List<Function> re1 = sf.getFunctions(connectContext);
Assertions.assertEquals(1, re1.size());
Assertions.assertEquals("test_for_create_function", re1.get(0));
Assertions.assertEquals("test_for_create_function", re1.get(0).functionName());

// test for no verbose
sf = new ShowFunctionsCommand(false, null, true);
List<String> re2 = sf.getFunctions(connectContext);
List<Function> re2 = sf.getFunctions(connectContext);
Assertions.assertEquals(1, re2.size());
Assertions.assertEquals("test_for_create_function", re2.get(0));
Assertions.assertEquals("test_for_create_function", re2.get(0).functionName());

// test for like condition
sf = new ShowFunctionsCommand(false, "test_for_create%", true);
List<String> re3 = sf.getFunctions(connectContext);
List<Function> re3 = sf.getFunctions(connectContext);
Assertions.assertEquals(1, re3.size());
Assertions.assertEquals("test_for_create_function", re3.get(0));
Assertions.assertEquals("test_for_create_function", re3.get(0).functionName());
}

@Test
void testGetResultRowSetByFunctions() throws AnalysisException {
connectContext.setDatabase("test");
// test for verbose
ShowFunctionsCommand sf = new ShowFunctionsCommand(true, null, true);
List<String> func3 = sf.getFunctions(connectContext);
List<Function> func3 = sf.getFunctions(connectContext);
List<List<String>> re3 = sf.getResultRowSetByFunctions(func3);
Assertions.assertEquals(1, re3.size());
Assertions.assertEquals("", re3.get(0).get(1));
Assertions.assertEquals("", re3.get(0).get(2));
Assertions.assertEquals("", re3.get(0).get(3));
Assertions.assertEquals("", re3.get(0).get(4));
Assertions.assertEquals(5, re3.get(0).size());
Assertions.assertTrue(re3.get(0).get(0).startsWith("test_for_create_function"));
Assertions.assertFalse(re3.get(0).get(1).isEmpty());
Assertions.assertFalse(re3.get(0).get(2).isEmpty());
Assertions.assertFalse(re3.get(0).get(4).isEmpty());

// test for not verbose
sf = new ShowFunctionsCommand(false, null, true);
List<String> func4 = sf.getFunctions(connectContext);
List<Function> func4 = sf.getFunctions(connectContext);
List<List<String>> re4 = sf.getResultRowSetByFunctions(func4);
Assertions.assertEquals(1, re4.get(0).size());
Assertions.assertEquals("test_for_create_function", re4.get(0).get(0));

// test for like condition
String where = "test_for_create_function%";
sf = new ShowFunctionsCommand(true, where, true);
List<String> func5 = sf.getFunctions(connectContext);
List<Function> func5 = sf.getFunctions(connectContext);
List<List<String>> re5 = sf.getResultRowSetByFunctions(func5);
Assertions.assertEquals(5, re5.get(0).size());
Assertions.assertEquals("test_for_create_function", re5.get(0).get(0));
Assertions.assertEquals("", re5.get(0).get(1));
Assertions.assertEquals("", re5.get(0).get(2));
Assertions.assertEquals("", re5.get(0).get(3));
Assertions.assertEquals("", re5.get(0).get(4));
Assertions.assertTrue(re5.get(0).get(0).startsWith("test_for_create_function"));
Assertions.assertFalse(re5.get(0).get(1).isEmpty());
Assertions.assertFalse(re5.get(0).get(2).isEmpty());
Assertions.assertFalse(re5.get(0).get(4).isEmpty());
}
}
Loading
Loading