mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 08:40:50 +00:00
Merge pull request #48017 from ClickHouse/rs/show_columns
MySQL compatibility: Implement `SHOW COLUMNS`
This commit is contained in:
commit
5d64841276
@ -30,7 +30,7 @@ This statement is identical to the query:
|
||||
SELECT name FROM system.databases [WHERE name [NOT] LIKE | ILIKE '<pattern>'] [LIMIT <N>] [INTO OUTFILE filename] [FORMAT format]
|
||||
```
|
||||
|
||||
### Examples
|
||||
**Examples**
|
||||
|
||||
Getting database names, containing the symbols sequence 'de' in their names:
|
||||
|
||||
@ -92,7 +92,7 @@ Result:
|
||||
└────────────────────────────────┘
|
||||
```
|
||||
|
||||
### See Also
|
||||
**See also**
|
||||
|
||||
- [CREATE DATABASE](https://clickhouse.com/docs/en/sql-reference/statements/create/database/#query-language-create-database)
|
||||
|
||||
@ -128,7 +128,7 @@ This statement is identical to the query:
|
||||
SELECT name FROM system.tables [WHERE name [NOT] LIKE | ILIKE '<pattern>'] [LIMIT <N>] [INTO OUTFILE <filename>] [FORMAT <format>]
|
||||
```
|
||||
|
||||
### Examples
|
||||
**Examples**
|
||||
|
||||
Getting table names, containing the symbols sequence 'user' in their names:
|
||||
|
||||
@ -191,11 +191,59 @@ Result:
|
||||
└────────────────────────────────┘
|
||||
```
|
||||
|
||||
### See Also
|
||||
**See also**
|
||||
|
||||
- [Create Tables](https://clickhouse.com/docs/en/getting-started/tutorial/#create-tables)
|
||||
- [SHOW CREATE TABLE](https://clickhouse.com/docs/en/sql-reference/statements/show/#show-create-table)
|
||||
|
||||
## SHOW COLUMNS
|
||||
|
||||
Displays a list of columns
|
||||
|
||||
```sql
|
||||
SHOW [EXTENDED] [FULL] COLUMNS {FROM | IN} <table> [{FROM | IN} <db>] [{[NOT] {LIKE | ILIKE} '<pattern>' | WHERE <expr>}] [LIMIT <N>] [INTO
|
||||
OUTFILE <filename>] [FORMAT <format>]
|
||||
```
|
||||
|
||||
The database and table name can be specified in abbreviated form as `<db>.<table>`, i.e. `FROM tab FROM db` and `FROM db.tab` are
|
||||
equivalent. If no database is specified, the query returns the list of columns from the current database.
|
||||
|
||||
The optional keyword `EXTENDED` currently has no effect, it only exists for MySQL compatibility.
|
||||
|
||||
The optional keyword `FULL` causes the output to include the collation, comment and privilege columns.
|
||||
|
||||
`SHOW COLUMNS` produces a result table with the following structure:
|
||||
- field - The name of the column (String)
|
||||
- type - The column data type (String)
|
||||
- null - If the column data type is Nullable (UInt8)
|
||||
- key - `PRI` if the column is part of the primary key, `SOR` if the column is part of the sorting key, empty otherwise (String)
|
||||
- default - Default expression of the column if it is of type `ALIAS`, `DEFAULT`, or `MATERIALIZED`, otherwise `NULL`. (Nullable(String))
|
||||
- extra - Additional information, currently unused (String)
|
||||
- collation - Collation of the column, always `NULL` because ClickHouse has no per-column collations, only if `FULL` keyword was specified (Nullable(String))
|
||||
- comment - Comment on the column, only if `FULL` keyword was specified (String)
|
||||
- privilege - The privilege you have on this column, currently not available, only if `FULL` keyword was specified (String)
|
||||
|
||||
**Examples**
|
||||
|
||||
Getting information about all columns in table 'order' starting with 'delivery_':
|
||||
|
||||
```sql
|
||||
SHOW COLUMNS FROM 'orders' LIKE 'delivery_%'
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
``` text
|
||||
┌─field───────────┬─type─────┬─null─┬─key─────┬─default─┬─extra─┐
|
||||
│ delivery_date │ DateTime │ 0 │ PRI SOR │ ᴺᵁᴸᴸ │ │
|
||||
│ delivery_status │ Bool │ 0 │ │ ᴺᵁᴸᴸ │ │
|
||||
└─────────────────┴──────────┴──────┴─────────┴─────────┴───────┘
|
||||
```
|
||||
|
||||
**See also**
|
||||
|
||||
- [system.columns](https://clickhouse.com/docs/en/operations/system-tables/columns)
|
||||
|
||||
## SHOW DICTIONARIES
|
||||
|
||||
Displays a list of [Dictionaries](../../sql-reference/dictionaries/index.md).
|
||||
@ -212,7 +260,7 @@ You can get the same results as the `SHOW DICTIONARIES` query in the following w
|
||||
SELECT name FROM system.dictionaries WHERE database = <db> [AND name LIKE <pattern>] [LIMIT <N>] [INTO OUTFILE <filename>] [FORMAT <format>]
|
||||
```
|
||||
|
||||
**Example**
|
||||
**Examples**
|
||||
|
||||
The following query selects the first two rows from the list of tables in the `system` database, whose names contain `reg`.
|
||||
|
||||
@ -231,7 +279,7 @@ SHOW DICTIONARIES FROM db LIKE '%reg%' LIMIT 2
|
||||
|
||||
Shows privileges for a user.
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW GRANTS [FOR user1 [, user2 ...]]
|
||||
@ -245,7 +293,7 @@ Shows parameters that were used at a [user creation](../../sql-reference/stateme
|
||||
|
||||
`SHOW CREATE USER` does not output user passwords.
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW CREATE USER [name1 [, name2 ...] | CURRENT_USER]
|
||||
@ -255,7 +303,7 @@ SHOW CREATE USER [name1 [, name2 ...] | CURRENT_USER]
|
||||
|
||||
Shows parameters that were used at a [role creation](../../sql-reference/statements/create/role.md).
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW CREATE ROLE name1 [, name2 ...]
|
||||
@ -265,7 +313,7 @@ SHOW CREATE ROLE name1 [, name2 ...]
|
||||
|
||||
Shows parameters that were used at a [row policy creation](../../sql-reference/statements/create/row-policy.md).
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW CREATE [ROW] POLICY name ON [database1.]table1 [, [database2.]table2 ...]
|
||||
@ -275,7 +323,7 @@ SHOW CREATE [ROW] POLICY name ON [database1.]table1 [, [database2.]table2 ...]
|
||||
|
||||
Shows parameters that were used at a [quota creation](../../sql-reference/statements/create/quota.md).
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW CREATE QUOTA [name1 [, name2 ...] | CURRENT]
|
||||
@ -285,7 +333,7 @@ SHOW CREATE QUOTA [name1 [, name2 ...] | CURRENT]
|
||||
|
||||
Shows parameters that were used at a [settings profile creation](../../sql-reference/statements/create/settings-profile.md).
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW CREATE [SETTINGS] PROFILE name1 [, name2 ...]
|
||||
@ -295,7 +343,7 @@ SHOW CREATE [SETTINGS] PROFILE name1 [, name2 ...]
|
||||
|
||||
Returns a list of [user account](../../guides/sre/user-management/index.md#user-account-management) names. To view user accounts parameters, see the system table [system.users](../../operations/system-tables/users.md#system_tables-users).
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW USERS
|
||||
@ -305,7 +353,7 @@ SHOW USERS
|
||||
|
||||
Returns a list of [roles](../../guides/sre/user-management/index.md#role-management). To view another parameters, see system tables [system.roles](../../operations/system-tables/roles.md#system_tables-roles) and [system.role_grants](../../operations/system-tables/role-grants.md#system_tables-role_grants).
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW [CURRENT|ENABLED] ROLES
|
||||
@ -314,7 +362,7 @@ SHOW [CURRENT|ENABLED] ROLES
|
||||
|
||||
Returns a list of [setting profiles](../../guides/sre/user-management/index.md#settings-profiles-management). To view user accounts parameters, see the system table [settings_profiles](../../operations/system-tables/settings_profiles.md#system_tables-settings_profiles).
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW [SETTINGS] PROFILES
|
||||
@ -324,7 +372,7 @@ SHOW [SETTINGS] PROFILES
|
||||
|
||||
Returns a list of [row policies](../../guides/sre/user-management/index.md#row-policy-management) for the specified table. To view user accounts parameters, see the system table [system.row_policies](../../operations/system-tables/row_policies.md#system_tables-row_policies).
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW [ROW] POLICIES [ON [db.]table]
|
||||
@ -334,7 +382,7 @@ SHOW [ROW] POLICIES [ON [db.]table]
|
||||
|
||||
Returns a list of [quotas](../../guides/sre/user-management/index.md#quotas-management). To view quotas parameters, see the system table [system.quotas](../../operations/system-tables/quotas.md#system_tables-quotas).
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW QUOTAS
|
||||
@ -344,7 +392,7 @@ SHOW QUOTAS
|
||||
|
||||
Returns a [quota](../../operations/quotas.md) consumption for all users or for current user. To view another parameters, see system tables [system.quotas_usage](../../operations/system-tables/quotas_usage.md#system_tables-quotas_usage) and [system.quota_usage](../../operations/system-tables/quota_usage.md#system_tables-quota_usage).
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW [CURRENT] QUOTA
|
||||
@ -353,7 +401,7 @@ SHOW [CURRENT] QUOTA
|
||||
|
||||
Shows all [users](../../guides/sre/user-management/index.md#user-account-management), [roles](../../guides/sre/user-management/index.md#role-management), [profiles](../../guides/sre/user-management/index.md#settings-profiles-management), etc. and all their [grants](../../sql-reference/statements/grant.md#grant-privileges).
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW ACCESS
|
||||
@ -366,13 +414,14 @@ Returns a list of clusters. All available clusters are listed in the [system.clu
|
||||
`SHOW CLUSTER name` query displays the contents of system.clusters table for this cluster.
|
||||
:::
|
||||
|
||||
### Syntax
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
SHOW CLUSTER '<name>'
|
||||
SHOW CLUSTERS [[NOT] LIKE|ILIKE '<pattern>'] [LIMIT <N>]
|
||||
```
|
||||
### Examples
|
||||
|
||||
**Examples**
|
||||
|
||||
Query:
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <Parsers/ASTShowEngineQuery.h>
|
||||
#include <Parsers/ASTShowProcesslistQuery.h>
|
||||
#include <Parsers/ASTShowTablesQuery.h>
|
||||
#include <Parsers/ASTShowColumnsQuery.h>
|
||||
#include <Parsers/ASTUseQuery.h>
|
||||
#include <Parsers/ASTWatchQuery.h>
|
||||
#include <Parsers/ASTCreateNamedCollectionQuery.h>
|
||||
@ -79,6 +80,7 @@
|
||||
#include <Interpreters/InterpreterShowEngineQuery.h>
|
||||
#include <Interpreters/InterpreterShowProcesslistQuery.h>
|
||||
#include <Interpreters/InterpreterShowTablesQuery.h>
|
||||
#include <Interpreters/InterpreterShowColumnsQuery.h>
|
||||
#include <Interpreters/InterpreterSystemQuery.h>
|
||||
#include <Interpreters/InterpreterUseQuery.h>
|
||||
#include <Interpreters/InterpreterWatchQuery.h>
|
||||
@ -175,6 +177,10 @@ std::unique_ptr<IInterpreter> InterpreterFactory::get(ASTPtr & query, ContextMut
|
||||
{
|
||||
return std::make_unique<InterpreterShowTablesQuery>(query, context);
|
||||
}
|
||||
else if (query->as<ASTShowColumnsQuery>())
|
||||
{
|
||||
return std::make_unique<InterpreterShowColumnsQuery>(query, context);
|
||||
}
|
||||
else if (query->as<ASTShowEnginesQuery>())
|
||||
{
|
||||
return std::make_unique<InterpreterShowEnginesQuery>(query, context);
|
||||
|
103
src/Interpreters/InterpreterShowColumnsQuery.cpp
Normal file
103
src/Interpreters/InterpreterShowColumnsQuery.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include <Interpreters/InterpreterShowColumnsQuery.h>
|
||||
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
#include <Parsers/ASTShowColumnsQuery.h>
|
||||
#include <Parsers/formatAST.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/executeQuery.h>
|
||||
#include <IO/Operators.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
|
||||
InterpreterShowColumnsQuery::InterpreterShowColumnsQuery(const ASTPtr & query_ptr_, ContextMutablePtr context_)
|
||||
: WithMutableContext(context_)
|
||||
, query_ptr(query_ptr_)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
String InterpreterShowColumnsQuery::getRewrittenQuery()
|
||||
{
|
||||
const auto & query = query_ptr->as<ASTShowColumnsQuery &>();
|
||||
|
||||
WriteBufferFromOwnString rewritten_query;
|
||||
|
||||
rewritten_query << "SELECT name AS field, type AS type, startsWith(type, 'Nullable') AS null, trim(concatWithSeparator(' ', if(is_in_primary_key, 'PRI', ''), if (is_in_sorting_key, 'SOR', ''))) AS key, if(default_kind IN ('ALIAS', 'DEFAULT', 'MATERIALIZED'), default_expression, NULL) AS default, '' AS extra ";
|
||||
|
||||
// TODO Interpret query.extended. It is supposed to show internal/virtual columns. Need to fetch virtual column names, see
|
||||
// IStorage::getVirtuals(). We can't easily do that via SQL.
|
||||
|
||||
if (query.full)
|
||||
{
|
||||
/// "Full" mode is mostly for MySQL compat
|
||||
/// - collation: no such thing in ClickHouse
|
||||
/// - comment
|
||||
/// - privileges: <not implemented, TODO ask system.grants>
|
||||
rewritten_query << ", NULL AS collation, comment, '' AS privileges ";
|
||||
}
|
||||
|
||||
rewritten_query << "FROM system.columns WHERE ";
|
||||
|
||||
String database;
|
||||
String table;
|
||||
if (query.from_table.contains("."))
|
||||
{
|
||||
/// FROM <db>.<table> (abbreviated form)
|
||||
chassert(query.from_database.empty());
|
||||
std::vector<String> split;
|
||||
boost::split(split, query.from_table, boost::is_any_of("."));
|
||||
chassert(split.size() == 2);
|
||||
database = split[0];
|
||||
table = split[1];
|
||||
}
|
||||
else if (query.from_database.empty())
|
||||
{
|
||||
/// FROM <table>
|
||||
chassert(!query.from_table.empty());
|
||||
database = getContext()->getCurrentDatabase();
|
||||
table = query.from_table;
|
||||
}
|
||||
else
|
||||
{
|
||||
/// FROM <database> FROM <table>
|
||||
chassert(!query.from_database.empty());
|
||||
chassert(!query.from_table.empty());
|
||||
database = query.from_database;
|
||||
table = query.from_table;
|
||||
}
|
||||
rewritten_query << "database = " << DB::quote << database;
|
||||
rewritten_query << " AND table = " << DB::quote << table;
|
||||
|
||||
if (!query.like.empty())
|
||||
rewritten_query
|
||||
<< " AND name "
|
||||
<< (query.not_like ? "NOT " : "")
|
||||
<< (query.case_insensitive_like ? "ILIKE " : "LIKE ")
|
||||
<< DB::quote << query.like;
|
||||
else if (query.where_expression)
|
||||
rewritten_query << " AND (" << query.where_expression << ")";
|
||||
|
||||
/// Sorting is strictly speaking not necessary but 1. it is convenient for users, 2. SQL currently does not allow to
|
||||
/// sort the output of SHOW COLUMNS otherwise (SELECT * FROM (SHOW COLUMNS ...) ORDER BY ...) is rejected) and 3. some
|
||||
/// SQL tests can take advantage of this.
|
||||
rewritten_query << " ORDER BY field, type, null, key, default, extra";
|
||||
|
||||
if (query.limit_length)
|
||||
rewritten_query << " LIMIT " << query.limit_length;
|
||||
|
||||
return rewritten_query.str();
|
||||
|
||||
}
|
||||
|
||||
|
||||
BlockIO InterpreterShowColumnsQuery::execute()
|
||||
{
|
||||
return executeQuery(getRewrittenQuery(), getContext(), true);
|
||||
}
|
||||
|
||||
|
||||
}
|
32
src/Interpreters/InterpreterShowColumnsQuery.h
Normal file
32
src/Interpreters/InterpreterShowColumnsQuery.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <Interpreters/IInterpreter.h>
|
||||
#include <Parsers/IAST_fwd.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
class Context;
|
||||
|
||||
|
||||
/// Returns a list of columns which meet some conditions.
|
||||
class InterpreterShowColumnsQuery : public IInterpreter, WithMutableContext
|
||||
{
|
||||
public:
|
||||
InterpreterShowColumnsQuery(const ASTPtr & query_ptr_, ContextMutablePtr context_);
|
||||
|
||||
BlockIO execute() override;
|
||||
|
||||
/// Ignore quota and limits here because execute() produces a SELECT query which checks quotas/limits by itself.
|
||||
bool ignoreQuota() const override { return true; }
|
||||
bool ignoreLimits() const override { return true; }
|
||||
|
||||
private:
|
||||
ASTPtr query_ptr;
|
||||
|
||||
String getRewrittenQuery();
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
#include <IO/ReadBufferFromString.h>
|
||||
#include <IO/WriteBufferFromString.h>
|
||||
#include <Parsers/ASTShowTablesQuery.h>
|
||||
#include <Parsers/formatAST.h>
|
||||
#include <Interpreters/Context.h>
|
||||
@ -24,7 +24,8 @@ namespace ErrorCodes
|
||||
|
||||
|
||||
InterpreterShowTablesQuery::InterpreterShowTablesQuery(const ASTPtr & query_ptr_, ContextMutablePtr context_)
|
||||
: WithMutableContext(context_), query_ptr(query_ptr_)
|
||||
: WithMutableContext(context_)
|
||||
, query_ptr(query_ptr_)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,7 @@ public:
|
||||
|
||||
BlockIO execute() override;
|
||||
|
||||
/// We ignore the quota and limits here because execute() will rewrite a show query as a SELECT query and then
|
||||
/// the SELECT query will checks the quota and limits.
|
||||
/// Ignore quota and limits here because execute() produces a SELECT query which checks quotas/limits by itself.
|
||||
bool ignoreQuota() const override { return true; }
|
||||
bool ignoreLimits() const override { return true; }
|
||||
|
||||
|
@ -17,17 +17,21 @@ class ASTTableIdentifier;
|
||||
void setIdentifierSpecial(ASTPtr & ast);
|
||||
|
||||
String getIdentifierName(const IAST * ast);
|
||||
|
||||
std::optional<String> tryGetIdentifierName(const IAST * ast);
|
||||
|
||||
bool tryGetIdentifierNameInto(const IAST * ast, String & name);
|
||||
|
||||
inline String getIdentifierName(const ASTPtr & ast)
|
||||
{
|
||||
return getIdentifierName(ast.get());
|
||||
}
|
||||
|
||||
inline std::optional<String> tryGetIdentifierName(const ASTPtr & ast)
|
||||
{
|
||||
return tryGetIdentifierName(ast.get());
|
||||
}
|
||||
|
||||
inline bool tryGetIdentifierNameInto(const ASTPtr & ast, String & name)
|
||||
{
|
||||
return tryGetIdentifierNameInto(ast.get(), name);
|
||||
|
53
src/Parsers/ASTShowColumnsQuery.cpp
Normal file
53
src/Parsers/ASTShowColumnsQuery.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include <Parsers/ASTShowColumnsQuery.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <Common/quoteString.h>
|
||||
#include <IO/Operators.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
ASTPtr ASTShowColumnsQuery::clone() const
|
||||
{
|
||||
auto res = std::make_shared<ASTShowColumnsQuery>(*this);
|
||||
res->children.clear();
|
||||
cloneOutputOptions(*res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void ASTShowColumnsQuery::formatQueryImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "")
|
||||
<< "SHOW "
|
||||
<< (extended ? "EXTENDED " : "")
|
||||
<< (full ? "FULL " : "")
|
||||
<< "COLUMNS"
|
||||
<< (settings.hilite ? hilite_none : "");
|
||||
|
||||
if (from_database.empty())
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " FROM " << (settings.hilite ? hilite_none : "") << backQuoteIfNeed(from_table);
|
||||
else
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " FROM " << (settings.hilite ? hilite_none : "") << backQuoteIfNeed(from_database) << "." << backQuoteIfNeed(from_table);
|
||||
|
||||
|
||||
if (!like.empty())
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "")
|
||||
<< (not_like ? " NOT " : "")
|
||||
<< (case_insensitive_like ? " ILIKE " : " LIKE")
|
||||
<< (settings.hilite ? hilite_none : "")
|
||||
<< DB::quote << like;
|
||||
|
||||
if (where_expression)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " WHERE " << (settings.hilite ? hilite_none : "");
|
||||
where_expression->formatImpl(settings, state, frame);
|
||||
}
|
||||
|
||||
if (limit_length)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " LIMIT " << (settings.hilite ? hilite_none : "");
|
||||
limit_length->formatImpl(settings, state, frame);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
34
src/Parsers/ASTShowColumnsQuery.h
Normal file
34
src/Parsers/ASTShowColumnsQuery.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST_fwd.h>
|
||||
#include <Parsers/ASTQueryWithOutput.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/// Query SHOW COLUMNS
|
||||
class ASTShowColumnsQuery : public ASTQueryWithOutput
|
||||
{
|
||||
public:
|
||||
bool extended = false;
|
||||
bool full = false;
|
||||
bool not_like = false;
|
||||
bool case_insensitive_like = false;
|
||||
|
||||
ASTPtr where_expression;
|
||||
ASTPtr limit_length;
|
||||
|
||||
String from_database;
|
||||
String from_table;
|
||||
|
||||
String like;
|
||||
|
||||
String getID(char) const override { return "ShowColumns"; }
|
||||
ASTPtr clone() const override;
|
||||
QueryKind getQueryKind() const override { return QueryKind::Show; }
|
||||
|
||||
protected:
|
||||
void formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
};
|
||||
|
||||
}
|
@ -14,31 +14,28 @@ namespace DB
|
||||
class ASTShowTablesQuery : public ASTQueryWithOutput
|
||||
{
|
||||
public:
|
||||
bool databases{false};
|
||||
bool clusters{false};
|
||||
bool cluster{false};
|
||||
bool dictionaries{false};
|
||||
bool m_settings{false};
|
||||
bool changed{false};
|
||||
bool temporary{false};
|
||||
bool caches{false};
|
||||
bool full{false};
|
||||
bool databases = false;
|
||||
bool clusters = false;
|
||||
bool cluster = false;
|
||||
bool dictionaries = false;
|
||||
bool m_settings = false;
|
||||
bool changed = false;
|
||||
bool temporary = false;
|
||||
bool caches = false;
|
||||
bool full = false;
|
||||
|
||||
String cluster_str;
|
||||
String from;
|
||||
String like;
|
||||
|
||||
bool not_like{false};
|
||||
bool case_insensitive_like{false};
|
||||
bool not_like = false;
|
||||
bool case_insensitive_like = false;
|
||||
|
||||
ASTPtr where_expression;
|
||||
ASTPtr limit_length;
|
||||
|
||||
/** Get the text that identifies this element. */
|
||||
String getID(char) const override { return "ShowTables"; }
|
||||
|
||||
ASTPtr clone() const override;
|
||||
|
||||
QueryKind getQueryKind() const override { return QueryKind::Show; }
|
||||
|
||||
protected:
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <Parsers/ParserSetQuery.h>
|
||||
#include <Parsers/ParserShowProcesslistQuery.h>
|
||||
#include <Parsers/ParserShowTablesQuery.h>
|
||||
#include <Parsers/ParserShowColumnsQuery.h>
|
||||
#include <Parsers/ParserShowEngineQuery.h>
|
||||
#include <Parsers/ParserTablePropertiesQuery.h>
|
||||
#include <Parsers/ParserWatchQuery.h>
|
||||
@ -35,6 +36,7 @@ namespace DB
|
||||
bool ParserQueryWithOutput::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
ParserShowTablesQuery show_tables_p;
|
||||
ParserShowColumnsQuery show_columns_p;
|
||||
ParserShowEnginesQuery show_engine_p;
|
||||
ParserSelectWithUnionQuery select_p;
|
||||
ParserTablePropertiesQuery table_p;
|
||||
@ -64,6 +66,7 @@ bool ParserQueryWithOutput::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
|| select_p.parse(pos, query, expected)
|
||||
|| show_create_access_entity_p.parse(pos, query, expected) /// should be before `show_tables_p`
|
||||
|| show_tables_p.parse(pos, query, expected)
|
||||
|| show_columns_p.parse(pos, query, expected)
|
||||
|| show_engine_p.parse(pos, query, expected)
|
||||
|| table_p.parse(pos, query, expected)
|
||||
|| describe_cache_p.parse(pos, query, expected)
|
||||
|
80
src/Parsers/ParserShowColumnsQuery.cpp
Normal file
80
src/Parsers/ParserShowColumnsQuery.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
#include <Parsers/ParserShowColumnsQuery.h>
|
||||
|
||||
#include <Parsers/ASTIdentifier_fwd.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/ASTShowColumnsQuery.h>
|
||||
#include <Parsers/CommonParsers.h>
|
||||
#include <Parsers/ExpressionElementParsers.h>
|
||||
#include <Parsers/ExpressionListParsers.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
bool ParserShowColumnsQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
{
|
||||
ASTPtr like;
|
||||
ASTPtr from_db;
|
||||
ASTPtr from_table;
|
||||
|
||||
auto query = std::make_shared<ASTShowColumnsQuery>();
|
||||
|
||||
if (!ParserKeyword("SHOW").ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
if (ParserKeyword("EXTENDED").ignore(pos, expected))
|
||||
query->extended = true;
|
||||
|
||||
if (ParserKeyword("FULL").ignore(pos, expected))
|
||||
query->full = true;
|
||||
|
||||
if (!ParserKeyword("COLUMNS").ignore(pos, expected) || ParserKeyword("FIELDS").ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
if (ParserKeyword("FROM").ignore(pos, expected) || ParserKeyword("IN").ignore(pos, expected))
|
||||
{
|
||||
if (!ParserCompoundIdentifier().parse(pos, from_table, expected))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
tryGetIdentifierNameInto(from_table, query->from_table);
|
||||
bool abbreviated_form = query->from_table.contains("."); /// FROM <db>.<table>
|
||||
|
||||
if (!abbreviated_form)
|
||||
if (ParserKeyword("FROM").ignore(pos, expected) || ParserKeyword("IN").ignore(pos, expected))
|
||||
if (!ParserIdentifier().parse(pos, from_db, expected))
|
||||
return false;
|
||||
|
||||
tryGetIdentifierNameInto(from_db, query->from_database);
|
||||
|
||||
if (ParserKeyword("NOT").ignore(pos, expected))
|
||||
query->not_like = true;
|
||||
|
||||
if (bool insensitive = ParserKeyword("ILIKE").ignore(pos, expected); insensitive || ParserKeyword("LIKE").ignore(pos, expected))
|
||||
{
|
||||
if (insensitive)
|
||||
query->case_insensitive_like = true;
|
||||
|
||||
if (!ParserStringLiteral().parse(pos, like, expected))
|
||||
return false;
|
||||
}
|
||||
else if (query->not_like)
|
||||
return false;
|
||||
else if (ParserKeyword("WHERE").ignore(pos, expected))
|
||||
if (!ParserExpressionWithOptionalAlias(false).parse(pos, query->where_expression, expected))
|
||||
return false;
|
||||
|
||||
if (ParserKeyword("LIMIT").ignore(pos, expected))
|
||||
if (!ParserExpressionWithOptionalAlias(false).parse(pos, query->limit_length, expected))
|
||||
return false;
|
||||
|
||||
if (like)
|
||||
query->like = like->as<ASTLiteral &>().value.safeGet<const String &>();
|
||||
|
||||
node = query;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
19
src/Parsers/ParserShowColumnsQuery.h
Normal file
19
src/Parsers/ParserShowColumnsQuery.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IParserBase.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/** Parses queries of the form
|
||||
* SHOW [EXTENDED] [FULL] COLUMNS (FROM|IN) tbl [(FROM|IN) db] [(([NOT] (LIKE|ILIKE) expr) | (WHERE expr))] [LIMIT n]
|
||||
*/
|
||||
class ParserShowColumnsQuery : public IParserBase
|
||||
{
|
||||
protected:
|
||||
const char * getName() const override { return "SHOW COLUMNS query"; }
|
||||
|
||||
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
||||
};
|
||||
|
||||
}
|
@ -149,10 +149,8 @@ bool ParserShowTablesQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
}
|
||||
|
||||
if (s_from.ignore(pos, expected) || s_in.ignore(pos, expected))
|
||||
{
|
||||
if (!name_p.parse(pos, database, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s_not.ignore(pos, expected))
|
||||
query->not_like = true;
|
||||
@ -168,16 +166,12 @@ bool ParserShowTablesQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
else if (query->not_like)
|
||||
return false;
|
||||
else if (s_where.ignore(pos, expected))
|
||||
{
|
||||
if (!exp_elem.parse(pos, query->where_expression, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s_limit.ignore(pos, expected))
|
||||
{
|
||||
if (!exp_elem.parse(pos, query->limit_length, expected))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
tryGetIdentifierNameInto(database, query->from);
|
||||
|
38
tests/queries/0_stateless/25402_show_columns.reference
Normal file
38
tests/queries/0_stateless/25402_show_columns.reference
Normal file
@ -0,0 +1,38 @@
|
||||
int32 Nullable(Int32) 1 \N
|
||||
str String 0 SOR \N
|
||||
uint64 UInt64 0 PRI SOR \N
|
||||
--- EXTENDED
|
||||
int32 Nullable(Int32) 1 \N
|
||||
str String 0 SOR \N
|
||||
uint64 UInt64 0 PRI SOR \N
|
||||
--- FULL
|
||||
int32 Nullable(Int32) 1 \N \N example comment
|
||||
str String 0 SOR \N \N
|
||||
uint64 UInt64 0 PRI SOR \N \N
|
||||
--- LIKE
|
||||
int32 Nullable(Int32) 1 \N
|
||||
uint64 UInt64 0 PRI SOR \N
|
||||
--- NOT LIKE
|
||||
str String 0 SOR \N
|
||||
--- ILIKE
|
||||
int32 Nullable(Int32) 1 \N
|
||||
uint64 UInt64 0 PRI SOR \N
|
||||
--- NOT ILIKE
|
||||
str String 0 SOR \N
|
||||
--- WHERE
|
||||
int32 Nullable(Int32) 1 \N
|
||||
uint64 UInt64 0 PRI SOR \N
|
||||
--- LIMIT
|
||||
int32 Nullable(Int32) 1 \N
|
||||
--- Original table
|
||||
int32 Nullable(Int32) 1 \N
|
||||
str String 0 SOR \N
|
||||
uint64 UInt64 0 PRI SOR \N
|
||||
--- Equally named table in other database
|
||||
int32 Int32 0 \N
|
||||
str String 0 \N
|
||||
uint64 UInt64 0 PRI SOR \N
|
||||
--- Short form
|
||||
int32 Int32 0 \N
|
||||
str String 0 \N
|
||||
uint64 UInt64 0 PRI SOR \N
|
70
tests/queries/0_stateless/25402_show_columns.sql
Normal file
70
tests/queries/0_stateless/25402_show_columns.sql
Normal file
@ -0,0 +1,70 @@
|
||||
-- Tags: no-parallel
|
||||
-- no-parallel: creates a custom database schema and expects to use it exclusively
|
||||
|
||||
-- Create a test table and verify that the output of SHOW COLUMNS is sane.
|
||||
-- The matching of actual/expected results relies on the fact that the output of SHOW COLUMNS is sorted.
|
||||
DROP TABLE IF EXISTS tab;
|
||||
CREATE TABLE tab
|
||||
(
|
||||
`uint64` UInt64,
|
||||
`int32` Nullable(Int32) COMMENT 'example comment',
|
||||
`str` String,
|
||||
INDEX idx str TYPE set(1000)
|
||||
)
|
||||
ENGINE = MergeTree
|
||||
PRIMARY KEY (uint64)
|
||||
ORDER BY (uint64, str);
|
||||
|
||||
SHOW COLUMNS FROM tab;
|
||||
|
||||
SELECT '--- EXTENDED';
|
||||
SHOW EXTENDED COLUMNS FROM tab;
|
||||
|
||||
SELECT '--- FULL';
|
||||
SHOW FULL COLUMNS FROM tab;
|
||||
|
||||
SELECT '--- LIKE';
|
||||
SHOW COLUMNS FROM tab LIKE '%int%';
|
||||
|
||||
SELECT '--- NOT LIKE';
|
||||
SHOW COLUMNS FROM tab NOT LIKE '%int%';
|
||||
|
||||
SELECT '--- ILIKE';
|
||||
SHOW COLUMNS FROM tab ILIKE '%INT%';
|
||||
|
||||
SELECT '--- NOT ILIKE';
|
||||
SHOW COLUMNS FROM tab NOT ILIKE '%INT%';
|
||||
|
||||
SELECT '--- WHERE';
|
||||
SHOW COLUMNS FROM tab WHERE field LIKE '%int%';
|
||||
|
||||
SELECT '--- LIMIT';
|
||||
SHOW COLUMNS FROM tab LIMIT 1;
|
||||
|
||||
-- Create a table in a different database. Intentionally useing the same table/column names as above so
|
||||
-- we notice if something is buggy in the implementation of SHOW COLUMNS.
|
||||
DROP DATABASE IF EXISTS database_123456789abcde;
|
||||
CREATE DATABASE database_123456789abcde; -- pseudo-random database name
|
||||
|
||||
DROP TABLE IF EXISTS database_123456789abcde.tab;
|
||||
CREATE TABLE database_123456789abcde.tab
|
||||
(
|
||||
`uint64` UInt64,
|
||||
`int32` Int32,
|
||||
`str` String
|
||||
)
|
||||
ENGINE = MergeTree
|
||||
ORDER BY uint64;
|
||||
|
||||
SELECT '--- Original table';
|
||||
SHOW COLUMNS FROM tab;
|
||||
|
||||
SELECT '--- Equally named table in other database';
|
||||
SHOW COLUMNS FROM tab FROM database_123456789abcde;
|
||||
|
||||
SELECT '--- Short form';
|
||||
SHOW COLUMNS FROM database_123456789abcde.tab;
|
||||
|
||||
DROP DATABASE database_123456789abcde;
|
||||
|
||||
DROP TABLE tab;
|
Loading…
Reference in New Issue
Block a user