Skip to content

Commit 22fc56b

Browse files
Merge pull request ClickHouse#80297 from ClickHouse/hilite-like-in-show-queries
Highlight metacharacters in `SHOW ... LIKE` queries
2 parents 85dc343 + f4d7e70 commit 22fc56b

File tree

9 files changed

+104
-60
lines changed

9 files changed

+104
-60
lines changed

src/Parsers/ASTDropQuery.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <Parsers/ASTDropQuery.h>
22
#include <Parsers/ASTIdentifier.h>
33
#include <Parsers/ASTExpressionList.h>
4+
#include <Parsers/ASTLiteral.h>
45
#include <Common/quoteString.h>
56
#include <IO/Operators.h>
67

@@ -109,11 +110,16 @@ void ASTDropQuery::formatQueryImpl(WriteBuffer & ostr, const FormatSettings & se
109110
}
110111

111112
if (!like.empty())
113+
{
112114
ostr << (settings.hilite ? hilite_keyword : "")
113-
<< (not_like ? " NOT" : "")
114-
<< (case_insensitive_like ? " ILIKE " : " LIKE")
115-
<< (settings.hilite ? hilite_none : "")
116-
<< DB::quote << like;
115+
<< (not_like ? " NOT" : "")
116+
<< (case_insensitive_like ? " ILIKE " : " LIKE")
117+
<< (settings.hilite ? hilite_none : "");
118+
if (settings.hilite)
119+
highlightStringWithMetacharacters(quoteString(like), ostr, "%_");
120+
else
121+
ostr << quoteString(like);
122+
}
117123

118124
formatOnCluster(ostr, settings);
119125

src/Parsers/ASTFunction.cpp

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -204,54 +204,6 @@ ASTPtr ASTFunction::toLiteral() const
204204
}
205205

206206

207-
/** A special hack. If it's [I]LIKE or NOT [I]LIKE expression and the right hand side is a string literal,
208-
* we will highlight unescaped metacharacters % and _ in string literal for convenience.
209-
* Motivation: most people are unaware that _ is a metacharacter and forgot to properly escape it with two backslashes.
210-
* With highlighting we make it clearly obvious.
211-
*
212-
* Another case is regexp match. Suppose the user types match(URL, 'www.clickhouse.com'). It often means that the user is unaware that . is a metacharacter.
213-
*/
214-
static bool highlightStringLiteralWithMetacharacters(const ASTPtr & node, WriteBuffer & ostr, const char * metacharacters)
215-
{
216-
if (const auto * literal = node->as<ASTLiteral>())
217-
{
218-
if (literal->value.getType() == Field::Types::String)
219-
{
220-
auto string = applyVisitor(FieldVisitorToString(), literal->value);
221-
222-
unsigned escaping = 0;
223-
for (auto c : string)
224-
{
225-
if (c == '\\')
226-
{
227-
ostr << c;
228-
if (escaping == 2)
229-
escaping = 0;
230-
++escaping;
231-
}
232-
else if (nullptr != strchr(metacharacters, c))
233-
{
234-
if (escaping == 2) /// Properly escaped metacharacter
235-
ostr << c;
236-
else /// Unescaped metacharacter
237-
ostr << "\033[1;35m" << c << "\033[0m";
238-
escaping = 0;
239-
}
240-
else
241-
{
242-
ostr << c;
243-
escaping = 0;
244-
}
245-
}
246-
247-
return true;
248-
}
249-
}
250-
251-
return false;
252-
}
253-
254-
255207
ASTSelectWithUnionQuery * ASTFunction::tryGetQueryArgument() const
256208
{
257209
if (arguments && arguments->children.size() == 1)

src/Parsers/ASTLiteral.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <Common/SipHash.h>
33
#include <Common/FieldVisitorToString.h>
44
#include <Common/FieldVisitorHash.h>
5+
#include <Common/quoteString.h>
56
#include <DataTypes/IDataType.h>
67
#include <Parsers/ASTLiteral.h>
78
#include <IO/WriteHelpers.h>
@@ -162,4 +163,48 @@ void ASTLiteral::formatImplWithoutAlias(WriteBuffer & ostr, const FormatSettings
162163
ostr << applyVisitor(FieldVisitorToStringPostgreSQL(), value);
163164
}
164165

166+
167+
bool highlightStringLiteralWithMetacharacters(const ASTPtr & node, WriteBuffer & ostr, const char * metacharacters)
168+
{
169+
if (const auto * literal = node->as<ASTLiteral>())
170+
{
171+
if (literal->value.getType() == Field::Types::String)
172+
{
173+
auto string = applyVisitor(FieldVisitorToString(), literal->value);
174+
highlightStringWithMetacharacters(string, ostr, metacharacters);
175+
return true;
176+
}
177+
}
178+
179+
return false;
180+
}
181+
182+
void highlightStringWithMetacharacters(const String & string, WriteBuffer & ostr, const char * metacharacters)
183+
{
184+
unsigned escaping = 0;
185+
for (auto c : string)
186+
{
187+
if (c == '\\')
188+
{
189+
ostr << c;
190+
if (escaping == 2)
191+
escaping = 0;
192+
++escaping;
193+
}
194+
else if (nullptr != strchr(metacharacters, c))
195+
{
196+
if (escaping == 2) /// Properly escaped metacharacter
197+
ostr << c;
198+
else /// Unescaped metacharacter
199+
ostr << "\033[1;35m" << c << "\033[0m";
200+
escaping = 0;
201+
}
202+
else
203+
{
204+
ostr << c;
205+
escaping = 0;
206+
}
207+
}
208+
}
209+
165210
}

src/Parsers/ASTLiteral.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,15 @@ class ASTLiteral : public ASTWithAlias
6363
void appendColumnNameImplLegacy(WriteBuffer & ostr) const;
6464
};
6565

66+
67+
/** A special UX improvement. If it's [I]LIKE or NOT [I]LIKE expression and the right hand side is a string literal,
68+
* we will highlight unescaped metacharacters % and _ in string literal for convenience.
69+
* Motivation: most people are unaware that _ is a metacharacter and forgot to properly escape it with two backslashes.
70+
* With highlighting we make it clearly obvious.
71+
*
72+
* Another case is regexp match. Suppose the user types match(URL, 'www.clickhouse.com'). It often means that the user is unaware that . is a metacharacter.
73+
*/
74+
bool highlightStringLiteralWithMetacharacters(const ASTPtr & node, WriteBuffer & ostr, const char * metacharacters);
75+
void highlightStringWithMetacharacters(const String & string, WriteBuffer & ostr, const char * metacharacters);
76+
6677
}

src/Parsers/ASTShowColumnsQuery.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <Parsers/ASTShowColumnsQuery.h>
2+
#include <Parsers/ASTLiteral.h>
23

34
#include <iomanip>
45
#include <Common/quoteString.h>
@@ -30,11 +31,17 @@ void ASTShowColumnsQuery::formatQueryImpl(WriteBuffer & ostr, const FormatSettin
3031

3132

3233
if (!like.empty())
33-
ostr << (settings.hilite ? hilite_keyword : "")
34-
<< (not_like ? " NOT" : "")
35-
<< (case_insensitive_like ? " ILIKE " : " LIKE")
36-
<< (settings.hilite ? hilite_none : "")
37-
<< DB::quote << like;
34+
{
35+
ostr
36+
<< (settings.hilite ? hilite_keyword : "")
37+
<< (not_like ? " NOT" : "")
38+
<< (case_insensitive_like ? " ILIKE " : " LIKE")
39+
<< (settings.hilite ? hilite_none : "");
40+
if (settings.hilite)
41+
highlightStringWithMetacharacters(quoteString(like), ostr, "%_");
42+
else
43+
ostr << quoteString(like);
44+
}
3845

3946
if (where_expression)
4047
{

src/Parsers/ASTShowFunctionsQuery.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include <Parsers/ASTShowFunctionsQuery.h>
2+
#include <Parsers/ASTLiteral.h>
3+
#include <Common/quoteString.h>
24

35

46
namespace DB
@@ -17,8 +19,14 @@ void ASTShowFunctionsQuery::formatQueryImpl(WriteBuffer & ostr, const FormatSett
1719
ostr << (settings.hilite ? hilite_keyword : "") << "SHOW FUNCTIONS" << (settings.hilite ? hilite_none : "");
1820

1921
if (!like.empty())
22+
{
2023
ostr << (settings.hilite ? hilite_keyword : "") << (case_insensitive_like ? " ILIKE " : " LIKE ")
21-
<< (settings.hilite ? hilite_none : "") << DB::quote << like;
24+
<< (settings.hilite ? hilite_none : "");
25+
if (settings.hilite)
26+
highlightStringWithMetacharacters(quoteString(like), ostr, "%_");
27+
else
28+
ostr << quoteString(like);
29+
}
2230
}
2331

2432
}

src/Parsers/ASTShowTablesQuery.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <iomanip>
22
#include <Parsers/ASTIdentifier_fwd.h>
33
#include <Parsers/ASTShowTablesQuery.h>
4+
#include <Parsers/ASTLiteral.h>
45
#include <Common/quoteString.h>
56
#include <IO/Operators.h>
67

@@ -28,12 +29,18 @@ String ASTShowTablesQuery::getFrom() const
2829
void ASTShowTablesQuery::formatLike(WriteBuffer & ostr, const FormatSettings & settings) const
2930
{
3031
if (!like.empty())
32+
{
3133
ostr
3234
<< (settings.hilite ? hilite_keyword : "")
3335
<< (not_like ? " NOT" : "")
3436
<< (case_insensitive_like ? " ILIKE " : " LIKE ")
35-
<< (settings.hilite ? hilite_none : "")
36-
<< DB::quote << like;
37+
<< (settings.hilite ? hilite_none : "");
38+
39+
if (settings.hilite)
40+
highlightStringWithMetacharacters(quoteString(like), ostr, "%_");
41+
else
42+
ostr << quoteString(like);
43+
}
3744
}
3845

3946
void ASTShowTablesQuery::formatLimit(WriteBuffer & ostr, const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
SHOW TABLES ILIKE '%te_st%'
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env bash
2+
3+
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
4+
# shellcheck source=../shell_config.sh
5+
. "$CURDIR"/../shell_config.sh
6+
7+
${CLICKHOUSE_FORMAT} --hilite <<< "SHOW TABLES ILIKE '%te_st%'"

0 commit comments

Comments
 (0)