mirror of https://github.com/ByConity/ByConity
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;
|
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 injectRequiredColumns(const MergeTreeData & storage, const StorageMetadataPtr & metadata_snapshot, const MergeTreeData::DataPartPtr & part, Names & columns)
|
||||||
{
|
{
|
||||||
NameSet required_columns{std::begin(columns), std::end(columns)};
|
NameSet required_columns{std::begin(columns), std::end(columns)};
|
||||||
NameSet injected_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();
|
const auto & storage_columns = metadata_snapshot->getColumns();
|
||||||
auto alter_conversions = storage.getAlterConversionsForPart(part);
|
auto alter_conversions = storage.getAlterConversionsForPart(part);
|
||||||
for (size_t i = 0; i < columns.size(); ++i)
|
for (size_t i = 0; i < columns.size(); ++i)
|
||||||
{
|
have_at_least_one_physical_column |= injectRequiredColumnsRecursively(
|
||||||
/// possibly renamed
|
columns[i], storage_columns, alter_conversions,
|
||||||
auto column_name_in_part = columns[i];
|
part, columns, required_columns, injected_columns);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add a column of the minimum size.
|
/** 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.
|
* 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.
|
* 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);
|
const auto minimum_size_column_name = part->getColumnNameWithMinumumCompressedSize(metadata_snapshot);
|
||||||
columns.push_back(minimum_size_column_name);
|
columns.push_back(minimum_size_column_name);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
1 1
|
1 1
|
||||||
1 1 1
|
1 1 1
|
||||||
|
1
|
||||||
2 2 4
|
2 2 4
|
||||||
2 2 2 4
|
2 2 2 4
|
||||||
3 3 9
|
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();
|
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);
|
INSERT INTO table_with_defaults_on_aliases (col1) VALUES (1);
|
||||||
|
|
||||||
SELECT * FROM table_with_defaults_on_aliases WHERE col1 = 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 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;
|
ALTER TABLE table_with_defaults_on_aliases ADD COLUMN col4 UInt64 DEFAULT col2 * col3;
|
||||||
|
|
||||||
INSERT INTO table_with_defaults_on_aliases (col1) VALUES (2);
|
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;
|
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;
|
ALTER TABLE table_with_defaults_on_aliases ADD COLUMN col6 UInt64 MATERIALIZED col2 * col4;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS table_with_defaults_on_aliases;
|
DROP TABLE IF EXISTS table_with_defaults_on_aliases;
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
a1 b1
|
||||||
|
a2 b2
|
||||||
|
a3 b3
|
||||||
|
c1
|
||||||
|
c2
|
||||||
|
c3
|
|
@ -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