Merge pull request #68492 from ClickHouse/pretty-print-tuples-in-create-table-statements

Pretty print tuples in CREATE TABLE statements
This commit is contained in:
Alexey Milovidov 2024-08-19 02:26:03 +00:00 committed by GitHub
commit 285f99f719
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 184 additions and 53 deletions

View File

@ -264,7 +264,11 @@ int mainEntryClickHouseFormat(int argc, char ** argv)
if (!backslash) if (!backslash)
{ {
WriteBufferFromOwnString str_buf; WriteBufferFromOwnString str_buf;
formatAST(*res, str_buf, hilite, oneline || approx_query_length < max_line_length); bool oneline_current_query = oneline || approx_query_length < max_line_length;
IAST::FormatSettings settings(str_buf, oneline_current_query, hilite);
settings.show_secrets = true;
settings.print_pretty_type_names = !oneline_current_query;
res->format(settings);
if (insert_query_payload) if (insert_query_payload)
{ {
@ -307,7 +311,11 @@ int mainEntryClickHouseFormat(int argc, char ** argv)
else else
{ {
WriteBufferFromOwnString str_buf; WriteBufferFromOwnString str_buf;
formatAST(*res, str_buf, hilite, oneline); bool oneline_current_query = oneline || approx_query_length < max_line_length;
IAST::FormatSettings settings(str_buf, oneline_current_query, hilite);
settings.show_secrets = true;
settings.print_pretty_type_names = !oneline_current_query;
res->format(settings);
auto res_string = str_buf.str(); auto res_string = str_buf.str();
WriteBufferFromOStream res_cout(std::cout, 4096); WriteBufferFromOStream res_cout(std::cout, 4096);

View File

@ -331,7 +331,11 @@ ASTPtr ClientBase::parseQuery(const char *& pos, const char * end, const Setting
{ {
output_stream << std::endl; output_stream << std::endl;
WriteBufferFromOStream res_buf(output_stream, 4096); WriteBufferFromOStream res_buf(output_stream, 4096);
formatAST(*res, res_buf); IAST::FormatSettings format_settings(res_buf, /* one_line */ false);
format_settings.hilite = true;
format_settings.show_secrets = true;
format_settings.print_pretty_type_names = true;
res->format(format_settings);
res_buf.finalize(); res_buf.finalize();
output_stream << std::endl << std::endl; output_stream << std::endl << std::endl;
} }

View File

@ -85,7 +85,7 @@ void BaseExternalTable::parseStructureFromStructureField(const std::string & arg
/// We use `formatWithPossiblyHidingSensitiveData` instead of `getColumnNameWithoutAlias` because `column->type` is an ASTFunction. /// We use `formatWithPossiblyHidingSensitiveData` instead of `getColumnNameWithoutAlias` because `column->type` is an ASTFunction.
/// `getColumnNameWithoutAlias` will return name of the function with `(arguments)` even if arguments is empty. /// `getColumnNameWithoutAlias` will return name of the function with `(arguments)` even if arguments is empty.
if (column) if (column)
structure.emplace_back(column->name, column->type->formatWithPossiblyHidingSensitiveData(0, true, true)); structure.emplace_back(column->name, column->type->formatWithPossiblyHidingSensitiveData(0, true, true, false));
else else
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Error while parsing table structure: expected column definition, got {}", child->formatForErrorMessage()); throw Exception(ErrorCodes::BAD_ARGUMENTS, "Error while parsing table structure: expected column definition, got {}", child->formatForErrorMessage());
} }
@ -102,7 +102,7 @@ void BaseExternalTable::parseStructureFromTypesField(const std::string & argumen
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Error while parsing table structure: {}", error); throw Exception(ErrorCodes::BAD_ARGUMENTS, "Error while parsing table structure: {}", error);
for (size_t i = 0; i < type_list_raw->children.size(); ++i) for (size_t i = 0; i < type_list_raw->children.size(); ++i)
structure.emplace_back("_" + toString(i + 1), type_list_raw->children[i]->formatWithPossiblyHidingSensitiveData(0, true, true)); structure.emplace_back("_" + toString(i + 1), type_list_raw->children[i]->formatWithPossiblyHidingSensitiveData(0, true, true, false));
} }
void BaseExternalTable::initSampleBlock() void BaseExternalTable::initSampleBlock()

View File

@ -882,7 +882,7 @@ class IColumn;
M(Bool, use_json_alias_for_old_object_type, false, "When enabled, JSON type alias will create old experimental Object type instead of a new JSON type", 0) \ M(Bool, use_json_alias_for_old_object_type, false, "When enabled, JSON type alias will create old experimental Object type instead of a new JSON type", 0) \
M(Bool, allow_create_index_without_type, false, "Allow CREATE INDEX query without TYPE. Query will be ignored. Made for SQL compatibility tests.", 0) \ M(Bool, allow_create_index_without_type, false, "Allow CREATE INDEX query without TYPE. Query will be ignored. Made for SQL compatibility tests.", 0) \
M(Bool, create_index_ignore_unique, false, "Ignore UNIQUE keyword in CREATE UNIQUE INDEX. Made for SQL compatibility tests.", 0) \ M(Bool, create_index_ignore_unique, false, "Ignore UNIQUE keyword in CREATE UNIQUE INDEX. Made for SQL compatibility tests.", 0) \
M(Bool, print_pretty_type_names, true, "Print pretty type names in DESCRIBE query and toTypeName() function", 0) \ M(Bool, print_pretty_type_names, true, "Print pretty type names in the DESCRIBE query and `toTypeName` function, as well as in the `SHOW CREATE TABLE` query and the `formatQuery` function.", 0) \
M(Bool, create_table_empty_primary_key_by_default, false, "Allow to create *MergeTree tables with empty primary key when ORDER BY and PRIMARY KEY not specified", 0) \ M(Bool, create_table_empty_primary_key_by_default, false, "Allow to create *MergeTree tables with empty primary key when ORDER BY and PRIMARY KEY not specified", 0) \
M(Bool, allow_named_collection_override_by_default, true, "Allow named collections' fields override by default.", 0) \ M(Bool, allow_named_collection_override_by_default, true, "Allow named collections' fields override by default.", 0) \
M(SQLSecurityType, default_normal_view_sql_security, SQLSecurityType::INVOKER, "Allows to set a default value for SQL SECURITY option when creating a normal view.", 0) \ M(SQLSecurityType, default_normal_view_sql_security, SQLSecurityType::INVOKER, "Allows to set a default value for SQL SECURITY option when creating a normal view.", 0) \

View File

@ -8,7 +8,6 @@
#include <Common/quoteString.h> #include <Common/quoteString.h>
#include <IO/WriteHelpers.h> #include <IO/WriteHelpers.h>
#include <IO/Operators.h>
#include <DataTypes/IDataType.h> #include <DataTypes/IDataType.h>
#include <DataTypes/DataTypeCustom.h> #include <DataTypes/DataTypeCustom.h>

View File

@ -504,7 +504,7 @@ void DatabaseOnDisk::renameTable(
} }
/// It returns create table statement (even if table is detached) /// It returns the create table statement (even if table is detached)
ASTPtr DatabaseOnDisk::getCreateTableQueryImpl(const String & table_name, ContextPtr, bool throw_on_error) const ASTPtr DatabaseOnDisk::getCreateTableQueryImpl(const String & table_name, ContextPtr, bool throw_on_error) const
{ {
ASTPtr ast; ASTPtr ast;

View File

@ -43,6 +43,7 @@ public:
max_query_size = settings.max_query_size; max_query_size = settings.max_query_size;
max_parser_depth = settings.max_parser_depth; max_parser_depth = settings.max_parser_depth;
max_parser_backtracks = settings.max_parser_backtracks; max_parser_backtracks = settings.max_parser_backtracks;
print_pretty_type_names = settings.print_pretty_type_names;
} }
String getName() const override { return name; } String getName() const override { return name; }
@ -138,7 +139,11 @@ private:
} }
} }
formatAST(*ast, buf, /*hilite*/ false, /*single_line*/ output_formatting == OutputFormatting::SingleLine); IAST::FormatSettings settings(buf, output_formatting == OutputFormatting::SingleLine, /*hilite*/ false);
settings.show_secrets = true;
settings.print_pretty_type_names = print_pretty_type_names;
ast->format(settings);
auto formatted = buf.stringView(); auto formatted = buf.stringView();
const size_t res_data_new_size = res_data_size + formatted.size() + 1; const size_t res_data_new_size = res_data_size + formatted.size() + 1;
@ -165,6 +170,7 @@ private:
size_t max_query_size; size_t max_query_size;
size_t max_parser_depth; size_t max_parser_depth;
size_t max_parser_backtracks; size_t max_parser_backtracks;
bool print_pretty_type_names;
}; };
} }

View File

@ -97,7 +97,12 @@ QueryPipeline InterpreterShowCreateQuery::executeImpl()
} }
MutableColumnPtr column = ColumnString::create(); MutableColumnPtr column = ColumnString::create();
column->insert(format({.ctx = getContext(), .query = *create_query, .one_line = false})); column->insert(format(
{
.ctx = getContext(),
.query = *create_query,
.one_line = false
}));
return QueryPipeline(std::make_shared<SourceFromSingleChunk>(Block{{ return QueryPipeline(std::make_shared<SourceFromSingleChunk>(Block{{
std::move(column), std::move(column),

View File

@ -786,7 +786,7 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
/// Verify that AST formatting is consistent: /// Verify that AST formatting is consistent:
/// If you format AST, parse it back, and format it again, you get the same string. /// If you format AST, parse it back, and format it again, you get the same string.
String formatted1 = ast->formatWithPossiblyHidingSensitiveData(0, true, true); String formatted1 = ast->formatWithPossiblyHidingSensitiveData(0, true, true, false);
/// The query can become more verbose after formatting, so: /// The query can become more verbose after formatting, so:
size_t new_max_query_size = max_query_size > 0 ? (1000 + 2 * max_query_size) : 0; size_t new_max_query_size = max_query_size > 0 ? (1000 + 2 * max_query_size) : 0;
@ -811,7 +811,7 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
chassert(ast2); chassert(ast2);
String formatted2 = ast2->formatWithPossiblyHidingSensitiveData(0, true, true); String formatted2 = ast2->formatWithPossiblyHidingSensitiveData(0, true, true, false);
if (formatted1 != formatted2) if (formatted1 != formatted2)
throw Exception(ErrorCodes::LOGICAL_ERROR, throw Exception(ErrorCodes::LOGICAL_ERROR,

View File

@ -25,7 +25,8 @@ inline String format(const SecretHidingFormatSettings & settings)
&& settings.ctx->getSettingsRef().format_display_secrets_in_show_and_select && settings.ctx->getSettingsRef().format_display_secrets_in_show_and_select
&& settings.ctx->getAccess()->isGranted(AccessType::displaySecretsInShowAndSelect); && settings.ctx->getAccess()->isGranted(AccessType::displaySecretsInShowAndSelect);
return settings.query.formatWithPossiblyHidingSensitiveData(settings.max_length, settings.one_line, show_secrets); return settings.query.formatWithPossiblyHidingSensitiveData(
settings.max_length, settings.one_line, show_secrets, settings.ctx->getSettingsRef().print_pretty_type_names);
} }
} }

View File

@ -66,17 +66,13 @@ void ASTColumnDeclaration::formatImpl(const FormatSettings & format_settings, Fo
{ {
frame.need_parens = false; frame.need_parens = false;
/// We have to always backquote column names to avoid ambiguouty with INDEX and other declarations in CREATE query. /// We have to always backquote column names to avoid ambiguity with INDEX and other declarations in CREATE query.
format_settings.ostr << backQuote(name); format_settings.ostr << backQuote(name);
if (type) if (type)
{ {
format_settings.ostr << ' '; format_settings.ostr << ' ';
type->formatImpl(format_settings, state, frame);
FormatStateStacked type_frame = frame;
type_frame.indent = 0;
type->formatImpl(format_settings, state, type_frame);
} }
if (null_modifier) if (null_modifier)

View File

@ -40,12 +40,22 @@ void ASTDataType::formatImpl(const FormatSettings & settings, FormatState & stat
{ {
settings.ostr << '(' << (settings.hilite ? hilite_none : ""); settings.ostr << '(' << (settings.hilite ? hilite_none : "");
for (size_t i = 0, size = arguments->children.size(); i < size; ++i) if (!settings.one_line && settings.print_pretty_type_names && name == "Tuple")
{ {
if (i != 0) ++frame.indent;
settings.ostr << ", "; std::string indent_str = settings.one_line ? "" : "\n" + std::string(4 * frame.indent, ' ');
for (size_t i = 0, size = arguments->children.size(); i < size; ++i)
arguments->children[i]->formatImpl(settings, state, frame); {
if (i != 0)
settings.ostr << ',';
settings.ostr << indent_str;
arguments->children[i]->formatImpl(settings, state, frame);
}
}
else
{
frame.expression_list_prepend_whitespace = false;
arguments->formatImpl(settings, state, frame);
} }
settings.ostr << (settings.hilite ? hilite_function : "") << ')'; settings.ostr << (settings.hilite ? hilite_function : "") << ')';

View File

@ -42,7 +42,8 @@ void ASTExpressionList::formatImpl(const FormatSettings & settings, FormatState
void ASTExpressionList::formatImplMultiline(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const void ASTExpressionList::formatImplMultiline(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
{ {
std::string indent_str = "\n" + std::string(4 * (frame.indent + 1), ' '); ++frame.indent;
std::string indent_str = "\n" + std::string(4 * frame.indent, ' ');
if (frame.expression_list_prepend_whitespace) if (frame.expression_list_prepend_whitespace)
{ {
@ -50,8 +51,6 @@ void ASTExpressionList::formatImplMultiline(const FormatSettings & settings, For
settings.ostr << ' '; settings.ostr << ' ';
} }
++frame.indent;
for (size_t i = 0, size = children.size(); i < size; ++i) for (size_t i = 0, size = children.size(); i < size; ++i)
{ {
if (i && separator) if (i && separator)

View File

@ -23,12 +23,8 @@ ASTPtr ASTNameTypePair::clone() const
void ASTNameTypePair::formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const void ASTNameTypePair::formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const
{ {
std::string indent_str = settings.one_line ? "" : std::string(4 * frame.indent, ' '); settings.ostr << backQuoteIfNeed(name) << ' ';
settings.ostr << indent_str << backQuoteIfNeed(name) << ' ';
type->formatImpl(settings, state, frame); type->formatImpl(settings, state, frame);
} }
} }

View File

@ -165,11 +165,12 @@ size_t IAST::checkDepthImpl(size_t max_depth) const
return res; return res;
} }
String IAST::formatWithPossiblyHidingSensitiveData(size_t max_length, bool one_line, bool show_secrets) const String IAST::formatWithPossiblyHidingSensitiveData(size_t max_length, bool one_line, bool show_secrets, bool print_pretty_type_names) const
{ {
WriteBufferFromOwnString buf; WriteBufferFromOwnString buf;
FormatSettings settings(buf, one_line); FormatSettings settings(buf, one_line);
settings.show_secrets = show_secrets; settings.show_secrets = show_secrets;
settings.print_pretty_type_names = print_pretty_type_names;
format(settings); format(settings);
return wipeSensitiveDataAndCutToLength(buf.str(), max_length); return wipeSensitiveDataAndCutToLength(buf.str(), max_length);
} }

View File

@ -201,6 +201,7 @@ public:
bool show_secrets; /// Show secret parts of the AST (e.g. passwords, encryption keys). bool show_secrets; /// Show secret parts of the AST (e.g. passwords, encryption keys).
char nl_or_ws; /// Newline or whitespace. char nl_or_ws; /// Newline or whitespace.
LiteralEscapingStyle literal_escaping_style; LiteralEscapingStyle literal_escaping_style;
bool print_pretty_type_names;
explicit FormatSettings( explicit FormatSettings(
WriteBuffer & ostr_, WriteBuffer & ostr_,
@ -209,7 +210,8 @@ public:
bool always_quote_identifiers_ = false, bool always_quote_identifiers_ = false,
IdentifierQuotingStyle identifier_quoting_style_ = IdentifierQuotingStyle::Backticks, IdentifierQuotingStyle identifier_quoting_style_ = IdentifierQuotingStyle::Backticks,
bool show_secrets_ = true, bool show_secrets_ = true,
LiteralEscapingStyle literal_escaping_style_ = LiteralEscapingStyle::Regular) LiteralEscapingStyle literal_escaping_style_ = LiteralEscapingStyle::Regular,
bool print_pretty_type_names_ = false)
: ostr(ostr_) : ostr(ostr_)
, one_line(one_line_) , one_line(one_line_)
, hilite(hilite_) , hilite(hilite_)
@ -218,6 +220,7 @@ public:
, show_secrets(show_secrets_) , show_secrets(show_secrets_)
, nl_or_ws(one_line ? ' ' : '\n') , nl_or_ws(one_line ? ' ' : '\n')
, literal_escaping_style(literal_escaping_style_) , literal_escaping_style(literal_escaping_style_)
, print_pretty_type_names(print_pretty_type_names_)
{ {
} }
@ -230,6 +233,7 @@ public:
, show_secrets(other.show_secrets) , show_secrets(other.show_secrets)
, nl_or_ws(other.nl_or_ws) , nl_or_ws(other.nl_or_ws)
, literal_escaping_style(other.literal_escaping_style) , literal_escaping_style(other.literal_escaping_style)
, print_pretty_type_names(other.print_pretty_type_names)
{ {
} }
@ -251,7 +255,7 @@ public:
/// The state that is copied when each node is formatted. For example, nesting level. /// The state that is copied when each node is formatted. For example, nesting level.
struct FormatStateStacked struct FormatStateStacked
{ {
UInt8 indent = 0; UInt16 indent = 0;
bool need_parens = false; bool need_parens = false;
bool expression_list_always_start_on_new_line = false; /// Line feed and indent before expression list even if it's of single element. bool expression_list_always_start_on_new_line = false; /// Line feed and indent before expression list even if it's of single element.
bool expression_list_prepend_whitespace = false; /// Prepend whitespace (if it is required) bool expression_list_prepend_whitespace = false; /// Prepend whitespace (if it is required)
@ -274,7 +278,7 @@ public:
/// Secrets are displayed regarding show_secrets, then SensitiveDataMasker is applied. /// Secrets are displayed regarding show_secrets, then SensitiveDataMasker is applied.
/// You can use Interpreters/formatWithPossiblyHidingSecrets.h for convenience. /// You can use Interpreters/formatWithPossiblyHidingSecrets.h for convenience.
String formatWithPossiblyHidingSensitiveData(size_t max_length, bool one_line, bool show_secrets) const; String formatWithPossiblyHidingSensitiveData(size_t max_length, bool one_line, bool show_secrets, bool print_pretty_type_names) const;
/** formatForLogging and formatForErrorMessage always hide secrets. This inconsistent /** formatForLogging and formatForErrorMessage always hide secrets. This inconsistent
* behaviour is due to the fact such functions are called from Client which knows nothing about * behaviour is due to the fact such functions are called from Client which knows nothing about
@ -283,12 +287,12 @@ public:
*/ */
String formatForLogging(size_t max_length = 0) const String formatForLogging(size_t max_length = 0) const
{ {
return formatWithPossiblyHidingSensitiveData(max_length, true, false); return formatWithPossiblyHidingSensitiveData(max_length, true, false, false);
} }
String formatForErrorMessage() const String formatForErrorMessage() const
{ {
return formatWithPossiblyHidingSensitiveData(0, true, false); return formatWithPossiblyHidingSensitiveData(0, true, false, false);
} }
virtual bool hasSecretParts() const { return childrenHaveSecretParts(); } virtual bool hasSecretParts() const { return childrenHaveSecretParts(); }

View File

@ -1,4 +1,4 @@
CREATE TABLE default.compression_codec\n(\n `id` UInt64 CODEC(DEFLATE_QPL),\n `data` String CODEC(DEFLATE_QPL),\n `ddd` Date CODEC(DEFLATE_QPL),\n `ddd32` Date32 CODEC(DEFLATE_QPL),\n `somenum` Float64 CODEC(DEFLATE_QPL),\n `somestr` FixedString(3) CODEC(DEFLATE_QPL),\n `othernum` Int64 CODEC(DEFLATE_QPL),\n `somearray` Array(UInt8) CODEC(DEFLATE_QPL),\n `somemap` Map(String, UInt32) CODEC(DEFLATE_QPL),\n `sometuple` Tuple(UInt16, UInt64) CODEC(DEFLATE_QPL)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192 CREATE TABLE default.compression_codec\n(\n `id` UInt64 CODEC(DEFLATE_QPL),\n `data` String CODEC(DEFLATE_QPL),\n `ddd` Date CODEC(DEFLATE_QPL),\n `ddd32` Date32 CODEC(DEFLATE_QPL),\n `somenum` Float64 CODEC(DEFLATE_QPL),\n `somestr` FixedString(3) CODEC(DEFLATE_QPL),\n `othernum` Int64 CODEC(DEFLATE_QPL),\n `somearray` Array(UInt8) CODEC(DEFLATE_QPL),\n `somemap` Map(String, UInt32) CODEC(DEFLATE_QPL),\n `sometuple` Tuple(\n UInt16,\n UInt64) CODEC(DEFLATE_QPL)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192
1 hello 2018-12-14 2018-12-14 1.1 aaa 5 [1,2,3] {'k1':1,'k2':2} (1,2) 1 hello 2018-12-14 2018-12-14 1.1 aaa 5 [1,2,3] {'k1':1,'k2':2} (1,2)
2 world 2018-12-15 2018-12-15 2.2 bbb 6 [4,5,6] {'k3':3,'k4':4} (3,4) 2 world 2018-12-15 2018-12-15 2.2 bbb 6 [4,5,6] {'k3':3,'k4':4} (3,4)
3 ! 2018-12-16 2018-12-16 3.3 ccc 7 [7,8,9] {'k5':5,'k6':6} (5,6) 3 ! 2018-12-16 2018-12-16 3.3 ccc 7 [7,8,9] {'k5':5,'k6':6} (5,6)

View File

@ -1,4 +1,4 @@
CREATE TABLE default.compression_codec\n(\n `id` UInt64 CODEC(ZSTD_QAT(1)),\n `data` String CODEC(ZSTD_QAT(1)),\n `ddd` Date CODEC(ZSTD_QAT(1)),\n `ddd32` Date32 CODEC(ZSTD_QAT(1)),\n `somenum` Float64 CODEC(ZSTD_QAT(1)),\n `somestr` FixedString(3) CODEC(ZSTD_QAT(1)),\n `othernum` Int64 CODEC(ZSTD_QAT(1)),\n `somearray` Array(UInt8) CODEC(ZSTD_QAT(1)),\n `somemap` Map(String, UInt32) CODEC(ZSTD_QAT(1)),\n `sometuple` Tuple(UInt16, UInt64) CODEC(ZSTD_QAT(1))\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192 CREATE TABLE default.compression_codec\n(\n `id` UInt64 CODEC(ZSTD_QAT(1)),\n `data` String CODEC(ZSTD_QAT(1)),\n `ddd` Date CODEC(ZSTD_QAT(1)),\n `ddd32` Date32 CODEC(ZSTD_QAT(1)),\n `somenum` Float64 CODEC(ZSTD_QAT(1)),\n `somestr` FixedString(3) CODEC(ZSTD_QAT(1)),\n `othernum` Int64 CODEC(ZSTD_QAT(1)),\n `somearray` Array(UInt8) CODEC(ZSTD_QAT(1)),\n `somemap` Map(String, UInt32) CODEC(ZSTD_QAT(1)),\n `sometuple` Tuple(\n UInt16,\n UInt64) CODEC(ZSTD_QAT(1))\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192
1 hello 2018-12-14 2018-12-14 1.1 aaa 5 [1,2,3] {'k1':1,'k2':2} (1,2) 1 hello 2018-12-14 2018-12-14 1.1 aaa 5 [1,2,3] {'k1':1,'k2':2} (1,2)
2 world 2018-12-15 2018-12-15 2.2 bbb 6 [4,5,6] {'k3':3,'k4':4} (3,4) 2 world 2018-12-15 2018-12-15 2.2 bbb 6 [4,5,6] {'k3':3,'k4':4} (3,4)
3 ! 2018-12-16 2018-12-16 3.3 ccc 7 [7,8,9] {'k5':5,'k6':6} (5,6) 3 ! 2018-12-16 2018-12-16 3.3 ccc 7 [7,8,9] {'k5':5,'k6':6} (5,6)

View File

@ -1,12 +1,16 @@
CREATE TABLE default.tuple CREATE TABLE default.tuple
( (
`j` Tuple(a Int8, b String) `j` Tuple(
a Int8,
b String)
) )
ENGINE = Memory ENGINE = Memory
j Tuple(\n a Int8,\n b String) j Tuple(\n a Int8,\n b String)
CREATE TABLE default.tuple CREATE TABLE default.tuple
( (
`j` Tuple(a Int8, b String) `j` Tuple(
a Int8,
b String)
) )
ENGINE = Memory ENGINE = Memory
j Tuple(\n a Int8,\n b String) j Tuple(\n a Int8,\n b String)

View File

@ -1,20 +1,20 @@
1 1 [[1]] (1,[1]) 1 1 [[1]] (1,[1])
1 1 [[1]] (1,[1]) 1 1 [[1]] (1,[1])
CREATE TABLE default.columns_with_multiple_streams\n(\n `field0` Nullable(Int64) CODEC(Delta(2), LZ4),\n `field1` Nullable(UInt8) CODEC(Delta(8), LZ4),\n `field2` Array(Array(Int64)) CODEC(Delta(8), LZ4),\n `field3` Tuple(UInt32, Array(UInt64)) CODEC(T64, Default)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS min_rows_for_wide_part = 0, min_bytes_for_wide_part = 0, index_granularity = 8192 CREATE TABLE default.columns_with_multiple_streams\n(\n `field0` Nullable(Int64) CODEC(Delta(2), LZ4),\n `field1` Nullable(UInt8) CODEC(Delta(8), LZ4),\n `field2` Array(Array(Int64)) CODEC(Delta(8), LZ4),\n `field3` Tuple(\n UInt32,\n Array(UInt64)) CODEC(T64, Default)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS min_rows_for_wide_part = 0, min_bytes_for_wide_part = 0, index_granularity = 8192
1 1 [[1]] (1,[1]) 1 1 [[1]] (1,[1])
2 2 [[2]] (2,[2]) 2 2 [[2]] (2,[2])
CREATE TABLE default.columns_with_multiple_streams\n(\n `field0` Nullable(Int64) CODEC(Delta(2), LZ4),\n `field1` Nullable(UInt8) CODEC(Delta(8), LZ4),\n `field2` Array(Array(Int64)) CODEC(Delta(8), LZ4),\n `field3` Tuple(UInt32, Array(UInt64)) CODEC(Delta, Default)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS min_rows_for_wide_part = 0, min_bytes_for_wide_part = 0, index_granularity = 8192 CREATE TABLE default.columns_with_multiple_streams\n(\n `field0` Nullable(Int64) CODEC(Delta(2), LZ4),\n `field1` Nullable(UInt8) CODEC(Delta(8), LZ4),\n `field2` Array(Array(Int64)) CODEC(Delta(8), LZ4),\n `field3` Tuple(\n UInt32,\n Array(UInt64)) CODEC(Delta, Default)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS min_rows_for_wide_part = 0, min_bytes_for_wide_part = 0, index_granularity = 8192
1 1 [[1]] (1,[1]) 1 1 [[1]] (1,[1])
2 2 [[2]] (2,[2]) 2 2 [[2]] (2,[2])
3 3 [[3]] (3,[3]) 3 3 [[3]] (3,[3])
1 1 [[1]] (1,[1]) 1 1 [[1]] (1,[1])
1 1 [[1]] (1,[1]) 1 1 [[1]] (1,[1])
CREATE TABLE default.columns_with_multiple_streams_compact\n(\n `field0` Nullable(Int64) CODEC(Delta(2), LZ4),\n `field1` Nullable(UInt8) CODEC(Delta(8), LZ4),\n `field2` Array(Array(Int64)) CODEC(Delta(8), LZ4),\n `field3` Tuple(UInt32, Array(UInt64)) CODEC(Delta, Default)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS min_rows_for_wide_part = 100000, min_bytes_for_wide_part = 100000, index_granularity = 8192 CREATE TABLE default.columns_with_multiple_streams_compact\n(\n `field0` Nullable(Int64) CODEC(Delta(2), LZ4),\n `field1` Nullable(UInt8) CODEC(Delta(8), LZ4),\n `field2` Array(Array(Int64)) CODEC(Delta(8), LZ4),\n `field3` Tuple(\n UInt32,\n Array(UInt64)) CODEC(Delta, Default)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS min_rows_for_wide_part = 100000, min_bytes_for_wide_part = 100000, index_granularity = 8192
1 1 [[1]] (1,[1]) 1 1 [[1]] (1,[1])
2 2 [[2]] (2,[2]) 2 2 [[2]] (2,[2])
1 1 [[1]] (1,[1]) 1 1 [[1]] (1,[1])
2 2 [[2]] (2,[2]) 2 2 [[2]] (2,[2])
CREATE TABLE default.columns_with_multiple_streams_compact\n(\n `field0` Nullable(Int64) CODEC(Delta(2), LZ4),\n `field1` Nullable(UInt8) CODEC(Delta(8), LZ4),\n `field2` Array(Array(Int64)) CODEC(Delta(8), LZ4),\n `field3` Tuple(UInt32, Array(UInt64)) CODEC(Delta, Default)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS min_rows_for_wide_part = 100000, min_bytes_for_wide_part = 100000, index_granularity = 8192 CREATE TABLE default.columns_with_multiple_streams_compact\n(\n `field0` Nullable(Int64) CODEC(Delta(2), LZ4),\n `field1` Nullable(UInt8) CODEC(Delta(8), LZ4),\n `field2` Array(Array(Int64)) CODEC(Delta(8), LZ4),\n `field3` Tuple(\n UInt32,\n Array(UInt64)) CODEC(Delta, Default)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS min_rows_for_wide_part = 100000, min_bytes_for_wide_part = 100000, index_granularity = 8192
1 1 [[1]] (1,[1]) 1 1 [[1]] (1,[1])
2 2 [[2]] (2,[2]) 2 2 [[2]] (2,[2])
3 3 [[3]] (3,[3]) 3 3 [[3]] (3,[3])

View File

@ -7,6 +7,7 @@ ENGINE = TinyLog
CREATE TABLE test CREATE TABLE test
( (
`a` Int64, `a` Int64,
`b` Tuple(a Int64) `b` Tuple(
a Int64)
) )
ENGINE = TinyLog ENGINE = TinyLog

View File

@ -1 +1 @@
CREATE TABLE default.test_table\n(\n `col1` DateTime,\n `col2` Int64,\n `col3` AggregateFunction(1, sumMap, Tuple(Array(UInt8), Array(UInt8)))\n)\nENGINE = AggregatingMergeTree\nORDER BY (col1, col2)\nSETTINGS index_granularity = 8192 CREATE TABLE default.test_table\n(\n `col1` DateTime,\n `col2` Int64,\n `col3` AggregateFunction(1, sumMap, Tuple(\n Array(UInt8),\n Array(UInt8)))\n)\nENGINE = AggregatingMergeTree\nORDER BY (col1, col2)\nSETTINGS index_granularity = 8192

View File

@ -510,9 +510,15 @@ CREATE TABLE system.parts
`rows_where_ttl_info.max` Array(DateTime), `rows_where_ttl_info.max` Array(DateTime),
`projections` Array(String), `projections` Array(String),
`visible` UInt8, `visible` UInt8,
`creation_tid` Tuple(UInt64, UInt64, UUID), `creation_tid` Tuple(
UInt64,
UInt64,
UUID),
`removal_tid_lock` UInt64, `removal_tid_lock` UInt64,
`removal_tid` Tuple(UInt64, UInt64, UUID), `removal_tid` Tuple(
UInt64,
UInt64,
UUID),
`creation_csn` UInt64, `creation_csn` UInt64,
`removal_csn` UInt64, `removal_csn` UInt64,
`has_lightweight_delete` UInt8, `has_lightweight_delete` UInt8,

View File

@ -1,4 +1,4 @@
CREATE TABLE default.t_tuple_numeric\n(\n `t` Tuple(`1` Tuple(`2` Int32, `3` Int32), `4` Int32)\n)\nENGINE = Memory CREATE TABLE default.t_tuple_numeric\n(\n `t` Tuple(\n `1` Tuple(\n `2` Int32,\n `3` Int32),\n `4` Int32)\n)\nENGINE = Memory
{"t":{"1":{"2":2,"3":3},"4":4}} {"t":{"1":{"2":2,"3":3},"4":4}}
2 3 4 2 3 4
2 3 4 2 3 4

View File

@ -1,8 +1,8 @@
BACKUP_CREATED BACKUP_CREATED
CREATE TABLE default.test\n(\n `test` Array(Tuple(foo String, bar Float64))\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192 CREATE TABLE default.test\n(\n `test` Array(Tuple(\n foo String,\n bar Float64))\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192
BACKUP_CREATED BACKUP_CREATED
CREATE TABLE default.test2\n(\n `test` Nested(foo String, bar Float64)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192 CREATE TABLE default.test2\n(\n `test` Nested(foo String, bar Float64)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192
RESTORED RESTORED
CREATE TABLE default.test\n(\n `test` Array(Tuple(foo String, bar Float64))\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192 CREATE TABLE default.test\n(\n `test` Array(Tuple(\n foo String,\n bar Float64))\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192
RESTORED RESTORED
CREATE TABLE default.test2\n(\n `test` Nested(foo String, bar Float64)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192 CREATE TABLE default.test2\n(\n `test` Nested(foo String, bar Float64)\n)\nENGINE = MergeTree\nORDER BY tuple()\nSETTINGS index_granularity = 8192

View File

@ -0,0 +1,56 @@
SHOW CREATE TABLE:
CREATE TABLE default.test
(
`x` Tuple(
a String,
b Array(Tuple(
c Tuple(
e String),
d String))),
`y` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS index_granularity = 8192
CREATE TABLE default.test
(
`x` Tuple(a String, b Array(Tuple(c Tuple(e String), d String))),
`y` String
)
ENGINE = MergeTree
ORDER BY tuple()
SETTINGS index_granularity = 8192
clickhouse-format:
CREATE TABLE test
(
`x` Tuple(
a String,
b Array(Tuple(
c Tuple(
e String),
d String))),
`y` String
)
ORDER BY tuple()
CREATE TABLE test (`x` Tuple(a String, b Array(Tuple(c Tuple(e String), d String))), `y` String) ORDER BY tuple()
formatQuery:
CREATE TABLE test
(
`x` Tuple(
a String,
b Array(Tuple(
c Tuple(
e String),
d String))),
`y` String
)
ORDER BY tuple()
CREATE TABLE test
(
`x` Tuple(a String, b Array(Tuple(c Tuple(e String), d String))),
`y` String
)
ORDER BY tuple()

View File

@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Tags: no-fasttest, no-asan, no-msan, no-tsan
# ^ requires S3
CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=../shell_config.sh
. "$CUR_DIR"/../shell_config.sh
echo
echo "SHOW CREATE TABLE:"
${CLICKHOUSE_CLIENT} --output-format Raw --query "
DROP TABLE IF EXISTS test;
CREATE TABLE test (x Tuple(a String, b Array(Tuple(c Tuple(e String), d String))), y String) ORDER BY ();
SET print_pretty_type_names = 1;
SHOW CREATE TABLE test;
SET print_pretty_type_names = 0;
SHOW CREATE TABLE test;
DROP TABLE test;
"
echo
echo "clickhouse-format:"
${CLICKHOUSE_FORMAT} --query "
CREATE TABLE test (x Tuple(a String, b Array(Tuple(c Tuple(e String), d String))), y String) ORDER BY ()
"
${CLICKHOUSE_FORMAT} --oneline --query "
CREATE TABLE test (x Tuple(a String, b Array(Tuple(c Tuple(e String), d String))), y String) ORDER BY ()
"
echo
echo "formatQuery:"
${CLICKHOUSE_CLIENT} --output-format Raw --query "
SELECT formatQuery('CREATE TABLE test (x Tuple(a String, b Array(Tuple(c Tuple(e String), d String))), y String) ORDER BY ()') SETTINGS print_pretty_type_names = 1;
SELECT formatQuery('CREATE TABLE test (x Tuple(a String, b Array(Tuple(c Tuple(e String), d String))), y String) ORDER BY ()') SETTINGS print_pretty_type_names = 0;
"