Merge pull request #73085 from Avogar/json-subcolumns-formatting

Improve formatting of identifiers with JSON subcolumns
This commit is contained in:
Pavel Kruglov 2024-12-13 15:15:06 +00:00 committed by GitHub
commit d318832015
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 60 additions and 7 deletions

View File

@ -5,6 +5,7 @@
#include <Interpreters/IdentifierSemantic.h>
#include <Interpreters/StorageID.h>
#include <Parsers/queryToString.h>
#include <Parsers/ExpressionElementParsers.h>
#include <IO/Operators.h>
@ -109,7 +110,15 @@ void ASTIdentifier::formatImplWithoutAlias(WriteBuffer & ostr, const FormatSetti
auto format_element = [&](const String & elem_name)
{
ostr << (settings.hilite ? hilite_identifier : "");
if (auto special_delimiter_and_identifier = ParserCompoundIdentifier::splitSpecialDelimiterAndIdentifierIfAny(elem_name))
{
ostr << special_delimiter_and_identifier->first;
settings.writeIdentifier(ostr, special_delimiter_and_identifier->second, /*ambiguous=*/false);
}
else
{
settings.writeIdentifier(ostr, elem_name, /*ambiguous=*/false);
}
ostr << (settings.hilite ? hilite_none : "");
};

View File

@ -415,6 +415,20 @@ bool ParserCompoundIdentifier::parseImpl(Pos & pos, ASTPtr & node, Expected & ex
return true;
}
std::optional<std::pair<char, String>> ParserCompoundIdentifier::splitSpecialDelimiterAndIdentifierIfAny(const String & name)
{
/// Identifier with special delimiter looks like this: <special_delimiter>`<identifier>`.
if (name.size() < 3
|| (name[0] != char(SpecialDelimiter::JSON_PATH_DYNAMIC_TYPE) && name[0] != char(SpecialDelimiter::JSON_PATH_PREFIX))
|| name[1] != '`' || name.back() != '`')
return std::nullopt;
String identifier;
ReadBufferFromMemory buf(name.data() + 1, name.size() - 1);
readBackQuotedString(identifier, buf);
return std::make_pair(name[0], identifier);
}
ASTPtr createFunctionCast(const ASTPtr & expr_ast, const ASTPtr & type_ast)
{

View File

@ -61,6 +61,16 @@ protected:
class ParserCompoundIdentifier : public IParserBase
{
public:
explicit ParserCompoundIdentifier(bool table_name_with_optional_uuid_ = false, bool allow_query_parameter_ = false, Highlight highlight_type_ = Highlight::identifier)
: table_name_with_optional_uuid(table_name_with_optional_uuid_), allow_query_parameter(allow_query_parameter_), highlight_type(highlight_type_)
{
}
/// Checks if the identirier is actually a pair of a special delimiter and the identifier in back quotes.
/// For example: :`UInt64` or ^`path` from special JSON subcolumns.
static std::optional<std::pair<char, String>> splitSpecialDelimiterAndIdentifierIfAny(const String & name);
protected:
enum class SpecialDelimiter : char
{
NONE = '\0',
@ -68,12 +78,6 @@ public:
JSON_PATH_PREFIX = '^',
};
explicit ParserCompoundIdentifier(bool table_name_with_optional_uuid_ = false, bool allow_query_parameter_ = false, Highlight highlight_type_ = Highlight::identifier)
: table_name_with_optional_uuid(table_name_with_optional_uuid_), allow_query_parameter(allow_query_parameter_), highlight_type(highlight_type_)
{
}
protected:
const char * getName() const override { return "compound identifier"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
bool table_name_with_optional_uuid;

View File

@ -0,0 +1,12 @@
SELECT json.^sub.object.path
FROM test
SELECT json.^`s^b`.object.path
FROM test
SELECT json.`^sub`.object.path
FROM test
SELECT json.path.:UInt64
FROM test
SELECT json.path.:`Array(JSON)`
FROM test
SELECT json.path.`:UInt64`
FROM test

View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=../shell_config.sh
. "$CURDIR"/../shell_config.sh
$CLICKHOUSE_FORMAT --query "select json.^sub.object.path from test";
$CLICKHOUSE_FORMAT --query "select json.^\`s^b\`.object.path from test";
$CLICKHOUSE_FORMAT --query "select json.\`^sub\`.object.path from test";
$CLICKHOUSE_FORMAT --query "select json.path.:UInt64 from test";
$CLICKHOUSE_FORMAT --query "select json.path.:\`Array(JSON)\` from test";
$CLICKHOUSE_FORMAT --query "select json.path.\`:UInt64\` from test";