Merge pull request #55604 from ClickHouse/evillique-partition-parameters

Implement query paramenters support in partition expression
This commit is contained in:
alesapin 2023-10-16 10:26:02 +02:00 committed by GitHub
commit 697c1e3bb0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 375 additions and 92 deletions

View File

@ -172,7 +172,7 @@ BlockIO InterpreterAlterQuery::executeToTable(const ASTAlterQuery & alter)
if (!partition_commands.empty())
{
table->checkAlterPartitionIsPossible(partition_commands, metadata_snapshot, getContext()->getSettingsRef());
table->checkAlterPartitionIsPossible(partition_commands, metadata_snapshot, getContext()->getSettingsRef(), getContext());
auto partition_commands_pipe = table->alterPartition(metadata_snapshot, partition_commands, getContext());
if (!partition_commands_pipe.empty())
res.pipeline = QueryPipeline(std::move(partition_commands_pipe));

View File

@ -5,12 +5,39 @@
namespace DB
{
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
}
void ASTPartition::setPartitionID(const ASTPtr & ast)
{
if (children.empty())
{
children.push_back(ast);
id = children[0].get();
}
else
throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot have multiple children for partition AST");
}
void ASTPartition::setPartitionValue(const ASTPtr & ast)
{
if (children.empty())
{
children.push_back(ast);
value = children[0].get();
}
else
throw Exception(ErrorCodes::LOGICAL_ERROR, "Cannot have multiple children for partition AST");
}
String ASTPartition::getID(char delim) const
{
if (value)
return "Partition";
else
return "Partition_ID" + (delim + id);
return "Partition_ID" + (delim + id->getID());
}
ASTPtr ASTPartition::clone() const
@ -20,8 +47,14 @@ ASTPtr ASTPartition::clone() const
if (value)
{
res->value = value->clone();
res->children.push_back(res->value);
res->children.push_back(children[0]->clone());
res->value = res->children[0].get();
}
if (id)
{
res->children.push_back(children[0]->clone());
res->id = res->children[0].get();
}
return res;
@ -33,18 +66,14 @@ void ASTPartition::formatImpl(const FormatSettings & settings, FormatState & sta
{
value->formatImpl(settings, state, frame);
}
else if (all)
{
settings.ostr << "ALL";
}
else
{
if (all)
settings.ostr << "ALL";
else
{
settings.ostr << (settings.hilite ? hilite_keyword : "") << "ID " << (settings.hilite ? hilite_none : "");
WriteBufferFromOwnString id_buf;
writeQuoted(id, id_buf);
settings.ostr << id_buf.str();
}
settings.ostr << (settings.hilite ? hilite_keyword : "") << "ID " << (settings.hilite ? hilite_none : "");
id->formatImpl(settings, state, frame);
}
}
}

View File

@ -1,7 +1,7 @@
#pragma once
#include <Parsers/IAST.h>
#include <optional>
namespace DB
{
@ -10,15 +10,24 @@ namespace DB
class ASTPartition : public IAST
{
public:
ASTPtr value;
size_t fields_count = 0;
IAST * value{nullptr};
std::optional<size_t> fields_count;
String id;
IAST * id{nullptr};
bool all = false;
String getID(char) const override;
ASTPtr clone() const override;
void setPartitionID(const ASTPtr & ast);
void setPartitionValue(const ASTPtr & ast);
void forEachPointerToChild(std::function<void(void **)> f) override
{
f(reinterpret_cast<void **>(&value));
f(reinterpret_cast<void **>(&id));
}
protected:
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
};

View File

@ -173,7 +173,7 @@ protected:
class ParserExpression : public IParserBase
{
public:
ParserExpression(bool allow_trailing_commas_ = false) : allow_trailing_commas(allow_trailing_commas_) {}
explicit ParserExpression(bool allow_trailing_commas_ = false) : allow_trailing_commas(allow_trailing_commas_) {}
protected:
const char * getName() const override { return "lambda expression"; }

View File

@ -7,6 +7,7 @@
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h>
#include <Common/typeid_cast.h>
#include <Parsers/ASTQueryParameter.h>
namespace DB
{
@ -16,19 +17,25 @@ bool ParserPartition::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
ParserKeyword s_id("ID");
ParserKeyword s_all("ALL");
ParserStringLiteral parser_string_literal;
ParserSubstitution parser_substitution;
ParserLiteral literal_parser;
ParserTupleOfLiterals tuple_of_literals;
ParserExpression parser_expr;
Pos begin = pos;
auto partition = std::make_shared<ASTPartition>();
if (s_id.ignore(pos, expected))
{
ASTPtr partition_id;
if (!parser_string_literal.parse(pos, partition_id, expected))
if (!parser_string_literal.parse(pos, partition_id, expected) && !parser_substitution.parse(pos, partition_id, expected))
return false;
partition->id = partition_id->as<ASTLiteral &>().value.get<String>();
if (auto * partition_id_literal = partition_id->as<ASTLiteral>(); partition_id_literal != nullptr)
partition->setPartitionID(partition_id);
else if (auto * partition_id_query_parameter = partition_id->as<ASTQueryParameter>(); partition_id_query_parameter != nullptr)
partition->setPartitionID(partition_id);
else
return false;
}
else if (s_all.ignore(pos, expected))
{
@ -37,27 +44,12 @@ bool ParserPartition::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
else
{
ASTPtr value;
if (!parser_expr.parse(pos, value, expected))
return false;
size_t fields_count;
const auto * tuple_ast = value->as<ASTFunction>();
bool surrounded_by_parens = false;
if (tuple_ast && tuple_ast->name == "tuple")
{
surrounded_by_parens = true;
const auto * arguments_ast = tuple_ast->arguments->as<ASTExpressionList>();
if (arguments_ast)
fields_count = arguments_ast->children.size();
else
fields_count = 0;
}
else if (const auto * literal = value->as<ASTLiteral>())
std::optional<size_t> fields_count;
if (literal_parser.parse(pos, value, expected) || tuple_of_literals.parse(pos, value, expected))
{
auto * literal = value->as<ASTLiteral>();
if (literal->value.getType() == Field::Types::Tuple)
{
surrounded_by_parens = true;
fields_count = literal->value.get<const Tuple &>().size();
}
else
@ -65,27 +57,31 @@ bool ParserPartition::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
fields_count = 1;
}
}
else
return false;
if (surrounded_by_parens)
else if (parser_substitution.parse(pos, value, expected))
{
Pos left_paren = begin;
Pos right_paren = pos;
while (left_paren != right_paren && left_paren->type != TokenType::OpeningRoundBracket)
++left_paren;
if (left_paren->type != TokenType::OpeningRoundBracket)
return false;
while (right_paren != left_paren && right_paren->type != TokenType::ClosingRoundBracket)
--right_paren;
if (right_paren->type != TokenType::ClosingRoundBracket)
/// It can be tuple substitution
fields_count = std::nullopt;
}
else if (parser_expr.parse(pos, value, expected))
{
const auto * tuple_ast = value->as<ASTFunction>();
if (tuple_ast && tuple_ast->name == "tuple")
{
const auto * arguments_ast = tuple_ast->arguments->as<ASTExpressionList>();
if (arguments_ast)
fields_count = arguments_ast->children.size();
else
fields_count = 0;
}
else
return false;
}
else
{
return false;
}
partition->value = value;
partition->children.push_back(value);
partition->setPartitionValue(value);
partition->fields_count = fields_count;
}

View File

@ -211,7 +211,10 @@ void IStorage::checkMutationIsPossible(const MutationCommands & /*commands*/, co
}
void IStorage::checkAlterPartitionIsPossible(
const PartitionCommands & /*commands*/, const StorageMetadataPtr & /*metadata_snapshot*/, const Settings & /*settings*/) const
const PartitionCommands & /*commands*/,
const StorageMetadataPtr & /*metadata_snapshot*/,
const Settings & /*settings*/,
ContextPtr /*context*/) const
{
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "Table engine {} doesn't support partitioning", getName());
}

View File

@ -495,7 +495,11 @@ public:
ContextPtr /* context */);
/// Checks that partition commands can be applied to storage.
virtual void checkAlterPartitionIsPossible(const PartitionCommands & commands, const StorageMetadataPtr & metadata_snapshot, const Settings & settings) const;
virtual void checkAlterPartitionIsPossible(
const PartitionCommands & commands,
const StorageMetadataPtr & metadata_snapshot,
const Settings & settings,
ContextPtr context) const;
/** Perform any background work. For example, combining parts in a MergeTree type table.
* Returns whether any work has been done.

View File

@ -37,6 +37,7 @@
#include <Interpreters/Context.h>
#include <Interpreters/convertFieldToType.h>
#include <Interpreters/evaluateConstantExpression.h>
#include <Interpreters/ReplaceQueryParameterVisitor.h>
#include <Interpreters/ExpressionAnalyzer.h>
#include <Interpreters/inplaceBlockConversions.h>
#include <Interpreters/InterpreterSelectQuery.h>
@ -52,6 +53,7 @@
#include <IO/SharedThreadPools.h>
#include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTIndexDeclaration.h>
#include <Parsers/ASTHelpers.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTNameTypePair.h>
@ -62,6 +64,7 @@
#include <Parsers/parseQuery.h>
#include <Parsers/queryToString.h>
#include <Parsers/ASTAlterQuery.h>
#include <Parsers/ASTQueryParameter.h>
#include <Processors/Formats/IInputFormat.h>
#include <Processors/QueryPlan/QueryIdHolder.h>
#include <Processors/QueryPlan/ReadFromMergeTree.h>
@ -2967,7 +2970,7 @@ void MergeTreeData::checkAlterIsPossible(const AlterCommands & commands, Context
/// Just validate partition expression
if (command.partition)
{
getPartitionIDFromQuery(command.partition, getContext());
getPartitionIDFromQuery(command.partition, local_context);
}
if (command.column_name == merging_params.version_column)
@ -4635,7 +4638,7 @@ void MergeTreeData::removePartContributionToColumnAndSecondaryIndexSizes(const D
}
void MergeTreeData::checkAlterPartitionIsPossible(
const PartitionCommands & commands, const StorageMetadataPtr & /*metadata_snapshot*/, const Settings & settings) const
const PartitionCommands & commands, const StorageMetadataPtr & /*metadata_snapshot*/, const Settings & settings, ContextPtr local_context) const
{
for (const auto & command : commands)
{
@ -4663,7 +4666,7 @@ void MergeTreeData::checkAlterPartitionIsPossible(
throw DB::Exception(ErrorCodes::SUPPORT_IS_DISABLED, "Only support DROP/DETACH PARTITION ALL currently");
}
else
getPartitionIDFromQuery(command.partition, getContext());
getPartitionIDFromQuery(command.partition, local_context);
}
}
}
@ -5342,8 +5345,71 @@ String MergeTreeData::getPartitionIDFromQuery(const ASTPtr & ast, ContextPtr loc
if (!partition_ast.value)
{
MergeTreePartInfo::validatePartitionID(partition_ast.id, format_version);
return partition_ast.id;
MergeTreePartInfo::validatePartitionID(partition_ast.id->clone(), format_version);
return partition_ast.id->as<ASTLiteral>()->value.safeGet<String>();
}
size_t partition_ast_fields_count = 0;
ASTPtr partition_value_ast = partition_ast.value->clone();
if (!partition_ast.fields_count.has_value())
{
if (partition_value_ast->as<ASTLiteral>())
{
partition_ast_fields_count = 1;
}
else if (const auto * tuple_ast = partition_value_ast->as<ASTFunction>())
{
if (tuple_ast->name != "tuple")
{
if (isFunctionCast(tuple_ast))
{
if (tuple_ast->arguments->as<ASTExpressionList>()->children.empty())
{
throw Exception(
ErrorCodes::INVALID_PARTITION_VALUE, "Expected tuple for complex partition key, got {}", tuple_ast->name);
}
auto first_arg = tuple_ast->arguments->as<ASTExpressionList>()->children.at(0);
if (const auto * inner_tuple = first_arg->as<ASTFunction>(); inner_tuple && inner_tuple->name == "tuple")
{
const auto * arguments_ast = tuple_ast->arguments->as<ASTExpressionList>();
if (arguments_ast)
partition_ast_fields_count = arguments_ast->children.size();
else
partition_ast_fields_count = 0;
}
else if (const auto * inner_literal_tuple = first_arg->as<ASTLiteral>(); inner_literal_tuple)
{
if (inner_literal_tuple->value.getType() == Field::Types::Tuple)
partition_ast_fields_count = inner_literal_tuple->value.safeGet<Tuple>().size();
else
partition_ast_fields_count = 1;
}
else
{
throw Exception(
ErrorCodes::INVALID_PARTITION_VALUE, "Expected tuple for complex partition key, got {}", tuple_ast->name);
}
}
else
throw Exception(ErrorCodes::INVALID_PARTITION_VALUE, "Expected tuple for complex partition key, got {}", tuple_ast->name);
}
else
{
const auto * arguments_ast = tuple_ast->arguments->as<ASTExpressionList>();
if (arguments_ast)
partition_ast_fields_count = arguments_ast->children.size();
else
partition_ast_fields_count = 0;
}
}
else
{
throw Exception(
ErrorCodes::INVALID_PARTITION_VALUE, "Expected literal or tuple for partition key, got {}", partition_value_ast->getID());
}
}
else
{
partition_ast_fields_count = *partition_ast.fields_count;
}
if (format_version < MERGE_TREE_DATA_MIN_FORMAT_VERSION_WITH_CUSTOM_PARTITIONING)
@ -5352,9 +5418,8 @@ String MergeTreeData::getPartitionIDFromQuery(const ASTPtr & ast, ContextPtr loc
const auto * partition_lit = partition_ast.value->as<ASTLiteral>();
if (partition_lit && partition_lit->value.getType() == Field::Types::String)
{
String partition_id = partition_lit->value.get<String>();
MergeTreePartInfo::validatePartitionID(partition_id, format_version);
return partition_id;
MergeTreePartInfo::validatePartitionID(partition_ast.value->clone(), format_version);
return partition_lit->value.get<String>();
}
}
@ -5362,35 +5427,48 @@ String MergeTreeData::getPartitionIDFromQuery(const ASTPtr & ast, ContextPtr loc
auto metadata_snapshot = getInMemoryMetadataPtr();
const Block & key_sample_block = metadata_snapshot->getPartitionKey().sample_block;
size_t fields_count = key_sample_block.columns();
if (partition_ast.fields_count != fields_count)
if (partition_ast_fields_count != fields_count)
throw Exception(ErrorCodes::INVALID_PARTITION_VALUE,
"Wrong number of fields in the partition expression: {}, must be: {}",
partition_ast.fields_count, fields_count);
partition_ast_fields_count, fields_count);
Row partition_row(fields_count);
if (fields_count == 0)
{
/// Function tuple(...) requires at least one argument, so empty key is a special case
assert(!partition_ast.fields_count);
assert(typeid_cast<ASTFunction *>(partition_ast.value.get()));
assert(partition_ast.value->as<ASTFunction>()->name == "tuple");
assert(partition_ast.value->as<ASTFunction>()->arguments);
auto args = partition_ast.value->as<ASTFunction>()->arguments;
assert(!partition_ast_fields_count);
assert(typeid_cast<ASTFunction *>(partition_value_ast.get()));
assert(partition_value_ast->as<ASTFunction>()->name == "tuple");
assert(partition_value_ast->as<ASTFunction>()->arguments);
auto args = partition_value_ast->as<ASTFunction>()->arguments;
if (!args)
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Expected at least one argument in partition AST");
bool empty_tuple = partition_ast.value->as<ASTFunction>()->arguments->children.empty();
bool empty_tuple = partition_value_ast->as<ASTFunction>()->arguments->children.empty();
if (!empty_tuple)
throw Exception(ErrorCodes::INVALID_PARTITION_VALUE, "Partition key is empty, expected 'tuple()' as partition key");
}
else if (fields_count == 1)
{
ASTPtr partition_value_ast = partition_ast.value;
if (auto * tuple = partition_value_ast->as<ASTFunction>())
if (auto * tuple = partition_value_ast->as<ASTFunction>(); tuple)
{
assert(tuple->name == "tuple");
assert(tuple->arguments);
assert(tuple->arguments->children.size() == 1);
partition_value_ast = tuple->arguments->children[0];
if (tuple->name == "tuple")
{
assert(tuple->arguments);
assert(tuple->arguments->children.size() == 1);
partition_value_ast = tuple->arguments->children[0];
}
else if (isFunctionCast(tuple))
{
assert(tuple->arguments);
assert(tuple->arguments->children.size() == 2);
}
else
{
throw Exception(
ErrorCodes::INVALID_PARTITION_VALUE,
"Expected literal or tuple for partition key, got {}",
partition_value_ast->getID());
}
}
/// Simple partition key, need to evaluate and cast
Field partition_key_value = evaluateConstantExpression(partition_value_ast, local_context).first;
@ -5399,7 +5477,7 @@ String MergeTreeData::getPartitionIDFromQuery(const ASTPtr & ast, ContextPtr loc
else
{
/// Complex key, need to evaluate, untuple and cast
Field partition_key_value = evaluateConstantExpression(partition_ast.value, local_context).first;
Field partition_key_value = evaluateConstantExpression(partition_value_ast, local_context).first;
if (partition_key_value.getType() != Field::Types::Tuple)
throw Exception(ErrorCodes::INVALID_PARTITION_VALUE,
"Expected tuple for complex partition key, got {}", partition_key_value.getTypeName());

View File

@ -723,7 +723,11 @@ public:
void checkMutationIsPossible(const MutationCommands & commands, const Settings & settings) const override;
/// Checks that partition name in all commands is valid
void checkAlterPartitionIsPossible(const PartitionCommands & commands, const StorageMetadataPtr & metadata_snapshot, const Settings & settings) const override;
void checkAlterPartitionIsPossible(
const PartitionCommands & commands,
const StorageMetadataPtr & metadata_snapshot,
const Settings & settings,
ContextPtr local_context) const override;
/// Change MergeTreeSettings
void changeSettings(

View File

@ -2,7 +2,8 @@
#include <IO/ReadBufferFromString.h>
#include <IO/ReadHelpers.h>
#include <IO/WriteHelpers.h>
#include "Core/ProtocolDefines.h"
#include <Core/ProtocolDefines.h>
#include <Parsers/ASTLiteral.h>
namespace DB
{
@ -23,8 +24,15 @@ MergeTreePartInfo MergeTreePartInfo::fromPartName(const String & part_name, Merg
throw Exception(ErrorCodes::BAD_DATA_PART_NAME, "Unexpected part name: {} for format version: {}", part_name, format_version);
}
void MergeTreePartInfo::validatePartitionID(const String & partition_id, MergeTreeDataFormatVersion format_version)
void MergeTreePartInfo::validatePartitionID(const ASTPtr & partition_id_ast, MergeTreeDataFormatVersion format_version)
{
std::string partition_id;
if (auto * literal = partition_id_ast->as<ASTLiteral>(); literal != nullptr && literal->value.getType() == Field::Types::String)
partition_id = literal->value.safeGet<String>();
else
throw Exception(ErrorCodes::INVALID_PARTITION_VALUE, "Partition id must be string literal");
if (partition_id.empty())
throw Exception(ErrorCodes::INVALID_PARTITION_VALUE, "Partition id is empty");

View File

@ -9,6 +9,7 @@
#include <base/DayNum.h>
#include <IO/ReadBuffer.h>
#include <IO/WriteBuffer.h>
#include <Parsers/IAST_fwd.h>
#include <Storages/MergeTree/MergeTreeDataFormatVersion.h>
@ -119,7 +120,7 @@ struct MergeTreePartInfo
void deserialize(ReadBuffer & in);
/// Simple sanity check for partition ID. Checking that it's not too long or too short, doesn't contain a lot of '_'.
static void validatePartitionID(const String & partition_id, MergeTreeDataFormatVersion format_version);
static void validatePartitionID(const ASTPtr & partition_id_ast, MergeTreeDataFormatVersion format_version);
static MergeTreePartInfo fromPartName(const String & part_name, MergeTreeDataFormatVersion format_version);

View File

@ -330,10 +330,11 @@ Pipe StorageMaterializedView::alterPartition(
}
void StorageMaterializedView::checkAlterPartitionIsPossible(
const PartitionCommands & commands, const StorageMetadataPtr & metadata_snapshot, const Settings & settings) const
const PartitionCommands & commands, const StorageMetadataPtr & metadata_snapshot,
const Settings & settings, ContextPtr local_context) const
{
checkStatementCanBeForwarded();
getTargetTable()->checkAlterPartitionIsPossible(commands, metadata_snapshot, settings);
getTargetTable()->checkAlterPartitionIsPossible(commands, metadata_snapshot, settings, local_context);
}
void StorageMaterializedView::mutate(const MutationCommands & commands, ContextPtr local_context)

View File

@ -64,7 +64,7 @@ public:
Pipe alterPartition(const StorageMetadataPtr & metadata_snapshot, const PartitionCommands & commands, ContextPtr context) override;
void checkAlterPartitionIsPossible(const PartitionCommands & commands, const StorageMetadataPtr & metadata_snapshot, const Settings & settings) const override;
void checkAlterPartitionIsPossible(const PartitionCommands & commands, const StorageMetadataPtr & metadata_snapshot, const Settings & settings, ContextPtr local_context) const override;
void mutate(const MutationCommands & commands, ContextPtr context) override;

View File

@ -115,9 +115,9 @@ public:
return getNested()->alterPartition(metadata_snapshot, commands, context);
}
void checkAlterPartitionIsPossible(const PartitionCommands & commands, const StorageMetadataPtr & metadata_snapshot, const Settings & settings) const override
void checkAlterPartitionIsPossible(const PartitionCommands & commands, const StorageMetadataPtr & metadata_snapshot, const Settings & settings, ContextPtr context) const override
{
getNested()->checkAlterPartitionIsPossible(commands, metadata_snapshot, settings);
getNested()->checkAlterPartitionIsPossible(commands, metadata_snapshot, settings, context);
}
bool optimize(

View File

@ -0,0 +1,9 @@
0
0
0
0
0
0
0
0
0

View File

@ -0,0 +1,141 @@
DROP TABLE IF EXISTS test;
CREATE TABLE test
(
EventDate Date
)
ENGINE = MergeTree
ORDER BY tuple()
PARTITION BY toMonday(EventDate);
INSERT INTO test VALUES(toDate('2023-10-09'));
SET param_partition='2023-10-09';
ALTER TABLE test DROP PARTITION {partition:String};
SELECT count() FROM test;
INSERT INTO test VALUES(toDate('2023-10-09'));
ALTER TABLE test DROP PARTITION tuple(toMonday({partition:Date}));
SELECT count() FROM test;
INSERT INTO test VALUES(toDate('2023-10-09'));
-- for some reason only tuples are allowed as non-string arguments
ALTER TABLE test DROP PARTITION toMonday({partition:String}); --{clientError 62}
set param_partition_id = '20231009';
ALTER TABLE test DROP PARTITION ID {partition_id:String};
SELECT count() FROM test;
INSERT INTO test VALUES(toDate('2023-10-09'));
ALTER TABLE test DROP PARTITION {partition:Date};
SELECT count() FROM test;
DROP TABLE IF EXISTS test;
DROP TABLE IF EXISTS test2;
CREATE TABLE test2
(
a UInt32,
b Int64
)
ENGINE = MergeTree
ORDER BY tuple()
PARTITION BY (a * b, b * b);
INSERT INTO test2 VALUES(1, 2);
SET param_first='2';
SET param_second='4';
ALTER TABLE test2 DROP PARTITION tuple({first:UInt32},{second:Int64});
SELECT count() FROM test2;
DROP TABLE IF EXISTS test2;
DROP TABLE IF EXISTS test3;
CREATE TABLE test3
(
a UInt32,
b Int64
)
ENGINE = MergeTree
ORDER BY tuple()
PARTITION BY a;
INSERT INTO test3 VALUES(1, 2);
SET param_simple='1';
ALTER TABLE test3 DROP PARTITION {simple:String};
SELECT count() FROM test3;
DROP TABLE IF EXISTS test3;
DROP TABLE IF EXISTS test4;
CREATE TABLE test4 (EventDate Date) ENGINE = MergeTree() ORDER BY tuple() PARTITION BY EventDate;
INSERT INTO test4 VALUES(toDate('2023-10-09'));
SET param_partition='2023-10-09';
ALTER TABLE test4 ON CLUSTER 'test_shard_localhost' DROP PARTITION {partition:String} FORMAT Null;
SELECT count() FROM test4;
DROP TABLE IF EXISTS test4;
DROP TABLE IF EXISTS test5;
CREATE TABLE test5
(
a UInt32,
b Int64
)
ENGINE = MergeTree
ORDER BY tuple()
PARTITION BY (a, b);
INSERT INTO test5 VALUES(1, 2);
SET param_f='1';
SET param_s='2';
ALTER TABLE test5 DROP PARTITION ({f:UInt32}, 2);
SELECT count() FROM test5;
DROP TABLE IF EXISTS test5;
DROP TABLE IF EXISTS test6;
CREATE TABLE test6
(
a UInt32,
b Int64
)
ENGINE = MergeTree
ORDER BY tuple()
PARTITION BY (a, b);
INSERT INTO test6 VALUES(1, 2);
SET param_tuple=(1, 2);
ALTER TABLE test6 DROP PARTITION {tuple:Tuple(UInt32, Int64)};
SELECT count() FROM test6;
DROP TABLE IF EXISTS test6;