mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-23 16:12:01 +00:00
Fix invalid virtual column expr
This commit is contained in:
parent
1bdd699f20
commit
50f2e488bd
@ -688,9 +688,11 @@ void MergeTreeData::MergingParams::check(const StorageInMemoryMetadata & metadat
|
|||||||
std::optional<UInt64> MergeTreeData::totalRowsByPartitionPredicateImpl(
|
std::optional<UInt64> MergeTreeData::totalRowsByPartitionPredicateImpl(
|
||||||
const SelectQueryInfo & query_info, ContextPtr local_context, const DataPartsVector & parts) const
|
const SelectQueryInfo & query_info, ContextPtr local_context, const DataPartsVector & parts) const
|
||||||
{
|
{
|
||||||
|
if (parts.empty())
|
||||||
|
return 0u;
|
||||||
auto metadata_snapshot = getInMemoryMetadataPtr();
|
auto metadata_snapshot = getInMemoryMetadataPtr();
|
||||||
ASTPtr expression_ast;
|
ASTPtr expression_ast;
|
||||||
Block virtual_columns_block = MergeTreeDataSelectExecutor::getSampleBlockWithVirtualPartColumns();
|
Block virtual_columns_block = MergeTreeDataSelectExecutor::getBlockWithVirtualPartColumns(parts, true /* one_part */);
|
||||||
|
|
||||||
// Generate valid expressions for filtering
|
// Generate valid expressions for filtering
|
||||||
bool valid = VirtualColumnUtils::prepareFilterBlockWithQuery(query_info.query, local_context, virtual_columns_block, expression_ast);
|
bool valid = VirtualColumnUtils::prepareFilterBlockWithQuery(query_info.query, local_context, virtual_columns_block, expression_ast);
|
||||||
@ -702,7 +704,7 @@ std::optional<UInt64> MergeTreeData::totalRowsByPartitionPredicateImpl(
|
|||||||
std::unordered_set<String> part_values;
|
std::unordered_set<String> part_values;
|
||||||
if (valid && expression_ast)
|
if (valid && expression_ast)
|
||||||
{
|
{
|
||||||
MergeTreeDataSelectExecutor::fillBlockWithVirtualPartColumns(parts, virtual_columns_block);
|
virtual_columns_block = MergeTreeDataSelectExecutor::getBlockWithVirtualPartColumns(parts, false /* one_part */);
|
||||||
VirtualColumnUtils::filterBlockWithQuery(query_info.query, virtual_columns_block, local_context, expression_ast);
|
VirtualColumnUtils::filterBlockWithQuery(query_info.query, virtual_columns_block, local_context, expression_ast);
|
||||||
part_values = VirtualColumnUtils::extractSingleValueFromBlock<String>(virtual_columns_block, "_part");
|
part_values = VirtualColumnUtils::extractSingleValueFromBlock<String>(virtual_columns_block, "_part");
|
||||||
if (part_values.empty())
|
if (part_values.empty())
|
||||||
|
@ -71,17 +71,13 @@ MergeTreeDataSelectExecutor::MergeTreeDataSelectExecutor(const MergeTreeData & d
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Block MergeTreeDataSelectExecutor::getBlockWithVirtualPartColumns(const MergeTreeData::DataPartsVector & parts, bool one_part)
|
||||||
Block MergeTreeDataSelectExecutor::getSampleBlockWithVirtualPartColumns()
|
|
||||||
{
|
{
|
||||||
return Block(std::initializer_list<ColumnWithTypeAndName>{
|
Block block(std::initializer_list<ColumnWithTypeAndName>{
|
||||||
ColumnWithTypeAndName(ColumnString::create(), std::make_shared<DataTypeString>(), "_part"),
|
ColumnWithTypeAndName(ColumnString::create(), std::make_shared<DataTypeString>(), "_part"),
|
||||||
ColumnWithTypeAndName(ColumnString::create(), std::make_shared<DataTypeString>(), "_partition_id"),
|
ColumnWithTypeAndName(ColumnString::create(), std::make_shared<DataTypeString>(), "_partition_id"),
|
||||||
ColumnWithTypeAndName(ColumnUUID::create(), std::make_shared<DataTypeUUID>(), "_part_uuid")});
|
ColumnWithTypeAndName(ColumnUUID::create(), std::make_shared<DataTypeUUID>(), "_part_uuid")});
|
||||||
}
|
|
||||||
|
|
||||||
void MergeTreeDataSelectExecutor::fillBlockWithVirtualPartColumns(const MergeTreeData::DataPartsVector & parts, Block & block)
|
|
||||||
{
|
|
||||||
MutableColumns columns = block.mutateColumns();
|
MutableColumns columns = block.mutateColumns();
|
||||||
|
|
||||||
auto & part_column = columns[0];
|
auto & part_column = columns[0];
|
||||||
@ -93,9 +89,17 @@ void MergeTreeDataSelectExecutor::fillBlockWithVirtualPartColumns(const MergeTre
|
|||||||
part_column->insert(part->name);
|
part_column->insert(part->name);
|
||||||
partition_id_column->insert(part->info.partition_id);
|
partition_id_column->insert(part->info.partition_id);
|
||||||
part_uuid_column->insert(part->uuid);
|
part_uuid_column->insert(part->uuid);
|
||||||
|
if (one_part)
|
||||||
|
{
|
||||||
|
part_column = ColumnConst::create(std::move(part_column), 1);
|
||||||
|
partition_id_column = ColumnConst::create(std::move(partition_id_column), 1);
|
||||||
|
part_uuid_column = ColumnConst::create(std::move(part_uuid_column), 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
block.setColumns(std::move(columns));
|
block.setColumns(std::move(columns));
|
||||||
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -179,6 +183,8 @@ QueryPlanPtr MergeTreeDataSelectExecutor::readFromParts(
|
|||||||
Names real_column_names;
|
Names real_column_names;
|
||||||
|
|
||||||
size_t total_parts = parts.size();
|
size_t total_parts = parts.size();
|
||||||
|
if (total_parts == 0)
|
||||||
|
return std::make_unique<QueryPlan>();
|
||||||
|
|
||||||
bool sample_factor_column_queried = false;
|
bool sample_factor_column_queried = false;
|
||||||
Float64 used_sample_factor = 1;
|
Float64 used_sample_factor = 1;
|
||||||
@ -220,7 +226,7 @@ QueryPlanPtr MergeTreeDataSelectExecutor::readFromParts(
|
|||||||
|
|
||||||
std::unordered_set<String> part_values;
|
std::unordered_set<String> part_values;
|
||||||
ASTPtr expression_ast;
|
ASTPtr expression_ast;
|
||||||
auto virtual_columns_block = getSampleBlockWithVirtualPartColumns();
|
auto virtual_columns_block = getBlockWithVirtualPartColumns(parts, true /* one_part */);
|
||||||
|
|
||||||
// Generate valid expressions for filtering
|
// Generate valid expressions for filtering
|
||||||
VirtualColumnUtils::prepareFilterBlockWithQuery(query_info.query, context, virtual_columns_block, expression_ast);
|
VirtualColumnUtils::prepareFilterBlockWithQuery(query_info.query, context, virtual_columns_block, expression_ast);
|
||||||
@ -228,7 +234,7 @@ QueryPlanPtr MergeTreeDataSelectExecutor::readFromParts(
|
|||||||
// If there is still something left, fill the virtual block and do the filtering.
|
// If there is still something left, fill the virtual block and do the filtering.
|
||||||
if (expression_ast)
|
if (expression_ast)
|
||||||
{
|
{
|
||||||
fillBlockWithVirtualPartColumns(parts, virtual_columns_block);
|
virtual_columns_block = getBlockWithVirtualPartColumns(parts, false /* one_part */);
|
||||||
VirtualColumnUtils::filterBlockWithQuery(query_info.query, virtual_columns_block, context, expression_ast);
|
VirtualColumnUtils::filterBlockWithQuery(query_info.query, virtual_columns_block, context, expression_ast);
|
||||||
part_values = VirtualColumnUtils::extractSingleValueFromBlock<String>(virtual_columns_block, "_part");
|
part_values = VirtualColumnUtils::extractSingleValueFromBlock<String>(virtual_columns_block, "_part");
|
||||||
if (part_values.empty())
|
if (part_values.empty())
|
||||||
|
@ -45,11 +45,9 @@ public:
|
|||||||
unsigned num_streams,
|
unsigned num_streams,
|
||||||
const PartitionIdToMaxBlock * max_block_numbers_to_read = nullptr) const;
|
const PartitionIdToMaxBlock * max_block_numbers_to_read = nullptr) const;
|
||||||
|
|
||||||
/// Construct a sample block consisting only of possible virtual columns for part pruning.
|
/// Construct a block consisting only of possible virtual columns for part pruning.
|
||||||
static Block getSampleBlockWithVirtualPartColumns();
|
/// If one_part is true, fill in at most one part.
|
||||||
|
static Block getBlockWithVirtualPartColumns(const MergeTreeData::DataPartsVector & parts, bool one_part);
|
||||||
/// Fill in values of possible virtual columns for part pruning.
|
|
||||||
static void fillBlockWithVirtualPartColumns(const MergeTreeData::DataPartsVector & parts, Block & block);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const MergeTreeData & data;
|
const MergeTreeData & data;
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include <Parsers/ASTSelectQuery.h>
|
#include <Parsers/ASTSelectQuery.h>
|
||||||
#include <Parsers/ASTSubquery.h>
|
#include <Parsers/ASTSubquery.h>
|
||||||
|
|
||||||
|
#include <Columns/ColumnConst.h>
|
||||||
#include <Columns/ColumnsNumber.h>
|
#include <Columns/ColumnsNumber.h>
|
||||||
#include <Columns/ColumnsCommon.h>
|
#include <Columns/ColumnsCommon.h>
|
||||||
#include <Columns/FilterDescription.h>
|
#include <Columns/FilterDescription.h>
|
||||||
@ -27,6 +28,11 @@
|
|||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace ErrorCodes
|
||||||
|
{
|
||||||
|
extern const int LOGICAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -124,6 +130,21 @@ void rewriteEntityInAst(ASTPtr ast, const String & column_name, const Field & va
|
|||||||
|
|
||||||
bool prepareFilterBlockWithQuery(const ASTPtr & query, ContextPtr context, Block block, ASTPtr & expression_ast)
|
bool prepareFilterBlockWithQuery(const ASTPtr & query, ContextPtr context, Block block, ASTPtr & expression_ast)
|
||||||
{
|
{
|
||||||
|
if (block.rows() == 0)
|
||||||
|
throw Exception("Cannot prepare filter with empty block", ErrorCodes::LOGICAL_ERROR);
|
||||||
|
|
||||||
|
/// Take the first row of the input block to build a constant block
|
||||||
|
auto columns = block.getColumns();
|
||||||
|
Columns const_columns(columns.size());
|
||||||
|
for (size_t i = 0; i < columns.size(); ++i)
|
||||||
|
{
|
||||||
|
if (isColumnConst(*columns[i]))
|
||||||
|
const_columns[i] = columns[i]->cloneResized(1);
|
||||||
|
else
|
||||||
|
const_columns[i] = ColumnConst::create(columns[i]->cloneResized(1), 1);
|
||||||
|
}
|
||||||
|
block.setColumns(const_columns);
|
||||||
|
|
||||||
bool unmodified = true;
|
bool unmodified = true;
|
||||||
const auto & select = query->as<ASTSelectQuery &>();
|
const auto & select = query->as<ASTSelectQuery &>();
|
||||||
if (!select.where() && !select.prewhere())
|
if (!select.where() && !select.prewhere())
|
||||||
@ -135,10 +156,6 @@ bool prepareFilterBlockWithQuery(const ASTPtr & query, ContextPtr context, Block
|
|||||||
else
|
else
|
||||||
condition_ast = select.prewhere() ? select.prewhere()->clone() : select.where()->clone();
|
condition_ast = select.prewhere() ? select.prewhere()->clone() : select.where()->clone();
|
||||||
|
|
||||||
// Prepare a constant block with valid expressions
|
|
||||||
for (size_t i = 0; i < block.columns(); ++i)
|
|
||||||
block.getByPosition(i).column = block.getByPosition(i).type->createColumnConstWithDefaultValue(1);
|
|
||||||
|
|
||||||
// Provide input columns as constant columns to check if an expression is constant.
|
// Provide input columns as constant columns to check if an expression is constant.
|
||||||
std::function<bool(const ASTPtr &)> is_constant = [&block, &context](const ASTPtr & node)
|
std::function<bool(const ASTPtr &)> is_constant = [&block, &context](const ASTPtr & node)
|
||||||
{
|
{
|
||||||
@ -169,6 +186,9 @@ bool prepareFilterBlockWithQuery(const ASTPtr & query, ContextPtr context, Block
|
|||||||
|
|
||||||
void filterBlockWithQuery(const ASTPtr & query, Block & block, ContextPtr context, ASTPtr expression_ast)
|
void filterBlockWithQuery(const ASTPtr & query, Block & block, ContextPtr context, ASTPtr expression_ast)
|
||||||
{
|
{
|
||||||
|
if (block.rows() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!expression_ast)
|
if (!expression_ast)
|
||||||
prepareFilterBlockWithQuery(query, context, block, expression_ast);
|
prepareFilterBlockWithQuery(query, context, block, expression_ast);
|
||||||
|
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
1 2 3
|
@ -10,6 +10,8 @@ CREATE TABLE data_01515
|
|||||||
Engine=MergeTree()
|
Engine=MergeTree()
|
||||||
ORDER BY key;
|
ORDER BY key;
|
||||||
|
|
||||||
|
INSERT INTO data_01515 VALUES (1, 2, 3);
|
||||||
|
|
||||||
SELECT * FROM data_01515;
|
SELECT * FROM data_01515;
|
||||||
SELECT * FROM data_01515 SETTINGS force_data_skipping_indices=''; -- { serverError 6 }
|
SELECT * FROM data_01515 SETTINGS force_data_skipping_indices=''; -- { serverError 6 }
|
||||||
SELECT * FROM data_01515 SETTINGS force_data_skipping_indices='d1_idx'; -- { serverError 277 }
|
SELECT * FROM data_01515 SETTINGS force_data_skipping_indices='d1_idx'; -- { serverError 277 }
|
||||||
|
@ -5,3 +5,13 @@
|
|||||||
1 2
|
1 2
|
||||||
1 3
|
1 3
|
||||||
3
|
3
|
||||||
|
1
|
||||||
|
11
|
||||||
|
21
|
||||||
|
31
|
||||||
|
41
|
||||||
|
51
|
||||||
|
61
|
||||||
|
71
|
||||||
|
81
|
||||||
|
91
|
||||||
|
@ -17,3 +17,15 @@ set max_rows_to_read = 1; -- one row for subquery
|
|||||||
select count() from x where _partition_id in (select partitionId(number + 1) from numbers(1));
|
select count() from x where _partition_id in (select partitionId(number + 1) from numbers(1));
|
||||||
|
|
||||||
drop table x;
|
drop table x;
|
||||||
|
|
||||||
|
drop table if exists mt;
|
||||||
|
|
||||||
|
create table mt (n UInt64) engine=MergeTree order by n partition by n % 10;
|
||||||
|
|
||||||
|
set max_rows_to_read = 200;
|
||||||
|
|
||||||
|
insert into mt select * from numbers(100);
|
||||||
|
|
||||||
|
select * from mt where toUInt64(substr(_part, 1, position(_part, '_') - 1)) = 1;
|
||||||
|
|
||||||
|
drop table mt;
|
||||||
|
Loading…
Reference in New Issue
Block a user