diff --git a/docs/documentation/cn/sql-reference/sql-statements/Data Definition/show-function.md b/docs/documentation/cn/sql-reference/sql-statements/Data Definition/show-functions.md similarity index 72% rename from docs/documentation/cn/sql-reference/sql-statements/Data Definition/show-function.md rename to docs/documentation/cn/sql-reference/sql-statements/Data Definition/show-functions.md index 97d22aed2d..e6d89b1e5c 100644 --- a/docs/documentation/cn/sql-reference/sql-statements/Data Definition/show-function.md +++ b/docs/documentation/cn/sql-reference/sql-statements/Data Definition/show-functions.md @@ -17,42 +17,56 @@ specific language governing permissions and limitations under the License. --> -# SHOW FUNCTION +# SHOW FUNCTIONS ## description ### Syntax ``` -SHOW FUNCTION [FROM db] +SHOW [FULL] [BUILTIN] FUNCTIONS [IN|FROM db] [LIKE 'function_pattern'] ``` ### Parameters -> `db`: 要查询的数据库名字 +>`full`:表示显示函数的详细信息 +>`builtin`:表示显示系统提供的函数 +>`db`: 要查询的数据库名字 +>`function_pattern`: 用来过滤函数名称的参数 -查看数据库下所有的自定义函数。如果用户指定了数据库,那么查看对应数据库的,否则直接查询当前会话所在数据库 +查看数据库下所有的自定义(系统提供)的函数。如果用户指定了数据库,那么查看对应数据库的,否则直接查询当前会话所在数据库 需要对这个数据库拥有 `SHOW` 权限 ## example ``` -mysql> show function in testDb\G +mysql> show full functions in testDb\G *************************** 1. row *************************** - Signature: my_count(BIGINT) - Return Type: BIGINT - Function Type: Aggregate -Intermediate Type: NULL - Properties: {"object_file":"http://host:port/libudasample.so","finalize_fn":"_ZN9doris_udf13CountFinalizeEPNS_15FunctionContextERKNS_9BigIntValE","init_fn":"_ZN9doris_udf9CountInitEPNS_15FunctionContextEPNS_9BigIntValE","merge_fn":"_ZN9doris_udf10CountMergeEPNS_15FunctionContextERKNS_9BigIntValEPS2_","md5":"37d185f80f95569e2676da3d5b5b9d2f","update_fn":"_ZN9doris_udf11CountUpdateEPNS_15FunctionContextERKNS_6IntValEPNS_9BigIntValE"} -*************************** 2. row *************************** Signature: my_add(INT,INT) Return Type: INT Function Type: Scalar Intermediate Type: NULL Properties: {"symbol":"_ZN9doris_udf6AddUdfEPNS_15FunctionContextERKNS_6IntValES4_","object_file":"http://host:port/libudfsample.so","md5":"cfe7a362d10f3aaf6c49974ee0f1f878"} +*************************** 2. row *************************** + Signature: my_count(BIGINT) + Return Type: BIGINT + Function Type: Aggregate +Intermediate Type: NULL + Properties: {"object_file":"http://host:port/libudasample.so","finalize_fn":"_ZN9doris_udf13CountFinalizeEPNS_15FunctionContextERKNS_9BigIntValE","init_fn":"_ZN9doris_udf9CountInitEPNS_15FunctionContextEPNS_9BigIntValE","merge_fn":"_ZN9doris_udf10CountMergeEPNS_15FunctionContextERKNS_9BigIntValEPS2_","md5":"37d185f80f95569e2676da3d5b5b9d2f","update_fn":"_ZN9doris_udf11CountUpdateEPNS_15FunctionContextERKNS_6IntValEPNS_9BigIntValE"} + +2 rows in set (0.00 sec) +mysql> show builtin functions in testDb like 'year%'; ++---------------+ +| Function Name | ++---------------+ +| year | +| years_add | +| years_diff | +| years_sub | ++---------------+ 2 rows in set (0.00 sec) ``` ## keyword - SHOW,FUNCTION + SHOW,FUNCTIONS diff --git a/docs/documentation/en/sql-reference/sql-statements/Data Definition/show-function_EN.md b/docs/documentation/en/sql-reference/sql-statements/Data Definition/show-function_EN.md deleted file mode 100644 index 2de504a1ae..0000000000 --- a/docs/documentation/en/sql-reference/sql-statements/Data Definition/show-function_EN.md +++ /dev/null @@ -1,56 +0,0 @@ - - -# SHOW FUNCTION -## Description -### Syntax - -``` -SHOW FUNCTION [FROM db] -``` - -### Parameters - ->` DB `: The name of the database to query - - -Look at all the custom functions under the database. If the user specifies the database, then look at the corresponding database, otherwise directly query the database where the current session is located. - -You need `SHOW'privileges for this database - -## example - -``` -mysql> show function in testDb\G -*********************************1. row ************************ -Signature: my_count(BIGINT) -Return Type: BIGINT -Function Type: Aggregate -Intermediate Type: NULL -Properties: {"object_file":"http://host:port/libudasample.so","finalize_fn":"_ZN9doris_udf13CountFinalizeEPNS_15FunctionContextERKNS_9BigIntValE","init_fn":"_ZN9doris_udf9CountInitEPNS_15FunctionContextEPNS_9BigIntValE","merge_fn":"_ZN9doris_udf10CountMergeEPNS_15FunctionContextERKNS_9BigIntValEPS2_","md5":"37d185f80f95569e2676da3d5b5b9d2f","update_fn":"_ZN9doris_udf11CountUpdateEPNS_15FunctionContextERKNS_6IntValEPNS_9BigIntValE"} -*********************************2. row ************************ -Signature: my_add(INT,INT) -Return Type: INT -Function Type: Scalar -Intermediate Type: NULL -Properties: {"symbol":"_ZN9doris_udf6AddUdfEPNS_15FunctionContextERKNS_6IntValES4_","object_file":"http://host:port/libudfsample.so","md5":"cfe7a362d10f3aaf6c49974ee0f1f878"} -2 rows in set (0.00 sec) -``` -##keyword -SHOW,FUNCTION diff --git a/docs/documentation/en/sql-reference/sql-statements/Data Definition/show-functions_EN.md b/docs/documentation/en/sql-reference/sql-statements/Data Definition/show-functions_EN.md new file mode 100644 index 0000000000..3e39319013 --- /dev/null +++ b/docs/documentation/en/sql-reference/sql-statements/Data Definition/show-functions_EN.md @@ -0,0 +1,70 @@ + + +# SHOW FUNCTIONS +## Description +### Syntax + +``` +SHOW [FULL] [BUILTIN] FUNCTIONS [IN|FROM db] [LIKE 'function_pattern'] +``` + +### Parameters + +>`full`: Indicate to show the details of function +>`builtin`: Indicate to show the functions that doris provides +>`db`: The name of the database to query +>`function_pattern`: The parameter to filter function name + +Look at all the custom(builtin) functions under the database. If the user specifies the database, then look at the corresponding database, otherwise directly query the database where the current session is located. + +You need `SHOW'privileges for this database + +## example + +``` +mysql> show full functions in testDb\G +*************************** 1. row *************************** + Signature: my_add(INT,INT) + Return Type: INT + Function Type: Scalar +Intermediate Type: NULL + Properties: {"symbol":"_ZN9doris_udf6AddUdfEPNS_15FunctionContextERKNS_6IntValES4_","object_file":"http://host:port/libudfsample.so","md5":"cfe7a362d10f3aaf6c49974ee0f1f878"} +*************************** 2. row *************************** + Signature: my_count(BIGINT) + Return Type: BIGINT + Function Type: Aggregate +Intermediate Type: NULL + Properties: {"object_file":"http://host:port/libudasample.so","finalize_fn":"_ZN9doris_udf13CountFinalizeEPNS_15FunctionContextERKNS_9BigIntValE","init_fn":"_ZN9doris_udf9CountInitEPNS_15FunctionContextEPNS_9BigIntValE","merge_fn":"_ZN9doris_udf10CountMergeEPNS_15FunctionContextERKNS_9BigIntValEPS2_","md5":"37d185f80f95569e2676da3d5b5b9d2f","update_fn":"_ZN9doris_udf11CountUpdateEPNS_15FunctionContextERKNS_6IntValEPNS_9BigIntValE"} + +2 rows in set (0.00 sec) +mysql> show builtin functions in testDb like 'year%'; ++---------------+ +| Function Name | ++---------------+ +| year | +| years_add | +| years_diff | +| years_sub | ++---------------+ +2 rows in set (0.00 sec) +``` + +##keyword +SHOW,FUNCTIONS diff --git a/fe/src/main/cup/sql_parser.cup b/fe/src/main/cup/sql_parser.cup index 2255d0c0e3..508c9b58f0 100644 --- a/fe/src/main/cup/sql_parser.cup +++ b/fe/src/main/cup/sql_parser.cup @@ -194,14 +194,14 @@ parser code {: // Total keywords of doris terminal String KW_ADD, KW_ADMIN, KW_AFTER, KW_AGGREGATE, KW_ALL, KW_ALTER, KW_AND, KW_ANTI, KW_AS, KW_ASC, KW_AUTHORS, - KW_BACKEND, KW_BACKUP, KW_BETWEEN, KW_BEGIN, KW_BIGINT, KW_BITMAP, KW_BITMAP_UNION, KW_BOOLEAN, KW_BOTH, KW_BROKER, KW_BACKENDS, KW_BY, + KW_BACKEND, KW_BACKUP, KW_BETWEEN, KW_BEGIN, KW_BIGINT, KW_BITMAP, KW_BITMAP_UNION, KW_BOOLEAN, KW_BOTH, KW_BROKER, KW_BACKENDS, KW_BY, KW_BUILTIN, KW_CANCEL, KW_CASE, KW_CAST, KW_CHAIN, KW_CHAR, KW_CHARSET, KW_CLUSTER, KW_CLUSTERS, KW_COLLATE, KW_COLLATION, KW_COLUMN, KW_COLUMNS, KW_COMMENT, KW_COMMIT, KW_COMMITTED, KW_CONFIG, KW_CONNECTION, KW_CONNECTION_ID, KW_CONSISTENT, KW_COUNT, KW_CREATE, KW_CROSS, KW_CUBE, KW_CURRENT, KW_CURRENT_USER, KW_DATA, KW_DATABASE, KW_DATABASES, KW_DATE, KW_DATETIME, KW_DAY, KW_DECIMAL, KW_DECOMMISSION, KW_DEFAULT, KW_DESC, KW_DESCRIBE, KW_DELETE, KW_DISTINCT, KW_DISTINCTPC, KW_DISTINCTPCSA, KW_DISTRIBUTED, KW_DISTRIBUTION, KW_DYNAMIC, KW_BUCKETS, KW_DIV, KW_DOUBLE, KW_DROP, KW_DROPP, KW_DUPLICATE, KW_ELSE, KW_END, KW_ENGINE, KW_ENGINES, KW_ENTER, KW_ERRORS, KW_EVENTS, KW_EXISTS, KW_EXPORT, KW_EXTERNAL, KW_EXTRACT, - KW_FALSE, KW_FOLLOWER, KW_FOLLOWING, KW_FREE, KW_FROM, KW_FILE, KW_FIRST, KW_FLOAT, KW_FOR, KW_FORMAT, KW_FRONTEND, KW_FRONTENDS, KW_FULL, KW_FUNCTION, + KW_FALSE, KW_FOLLOWER, KW_FOLLOWING, KW_FREE, KW_FROM, KW_FILE, KW_FIRST, KW_FLOAT, KW_FOR, KW_FORMAT, KW_FRONTEND, KW_FRONTENDS, KW_FULL, KW_FUNCTION, KW_FUNCTIONS, KW_GLOBAL, KW_GRANT, KW_GRANTS, KW_GROUP, KW_GROUPING, KW_HASH, KW_HAVING, KW_HELP,KW_HLL, KW_HLL_UNION, KW_HOUR, KW_HUB, KW_IDENTIFIED, KW_IF, KW_IN, KW_INDEX, KW_INDEXES, KW_INFILE, @@ -429,6 +429,7 @@ nonterminal Boolean opt_external; nonterminal IndexDef.IndexType opt_index_type; nonterminal ShowAlterStmt.AlterType opt_alter_type; +nonterminal Boolean opt_builtin; precedence left KW_FULL, KW_MERGE; precedence left DOT; @@ -2094,9 +2095,9 @@ show_param ::= {: RESULT = new ShowRolesStmt(); :} - | KW_FUNCTION opt_db:dbName + | opt_full opt_builtin:isBuiltin KW_FUNCTIONS opt_db:dbName opt_wild_where {: - RESULT = new ShowFunctionStmt(dbName); + RESULT = new ShowFunctionsStmt(dbName, isBuiltin, parser.isVerbose, parser.wild, parser.where); :} | KW_FILE opt_db:dbName {: @@ -2247,6 +2248,16 @@ opt_alter_type ::= :} ; +opt_builtin ::= + {: + RESULT = false; + :} + | KW_BUILTIN + {: + RESULT = true; + :} + ; + // Describe statement describe_stmt ::= describe_command table_name:table @@ -4189,6 +4200,8 @@ keyword ::= {: RESULT = id; :} | KW_BACKENDS:id {: RESULT = id; :} + | KW_BUILTIN:id + {: RESULT = id; :} | KW_CHAIN:id {: RESULT = id; :} | KW_CHARSET:id diff --git a/fe/src/main/java/org/apache/doris/analysis/ShowFunctionStmt.java b/fe/src/main/java/org/apache/doris/analysis/ShowFunctionsStmt.java similarity index 61% rename from fe/src/main/java/org/apache/doris/analysis/ShowFunctionStmt.java rename to fe/src/main/java/org/apache/doris/analysis/ShowFunctionsStmt.java index 285eb7a757..d2686e543f 100644 --- a/fe/src/main/java/org/apache/doris/analysis/ShowFunctionStmt.java +++ b/fe/src/main/java/org/apache/doris/analysis/ShowFunctionsStmt.java @@ -22,6 +22,7 @@ import org.apache.doris.catalog.Catalog; import org.apache.doris.catalog.Column; 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; @@ -29,7 +30,7 @@ import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.ShowResultSetMetaData; -public class ShowFunctionStmt extends ShowStmt { +public class ShowFunctionsStmt extends ShowStmt { private static final ShowResultSetMetaData META_DATA = ShowResultSetMetaData.builder() .addColumn(new Column("Signature", ScalarType.createVarchar(256))) @@ -41,15 +42,49 @@ public class ShowFunctionStmt extends ShowStmt { private String dbName; - public ShowFunctionStmt(String dbName) { + private boolean isBuiltin; + + private boolean isVerbose; + + private String wild; + + private Expr expr; + + public ShowFunctionsStmt(String dbName, boolean isBuiltin, boolean isVerbose, String wild, Expr expr) { this.dbName = dbName; + this.isBuiltin = isBuiltin; + this.isVerbose = isVerbose; + this.wild = wild; + this.expr = expr; } public String getDbName() { return dbName; } + public boolean getIsBuiltin() { + return isBuiltin; + } + + public boolean getIsVerbose() { + return isVerbose; + } + + public String getWild() { + return wild; + } + + public Expr getExpr() { + return expr; + } + + public boolean like(String str) { + str = str.toLowerCase(); + return str.matches(wild.replace(".", "\\.").replace("?", ".").replace("%", ".*").toLowerCase()); + } + @Override public void analyze(Analyzer analyzer) throws UserException { super.analyze(analyzer); + if (Strings.isNullOrEmpty(dbName)) { dbName = analyzer.getDefaultDb(); if (Strings.isNullOrEmpty(dbName)) { @@ -61,7 +96,11 @@ public class ShowFunctionStmt extends ShowStmt { if (!Catalog.getCurrentCatalog().getAuth().checkDbPriv(ConnectContext.get(), dbName, PrivPredicate.SHOW)) { ErrorReport.reportAnalysisException( - ErrorCode.ERR_DB_ACCESS_DENIED, ConnectContext.get().getQualifiedUser(), dbName); + ErrorCode.ERR_DB_ACCESS_DENIED, ConnectContext.get().getQualifiedUser(), dbName); + } + + if (expr != null) { + throw new AnalysisException("Only support like 'function_pattern' syntax."); } } @@ -69,4 +108,31 @@ public class ShowFunctionStmt extends ShowStmt { public ShowResultSetMetaData getMetaData() { return META_DATA; } + + + @Override + public String toSql() { + StringBuilder sb = new StringBuilder(); + sb.append("SHOW "); + if (isVerbose) { + sb.append("FULL "); + } + if (isBuiltin) { + sb.append("BUILTIN "); + } + sb.append("FUNCTIONS FROM "); + if (!Strings.isNullOrEmpty(dbName)) { + sb.append("`").append(dbName).append("` "); + } + if (wild != null) { + sb.append("LIKE ").append("`").append(wild).append("`"); + } + return sb.toString(); + } + + @Override + public String toString() { + return toSql(); + } + } diff --git a/fe/src/main/java/org/apache/doris/catalog/AggregateFunction.java b/fe/src/main/java/org/apache/doris/catalog/AggregateFunction.java index 24b03144b5..da6ffbe295 100644 --- a/fe/src/main/java/org/apache/doris/catalog/AggregateFunction.java +++ b/fe/src/main/java/org/apache/doris/catalog/AggregateFunction.java @@ -457,7 +457,7 @@ public class AggregateFunction extends Function { @Override public String getProperties() { Map properties = Maps.newHashMap(); - properties.put(CreateFunctionStmt.OBJECT_FILE_KEY, getLocation().toString()); + properties.put(CreateFunctionStmt.OBJECT_FILE_KEY, getLocation() == null ? "" : getLocation().toString()); properties.put(CreateFunctionStmt.MD5_CHECKSUM, checksum); properties.put(CreateFunctionStmt.INIT_KEY, initFnSymbol); properties.put(CreateFunctionStmt.UPDATE_KEY, updateFnSymbol); diff --git a/fe/src/main/java/org/apache/doris/catalog/Catalog.java b/fe/src/main/java/org/apache/doris/catalog/Catalog.java index 52c4ecc329..b9cf8953b1 100644 --- a/fe/src/main/java/org/apache/doris/catalog/Catalog.java +++ b/fe/src/main/java/org/apache/doris/catalog/Catalog.java @@ -5268,6 +5268,10 @@ public class Catalog { return functionSet.getFunction(desc, mode); } + public List getBuiltinFunctions() { + return functionSet.getBulitinFunctions(); + } + /** * create cluster * diff --git a/fe/src/main/java/org/apache/doris/catalog/Function.java b/fe/src/main/java/org/apache/doris/catalog/Function.java index 5d56a7c135..f5f7710567 100644 --- a/fe/src/main/java/org/apache/doris/catalog/Function.java +++ b/fe/src/main/java/org/apache/doris/catalog/Function.java @@ -21,6 +21,7 @@ import static org.apache.doris.common.io.IOUtils.writeOptionString; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; import org.apache.doris.analysis.FunctionName; import org.apache.doris.analysis.HdfsURI; import org.apache.doris.common.io.Text; @@ -668,4 +669,34 @@ public class Function implements Writable { public String getProperties() { return ""; } + + public List getInfo(boolean isVerbose) { + List row = Lists.newArrayList(); + if (isVerbose) { + // signature + row.add(getSignature()); + // return type + row.add(getReturnType().getPrimitiveType().toString()); + // function type + // intermediate type + if (this instanceof ScalarFunction) { + row.add("Scalar"); + row.add("NULL"); + } else { + row.add("Aggregate"); + AggregateFunction aggFunc = (AggregateFunction) this; + Type intermediateType = aggFunc.getIntermediateType(); + if (intermediateType != null) { + row.add(intermediateType.getPrimitiveType().toString()); + } else { + row.add("NULL"); + } + } + // property + row.add(getProperties()); + } else { + row.add(functionName()); + } + return row; + } } diff --git a/fe/src/main/java/org/apache/doris/catalog/FunctionSet.java b/fe/src/main/java/org/apache/doris/catalog/FunctionSet.java index 3e542bcc03..a5b436ad31 100644 --- a/fe/src/main/java/org/apache/doris/catalog/FunctionSet.java +++ b/fe/src/main/java/org/apache/doris/catalog/FunctionSet.java @@ -1320,4 +1320,12 @@ public class FunctionSet { } } + + public List getBulitinFunctions() { + List builtinFunctions = Lists.newArrayList(); + for (Map.Entry> entry : functions.entrySet()) { + builtinFunctions.addAll(entry.getValue()); + } + return builtinFunctions; + } } diff --git a/fe/src/main/java/org/apache/doris/catalog/ScalarFunction.java b/fe/src/main/java/org/apache/doris/catalog/ScalarFunction.java index 8871a82ea2..7f0aba2a00 100644 --- a/fe/src/main/java/org/apache/doris/catalog/ScalarFunction.java +++ b/fe/src/main/java/org/apache/doris/catalog/ScalarFunction.java @@ -304,7 +304,7 @@ public class ScalarFunction extends Function { @Override public String getProperties() { Map properties = Maps.newHashMap(); - properties.put(CreateFunctionStmt.OBJECT_FILE_KEY, getLocation().toString()); + properties.put(CreateFunctionStmt.OBJECT_FILE_KEY, getLocation() == null ? "" : getLocation().toString()); properties.put(CreateFunctionStmt.MD5_CHECKSUM, checksum); properties.put(CreateFunctionStmt.SYMBOL_KEY, symbolName); return new Gson().toJson(properties); diff --git a/fe/src/main/java/org/apache/doris/qe/ShowExecutor.java b/fe/src/main/java/org/apache/doris/qe/ShowExecutor.java index 82b8d02b9c..b0284aa20f 100644 --- a/fe/src/main/java/org/apache/doris/qe/ShowExecutor.java +++ b/fe/src/main/java/org/apache/doris/qe/ShowExecutor.java @@ -39,7 +39,7 @@ import org.apache.doris.analysis.ShowDynamicPartitionStmt; import org.apache.doris.analysis.ShowEnginesStmt; import org.apache.doris.analysis.ShowExportStmt; import org.apache.doris.analysis.ShowFrontendsStmt; -import org.apache.doris.analysis.ShowFunctionStmt; +import org.apache.doris.analysis.ShowFunctionsStmt; import org.apache.doris.analysis.ShowGrantsStmt; import org.apache.doris.analysis.ShowIndexStmt; import org.apache.doris.analysis.ShowLoadStmt; @@ -67,7 +67,6 @@ import org.apache.doris.backup.AbstractJob; import org.apache.doris.backup.BackupJob; import org.apache.doris.backup.Repository; import org.apache.doris.backup.RestoreJob; -import org.apache.doris.catalog.AggregateFunction; import org.apache.doris.catalog.Catalog; import org.apache.doris.catalog.Column; import org.apache.doris.catalog.Database; @@ -80,11 +79,10 @@ import org.apache.doris.catalog.MetadataViewer; import org.apache.doris.catalog.OlapTable; import org.apache.doris.catalog.Partition; import org.apache.doris.catalog.Replica; -import org.apache.doris.catalog.ScalarFunction; +import org.apache.doris.catalog.ScalarType; import org.apache.doris.catalog.Table; import org.apache.doris.catalog.Tablet; import org.apache.doris.catalog.TabletInvertedIndex; -import org.apache.doris.catalog.Type; import org.apache.doris.catalog.View; import org.apache.doris.clone.DynamicPartitionScheduler; import org.apache.doris.cluster.BaseParam; @@ -138,6 +136,7 @@ import java.net.URLConnection; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -183,8 +182,8 @@ public class ShowExecutor { handleShowProcesslist(); } else if (stmt instanceof ShowEnginesStmt) { handleShowEngines(); - } else if (stmt instanceof ShowFunctionStmt) { - handleShowFunction(); + } else if (stmt instanceof ShowFunctionsStmt) { + handleShowFunctions(); } else if (stmt instanceof ShowVariablesStmt) { handleShowVariables(); } else if (stmt instanceof ShowColumnStmt) { @@ -302,44 +301,51 @@ public class ShowExecutor { resultSet = new ShowResultSet(showStmt.getMetaData(), rowSet); } - // Handle show function - private void handleShowFunction() throws AnalysisException { - ShowFunctionStmt showStmt = (ShowFunctionStmt) stmt; - + // Handle show functions + private void handleShowFunctions() throws AnalysisException { + ShowFunctionsStmt showStmt = (ShowFunctionsStmt) stmt; Database db = ctx.getCatalog().getDb(showStmt.getDbName()); if (db == null) { ErrorReport.reportAnalysisException(ErrorCode.ERR_BAD_DB_ERROR, showStmt.getDbName()); } - List functions = db.getFunctions(); + List functions = showStmt.getIsBuiltin() ? ctx.getCatalog().getBuiltinFunctions() : + db.getFunctions(); - List> rowSet = Lists.newArrayList(); + List> rowSet = Lists.newArrayList(); for (Function function : functions) { - List row = Lists.newArrayList(); - // signature - row.add(function.getSignature()); - // return type - row.add(function.getReturnType().getPrimitiveType().toString()); - // function type - // intermediate type - if (function instanceof ScalarFunction) { - row.add("Scalar"); - row.add("NULL"); - } else { - row.add("Aggregate"); - AggregateFunction aggFunc = (AggregateFunction) function; - Type intermediateType = aggFunc.getIntermediateType(); - if (intermediateType != null) { - row.add(intermediateType.getPrimitiveType().toString()); - } else { - row.add("NULL"); - } + List row = function.getInfo(showStmt.getIsVerbose()); + // like predicate + if (showStmt.getWild() == null || showStmt.like(function.functionName())) { + rowSet.add(row); } - // property - row.add(function.getProperties()); - rowSet.add(row); } + + // sort function rows by first column asc + ListComparator> comparator = null; + OrderByPair orderByPair = new OrderByPair(0, false); + comparator = new ListComparator<>(orderByPair); + Collections.sort(rowSet, comparator); + List> resultRowSet = Lists.newArrayList(); + + Set functionNameSet = new HashSet<>(); + for (List row : rowSet) { + List 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)); + } + // Only success - resultSet = new ShowResultSet(showStmt.getMetaData(), rowSet); + ShowResultSetMetaData showMetaData = showStmt.getIsVerbose() ? showStmt.getMetaData() : + ShowResultSetMetaData.builder() + .addColumn(new Column("Function Name", ScalarType.createVarchar(256))).build(); + resultSet = new ShowResultSet(showMetaData, resultRowSet); } private void handleShowProc() throws AnalysisException { diff --git a/fe/src/main/jflex/sql_scanner.flex b/fe/src/main/jflex/sql_scanner.flex index 61de8d8020..d5b494293b 100644 --- a/fe/src/main/jflex/sql_scanner.flex +++ b/fe/src/main/jflex/sql_scanner.flex @@ -111,6 +111,7 @@ import org.apache.doris.qe.SqlModeHelper; keywordMap.put("both", new Integer(SqlParserSymbols.KW_BOTH)); keywordMap.put("broker", new Integer(SqlParserSymbols.KW_BROKER)); keywordMap.put("buckets", new Integer(SqlParserSymbols.KW_BUCKETS)); + keywordMap.put("builtin", new Integer(SqlParserSymbols.KW_BUILTIN)); keywordMap.put("by", new Integer(SqlParserSymbols.KW_BY)); keywordMap.put("cancel", new Integer(SqlParserSymbols.KW_CANCEL)); keywordMap.put("case", new Integer(SqlParserSymbols.KW_CASE)); @@ -189,6 +190,7 @@ import org.apache.doris.qe.SqlModeHelper; keywordMap.put("frontends", new Integer(SqlParserSymbols.KW_FRONTENDS)); keywordMap.put("full", new Integer(SqlParserSymbols.KW_FULL)); keywordMap.put("function", new Integer(SqlParserSymbols.KW_FUNCTION)); + keywordMap.put("functions", new Integer(SqlParserSymbols.KW_FUNCTIONS)); keywordMap.put("global", new Integer(SqlParserSymbols.KW_GLOBAL)); keywordMap.put("grant", new Integer(SqlParserSymbols.KW_GRANT)); keywordMap.put("grants", new Integer(SqlParserSymbols.KW_GRANTS)); diff --git a/fe/src/test/java/org/apache/doris/analysis/ShowFunctionsStmtTest.java b/fe/src/test/java/org/apache/doris/analysis/ShowFunctionsStmtTest.java new file mode 100644 index 0000000000..fe061e36ed --- /dev/null +++ b/fe/src/test/java/org/apache/doris/analysis/ShowFunctionsStmtTest.java @@ -0,0 +1,92 @@ +// 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 mockit.Expectations; +import mockit.Mocked; +import org.apache.doris.catalog.Catalog; +import org.apache.doris.catalog.FakeCatalog; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.common.UserException; +import org.apache.doris.mysql.privilege.MockedAuth; +import org.apache.doris.mysql.privilege.PaloAuth; +import org.apache.doris.qe.ConnectContext; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class ShowFunctionsStmtTest { + @Mocked + private Analyzer analyzer; + private Catalog catalog; + + @Mocked + private PaloAuth auth; + @Mocked + private ConnectContext ctx; + private FakeCatalog fakeCatalog; + + @Rule + public ExpectedException expectedEx = ExpectedException.none(); + + @Before + public void setUp() { + fakeCatalog = new FakeCatalog(); + catalog = AccessTestUtil.fetchAdminCatalog(); + MockedAuth.mockedAuth(auth); + MockedAuth.mockedConnectContext(ctx, "root", "192.188.3.1"); + FakeCatalog.setCatalog(catalog); + + new Expectations() { + { + analyzer.getDefaultDb(); + minTimes = 0; + result = "testDb"; + + analyzer.getCatalog(); + minTimes = 0; + result = catalog; + + analyzer.getClusterName(); + minTimes = 0; + result = "testCluster"; + } + }; + } + + @Test + public void testNormal() throws UserException { + ShowFunctionsStmt stmt = new ShowFunctionsStmt(null, true, true, "%year%", null); + stmt.analyze(analyzer); + Assert.assertEquals("SHOW FULL BUILTIN FUNCTIONS FROM `testDb` LIKE `%year%`", stmt.toString()); + } + + @Test + public void testUnsupportFilter() throws UserException { + SlotRef slotRef = new SlotRef(null, "Signature"); + StringLiteral stringLiteral = new StringLiteral("year(DATETIME)"); + BinaryPredicate binaryPredicate = new BinaryPredicate(BinaryPredicate.Operator.EQ, slotRef, stringLiteral); + ShowFunctionsStmt stmt = new ShowFunctionsStmt(null, true, true, null, binaryPredicate); + expectedEx.expect(AnalysisException.class); + expectedEx.expectMessage("Only support like 'function_pattern' syntax."); + stmt.analyze(analyzer); + } + +}