mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-03 13:02:00 +00:00
Fix alias on default columns
This commit is contained in:
parent
a75254766e
commit
8828a78174
@ -12,59 +12,76 @@ namespace ErrorCodes
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/// Columns absent in part may depend on other absent columns so we are
|
||||
/// searching all required columns recursively. Return true if found at least
|
||||
/// one existing column in part.
|
||||
bool injectRequiredColumnsRecursively(
|
||||
const String & column_name,
|
||||
const ColumnsDescription & storage_columns,
|
||||
const MergeTreeData::AlterConversions & alter_conversions,
|
||||
const MergeTreeData::DataPartPtr & part,
|
||||
Names & columns,
|
||||
NameSet & required_columns,
|
||||
NameSet & injected_columns)
|
||||
{
|
||||
String column_name_in_part = column_name;
|
||||
if (alter_conversions.isColumnRenamed(column_name_in_part))
|
||||
column_name_in_part = alter_conversions.getColumnOldName(column_name_in_part);
|
||||
|
||||
/// column has files and hence does not require evaluation
|
||||
if (storage_columns.hasPhysical(column_name) && part->hasColumnFiles(column_name_in_part, *storage_columns.getPhysical(column_name).type))
|
||||
{
|
||||
/// ensure each column is added only once
|
||||
if (required_columns.count(column_name) == 0)
|
||||
{
|
||||
columns.emplace_back(column_name);
|
||||
required_columns.emplace(column_name);
|
||||
injected_columns.emplace(column_name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Column doesn't have default value and don't exist in part
|
||||
/// don't need to add to required set.
|
||||
const auto column_default = storage_columns.getDefault(column_name);
|
||||
if (!column_default)
|
||||
return false;
|
||||
|
||||
/// collect identifiers required for evaluation
|
||||
IdentifierNameSet identifiers;
|
||||
column_default->expression->collectIdentifierNames(identifiers);
|
||||
|
||||
bool result = false;
|
||||
for (const auto & identifier : identifiers)
|
||||
result |= injectRequiredColumnsRecursively(identifier, storage_columns, alter_conversions, part, columns, required_columns, injected_columns);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NameSet injectRequiredColumns(const MergeTreeData & storage, const StorageMetadataPtr & metadata_snapshot, const MergeTreeData::DataPartPtr & part, Names & columns)
|
||||
{
|
||||
NameSet required_columns{std::begin(columns), std::end(columns)};
|
||||
NameSet injected_columns;
|
||||
|
||||
auto all_column_files_missing = true;
|
||||
bool have_at_least_one_physical_column = false;
|
||||
|
||||
const auto & storage_columns = metadata_snapshot->getColumns();
|
||||
auto alter_conversions = storage.getAlterConversionsForPart(part);
|
||||
for (size_t i = 0; i < columns.size(); ++i)
|
||||
{
|
||||
/// possibly renamed
|
||||
auto column_name_in_part = columns[i];
|
||||
|
||||
if (alter_conversions.isColumnRenamed(column_name_in_part))
|
||||
column_name_in_part = alter_conversions.getColumnOldName(column_name_in_part);
|
||||
|
||||
/// column has files and hence does not require evaluation
|
||||
if (part->hasColumnFiles(column_name_in_part, *storage_columns.getPhysical(columns[i]).type))
|
||||
{
|
||||
all_column_files_missing = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto column_default = storage_columns.getDefault(columns[i]);
|
||||
if (!column_default)
|
||||
continue;
|
||||
|
||||
/// collect identifiers required for evaluation
|
||||
IdentifierNameSet identifiers;
|
||||
column_default->expression->collectIdentifierNames(identifiers);
|
||||
|
||||
for (const auto & identifier : identifiers)
|
||||
{
|
||||
if (storage_columns.hasPhysical(identifier))
|
||||
{
|
||||
/// ensure each column is added only once
|
||||
if (required_columns.count(identifier) == 0)
|
||||
{
|
||||
columns.emplace_back(identifier);
|
||||
required_columns.emplace(identifier);
|
||||
injected_columns.emplace(identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
have_at_least_one_physical_column |= injectRequiredColumnsRecursively(
|
||||
columns[i], storage_columns, alter_conversions,
|
||||
part, columns, required_columns, injected_columns);
|
||||
|
||||
/** Add a column of the minimum size.
|
||||
* Used in case when no column is needed or files are missing, but at least you need to know number of rows.
|
||||
* Adds to the columns.
|
||||
*/
|
||||
if (all_column_files_missing)
|
||||
if (!have_at_least_one_physical_column)
|
||||
{
|
||||
const auto minimum_size_column_name = part->getColumnNameWithMinumumCompressedSize(metadata_snapshot);
|
||||
columns.push_back(minimum_size_column_name);
|
||||
|
@ -1,5 +1,6 @@
|
||||
1 1
|
||||
1 1 1
|
||||
1
|
||||
2 2 4
|
||||
2 2 2 4
|
||||
3 3 9
|
||||
|
@ -2,12 +2,16 @@ DROP TABLE IF EXISTS table_with_defaults_on_aliases;
|
||||
|
||||
CREATE TABLE table_with_defaults_on_aliases (col1 UInt32, col2 ALIAS col1, col3 DEFAULT col2) Engine = MergeTree() ORDER BY tuple();
|
||||
|
||||
SYSTEM STOP MERGES table_with_defaults_on_aliases;
|
||||
|
||||
INSERT INTO table_with_defaults_on_aliases (col1) VALUES (1);
|
||||
|
||||
SELECT * FROM table_with_defaults_on_aliases WHERE col1 = 1;
|
||||
|
||||
SELECT col1, col2, col3 FROM table_with_defaults_on_aliases WHERE col1 = 1;
|
||||
|
||||
SELECT col3 FROM table_with_defaults_on_aliases; -- important to check without WHERE
|
||||
|
||||
ALTER TABLE table_with_defaults_on_aliases ADD COLUMN col4 UInt64 DEFAULT col2 * col3;
|
||||
|
||||
INSERT INTO table_with_defaults_on_aliases (col1) VALUES (2);
|
||||
@ -24,7 +28,6 @@ SELECT * FROM table_with_defaults_on_aliases WHERE col1 = 3;
|
||||
|
||||
SELECT col1, col2, col3, col4, col5 FROM table_with_defaults_on_aliases WHERE col1 = 3;
|
||||
|
||||
|
||||
ALTER TABLE table_with_defaults_on_aliases ADD COLUMN col6 UInt64 MATERIALIZED col2 * col4;
|
||||
|
||||
DROP TABLE IF EXISTS table_with_defaults_on_aliases;
|
||||
|
@ -0,0 +1,6 @@
|
||||
a1 b1
|
||||
a2 b2
|
||||
a3 b3
|
||||
c1
|
||||
c2
|
||||
c3
|
21
tests/queries/0_stateless/01497_alias_on_default_array.sql
Normal file
21
tests/queries/0_stateless/01497_alias_on_default_array.sql
Normal file
@ -0,0 +1,21 @@
|
||||
DROP TABLE IF EXISTS test_new_col;
|
||||
|
||||
CREATE TABLE test_new_col
|
||||
(
|
||||
`_csv` String,
|
||||
`csv_as_array` Array(String) ALIAS splitByChar(';',_csv),
|
||||
`csv_col1` String DEFAULT csv_as_array[1],
|
||||
`csv_col2` String DEFAULT csv_as_array[2]
|
||||
)
|
||||
ENGINE = MergeTree
|
||||
ORDER BY tuple();
|
||||
|
||||
INSERT INTO test_new_col (_csv) VALUES ('a1;b1;c1;d1'), ('a2;b2;c2;d2'), ('a3;b3;c3;d3');
|
||||
|
||||
SELECT csv_col1, csv_col2 FROM test_new_col ORDER BY csv_col1;
|
||||
|
||||
ALTER TABLE test_new_col ADD COLUMN `csv_col3` String DEFAULT csv_as_array[3];
|
||||
|
||||
SELECT csv_col3 FROM test_new_col ORDER BY csv_col3;
|
||||
|
||||
DROP TABLE IF EXISTS test_new_col;
|
Loading…
Reference in New Issue
Block a user