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

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


The following commit(s) were added to refs/heads/master by this push:
     new 562f572311 [enhancement](UDF) The user defined functions support 
global ('show functions'/'show create') operation (#16973) (#17964)
562f572311 is described below

commit 562f5723113c4f73a2c9e1df872efe16e76f58ba
Author: lexluo09 <[email protected]>
AuthorDate: Fri Mar 24 19:07:38 2023 +0800

    [enhancement](UDF) The user defined functions support global ('show 
functions'/'show create') operation (#16973) (#17964)
    
    1. add the global keyword.
    
    SHOW [GLOBAL] [FULL] [BUILTIN] FUNCTIONS [IN|FROM db] [LIKE 
'function_pattern']
    
    SHOW CREATE GLOBAL FUNCTION function_name(arg_type [, ...]);
    
    2. show the details of the global udf.
---
 .../Show-Statements/SHOW-CREATE-FUNCTION.md        |  15 +-
 .../Show-Statements/SHOW-FUNCTIONS.md              |  41 ++++-
 .../Show-Statements/SHOW-CREATE-FUNCTION.md        |  17 ++-
 .../Show-Statements/SHOW-FUNCTIONS.md              |  41 ++++-
 fe/fe-core/src/main/cup/sql_parser.cup             |   8 +-
 .../doris/analysis/ShowCreateFunctionStmt.java     |  52 +++++--
 .../apache/doris/analysis/ShowFunctionsStmt.java   |  30 ++--
 .../apache/doris/catalog/AggregateFunction.java    |  50 ++++---
 .../org/apache/doris/catalog/AliasFunction.java    |   8 +-
 .../java/org/apache/doris/catalog/Function.java    |  15 +-
 .../org/apache/doris/catalog/FunctionUtil.java     |  39 ++++-
 .../apache/doris/catalog/GlobalFunctionMgr.java    |   2 +
 .../org/apache/doris/catalog/ScalarFunction.java   |  27 ++--
 .../java/org/apache/doris/qe/ShowExecutor.java     | 166 +++++++++++++++------
 .../doris/analysis/ShowCreateFunctionTest.java     |  61 ++++++++
 .../apache/doris/analysis/ShowFunctionsTest.java   |  62 ++++++++
 .../apache/doris/utframe/TestWithFeService.java    |  23 ++-
 17 files changed, 537 insertions(+), 120 deletions(-)

diff --git 
a/docs/en/docs/sql-manual/sql-reference/Show-Statements/SHOW-CREATE-FUNCTION.md 
b/docs/en/docs/sql-manual/sql-reference/Show-Statements/SHOW-CREATE-FUNCTION.md
index cdfd25374a..32a665d02b 100644
--- 
a/docs/en/docs/sql-manual/sql-reference/Show-Statements/SHOW-CREATE-FUNCTION.md
+++ 
b/docs/en/docs/sql-manual/sql-reference/Show-Statements/SHOW-CREATE-FUNCTION.md
@@ -37,14 +37,16 @@ This statement is used to display the creation statement of 
the user-defined fun
 grammar:
 
 ```sql
-SHOW CREATE FUNCTION function_name(arg_type [, ...]) [FROM db_name]];
+SHOW CREATE [GLOBAL] FUNCTION function_name(arg_type [, ...]) [FROM db_name]];
 ````
 
 illustrate:
+1. `global`: The show function is global 
+2. `function_name`: The name of the function to display
+3. `arg_type`: The parameter list of the function to display
+4. If db_name is not specified, the current default db is used
 
-1. `function_name`: The name of the function to display
-2. `arg_type`: The parameter list of the function to display
-3. If db_name is not specified, the current default db is used
+**Note: the "global" keyword is only available after v2.0**
 
 ### Example
 
@@ -53,6 +55,11 @@ illustrate:
     ```sql
     SHOW CREATE FUNCTION my_add(INT, INT)
     ````
+2. Show the creation statement of the specified global function
+
+    ```sql
+    SHOW CREATE GLOBAL FUNCTION my_add(INT, INT)
+    ````
 
 ### Keywords
 
diff --git 
a/docs/en/docs/sql-manual/sql-reference/Show-Statements/SHOW-FUNCTIONS.md 
b/docs/en/docs/sql-manual/sql-reference/Show-Statements/SHOW-FUNCTIONS.md
index 5602ec09ae..90318dd094 100644
--- a/docs/en/docs/sql-manual/sql-reference/Show-Statements/SHOW-FUNCTIONS.md
+++ b/docs/en/docs/sql-manual/sql-reference/Show-Statements/SHOW-FUNCTIONS.md
@@ -42,13 +42,27 @@ grammar
 SHOW [FULL] [BUILTIN] FUNCTIONS [IN|FROM db] [LIKE 'function_pattern']
 ````
 
- Parameters
+Parameters
 
 >`full`: Indicates the detailed information of the display function
 >`builtin`: Indicates the functions provided by the display system
 >`db`: database name to query
 >`function_pattern`: parameter used to filter function names
 
+grammar
+
+```sql
+SHOW GLOBAL [FULL] FUNCTIONS [LIKE 'function_pattern']
+````
+
+Parameters
+
+>`global`: Indicates it means that the show function is a global function
+>`full`: Indicates the detailed information of the display function
+>`function_pattern`: parameter used to filter function names
+
+**Note: the "global" keyword is only available after v2.0**
+
 ### Example
 
 ````sql
@@ -83,6 +97,31 @@ mysql> show builtin functions in testDb like 'year%';
 | years_sub     |
 +---------------+
 2 rows in set (0.00 sec)
+
+mysql> show global full functions\G;
+*************************** 1. row ***************************
+        Signature: decimal(ALL, INT, INT)
+      Return Type: VARCHAR
+    Function Type: Alias
+Intermediate Type: NULL
+       Properties: {"parameter":"col, precision, 
scale","origin_function":"CAST(`col` AS decimal(`precision`, `scale`))"}
+*************************** 2. row ***************************
+        Signature: id_masking(BIGINT)
+      Return Type: VARCHAR
+    Function Type: Alias
+Intermediate Type: NULL
+       Properties: {"parameter":"id","origin_function":"concat(left(`id`, 3), 
`****`, right(`id`, 4))"}
+2 rows in set (0.00 sec)
+    
+mysql> show global functions ;
++---------------+
+| Function Name |
++---------------+
+| decimal       |
+| id_masking    |
++---------------+
+2 rows in set (0.00 sec)    
+    
 ````
 
 ### Keywords
diff --git 
a/docs/zh-CN/docs/sql-manual/sql-reference/Show-Statements/SHOW-CREATE-FUNCTION.md
 
b/docs/zh-CN/docs/sql-manual/sql-reference/Show-Statements/SHOW-CREATE-FUNCTION.md
index c081019218..f6272bbc7b 100644
--- 
a/docs/zh-CN/docs/sql-manual/sql-reference/Show-Statements/SHOW-CREATE-FUNCTION.md
+++ 
b/docs/zh-CN/docs/sql-manual/sql-reference/Show-Statements/SHOW-CREATE-FUNCTION.md
@@ -37,13 +37,16 @@ SHOW CREATE FUNCTION
 语法:
 
 ```sql
-SHOW CREATE FUNCTION function_name(arg_type [, ...]) [FROM db_name]];
+SHOW CREATE [GLOBAL] FUNCTION function_name(arg_type [, ...]) [FROM db_name]];
 ```
 
 说明:
-          1. `function_name`: 要展示的函数名称
-          2. `arg_type`: 要展示的函数的参数列表
-          3. 如果不指定 db_name,使用当前默认 db
+          1. `global`: 要展示的是全局函数
+          2. `function_name`: 要展示的函数名称
+          3. `arg_type`: 要展示的函数的参数列表
+          4. 如果不指定 db_name,使用当前默认 db
+
+**注意: "global"关键字在v2.0版本及以后才可用**
 
 ### Example
 
@@ -53,6 +56,12 @@ SHOW CREATE FUNCTION function_name(arg_type [, ...]) [FROM 
db_name]];
     SHOW CREATE FUNCTION my_add(INT, INT)
     ```
 
+2. 展示指定的全局函数的创建语句
+
+    ```sql
+    SHOW CREATE GLOBAL FUNCTION my_add(INT, INT)
+    ```
+
 ### Keywords
 
     SHOW, CREATE, FUNCTION
diff --git 
a/docs/zh-CN/docs/sql-manual/sql-reference/Show-Statements/SHOW-FUNCTIONS.md 
b/docs/zh-CN/docs/sql-manual/sql-reference/Show-Statements/SHOW-FUNCTIONS.md
index 28c0525af5..50d226bc72 100644
--- a/docs/zh-CN/docs/sql-manual/sql-reference/Show-Statements/SHOW-FUNCTIONS.md
+++ b/docs/zh-CN/docs/sql-manual/sql-reference/Show-Statements/SHOW-FUNCTIONS.md
@@ -42,13 +42,27 @@ SHOW FUNCTIONS
 SHOW [FULL] [BUILTIN] FUNCTIONS [IN|FROM db] [LIKE 'function_pattern']
 ```
 
- Parameters
+Parameters
 
 >`full`:表示显示函数的详细信息
 >`builtin`:表示显示系统提供的函数
 >`db`: 要查询的数据库名字
 >`function_pattern`: 用来过滤函数名称的参数
 
+语法
+
+```sql
+SHOW GLOBAL [FULL] FUNCTIONS [LIKE 'function_pattern']
+```
+
+Parameters
+
+>`global`:表示要展示的是全局函数
+>`full`:表示显示函数的详细信息
+>`function_pattern`: 用来过滤函数名称的参数
+
+**注意: "global"关键字在v2.0版本及以后才可用**
+
 ### Example
 
 ```sql
@@ -83,6 +97,31 @@ mysql> show builtin functions in testDb like 'year%';
 | years_sub     |
 +---------------+
 2 rows in set (0.00 sec)
+    
+mysql> show global full functions\G;
+*************************** 1. row ***************************
+        Signature: decimal(ALL, INT, INT)
+      Return Type: VARCHAR
+    Function Type: Alias
+Intermediate Type: NULL
+       Properties: {"parameter":"col, precision, 
scale","origin_function":"CAST(`col` AS decimal(`precision`, `scale`))"}
+*************************** 2. row ***************************
+        Signature: id_masking(BIGINT)
+      Return Type: VARCHAR
+    Function Type: Alias
+Intermediate Type: NULL
+       Properties: {"parameter":"id","origin_function":"concat(left(`id`, 3), 
`****`, right(`id`, 4))"}
+2 rows in set (0.00 sec)
+    
+mysql> show global functions ;
++---------------+
+| Function Name |
++---------------+
+| decimal       |
+| id_masking    |
++---------------+
+2 rows in set (0.00 sec)
+
 ```
 
 ### Keywords
diff --git a/fe/fe-core/src/main/cup/sql_parser.cup 
b/fe/fe-core/src/main/cup/sql_parser.cup
index 3936c9c56a..3faf2ff64d 100644
--- a/fe/fe-core/src/main/cup/sql_parser.cup
+++ b/fe/fe-core/src/main/cup/sql_parser.cup
@@ -3641,9 +3641,9 @@ show_param ::=
             RESULT = new ShowCreateCatalogStmt(catalogName);
         :}
     /* Create Function */
-    | KW_CREATE KW_FUNCTION function_name:functionName LPAREN 
func_args_def:args RPAREN opt_db:dbName
+    | KW_CREATE opt_var_type:type KW_FUNCTION function_name:functionName 
LPAREN func_args_def:args RPAREN opt_db:dbName
     {:
-        RESULT = new ShowCreateFunctionStmt(dbName, functionName, args);
+        RESULT = new ShowCreateFunctionStmt(type, dbName, functionName, args);
     :}
     /* Cluster */
     | KW_CLUSTERS
@@ -3860,6 +3860,10 @@ show_param ::=
     {:
         RESULT = new ShowFunctionsStmt(dbName, isBuiltin, parser.isVerbose, 
parser.wild, parser.where);
     :}
+    | KW_GLOBAL opt_full KW_FUNCTIONS opt_wild_where
+    {:
+        RESULT = new ShowFunctionsStmt(parser.isVerbose, parser.wild, 
parser.where);
+    :}
     | KW_TYPECAST opt_db:dbName
     {:
         RESULT = new ShowTypeCastStmt(dbName, parser.where);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowCreateFunctionStmt.java
 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowCreateFunctionStmt.java
index 9b78f44556..3e6a5b6888 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowCreateFunctionStmt.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowCreateFunctionStmt.java
@@ -20,8 +20,10 @@ package org.apache.doris.analysis;
 import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.FunctionSearchDesc;
+import org.apache.doris.catalog.FunctionUtil;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.cluster.ClusterNamespace;
+import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
 import org.apache.doris.common.UserException;
@@ -40,11 +42,13 @@ public class ShowCreateFunctionStmt extends ShowStmt {
     private String dbName;
     private final FunctionName functionName;
     private final FunctionArgsDef argsDef;
+    private SetType type = SetType.DEFAULT;
 
     // set after analyzed
     private FunctionSearchDesc function;
 
-    public ShowCreateFunctionStmt(String dbName, FunctionName functionName, 
FunctionArgsDef argsDef) {
+    public ShowCreateFunctionStmt(SetType type, String dbName, FunctionName 
functionName, FunctionArgsDef argsDef) {
+        this.type = type;
         this.dbName = dbName;
         this.functionName = functionName;
         this.argsDef = argsDef;
@@ -66,20 +70,17 @@ public class ShowCreateFunctionStmt extends ShowStmt {
     public void analyze(Analyzer analyzer) throws UserException {
         super.analyze(analyzer);
 
-        if (Strings.isNullOrEmpty(dbName)) {
-            dbName = analyzer.getDefaultDb();
-            if (Strings.isNullOrEmpty(dbName)) {
-                ErrorReport.reportAnalysisException(ErrorCode.ERR_NO_DB_ERROR);
-            }
-        } else {
-            dbName = ClusterNamespace.getFullName(getClusterName(), dbName);
+        // the global function does not need to fetch/check the dbName
+        if (!FunctionUtil.isGlobalFunction(this.type)) {
+            dbName = FunctionUtil.reAcquireDbName(analyzer, dbName, 
getClusterName());
         }
 
         // analyze function name
-        functionName.analyze(analyzer, SetType.DEFAULT);
+        functionName.analyze(analyzer, this.type);
 
-        // check operation privilege
-        if 
(!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(), 
dbName, PrivPredicate.SHOW)) {
+        // check operation privilege , except global function
+        if (!FunctionUtil.isGlobalFunction(this.type) && 
!Env.getCurrentEnv().getAccessManager()
+                .checkDbPriv(ConnectContext.get(), dbName, 
PrivPredicate.SHOW)) {
             ErrorReport.reportAnalysisException(
                     ErrorCode.ERR_DBACCESS_DENIED_ERROR, 
ConnectContext.get().getQualifiedUser(), dbName);
         }
@@ -88,11 +89,32 @@ public class ShowCreateFunctionStmt extends ShowStmt {
         function = new FunctionSearchDesc(functionName, argsDef.getArgTypes(), 
argsDef.isVariadic());
     }
 
+
+    /***
+     * reAcquire dbName and check "No database selected"
+     * @param analyzer
+     * @throws AnalysisException
+     */
+    private void reAcquireDbName(Analyzer analyzer) throws AnalysisException {
+        if (Strings.isNullOrEmpty(dbName)) {
+            dbName = analyzer.getDefaultDb();
+            if (Strings.isNullOrEmpty(dbName)) {
+                ErrorReport.reportAnalysisException(ErrorCode.ERR_NO_DB_ERROR);
+            }
+        } else {
+            dbName = ClusterNamespace.getFullName(getClusterName(), dbName);
+        }
+    }
+
     @Override
     public String toSql() {
         StringBuilder stringBuilder = new StringBuilder();
-        stringBuilder.append("SHOW CREATE FUNCTION 
").append(functionName).append(argsDef)
-                .append(" IN ").append(dbName);
+        if (FunctionUtil.isGlobalFunction(this.type)) {
+            stringBuilder.append("SHOW CREATE GLOBAL FUNCTION 
").append(functionName).append(argsDef);
+        } else {
+            stringBuilder.append("SHOW CREATE FUNCTION 
").append(functionName).append(argsDef)
+                    .append(" IN ").append(dbName);
+        }
         return stringBuilder.toString();
     }
 
@@ -105,4 +127,8 @@ public class ShowCreateFunctionStmt extends ShowStmt {
     public ShowResultSetMetaData getMetaData() {
         return META_DATA;
     }
+
+    public SetType getType() {
+        return type;
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowFunctionsStmt.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowFunctionsStmt.java
index dee678dd37..0c2416d2c0 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowFunctionsStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowFunctionsStmt.java
@@ -19,8 +19,8 @@ package org.apache.doris.analysis;
 
 import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.Env;
+import org.apache.doris.catalog.FunctionUtil;
 import org.apache.doris.catalog.ScalarType;
-import org.apache.doris.cluster.ClusterNamespace;
 import org.apache.doris.common.AnalysisException;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
@@ -51,6 +51,8 @@ public class ShowFunctionsStmt extends ShowStmt {
 
     private Expr expr;
 
+    private SetType type = SetType.DEFAULT;
+
     public ShowFunctionsStmt(String dbName, boolean isBuiltin, boolean 
isVerbose, String wild,
             Expr expr) {
         this.dbName = dbName;
@@ -60,6 +62,13 @@ public class ShowFunctionsStmt extends ShowStmt {
         this.expr = expr;
     }
 
+    public ShowFunctionsStmt(boolean isVerbose, String wild, Expr expr) {
+        this.type = SetType.GLOBAL;
+        this.isVerbose = isVerbose;
+        this.wild = wild;
+        this.expr = expr;
+    }
+
     public String getDbName() {
         return dbName;
     }
@@ -80,6 +89,10 @@ public class ShowFunctionsStmt extends ShowStmt {
         return expr;
     }
 
+    public SetType getType() {
+        return type;
+    }
+
     public boolean like(String str) {
         str = str.toLowerCase();
         return str.matches(wild.replace(".", "\\.").replace("?", 
".").replace("%", ".*").toLowerCase());
@@ -89,16 +102,12 @@ public class ShowFunctionsStmt extends ShowStmt {
     public void analyze(Analyzer analyzer) throws UserException {
         super.analyze(analyzer);
 
-        if (Strings.isNullOrEmpty(dbName)) {
-            dbName = analyzer.getDefaultDb();
-            if (Strings.isNullOrEmpty(dbName)) {
-                ErrorReport.reportAnalysisException(ErrorCode.ERR_NO_DB_ERROR);
-            }
-        } else {
-            dbName = ClusterNamespace.getFullName(getClusterName(), dbName);
+        if (!FunctionUtil.isGlobalFunction(this.type)) {
+            this.dbName = FunctionUtil.reAcquireDbName(analyzer, dbName, 
getClusterName());
         }
 
-        if 
(!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(), 
dbName, PrivPredicate.SHOW)) {
+        if (!FunctionUtil.isGlobalFunction(this.type) && 
!Env.getCurrentEnv().getAccessManager()
+                .checkDbPriv(ConnectContext.get(), dbName, 
PrivPredicate.SHOW)) {
             ErrorReport.reportAnalysisException(
                     ErrorCode.ERR_DBACCESS_DENIED_ERROR, 
ConnectContext.get().getQualifiedUser(), dbName);
         }
@@ -118,6 +127,9 @@ public class ShowFunctionsStmt extends ShowStmt {
     public String toSql() {
         StringBuilder sb = new StringBuilder();
         sb.append("SHOW ");
+        if (FunctionUtil.isGlobalFunction(this.type)) {
+            sb.append("GLOBAL ");
+        }
         if (isVerbose) {
             sb.append("FULL ");
         }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/AggregateFunction.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/AggregateFunction.java
index 885a85866a..324b043541 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/AggregateFunction.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/AggregateFunction.java
@@ -102,7 +102,7 @@ public class AggregateFunction extends Function {
     // empty input in BE).
     private boolean returnsNonNullOnEmpty;
 
-    //use for java-udaf to point the class of user define
+    // use for java-udaf to point the class of user define
     private String symbolName;
 
     // only used for serialization
@@ -154,28 +154,28 @@ public class AggregateFunction extends Function {
     }
 
     public AggregateFunction(FunctionName fnName, List<Type> argTypes,
-                             Type retType, Type intermediateType,
-                             URI location, String updateFnSymbol, String 
initFnSymbol,
-                             String serializeFnSymbol, String mergeFnSymbol, 
String getValueFnSymbol,
-                             String removeFnSymbol, String finalizeFnSymbol, 
boolean vectorized) {
+            Type retType, Type intermediateType,
+            URI location, String updateFnSymbol, String initFnSymbol,
+            String serializeFnSymbol, String mergeFnSymbol, String 
getValueFnSymbol,
+            String removeFnSymbol, String finalizeFnSymbol, boolean 
vectorized) {
         this(fnName, argTypes, retType, intermediateType, false, location,
                 updateFnSymbol, initFnSymbol, serializeFnSymbol,
                 mergeFnSymbol, getValueFnSymbol, removeFnSymbol, 
finalizeFnSymbol, vectorized);
     }
 
     public AggregateFunction(FunctionName fnName, List<Type> argTypes,
-                             Type retType, Type intermediateType, boolean 
hasVarArgs,
-                             URI location, String updateFnSymbol, String 
initFnSymbol,
-                             String serializeFnSymbol, String mergeFnSymbol, 
String getValueFnSymbol,
-                             String removeFnSymbol, String finalizeFnSymbol, 
boolean vectorized) {
+            Type retType, Type intermediateType, boolean hasVarArgs,
+            URI location, String updateFnSymbol, String initFnSymbol,
+            String serializeFnSymbol, String mergeFnSymbol, String 
getValueFnSymbol,
+            String removeFnSymbol, String finalizeFnSymbol, boolean 
vectorized) {
         // only `count` is always not nullable, other aggregate function is 
always nullable
         super(fnName, argTypes, retType, hasVarArgs, vectorized,
                 
AggregateFunction.NOT_NULLABLE_AGGREGATE_FUNCTION_NAME_SET.contains(fnName.getFunction())
                         ? NullableMode.ALWAYS_NOT_NULLABLE :
-                
AggregateFunction.ALWAYS_NULLABLE_AGGREGATE_FUNCTION_NAME_SET.contains(fnName.getFunction())
-                        ? NullableMode.ALWAYS_NULLABLE :
-                
AggregateFunction.CUSTOM_AGGREGATE_FUNCTION_NAME_SET.contains(fnName.getFunction())
-                        ? NullableMode.CUSTOM : 
NullableMode.DEPEND_ON_ARGUMENT);
+                        
AggregateFunction.ALWAYS_NULLABLE_AGGREGATE_FUNCTION_NAME_SET.contains(fnName.getFunction())
+                                ? NullableMode.ALWAYS_NULLABLE :
+                                
AggregateFunction.CUSTOM_AGGREGATE_FUNCTION_NAME_SET.contains(fnName.getFunction())
+                                        ? NullableMode.CUSTOM : 
NullableMode.DEPEND_ON_ARGUMENT);
         setLocation(location);
         this.intermediateType = (intermediateType.equals(retType)) ? null : 
intermediateType;
         this.updateFnSymbol = updateFnSymbol;
@@ -330,10 +330,10 @@ public class AggregateFunction extends Function {
 
     // Used to create UDAF
     public AggregateFunction(FunctionName fnName, Type[] argTypes,
-                             Type retType, boolean hasVarArgs, Type 
intermediateType, URI location,
-                             String initFnSymbol, String updateFnSymbol, 
String mergeFnSymbol,
-                             String serializeFnSymbol, String finalizeFnSymbol,
-                             String getValueFnSymbol, String removeFnSymbol) {
+            Type retType, boolean hasVarArgs, Type intermediateType, URI 
location,
+            String initFnSymbol, String updateFnSymbol, String mergeFnSymbol,
+            String serializeFnSymbol, String finalizeFnSymbol,
+            String getValueFnSymbol, String removeFnSymbol) {
         super(fnName, Arrays.asList(argTypes), retType, hasVarArgs);
         this.setLocation(location);
         this.intermediateType = (intermediateType.equals(retType)) ? null : 
intermediateType;
@@ -559,7 +559,13 @@ public class AggregateFunction extends Function {
 
     @Override
     public String toSql(boolean ifNotExists) {
-        StringBuilder sb = new StringBuilder("CREATE AGGREGATE FUNCTION ");
+        StringBuilder sb = new StringBuilder("CREATE ");
+
+        if (this.isGlobal) {
+            sb.append("GLOBAL ");
+        }
+        sb.append("AGGREGATE FUNCTION ");
+
         if (ifNotExists) {
             sb.append("IF NOT EXISTS ");
         }
@@ -610,13 +616,13 @@ public class AggregateFunction extends Function {
             aggFn.setSerializeFnSymbol(serializeFnSymbol);
         }
         aggFn.setMergeFnSymbol(mergeFnSymbol);
-        if (getValueFnSymbol  != null) {
+        if (getValueFnSymbol != null) {
             aggFn.setGetValueFnSymbol(getValueFnSymbol);
         }
-        if (removeFnSymbol  != null) {
+        if (removeFnSymbol != null) {
             aggFn.setRemoveFnSymbol(removeFnSymbol);
         }
-        if (finalizeFnSymbol  != null) {
+        if (finalizeFnSymbol != null) {
             aggFn.setFinalizeFnSymbol(finalizeFnSymbol);
         }
         if (symbolName != null) {
@@ -691,7 +697,7 @@ public class AggregateFunction extends Function {
         properties.put(CreateFunctionStmt.SERIALIZE_KEY, serializeFnSymbol);
         properties.put(CreateFunctionStmt.FINALIZE_KEY, finalizeFnSymbol);
 
-        //getValueFn and removeFn may be null if not analytic agg
+        // getValueFn and removeFn may be null if not analytic agg
         if (getValueFnSymbol != null) {
             properties.put(CreateFunctionStmt.GET_VALUE_KEY, getValueFnSymbol);
         }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/AliasFunction.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/AliasFunction.java
index ed70173e7a..76d84bc026 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/AliasFunction.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/AliasFunction.java
@@ -234,7 +234,13 @@ public class AliasFunction extends Function {
     @Override
     public String toSql(boolean ifNotExists) {
         setSlotRefLabel(originFunction);
-        StringBuilder sb = new StringBuilder("CREATE ALIAS FUNCTION ");
+        StringBuilder sb = new StringBuilder("CREATE ");
+
+        if (this.isGlobal) {
+            sb.append("GLOBAL ");
+        }
+        sb.append("ALIAS FUNCTION ");
+
         if (ifNotExists) {
             sb.append("IF NOT EXISTS ");
         }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java
index d28448730b..56fe4b4222 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java
@@ -126,6 +126,9 @@ public class Function implements Writable {
     // library's checksum to make sure all backends use one library to serve 
user's request
     protected String checksum = "";
 
+    // If true, this function is global function
+    protected boolean isGlobal = false;
+
     // Only used for serialization
     protected Function() {
     }
@@ -144,7 +147,7 @@ public class Function implements Writable {
     }
 
     public Function(long id, FunctionName name, List<Type> argTypes, Type 
retType, boolean hasVarArgs,
-                    TFunctionBinaryType binaryType, boolean userVisible, 
boolean vectorized, NullableMode mode) {
+            TFunctionBinaryType binaryType, boolean userVisible, boolean 
vectorized, NullableMode mode) {
         this.id = id;
         this.name = name;
         this.hasVarArgs = hasVarArgs;
@@ -161,7 +164,7 @@ public class Function implements Writable {
     }
 
     public Function(long id, FunctionName name, List<Type> argTypes, Type 
retType,
-                    boolean hasVarArgs, boolean vectorized, NullableMode mode) 
{
+            boolean hasVarArgs, boolean vectorized, NullableMode mode) {
         this(id, name, argTypes, retType, hasVarArgs, 
TFunctionBinaryType.BUILTIN, true, vectorized, mode);
     }
 
@@ -274,6 +277,14 @@ public class Function implements Writable {
         return checksum;
     }
 
+    public boolean isGlobal() {
+        return isGlobal;
+    }
+
+    public void setGlobal(boolean global) {
+        isGlobal = global;
+    }
+
     // TODO(cmy): Currently we judge whether it is UDF by wheter the 
'location' is set.
     // Maybe we should use a separate variable to identify,
     // but additional variables need to modify the persistence information.
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionUtil.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionUtil.java
index 25155a8599..641d30c1a5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionUtil.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionUtil.java
@@ -17,10 +17,16 @@
 
 package org.apache.doris.catalog;
 
+import org.apache.doris.analysis.Analyzer;
+import org.apache.doris.analysis.SetType;
+import org.apache.doris.cluster.ClusterNamespace;
 import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.ErrorCode;
+import org.apache.doris.common.ErrorReport;
 import org.apache.doris.common.UserException;
 import org.apache.doris.common.io.Text;
 
+import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import org.apache.logging.log4j.LogManager;
@@ -128,7 +134,7 @@ public class FunctionUtil {
         String functionName = function.getName().getFunction();
         List<Function> existFuncs = name2Function.get(functionName);
         if (existFuncs == null) {
-            throw new AnalysisException("Unknown function, function=" + 
function.toString());
+            throw new AnalysisException("Unknown function, function=" + 
function);
         }
 
         for (Function existFunc : existFuncs) {
@@ -136,7 +142,7 @@ public class FunctionUtil {
                 return existFunc;
             }
         }
-        throw new AnalysisException("Unknown function, function=" + 
function.toString());
+        throw new AnalysisException("Unknown function, function=" + function);
     }
 
     public static List<Function> getFunctions(ConcurrentMap<String, 
ImmutableList<Function>> name2Function) {
@@ -182,4 +188,33 @@ public class FunctionUtil {
             name2Function.put(name, builder.build());
         }
     }
+
+    /***
+     * is global function
+     * @return
+     */
+    public static boolean isGlobalFunction(SetType type) {
+        return SetType.GLOBAL == type;
+    }
+
+    /***
+     * reAcquire dbName and check "No database selected"
+     * @param analyzer
+     * @param dbName
+     * @param clusterName
+     * @return
+     * @throws AnalysisException
+     */
+    public static String reAcquireDbName(Analyzer analyzer, String dbName, 
String clusterName)
+            throws AnalysisException {
+        if (Strings.isNullOrEmpty(dbName)) {
+            dbName = analyzer.getDefaultDb();
+            if (Strings.isNullOrEmpty(dbName)) {
+                ErrorReport.reportAnalysisException(ErrorCode.ERR_NO_DB_ERROR);
+            }
+        } else {
+            dbName = ClusterNamespace.getFullName(clusterName, dbName);
+        }
+        return dbName;
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/GlobalFunctionMgr.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/GlobalFunctionMgr.java
index 02560a26fc..a23306d93d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/GlobalFunctionMgr.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/GlobalFunctionMgr.java
@@ -58,6 +58,7 @@ public class GlobalFunctionMgr extends MetaObject {
     }
 
     public synchronized void addFunction(Function function, boolean 
ifNotExists) throws UserException {
+        function.setGlobal(true);
         function.checkWritable();
         if (FunctionUtil.addFunctionImpl(function, ifNotExists, false, 
name2Function)) {
             Env.getCurrentEnv().getEditLog().logAddGlobalFunction(function);
@@ -67,6 +68,7 @@ public class GlobalFunctionMgr extends MetaObject {
 
     public synchronized void replayAddFunction(Function function) {
         try {
+            function.setGlobal(true);
             FunctionUtil.addFunctionImpl(function, false, true, name2Function);
         } catch (UserException e) {
             throw new RuntimeException(e);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/ScalarFunction.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/ScalarFunction.java
index f5c11fd4c4..6495b8ae70 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/ScalarFunction.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/ScalarFunction.java
@@ -60,7 +60,7 @@ public class ScalarFunction extends Function {
     }
 
     public ScalarFunction(FunctionName fnName, List<Type> argTypes, Type 
retType, boolean hasVarArgs,
-             boolean userVisible) {
+            boolean userVisible) {
         this(fnName, argTypes, retType, hasVarArgs, 
TFunctionBinaryType.BUILTIN, userVisible, false);
     }
 
@@ -70,12 +70,14 @@ public class ScalarFunction extends Function {
     }
 
     public ScalarFunction(FunctionName fnName, List<Type> argTypes, Type 
retType, boolean hasVarArgs,
-                          TFunctionBinaryType binaryType, boolean userVisible, 
boolean isVec) {
+            TFunctionBinaryType binaryType, boolean userVisible, boolean 
isVec) {
         super(0, fnName, argTypes, retType, hasVarArgs, binaryType, 
userVisible, isVec,
                 NullableMode.DEPEND_ON_ARGUMENT);
     }
 
-    /** nerieds custom scalar function */
+    /**
+     * nerieds custom scalar function
+     */
     public ScalarFunction(FunctionName fnName, List<Type> argTypes, Type 
retType, boolean hasVarArgs, String symbolName,
             TFunctionBinaryType binaryType, boolean userVisible, boolean 
isVec, NullableMode nullableMode) {
         super(0, fnName, argTypes, retType, hasVarArgs, binaryType, 
userVisible, isVec, nullableMode);
@@ -83,8 +85,8 @@ public class ScalarFunction extends Function {
     }
 
     public ScalarFunction(FunctionName fnName, List<Type> argTypes,
-                          Type retType, URI location, String symbolName, 
String initFnSymbol,
-                          String closeFnSymbol) {
+            Type retType, URI location, String symbolName, String initFnSymbol,
+            String closeFnSymbol) {
         super(fnName, argTypes, retType, false);
         setLocation(location);
         setSymbolName(symbolName);
@@ -97,9 +99,9 @@ public class ScalarFunction extends Function {
      * into one call.
      */
     public static ScalarFunction createBuiltin(String name, Type retType,
-                                               ArrayList<Type> argTypes, 
boolean hasVarArgs,
-                                               String symbol, String 
prepareFnSymbol, String closeFnSymbol,
-                                               boolean userVisible) {
+            ArrayList<Type> argTypes, boolean hasVarArgs,
+            String symbol, String prepareFnSymbol, String closeFnSymbol,
+            boolean userVisible) {
         return createBuiltin(name, retType, NullableMode.DEPEND_ON_ARGUMENT, 
argTypes, hasVarArgs,
                 symbol, prepareFnSymbol, closeFnSymbol, userVisible);
     }
@@ -309,7 +311,7 @@ public class ScalarFunction extends Function {
         return createVecBuiltin(name, null, symbol, null, argTypes, false, 
retType, false, nullableMode);
     }
 
-    //TODO: This method should not be here, move to other place in the future
+    // TODO: This method should not be here, move to other place in the future
     public static ScalarFunction createVecBuiltin(String name, String 
prepareFnSymbolBName, String symbol,
             String closeFnSymbolName, ArrayList<Type> argTypes, boolean 
hasVarArgs, Type retType, boolean userVisible,
             NullableMode nullableMode) {
@@ -379,7 +381,12 @@ public class ScalarFunction extends Function {
 
     @Override
     public String toSql(boolean ifNotExists) {
-        StringBuilder sb = new StringBuilder("CREATE FUNCTION ");
+        StringBuilder sb = new StringBuilder("CREATE ");
+        if (this.isGlobal) {
+            sb.append("GLOBAL ");
+        }
+        sb.append("FUNCTION ");
+
         if (ifNotExists) {
             sb.append("IF NOT EXISTS ");
         }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java
index 9aa7a0de5b..7f61e04a16 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ShowExecutor.java
@@ -111,6 +111,7 @@ import org.apache.doris.catalog.DynamicPartitionProperty;
 import org.apache.doris.catalog.EncryptKey;
 import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.Function;
+import org.apache.doris.catalog.FunctionUtil;
 import org.apache.doris.catalog.HiveMetaStoreClientHelper;
 import org.apache.doris.catalog.Index;
 import org.apache.doris.catalog.MaterializedIndex;
@@ -217,6 +218,7 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
@@ -290,7 +292,7 @@ public class ShowExecutor {
             handleShowCreateRoutineLoad();
         } else if (stmt instanceof ShowCreateLoadStmt) {
             handleShowCreateLoad();
-        }  else if (stmt instanceof ShowDeleteStmt) {
+        } else if (stmt instanceof ShowDeleteStmt) {
             handleShowDelete();
         } else if (stmt instanceof ShowAlterStmt) {
             handleShowAlter();
@@ -457,43 +459,8 @@ public class ShowExecutor {
     // Handle show functions
     private void handleShowFunctions() throws AnalysisException {
         ShowFunctionsStmt showStmt = (ShowFunctionsStmt) stmt;
-        Util.prohibitExternalCatalog(ctx.getDefaultCatalog(), 
stmt.getClass().getSimpleName());
-        DatabaseIf db = 
ctx.getCurrentCatalog().getDbOrAnalysisException(showStmt.getDbName());
-
-        List<List<String>> resultRowSet = Lists.newArrayList();
-        if (db instanceof Database) {
-            List<Function> functions = showStmt.getIsBuiltin() ? 
ctx.getEnv().getBuiltinFunctions()
-                    : ((Database) db).getFunctions();
-
-            List<List<Comparable>> rowSet = Lists.newArrayList();
-            for (Function function : functions) {
-                List<Comparable> row = 
function.getInfo(showStmt.getIsVerbose());
-                // like predicate
-                if (showStmt.getWild() == null || 
showStmt.like(function.functionName())) {
-                    rowSet.add(row);
-                }
-            }
 
-            // sort function rows by first column asc
-            ListComparator<List<Comparable>> comparator = null;
-            OrderByPair orderByPair = new OrderByPair(0, false);
-            comparator = new ListComparator<>(orderByPair);
-            Collections.sort(rowSet, comparator);
-
-            Set<String> functionNameSet = new HashSet<>();
-            for (List<Comparable> row : rowSet) {
-                List<String> resultRow = Lists.newArrayList();
-                // if not verbose, remove duplicate function name
-                if (functionNameSet.contains(row.get(0).toString())) {
-                    continue;
-                }
-                for (Comparable column : row) {
-                    resultRow.add(column.toString());
-                }
-                resultRowSet.add(resultRow);
-                functionNameSet.add(resultRow.get(0));
-            }
-        }
+        List<List<String>> resultRowSet = getResultRowSet(showStmt);
 
         // Only success
         ShowResultSetMetaData showMetaData = showStmt.getIsVerbose() ? 
showStmt.getMetaData() :
@@ -502,22 +469,125 @@ public class ShowExecutor {
         resultSet = new ShowResultSet(showMetaData, resultRowSet);
     }
 
-    // Handle show create function
-    private void handleShowCreateFunction() throws AnalysisException {
-        ShowCreateFunctionStmt showCreateFunctionStmt = 
(ShowCreateFunctionStmt) stmt;
-        Util.prohibitExternalCatalog(ctx.getDefaultCatalog(), 
stmt.getClass().getSimpleName());
-        DatabaseIf db = 
ctx.getCurrentCatalog().getDbOrAnalysisException(showCreateFunctionStmt.getDbName());
+    /***
+     * get resultRowSet by showFunctionsStmt
+     * @param showStmt
+     * @return
+     * @throws AnalysisException
+     */
+    private List<List<String>> getResultRowSet(ShowFunctionsStmt showStmt) 
throws AnalysisException {
+        List<Function> functions = getFunctions(showStmt);
+        return getResultRowSetByFunctions(showStmt, functions);
+    }
+
+    /***
+     * get functions by showFunctionsStmt
+     * @param showStmt
+     * @return
+     * @throws AnalysisException
+     */
+    private List<Function> getFunctions(ShowFunctionsStmt showStmt) throws 
AnalysisException {
+        List<Function> functions = Lists.newArrayList();
+        if (!FunctionUtil.isGlobalFunction(showStmt.getType())) {
+            Util.prohibitExternalCatalog(ctx.getDefaultCatalog(), 
stmt.getClass().getSimpleName());
+            DatabaseIf db = 
ctx.getCurrentCatalog().getDbOrAnalysisException(showStmt.getDbName());
+            if (db instanceof Database) {
+                functions = showStmt.getIsBuiltin() ? 
ctx.getEnv().getBuiltinFunctions()
+                        : ((Database) db).getFunctions();
+            }
+        } else {
+            functions = 
Env.getCurrentEnv().getGlobalFunctionMgr().getFunctions();
+        }
+        return functions;
+    }
+
+    /***
+     * get resultRowSet By showFunctionsStmt and functions
+     * @param showStmt
+     * @param functions
+     * @return
+     */
+    private List<List<String>> getResultRowSetByFunctions(ShowFunctionsStmt 
showStmt, List<Function> functions) {
         List<List<String>> resultRowSet = Lists.newArrayList();
-        if (db instanceof Database) {
-            Function function = ((Database) 
db).getFunction(showCreateFunctionStmt.getFunction());
+        List<List<Comparable>> rowSet = Lists.newArrayList();
+        for (Function function : functions) {
+            List<Comparable> row = function.getInfo(showStmt.getIsVerbose());
+            // like predicate
+            if (showStmt.getWild() == null || 
showStmt.like(function.functionName())) {
+                rowSet.add(row);
+            }
+        }
+
+        // sort function rows by first column asc
+        ListComparator<List<Comparable>> comparator = null;
+        OrderByPair orderByPair = new OrderByPair(0, false);
+        comparator = new ListComparator<>(orderByPair);
+        Collections.sort(rowSet, comparator);
+
+        Set<String> functionNameSet = new HashSet<>();
+        for (List<Comparable> row : rowSet) {
             List<String> resultRow = Lists.newArrayList();
-            resultRow.add(function.signatureString());
-            resultRow.add(function.toSql(false));
+            // if not verbose, remove duplicate function name
+            if (functionNameSet.contains(row.get(0).toString())) {
+                continue;
+            }
+            for (Comparable column : row) {
+                resultRow.add(column.toString());
+            }
             resultRowSet.add(resultRow);
+            functionNameSet.add(resultRow.get(0));
         }
+        return resultRowSet;
+    }
+
+    // Handle show create function
+    private void handleShowCreateFunction() throws AnalysisException {
+        ShowCreateFunctionStmt showCreateFunctionStmt = 
(ShowCreateFunctionStmt) stmt;
+        List<List<String>> resultRowSet = 
getResultRowSet(showCreateFunctionStmt);
         resultSet = new ShowResultSet(showCreateFunctionStmt.getMetaData(), 
resultRowSet);
     }
 
+    /***
+     * get resultRowSet by showCreateFunctionStmt
+     * @param showCreateFunctionStmt
+     * @return
+     * @throws AnalysisException
+     */
+    private List<List<String>> getResultRowSet(ShowCreateFunctionStmt 
showCreateFunctionStmt) throws AnalysisException {
+        Function function = getFunction(showCreateFunctionStmt);
+        return getResultRowSetByFunction(function);
+    }
+
+    private Function getFunction(ShowCreateFunctionStmt 
showCreateFunctionStmt) throws AnalysisException {
+        if (!FunctionUtil.isGlobalFunction(showCreateFunctionStmt.getType())) {
+            Util.prohibitExternalCatalog(ctx.getDefaultCatalog(), 
stmt.getClass().getSimpleName());
+            DatabaseIf db = 
ctx.getCurrentCatalog().getDbOrAnalysisException(showCreateFunctionStmt.getDbName());
+            if (db instanceof Database) {
+                return ((Database) 
db).getFunction(showCreateFunctionStmt.getFunction());
+            }
+        } else {
+            return 
Env.getCurrentEnv().getGlobalFunctionMgr().getFunction(showCreateFunctionStmt.getFunction());
+        }
+        return null;
+    }
+
+    /***
+     * get resultRowSet by function
+     * @param function
+     * @return
+     */
+    private List<List<String>> getResultRowSetByFunction(Function function) {
+        if (Objects.isNull(function)) {
+            return Lists.newArrayList();
+        }
+        List<List<String>> resultRowSet = Lists.newArrayList();
+        List<String> resultRow = Lists.newArrayList();
+        resultRow.add(function.signatureString());
+        resultRow.add(function.toSql(false));
+        resultRowSet.add(resultRow);
+        return resultRowSet;
+    }
+
     // Handle show encryptkeys
     private void handleShowEncryptKeys() throws AnalysisException {
         ShowEncryptKeysStmt showStmt = (ShowEncryptKeysStmt) stmt;
@@ -996,7 +1066,7 @@ public class ShowExecutor {
         resultSet = new ShowResultSet(showStmt.getMetaData(), rows);
     }
 
-    //Show view statement.
+    // Show view statement.
     private void handleShowView() {
         ShowViewStmt showStmt = (ShowViewStmt) stmt;
         List<List<String>> rows = Lists.newArrayList();
@@ -1419,7 +1489,7 @@ public class ShowExecutor {
         ProcNodeInterface procNodeI = showStmt.getNode();
         Preconditions.checkNotNull(procNodeI);
         List<List<String>> rows;
-        //Only SchemaChangeProc support where/order by/limit syntax
+        // Only SchemaChangeProc support where/order by/limit syntax
         if (procNodeI instanceof SchemaChangeProcDir) {
             rows = ((SchemaChangeProcDir) 
procNodeI).fetchResultByFilter(showStmt.getFilterMap(),
                     showStmt.getOrderPairs(), 
showStmt.getLimitElement()).getRows();
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowCreateFunctionTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowCreateFunctionTest.java
new file mode 100644
index 0000000000..f89f6fdbf3
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowCreateFunctionTest.java
@@ -0,0 +1,61 @@
+// 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.
+
+package org.apache.doris.analysis;
+
+import org.apache.doris.common.FeConstants;
+import org.apache.doris.qe.ShowResultSet;
+import org.apache.doris.utframe.TestWithFeService;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class ShowCreateFunctionTest extends TestWithFeService {
+
+    private String dbName = "testDb";
+
+    @Override
+    protected void runBeforeAll() throws Exception {
+        FeConstants.runningUnitTest = true;
+        createDatabase(dbName);
+        useDatabase(dbName);
+        createFunction(
+                "CREATE ALIAS FUNCTION id_masking(bigint) WITH PARAMETER(id) 
AS CONCAT(LEFT(id,3),'****',RIGHT(id,4));");
+
+        createFunction(
+                "CREATE GLOBAL ALIAS FUNCTION id_masking_global(bigint) WITH 
PARAMETER(id) AS CONCAT(LEFT(id,3),'****',RIGHT(id,4));");
+    }
+
+
+    @Test
+    public void testNormal() throws Exception {
+        String sql = "SHOW CREATE FUNCTION id_masking(bigint)";
+        ShowResultSet showResultSet = showCreateFunction(sql);
+        String showSql = showResultSet.getResultRows().get(0).get(1);
+        Assertions.assertTrue(showSql.contains("CREATE ALIAS FUNCTION 
id_masking(BIGINT) WITH PARAMETER(id)"));
+    }
+
+    @Test
+    public void testShowCreateGlobalFunction() throws Exception {
+        String sql = "SHOW CREATE GLOBAL FUNCTION id_masking_global(bigint)";
+        ShowResultSet showResultSet = showCreateFunction(sql);
+        String showSql = showResultSet.getResultRows().get(0).get(1);
+        Assertions.assertTrue(
+                showSql.contains("CREATE GLOBAL ALIAS FUNCTION 
id_masking_global(BIGINT) WITH PARAMETER(id)"));
+    }
+
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowFunctionsTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowFunctionsTest.java
new file mode 100644
index 0000000000..381bbb0a74
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/ShowFunctionsTest.java
@@ -0,0 +1,62 @@
+// 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.
+
+package org.apache.doris.analysis;
+
+import org.apache.doris.common.FeConstants;
+import org.apache.doris.qe.ShowResultSet;
+import org.apache.doris.utframe.TestWithFeService;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class ShowFunctionsTest extends TestWithFeService {
+    private String dbName = "testDb";
+
+    @Override
+    protected void runBeforeAll() throws Exception {
+        FeConstants.runningUnitTest = true;
+        createDatabase(dbName);
+        useDatabase(dbName);
+        createFunction(
+                "CREATE ALIAS FUNCTION id_masking(bigint) WITH PARAMETER(id) 
AS CONCAT(LEFT(id,3),'****',RIGHT(id,4));");
+
+        createFunction(
+                "CREATE GLOBAL ALIAS FUNCTION id_masking_global(bigint) WITH 
PARAMETER(id) AS CONCAT(LEFT(id,3),'****',RIGHT(id,4));");
+    }
+
+    @Test
+    public void testShowFunctions() throws Exception {
+        String sql = "SHOW  FUNCTIONS";
+        ShowResultSet showResultSet = showFunctions(sql);
+        String showSql = showResultSet.getResultRows().get(0).get(0);
+        Assertions.assertTrue("id_masking".equalsIgnoreCase(showSql));
+
+        sql = "SHOW FULL FUNCTIONS";
+        showResultSet = showFunctions(sql);
+        showSql = showResultSet.getResultRows().get(0).get(0);
+        Assertions.assertTrue(showSql.contains("id_masking"));
+    }
+
+    @Test
+    public void testShowGlobalFunctions() throws Exception {
+        String sql = "SHOW GLOBAL FUNCTIONS";
+        ShowResultSet showResultSet = showFunctions(sql);
+        String showSql = showResultSet.getResultRows().get(0).get(0);
+        Assertions.assertTrue("id_masking_global".equalsIgnoreCase(showSql));
+    }
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java 
b/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java
index 0507e035a3..cf99d6f7f1 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java
@@ -22,6 +22,7 @@ import org.apache.doris.analysis.AlterSqlBlockRuleStmt;
 import org.apache.doris.analysis.AlterTableStmt;
 import org.apache.doris.analysis.Analyzer;
 import org.apache.doris.analysis.CreateDbStmt;
+import org.apache.doris.analysis.CreateFunctionStmt;
 import org.apache.doris.analysis.CreateMaterializedViewStmt;
 import org.apache.doris.analysis.CreatePolicyStmt;
 import org.apache.doris.analysis.CreateSqlBlockRuleStmt;
@@ -33,7 +34,9 @@ import org.apache.doris.analysis.DropSqlBlockRuleStmt;
 import org.apache.doris.analysis.DropTableStmt;
 import org.apache.doris.analysis.ExplainOptions;
 import org.apache.doris.analysis.RecoverTableStmt;
+import org.apache.doris.analysis.ShowCreateFunctionStmt;
 import org.apache.doris.analysis.ShowCreateTableStmt;
+import org.apache.doris.analysis.ShowFunctionsStmt;
 import org.apache.doris.analysis.SqlParser;
 import org.apache.doris.analysis.SqlScanner;
 import org.apache.doris.analysis.StatementBase;
@@ -492,6 +495,18 @@ public abstract class TestWithFeService {
         return executor.execute();
     }
 
+    protected ShowResultSet showCreateFunction(String sql) throws Exception {
+        ShowCreateFunctionStmt stmt = (ShowCreateFunctionStmt) 
parseAndAnalyzeStmt(sql);
+        ShowExecutor executor = new ShowExecutor(connectContext, stmt);
+        return executor.execute();
+    }
+
+    protected ShowResultSet showFunctions(String sql) throws Exception {
+        ShowFunctionsStmt stmt = (ShowFunctionsStmt) parseAndAnalyzeStmt(sql);
+        ShowExecutor executor = new ShowExecutor(connectContext, stmt);
+        return executor.execute();
+    }
+
     protected ShowResultSet showCreateTableByName(String table) throws 
Exception {
         ShowCreateTableStmt stmt = (ShowCreateTableStmt) 
parseAndAnalyzeStmt("show create table " + table);
         ShowExecutor executor = new ShowExecutor(connectContext, stmt);
@@ -542,6 +557,11 @@ public abstract class TestWithFeService {
         Env.getCurrentEnv().getPolicyMgr().createPolicy(createPolicyStmt);
     }
 
+    public void createFunction(String sql) throws Exception {
+        CreateFunctionStmt createFunctionStmt = (CreateFunctionStmt) 
parseAndAnalyzeStmt(sql);
+        Env.getCurrentEnv().createFunction(createFunctionStmt);
+    }
+
     protected void dropPolicy(String sql) throws Exception {
         DropPolicyStmt stmt = (DropPolicyStmt) parseAndAnalyzeStmt(sql);
         Env.getCurrentEnv().getPolicyMgr().dropPolicy(stmt);
@@ -600,7 +620,8 @@ public abstract class TestWithFeService {
     }
 
     private void updateReplicaPathHash() {
-        com.google.common.collect.Table<Long, Long, Replica> replicaMetaTable 
= Env.getCurrentInvertedIndex().getReplicaMetaTable();
+        com.google.common.collect.Table<Long, Long, Replica> replicaMetaTable 
= Env.getCurrentInvertedIndex()
+                .getReplicaMetaTable();
         for (com.google.common.collect.Table.Cell<Long, Long, Replica> cell : 
replicaMetaTable.cellSet()) {
             long beId = cell.getColumnKey();
             Backend be = Env.getCurrentSystemInfo().getBackend(beId);


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to