Merge pull request #280 from aSealBack/BlockStructureDiff

Added new diff for block structures.
This commit is contained in:
alexey-milovidov 2016-12-21 02:59:41 +04:00 committed by GitHub
commit d277d55763
3 changed files with 76 additions and 0 deletions

View File

@ -137,6 +137,9 @@ using BlocksList = std::list<Block>;
/// Сравнить типы столбцов у блоков. Порядок столбцов имеет значение. Имена не имеют значения.
bool blocksHaveEqualStructure(const Block & lhs, const Block & rhs);
/// Записать различные столбцы у блоков.
void getColumnDiff(const Block & lhs, const Block & rhs, std::string & lhs_diff, std::string & rhs_diff);
/** Дополнительные данные к блокам. Они пока нужны только для запроса
* DESCRIBE TABLE с Distributed-таблицами.
*/

View File

@ -31,6 +31,24 @@ struct ColumnWithTypeAndName
return res;
}
bool operator==(const ColumnWithTypeAndName & other) const
{
return name == other.name
&& ((!type && !other.type) || (type && other.type && type->getName() == other.type->getName()))
&& ((!column && !other.column) || (column && other.column && column->getName() == other.column->getName()));
}
std::string prettyPrint() const
{
std::stringstream str;
str << name << ' ';
if (type)
str << type->getName() << ' ';
if (column)
str << column->getName();
return str.str();
}
};
}

View File

@ -455,6 +455,61 @@ bool blocksHaveEqualStructure(const Block & lhs, const Block & rhs)
return true;
}
void getColumnDiff(const Block & lhs, const Block & rhs, std::string & lhs_diff, std::string & rhs_diff)
{
/// Традиционная задача: наибольшая общая подпоследовательность (LCS).
/// Полагаем, что порядок важен. Если это когда-то станет не так, упростим: например, намутим 2 set'а.
std::vector<std::vector<int>> LCS;
LCS.resize(lhs.columns() + 1);
for (auto & v : LCS)
v.resize(rhs.columns() + 1, 0);
for (size_t i = 1; i <= lhs.columns(); ++i)
for (size_t j = 1; j <= rhs.columns(); ++j)
{
if (lhs.getByPosition(i-1) == rhs.getByPosition(j-1))
LCS[i][j] = LCS[i-1][j-1] + 1;
else
LCS[i][j] = std::max(LCS[i-1][j], LCS[i][j-1]);
}
/// Теперь идем обратно и собираем ответ.
std::vector<std::string> left_columns, right_columns;
size_t l = lhs.columns(), r = rhs.columns();
while (l > 0 && r > 0)
{
if (lhs.getByPosition(l-1) == rhs.getByPosition(r-1))
{
/// Данный элемент в обеих последовательностях, значит, в diff не попадает.
--l;
--r;
}
else
{
/// Маленькая эвристика: чаще всего используется при получении разницы для (expected_block, actual_block).
/// Поэтому предпочтение будем отдавать полю, которое есть в левом блоке (expected_block), поэтому
/// в diff попадет столбец из actual_block.
if (LCS[l][r-1] >= LCS[l-1][r])
right_columns.push_back(rhs.getByPosition(--r).prettyPrint());
else
left_columns.push_back(lhs.getByPosition(--l).prettyPrint());
}
}
while (l > 0)
left_columns.push_back(lhs.getByPosition(--l).prettyPrint());
while (r > 0)
right_columns.push_back(rhs.getByPosition(--r).prettyPrint());
std::stringstream lhs_columns_diff, rhs_columns_diff;
for (auto it = left_columns.rbegin(); it != left_columns.rend(); ++it)
lhs_columns_diff << *it << '\n';
for (auto it = right_columns.rbegin(); it != right_columns.rend(); ++it)
rhs_columns_diff << *it << '\n';
lhs_diff = lhs_columns_diff.str();
rhs_diff = rhs_columns_diff.str();
}
void Block::clear()
{