Skip to content

Commit 07b7d7a

Browse files
committed
1
1 parent cbcbb04 commit 07b7d7a

File tree

5 files changed

+278
-78
lines changed

5 files changed

+278
-78
lines changed

fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ShowFunctionsCommand.java

Lines changed: 121 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818
package org.apache.doris.nereids.trees.plans.commands;
1919

2020
import org.apache.doris.analysis.SetType;
21+
import org.apache.doris.catalog.AggregateFunction;
22+
import org.apache.doris.catalog.AliasFunction;
2123
import org.apache.doris.catalog.Column;
2224
import org.apache.doris.catalog.Database;
2325
import org.apache.doris.catalog.DatabaseIf;
2426
import org.apache.doris.catalog.Env;
25-
import org.apache.doris.catalog.FunctionRegistry;
27+
import org.apache.doris.catalog.Function;
2628
import org.apache.doris.catalog.FunctionUtil;
29+
import org.apache.doris.catalog.ScalarFunction;
2730
import org.apache.doris.catalog.ScalarType;
2831
import org.apache.doris.common.AnalysisException;
2932
import org.apache.doris.common.ErrorCode;
@@ -33,7 +36,6 @@
3336
import org.apache.doris.common.util.Util;
3437
import org.apache.doris.datasource.InternalCatalog;
3538
import org.apache.doris.mysql.privilege.PrivPredicate;
36-
import org.apache.doris.nereids.trees.expressions.functions.FunctionBuilder;
3739
import org.apache.doris.nereids.trees.plans.PlanType;
3840
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
3941
import org.apache.doris.qe.ConnectContext;
@@ -45,13 +47,13 @@
4547
import com.google.common.base.Strings;
4648
import com.google.common.collect.Lists;
4749

48-
import java.util.ArrayList;
4950
import java.util.Collections;
50-
import java.util.HashMap;
5151
import java.util.HashSet;
52+
import java.util.LinkedHashMap;
5253
import java.util.List;
5354
import java.util.Map;
5455
import java.util.Set;
56+
import java.util.stream.Collectors;
5557

5658
/**
5759
* show functions command
@@ -97,21 +99,21 @@ public ShowFunctionsCommand(boolean isVerbose, String likeCondition, boolean isG
9799
* get Info by nereids.
98100
* To make the code in nereids more concise, all irrelevant information here will use an empty string.
99101
*/
100-
private List<Comparable> getInfo(boolean isVerbose, String funcName) {
102+
private List<Comparable> getInfo(boolean isVerbose, Function function) {
101103
List<Comparable> row = Lists.newArrayList();
102104
if (isVerbose) {
103105
// signature
104-
row.add(funcName);
106+
row.add(function.signatureString());
105107
// return type
106-
row.add("");
108+
row.add(function.getReturnType().toString());
107109
// function type
108110
// intermediate type
109-
row.add("");
110-
row.add("");
111+
row.add(buildFunctionType(function));
112+
row.add(buildIntermediateType(function));
111113
// property
112-
row.add("");
114+
row.add(buildProperties(function));
113115
} else {
114-
row.add(funcName);
116+
row.add(function.functionName());
115117
}
116118
return row;
117119
}
@@ -126,13 +128,13 @@ protected boolean like(String funcName, String likeCondition) {
126128
* get resultRowSet
127129
*/
128130
@VisibleForTesting
129-
protected List<List<String>> getResultRowSetByFunctions(List<String> functions) {
131+
protected List<List<String>> getResultRowSetByFunctions(List<Function> functions) {
130132
List<List<String>> resultRowSet = Lists.newArrayList();
131133
List<List<Comparable>> rowSet = Lists.newArrayList();
132-
for (String function : functions) {
134+
for (Function function : functions) {
133135
List<Comparable> row = getInfo(isVerbose, function);
134136
// like predicate
135-
if (likeCondition == null || like(function, likeCondition)) {
137+
if (likeCondition == null || like(function.functionName(), likeCondition)) {
136138
rowSet.add(row);
137139
}
138140
}
@@ -163,7 +165,7 @@ protected List<List<String>> getResultRowSetByFunctions(List<String> functions)
163165
* get resultRowSet
164166
*/
165167
private List<List<String>> getResultRowSet(ConnectContext ctx) throws AnalysisException {
166-
List<String> functions = getFunctions(ctx);
168+
List<Function> functions = getFunctions(ctx);
167169
return getResultRowSetByFunctions(functions);
168170
}
169171

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

181-
FunctionRegistry functionRegistry = ctx.getEnv().getFunctionRegistry();
182-
Map<String, Map<String, List<FunctionBuilder>>> udfFunctions = functionRegistry.getName2UdfBuilders();
183+
if (!FunctionUtil.isGlobalFunction(type)) {
184+
dbName = reAcquireDbName(ctx, dbName);
185+
}
186+
183187
if (FunctionUtil.isGlobalFunction(type)) {
184-
// handle show global functions
185-
functions = new ArrayList<>(udfFunctions
186-
.getOrDefault(functionRegistry.getGlobalFunctionDbName(), new HashMap<>()).keySet());
188+
functions = Env.getCurrentEnv().getGlobalFunctionMgr().getFunctions();
187189
} else {
188190
Util.prohibitExternalCatalog(ctx.getDefaultCatalog(), this.getClass().getSimpleName());
189191
DatabaseIf db = ctx.getCurrentCatalog().getDbOrAnalysisException(dbName);
190192
if (db instanceof Database) {
191-
functions = new ArrayList<>(udfFunctions.getOrDefault(dbName, new HashMap<>()).keySet());
193+
functions = ((Database) db).getFunctions();
192194
}
193195
}
194196
return functions;
@@ -244,4 +246,100 @@ public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
244246
return visitor.visitShowFunctionsCommand(this, context);
245247
}
246248

249+
private String buildFunctionType(Function function) {
250+
if (function instanceof AggregateFunction) {
251+
return "AGGREGATE/" + function.getBinaryType();
252+
}
253+
if (function.isUDTFunction()) {
254+
return "UDTF/" + function.getBinaryType();
255+
}
256+
if (function instanceof AliasFunction) {
257+
return "ALIAS/" + function.getBinaryType();
258+
}
259+
return "SCALAR/" + function.getBinaryType();
260+
}
261+
262+
private String buildIntermediateType(Function function) {
263+
if (function instanceof AggregateFunction) {
264+
AggregateFunction aggregateFunction = (AggregateFunction) function;
265+
return aggregateFunction.getIntermediateType() == null
266+
? ""
267+
: aggregateFunction.getIntermediateType().toString();
268+
}
269+
return "";
270+
}
271+
272+
private String buildProperties(Function function) {
273+
Map<String, String> properties = new LinkedHashMap<>();
274+
if (!Strings.isNullOrEmpty(function.getChecksum())) {
275+
properties.put("CHECKSUM", function.getChecksum());
276+
}
277+
if (function.getLocation() != null) {
278+
String locationKey = function.getBinaryType() == null
279+
|| function.getBinaryType().name().startsWith("JAVA")
280+
? "FILE"
281+
: "OBJECT_FILE";
282+
properties.put(locationKey, function.getLocation().toString());
283+
}
284+
properties.put("NULLABLE_MODE", function.getNullableMode().name());
285+
properties.put("EXPIRATION", String.valueOf(function.getExpirationTime()));
286+
if (function.isStaticLoad()) {
287+
properties.put("STATIC_LOAD", String.valueOf(function.isStaticLoad()));
288+
}
289+
if (!Strings.isNullOrEmpty(function.getRuntimeVersion())) {
290+
properties.put("RUNTIME_VERSION", function.getRuntimeVersion());
291+
}
292+
293+
if (function instanceof ScalarFunction) {
294+
ScalarFunction scalarFunction = (ScalarFunction) function;
295+
properties.put("SYMBOL", Strings.nullToEmpty(scalarFunction.getSymbolName()));
296+
if (scalarFunction.getPrepareFnSymbol() != null) {
297+
properties.put("PREPARE_FN", scalarFunction.getPrepareFnSymbol());
298+
}
299+
if (scalarFunction.getCloseFnSymbol() != null) {
300+
properties.put("CLOSE_FN", scalarFunction.getCloseFnSymbol());
301+
}
302+
}
303+
304+
if (function instanceof AggregateFunction) {
305+
AggregateFunction aggregateFunction = (AggregateFunction) function;
306+
properties.put("INIT_FN", Strings.nullToEmpty(aggregateFunction.getInitFnSymbol()));
307+
properties.put("UPDATE_FN", Strings.nullToEmpty(aggregateFunction.getUpdateFnSymbol()));
308+
properties.put("MERGE_FN", Strings.nullToEmpty(aggregateFunction.getMergeFnSymbol()));
309+
if (aggregateFunction.getSerializeFnSymbol() != null) {
310+
properties.put("SERIALIZE_FN", aggregateFunction.getSerializeFnSymbol());
311+
}
312+
if (aggregateFunction.getFinalizeFnSymbol() != null) {
313+
properties.put("FINALIZE_FN", aggregateFunction.getFinalizeFnSymbol());
314+
}
315+
if (aggregateFunction.getGetValueFnSymbol() != null) {
316+
properties.put("GET_VALUE_FN", aggregateFunction.getGetValueFnSymbol());
317+
}
318+
if (aggregateFunction.getRemoveFnSymbol() != null) {
319+
properties.put("REMOVE_FN", aggregateFunction.getRemoveFnSymbol());
320+
}
321+
if (aggregateFunction.getSymbolName() != null) {
322+
properties.put("SYMBOL", aggregateFunction.getSymbolName());
323+
}
324+
}
325+
326+
if (function instanceof AliasFunction) {
327+
AliasFunction aliasFunction = (AliasFunction) function;
328+
properties.put("ALIAS_OF", aliasFunction.getOriginFunction().toSqlWithoutTbl());
329+
if (aliasFunction.getParameters() != null && !aliasFunction.getParameters().isEmpty()) {
330+
properties.put("PARAMETERS", String.join(",", aliasFunction.getParameters()));
331+
}
332+
}
333+
334+
// inline python UDF/UDTF/UDAF code
335+
if (function.getBinaryType() != null && function.getBinaryType().name().contains("PYTHON")
336+
&& !Strings.isNullOrEmpty(function.getFunctionCode())) {
337+
properties.put("INLINE_CODE", function.getFunctionCode());
338+
}
339+
340+
return properties.entrySet().stream()
341+
.map(entry -> entry.getKey() + "=" + entry.getValue())
342+
.collect(Collectors.joining(", "));
343+
}
344+
247345
}

fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowFunctionsCommandTest.java

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.doris.catalog.AccessPrivilege;
2424
import org.apache.doris.catalog.AccessPrivilegeWithCols;
2525
import org.apache.doris.catalog.Env;
26+
import org.apache.doris.catalog.Function;
2627
import org.apache.doris.common.AnalysisException;
2728
import org.apache.doris.common.UserException;
2829
import org.apache.doris.mysql.privilege.Auth;
@@ -59,13 +60,13 @@ void testGetFunctions() throws AnalysisException {
5960

6061
// test for not builtin functions
6162
sf = new ShowFunctionsCommand("test", false, null);
62-
List<String> re2 = sf.getFunctions(connectContext);
63+
List<Function> re2 = sf.getFunctions(connectContext);
6364
Assertions.assertEquals(1, re2.size());
64-
Assertions.assertEquals("test_for_create_function", re2.get(0));
65+
Assertions.assertEquals("test_for_create_function", re2.get(0).functionName());
6566

6667
// test for full not builtin functions
6768
sf = new ShowFunctionsCommand("test", true, null);
68-
List<String> re4 = sf.getFunctions(connectContext);
69+
List<Function> re4 = sf.getFunctions(connectContext);
6970
Assertions.assertEquals(1, re4.size());
7071
}
7172

@@ -75,34 +76,32 @@ void testGetResultRowSetByFunctions() throws AnalysisException {
7576
ShowFunctionsCommand sf;
7677
connectContext.setDatabase("test");
7778
sf = new ShowFunctionsCommand("test", false, null);
78-
List<String> func2 = sf.getFunctions(connectContext);
79+
List<Function> func2 = sf.getFunctions(connectContext);
7980
List<List<String>> re2 = sf.getResultRowSetByFunctions(func2);
8081
Assertions.assertEquals(1, re2.get(0).size());
8182
Assertions.assertEquals("test_for_create_function", re2.get(0).get(0));
8283

8384
// test for full not builtin functions
8485
connectContext.setDatabase("test");
8586
sf = new ShowFunctionsCommand("test", true, null);
86-
List<String> func4 = sf.getFunctions(connectContext);
87+
List<Function> func4 = sf.getFunctions(connectContext);
8788
List<List<String>> re4 = sf.getResultRowSetByFunctions(func4);
8889
Assertions.assertEquals(5, re4.get(0).size());
89-
Assertions.assertEquals("test_for_create_function", re4.get(0).get(0));
90-
Assertions.assertEquals("", re4.get(0).get(1));
91-
Assertions.assertEquals("", re4.get(0).get(2));
92-
Assertions.assertEquals("", re4.get(0).get(3));
93-
Assertions.assertEquals("", re4.get(0).get(4));
90+
Assertions.assertTrue(re4.get(0).get(0).startsWith("test_for_create_function"));
91+
Assertions.assertFalse(re4.get(0).get(1).isEmpty());
92+
Assertions.assertFalse(re4.get(0).get(2).isEmpty());
93+
Assertions.assertFalse(re4.get(0).get(4).isEmpty());
9494

9595
// test for full not builtin functions with where condition
9696
String where = "test_for_create_function%";
9797
sf = new ShowFunctionsCommand("test", true, where);
98-
List<String> func5 = sf.getFunctions(connectContext);
98+
List<Function> func5 = sf.getFunctions(connectContext);
9999
List<List<String>> re5 = sf.getResultRowSetByFunctions(func5);
100100
Assertions.assertEquals(5, re5.get(0).size());
101-
Assertions.assertEquals("test_for_create_function", re5.get(0).get(0));
102-
Assertions.assertEquals("", re5.get(0).get(1));
103-
Assertions.assertEquals("", re5.get(0).get(2));
104-
Assertions.assertEquals("", re5.get(0).get(3));
105-
Assertions.assertEquals("", re5.get(0).get(4));
101+
Assertions.assertTrue(re5.get(0).get(0).startsWith("test_for_create_function"));
102+
Assertions.assertFalse(re5.get(0).get(1).isEmpty());
103+
Assertions.assertFalse(re5.get(0).get(2).isEmpty());
104+
Assertions.assertFalse(re5.get(0).get(4).isEmpty());
106105
}
107106

108107
@Test

fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/commands/ShowGlobalFunctionsCommandTest.java

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

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

20+
import org.apache.doris.catalog.Function;
2021
import org.apache.doris.common.AnalysisException;
2122
import org.apache.doris.utframe.TestWithFeService;
2223

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

4546
// test for verbose
4647
connectContext.setDatabase("test");
4748
sf = new ShowFunctionsCommand(true, null, true);
48-
List<String> re1 = sf.getFunctions(connectContext);
49+
List<Function> re1 = sf.getFunctions(connectContext);
4950
Assertions.assertEquals(1, re1.size());
50-
Assertions.assertEquals("test_for_create_function", re1.get(0));
51+
Assertions.assertEquals("test_for_create_function", re1.get(0).functionName());
5152

5253
// test for no verbose
5354
sf = new ShowFunctionsCommand(false, null, true);
54-
List<String> re2 = sf.getFunctions(connectContext);
55+
List<Function> re2 = sf.getFunctions(connectContext);
5556
Assertions.assertEquals(1, re2.size());
56-
Assertions.assertEquals("test_for_create_function", re2.get(0));
57+
Assertions.assertEquals("test_for_create_function", re2.get(0).functionName());
5758

5859
// test for like condition
5960
sf = new ShowFunctionsCommand(false, "test_for_create%", true);
60-
List<String> re3 = sf.getFunctions(connectContext);
61+
List<Function> re3 = sf.getFunctions(connectContext);
6162
Assertions.assertEquals(1, re3.size());
62-
Assertions.assertEquals("test_for_create_function", re3.get(0));
63+
Assertions.assertEquals("test_for_create_function", re3.get(0).functionName());
6364
}
6465

6566
@Test
6667
void testGetResultRowSetByFunctions() throws AnalysisException {
6768
connectContext.setDatabase("test");
6869
// test for verbose
6970
ShowFunctionsCommand sf = new ShowFunctionsCommand(true, null, true);
70-
List<String> func3 = sf.getFunctions(connectContext);
71+
List<Function> func3 = sf.getFunctions(connectContext);
7172
List<List<String>> re3 = sf.getResultRowSetByFunctions(func3);
7273
Assertions.assertEquals(1, re3.size());
73-
Assertions.assertEquals("", re3.get(0).get(1));
74-
Assertions.assertEquals("", re3.get(0).get(2));
75-
Assertions.assertEquals("", re3.get(0).get(3));
76-
Assertions.assertEquals("", re3.get(0).get(4));
74+
Assertions.assertEquals(5, re3.get(0).size());
75+
Assertions.assertTrue(re3.get(0).get(0).startsWith("test_for_create_function"));
76+
Assertions.assertFalse(re3.get(0).get(1).isEmpty());
77+
Assertions.assertFalse(re3.get(0).get(2).isEmpty());
78+
Assertions.assertFalse(re3.get(0).get(4).isEmpty());
7779

7880
// test for not verbose
7981
sf = new ShowFunctionsCommand(false, null, true);
80-
List<String> func4 = sf.getFunctions(connectContext);
82+
List<Function> func4 = sf.getFunctions(connectContext);
8183
List<List<String>> re4 = sf.getResultRowSetByFunctions(func4);
8284
Assertions.assertEquals(1, re4.get(0).size());
8385
Assertions.assertEquals("test_for_create_function", re4.get(0).get(0));
8486

8587
// test for like condition
8688
String where = "test_for_create_function%";
8789
sf = new ShowFunctionsCommand(true, where, true);
88-
List<String> func5 = sf.getFunctions(connectContext);
90+
List<Function> func5 = sf.getFunctions(connectContext);
8991
List<List<String>> re5 = sf.getResultRowSetByFunctions(func5);
9092
Assertions.assertEquals(5, re5.get(0).size());
91-
Assertions.assertEquals("test_for_create_function", re5.get(0).get(0));
92-
Assertions.assertEquals("", re5.get(0).get(1));
93-
Assertions.assertEquals("", re5.get(0).get(2));
94-
Assertions.assertEquals("", re5.get(0).get(3));
95-
Assertions.assertEquals("", re5.get(0).get(4));
93+
Assertions.assertTrue(re5.get(0).get(0).startsWith("test_for_create_function"));
94+
Assertions.assertFalse(re5.get(0).get(1).isEmpty());
95+
Assertions.assertFalse(re5.get(0).get(2).isEmpty());
96+
Assertions.assertFalse(re5.get(0).get(4).isEmpty());
9697
}
9798
}

0 commit comments

Comments
 (0)