-
Notifications
You must be signed in to change notification settings - Fork 8.3k
FEATURE: Add function signatures to information returned when querying system.functions #36023
Description
Use case :
Dynamic access to function signatures would be useful for clickhouse context-aware autocompletion and syntax highlighting.
As of now, this information is only available in the documentation and not programmatically accessible.
Proposed solution :
Add a signature column to the system.functions table which includes a list of expected arguments as strings. Some token could indicate a variable number of arguments for a specific argument type.
(Optional) Add a argument_type column that is a list of the same length as in the args column where each position maps to a list of possible types accepted for that argument.
Example:
Current :
SELECT name, is_aggregate, case_insensitive, origin FROM system.functions WHERE name = 'uniq' OR name = 'has' OR name = 'concat';

Proposed :
SELECT name, is_aggregate, case_insensitive, origin, arguments, argument_types FROM system.functions WHERE name = 'uniq' OR name = 'has' OR name = 'concat';

Additional context :
Multiple IDEs and visualisation platforms offer function signature completion for Clickhouse but so far they run on hard-coded files (see Grafana-clickhouse support for example). However, these files must be updated regularly to accommodate Clickhouse’s rapidly growing set of available functions.
For reasons of maintainability, it would be very helpful to have dynamic access to function signatures.
Proposed implementation :
A rough idea of how this could be perhaps implemented is to use reflection to gather the data types from all functions. They could then be provided to the system.functions fillRows function below.
ClickHouse/src/Storages/System/StorageSystemFunctions.cpp
Lines 26 to 48 in 85a4d4b
| void fillRow(MutableColumns & res_columns, const String & name, UInt64 is_aggregate, const String & create_query, FunctionOrigin function_origin, const Factory & f) | |
| { | |
| res_columns[0]->insert(name); | |
| res_columns[1]->insert(is_aggregate); | |
| if constexpr (std::is_same_v<Factory, UserDefinedSQLFunctionFactory> || std::is_same_v<Factory, UserDefinedExecutableFunctionFactory>) | |
| { | |
| res_columns[2]->insert(false); | |
| res_columns[3]->insertDefault(); | |
| } | |
| else | |
| { | |
| res_columns[2]->insert(f.isCaseInsensitive(name)); | |
| if (f.isAlias(name)) | |
| res_columns[3]->insert(f.aliasTo(name)); | |
| else | |
| res_columns[3]->insertDefault(); | |
| } | |
| res_columns[4]->insert(create_query); | |
| res_columns[5]->insert(static_cast<Int8>(function_origin)); | |
| } | |
| } |