2010-03-12 20:44:25 +00:00
|
|
|
|
#include <iterator>
|
|
|
|
|
|
2015-10-05 01:35:28 +00:00
|
|
|
|
#include <DB/Common/Exception.h>
|
2010-03-04 19:20:28 +00:00
|
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
|
#include <DB/Core/Block.h>
|
|
|
|
|
|
2014-10-21 12:11:20 +00:00
|
|
|
|
#include <DB/Storages/ColumnDefault.h>
|
|
|
|
|
|
2013-08-02 14:26:04 +00:00
|
|
|
|
#include <DB/Columns/ColumnArray.h>
|
2016-08-24 16:02:34 +00:00
|
|
|
|
#include <DB/Columns/ColumnNullable.h>
|
2013-08-02 14:26:04 +00:00
|
|
|
|
#include <DB/DataTypes/DataTypeNested.h>
|
2015-04-09 02:10:06 +00:00
|
|
|
|
#include <DB/DataTypes/DataTypeArray.h>
|
2016-07-25 18:26:45 +00:00
|
|
|
|
#include <DB/DataTypes/DataTypesNumberFixed.h>
|
2016-12-21 00:18:11 +00:00
|
|
|
|
#include <DB/IO/WriteBufferFromString.h>
|
|
|
|
|
#include <DB/IO/Operators.h>
|
2013-08-02 14:26:04 +00:00
|
|
|
|
|
2014-09-30 03:08:47 +00:00
|
|
|
|
#include <DB/Parsers/ASTExpressionList.h>
|
2015-02-10 21:10:58 +00:00
|
|
|
|
#include <memory>
|
2014-09-30 03:08:47 +00:00
|
|
|
|
|
|
|
|
|
#include <DB/Parsers/formatAST.h>
|
|
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
2016-01-11 21:46:36 +00:00
|
|
|
|
namespace ErrorCodes
|
|
|
|
|
{
|
|
|
|
|
extern const int POSITION_OUT_OF_BOUND;
|
|
|
|
|
extern const int NOT_FOUND_COLUMN_IN_BLOCK;
|
|
|
|
|
extern const int SIZES_OF_COLUMNS_DOESNT_MATCH;
|
|
|
|
|
extern const int SIZES_OF_ARRAYS_DOESNT_MATCH;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-12 20:44:25 +00:00
|
|
|
|
|
2014-10-16 16:55:23 +00:00
|
|
|
|
void Block::addDefaults(const NamesAndTypesList & required_columns)
|
2013-10-30 09:23:37 +00:00
|
|
|
|
{
|
2015-04-09 02:10:06 +00:00
|
|
|
|
/// Для недостающих столбцов из вложенной структуры нужно создавать не столбец пустых массивов, а столбец массивов правильных длин.
|
|
|
|
|
/// Сначала запомним столбцы смещений для всех массивов в блоке.
|
|
|
|
|
std::map<String, ColumnPtr> offset_columns;
|
|
|
|
|
|
|
|
|
|
for (const auto & elem : data)
|
|
|
|
|
{
|
|
|
|
|
if (const ColumnArray * array = typeid_cast<const ColumnArray *>(&*elem.column))
|
|
|
|
|
{
|
|
|
|
|
String offsets_name = DataTypeNested::extractNestedTableName(elem.name);
|
|
|
|
|
auto & offsets_column = offset_columns[offsets_name];
|
|
|
|
|
|
|
|
|
|
/// Если почему-то есть разные столбцы смещений для одной вложенной структуры, то берём непустой.
|
|
|
|
|
if (!offsets_column || offsets_column->empty())
|
|
|
|
|
offsets_column = array->getOffsetsColumn();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const auto & requested_column : required_columns)
|
|
|
|
|
{
|
|
|
|
|
if (has(requested_column.name))
|
|
|
|
|
continue;
|
|
|
|
|
|
2015-07-17 01:27:35 +00:00
|
|
|
|
ColumnWithTypeAndName column_to_add;
|
2015-04-09 02:10:06 +00:00
|
|
|
|
column_to_add.name = requested_column.name;
|
|
|
|
|
column_to_add.type = requested_column.type;
|
|
|
|
|
|
|
|
|
|
String offsets_name = DataTypeNested::extractNestedTableName(column_to_add.name);
|
|
|
|
|
if (offset_columns.count(offsets_name))
|
|
|
|
|
{
|
|
|
|
|
ColumnPtr offsets_column = offset_columns[offsets_name];
|
|
|
|
|
DataTypePtr nested_type = typeid_cast<DataTypeArray &>(*column_to_add.type).getNestedType();
|
|
|
|
|
size_t nested_rows = offsets_column->empty() ? 0
|
|
|
|
|
: typeid_cast<ColumnUInt64 &>(*offsets_column).getData().back();
|
|
|
|
|
|
|
|
|
|
ColumnPtr nested_column = dynamic_cast<IColumnConst &>(
|
|
|
|
|
*nested_type->createConstColumn(
|
|
|
|
|
nested_rows, nested_type->getDefault())).convertToFullColumn();
|
|
|
|
|
|
2016-05-28 05:31:36 +00:00
|
|
|
|
column_to_add.column = std::make_shared<ColumnArray>(nested_column, offsets_column);
|
2015-04-09 02:10:06 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/** Нужно превратить константный столбец в полноценный, так как в части блоков (из других кусков),
|
|
|
|
|
* он может быть полноценным (а то интерпретатор может посчитать, что он константный везде).
|
|
|
|
|
*/
|
|
|
|
|
column_to_add.column = dynamic_cast<IColumnConst &>(
|
|
|
|
|
*column_to_add.type->createConstColumn(
|
2017-01-02 20:42:49 +00:00
|
|
|
|
rows(), column_to_add.type->getDefault())).convertToFullColumn();
|
2015-04-09 02:10:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-05 02:28:34 +00:00
|
|
|
|
insert(std::move(column_to_add));
|
2015-04-09 02:10:06 +00:00
|
|
|
|
}
|
2014-09-30 03:08:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
|
|
2015-07-17 01:27:35 +00:00
|
|
|
|
void Block::insert(size_t position, const ColumnWithTypeAndName & elem)
|
2010-03-01 16:59:51 +00:00
|
|
|
|
{
|
2016-08-04 21:40:20 +00:00
|
|
|
|
if (position > data.size())
|
2011-08-14 00:49:30 +00:00
|
|
|
|
throw Exception("Position out of bound in Block::insert(), max position = "
|
2016-08-04 21:40:20 +00:00
|
|
|
|
+ toString(data.size()), ErrorCodes::POSITION_OUT_OF_BOUND);
|
2014-06-25 00:17:51 +00:00
|
|
|
|
|
2016-08-05 19:15:07 +00:00
|
|
|
|
for (auto & name_pos : index_by_name)
|
|
|
|
|
if (name_pos.second >= position)
|
|
|
|
|
++name_pos.second;
|
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
index_by_name[elem.name] = position;
|
|
|
|
|
data.emplace(data.begin() + position, elem);
|
|
|
|
|
}
|
2013-11-17 19:14:17 +00:00
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
void Block::insert(size_t position, ColumnWithTypeAndName && elem)
|
|
|
|
|
{
|
|
|
|
|
if (position > data.size())
|
|
|
|
|
throw Exception("Position out of bound in Block::insert(), max position = "
|
|
|
|
|
+ toString(data.size()), ErrorCodes::POSITION_OUT_OF_BOUND);
|
2013-11-17 19:14:17 +00:00
|
|
|
|
|
2016-08-05 19:15:07 +00:00
|
|
|
|
for (auto & name_pos : index_by_name)
|
|
|
|
|
if (name_pos.second >= position)
|
|
|
|
|
++name_pos.second;
|
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
index_by_name[elem.name] = position;
|
|
|
|
|
data.emplace(data.begin() + position, std::move(elem));
|
2010-03-01 16:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-07-17 01:27:35 +00:00
|
|
|
|
void Block::insert(const ColumnWithTypeAndName & elem)
|
2010-03-05 15:29:17 +00:00
|
|
|
|
{
|
2016-08-04 21:40:20 +00:00
|
|
|
|
index_by_name[elem.name] = data.size();
|
|
|
|
|
data.emplace_back(elem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Block::insert(ColumnWithTypeAndName && elem)
|
|
|
|
|
{
|
|
|
|
|
index_by_name[elem.name] = data.size();
|
|
|
|
|
data.emplace_back(std::move(elem));
|
2011-09-04 05:14:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 20:37:30 +00:00
|
|
|
|
|
2015-07-17 01:27:35 +00:00
|
|
|
|
void Block::insertUnique(const ColumnWithTypeAndName & elem)
|
2011-09-04 05:14:52 +00:00
|
|
|
|
{
|
|
|
|
|
if (index_by_name.end() == index_by_name.find(elem.name))
|
|
|
|
|
insert(elem);
|
2010-03-05 15:29:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
void Block::insertUnique(ColumnWithTypeAndName && elem)
|
|
|
|
|
{
|
|
|
|
|
if (index_by_name.end() == index_by_name.find(elem.name))
|
|
|
|
|
insert(std::move(elem));
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-05 15:29:17 +00:00
|
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
|
void Block::erase(size_t position)
|
|
|
|
|
{
|
2016-08-04 21:40:20 +00:00
|
|
|
|
if (data.empty())
|
2015-07-30 23:41:02 +00:00
|
|
|
|
throw Exception("Block is empty", ErrorCodes::POSITION_OUT_OF_BOUND);
|
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
if (position >= data.size())
|
2011-08-14 00:49:30 +00:00
|
|
|
|
throw Exception("Position out of bound in Block::erase(), max position = "
|
2016-08-04 21:40:20 +00:00
|
|
|
|
+ toString(data.size() - 1), ErrorCodes::POSITION_OUT_OF_BOUND);
|
2014-06-25 00:17:51 +00:00
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
eraseImpl(position);
|
|
|
|
|
}
|
2014-06-25 00:17:51 +00:00
|
|
|
|
|
2013-11-17 19:14:17 +00:00
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
void Block::eraseImpl(size_t position)
|
|
|
|
|
{
|
|
|
|
|
data.erase(data.begin() + position);
|
2013-11-17 19:14:17 +00:00
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
for (auto it = index_by_name.begin(); it != index_by_name.end();)
|
|
|
|
|
{
|
|
|
|
|
if (it->second == position)
|
|
|
|
|
index_by_name.erase(it++);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (it->second > position)
|
|
|
|
|
--it->second;
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-03-01 16:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
|
void Block::erase(const String & name)
|
|
|
|
|
{
|
2016-08-04 21:40:20 +00:00
|
|
|
|
auto index_it = index_by_name.find(name);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
if (index_it == index_by_name.end())
|
|
|
|
|
throw Exception("No such name in Block::erase(): '"
|
|
|
|
|
+ name + "'", ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK);
|
2014-06-25 00:17:51 +00:00
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
eraseImpl(index_it->second);
|
2013-05-24 10:49:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
ColumnWithTypeAndName & Block::safeGetByPosition(size_t position)
|
2010-03-01 16:59:51 +00:00
|
|
|
|
{
|
2016-08-04 21:40:20 +00:00
|
|
|
|
if (data.empty())
|
2015-07-30 23:41:02 +00:00
|
|
|
|
throw Exception("Block is empty", ErrorCodes::POSITION_OUT_OF_BOUND);
|
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
if (position >= data.size())
|
2013-06-21 20:34:19 +00:00
|
|
|
|
throw Exception("Position " + toString(position)
|
2017-01-02 20:12:12 +00:00
|
|
|
|
+ " is out of bound in Block::safeGetByPosition(), max position = "
|
2016-08-04 21:40:20 +00:00
|
|
|
|
+ toString(data.size() - 1)
|
2011-09-05 00:32:22 +00:00
|
|
|
|
+ ", there are columns: " + dumpNames(), ErrorCodes::POSITION_OUT_OF_BOUND);
|
2014-06-25 00:17:51 +00:00
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
return data[position];
|
2010-03-01 16:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const ColumnWithTypeAndName & Block::safeGetByPosition(size_t position) const
|
2010-03-01 16:59:51 +00:00
|
|
|
|
{
|
2016-08-04 21:40:20 +00:00
|
|
|
|
if (data.empty())
|
2015-07-30 23:41:02 +00:00
|
|
|
|
throw Exception("Block is empty", ErrorCodes::POSITION_OUT_OF_BOUND);
|
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
if (position >= data.size())
|
2013-06-21 20:34:19 +00:00
|
|
|
|
throw Exception("Position " + toString(position)
|
2017-01-02 20:12:12 +00:00
|
|
|
|
+ " is out of bound in Block::safeGetByPosition(), max position = "
|
2016-08-04 21:40:20 +00:00
|
|
|
|
+ toString(data.size() - 1)
|
2011-09-05 00:32:22 +00:00
|
|
|
|
+ ", there are columns: " + dumpNames(), ErrorCodes::POSITION_OUT_OF_BOUND);
|
2014-06-25 00:17:51 +00:00
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
return data[position];
|
2010-03-01 16:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-07-17 01:27:35 +00:00
|
|
|
|
ColumnWithTypeAndName & Block::getByName(const std::string & name)
|
2010-03-01 16:59:51 +00:00
|
|
|
|
{
|
2016-08-04 21:40:20 +00:00
|
|
|
|
auto it = index_by_name.find(name);
|
2011-08-21 03:41:37 +00:00
|
|
|
|
if (index_by_name.end() == it)
|
|
|
|
|
throw Exception("Not found column " + name + " in block. There are only columns: " + dumpNames()
|
|
|
|
|
, ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK);
|
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
return data[it->second];
|
2010-03-01 16:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-07-17 01:27:35 +00:00
|
|
|
|
const ColumnWithTypeAndName & Block::getByName(const std::string & name) const
|
2010-03-01 16:59:51 +00:00
|
|
|
|
{
|
2016-08-04 21:40:20 +00:00
|
|
|
|
auto it = index_by_name.find(name);
|
2010-03-04 19:20:28 +00:00
|
|
|
|
if (index_by_name.end() == it)
|
2011-08-14 00:49:30 +00:00
|
|
|
|
throw Exception("Not found column " + name + " in block. There are only columns: " + dumpNames()
|
|
|
|
|
, ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK);
|
2010-03-04 19:20:28 +00:00
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
return data[it->second];
|
2010-03-04 19:20:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-12-12 06:15:34 +00:00
|
|
|
|
bool Block::has(const std::string & name) const
|
|
|
|
|
{
|
|
|
|
|
return index_by_name.end() != index_by_name.find(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-08-12 20:39:42 +00:00
|
|
|
|
size_t Block::getPositionByName(const std::string & name) const
|
|
|
|
|
{
|
2016-08-04 21:40:20 +00:00
|
|
|
|
auto it = index_by_name.find(name);
|
2011-08-12 20:39:42 +00:00
|
|
|
|
if (index_by_name.end() == it)
|
2011-08-14 00:49:30 +00:00
|
|
|
|
throw Exception("Not found column " + name + " in block. There are only columns: " + dumpNames()
|
|
|
|
|
, ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK);
|
2011-08-12 20:39:42 +00:00
|
|
|
|
|
2016-08-04 21:40:20 +00:00
|
|
|
|
return it->second;
|
2011-08-12 20:39:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-01-02 20:42:49 +00:00
|
|
|
|
void Block::checkNumberOfRows() const
|
2010-03-04 19:20:28 +00:00
|
|
|
|
{
|
2017-01-02 20:42:49 +00:00
|
|
|
|
ssize_t rows = -1;
|
2015-04-09 02:10:06 +00:00
|
|
|
|
for (const auto & elem : data)
|
2010-03-04 19:20:28 +00:00
|
|
|
|
{
|
2017-01-02 20:42:49 +00:00
|
|
|
|
if (!elem.column)
|
|
|
|
|
throw Exception("Column " + elem.name + " in block is nullptr, in method checkNumberOfRows."
|
|
|
|
|
, ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
|
|
|
|
|
2017-01-02 20:47:59 +00:00
|
|
|
|
ssize_t size = elem.column->size();
|
2010-03-04 19:20:28 +00:00
|
|
|
|
|
2017-01-02 20:42:49 +00:00
|
|
|
|
if (rows == -1)
|
|
|
|
|
rows = size;
|
|
|
|
|
else if (rows != size)
|
2011-08-14 00:49:30 +00:00
|
|
|
|
throw Exception("Sizes of columns doesn't match: "
|
2017-01-02 20:42:49 +00:00
|
|
|
|
+ data.front().name + ": " + toString(rows)
|
2015-04-09 02:10:06 +00:00
|
|
|
|
+ ", " + elem.name + ": " + toString(size)
|
2011-08-14 00:49:30 +00:00
|
|
|
|
, ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
2010-03-04 19:20:28 +00:00
|
|
|
|
}
|
2010-03-01 16:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-03-04 19:20:28 +00:00
|
|
|
|
|
2017-01-02 20:42:49 +00:00
|
|
|
|
size_t Block::rows() const
|
2013-06-08 20:19:29 +00:00
|
|
|
|
{
|
2015-04-09 02:10:06 +00:00
|
|
|
|
for (const auto & elem : data)
|
2016-05-28 05:31:36 +00:00
|
|
|
|
if (elem.column)
|
2015-04-09 02:10:06 +00:00
|
|
|
|
return elem.column->size();
|
2013-06-08 20:19:29 +00:00
|
|
|
|
|
2014-07-03 12:13:32 +00:00
|
|
|
|
return 0;
|
2013-06-08 20:19:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-05-17 19:15:53 +00:00
|
|
|
|
size_t Block::bytes() const
|
|
|
|
|
{
|
|
|
|
|
size_t res = 0;
|
2015-04-09 02:10:06 +00:00
|
|
|
|
for (const auto & elem : data)
|
|
|
|
|
res += elem.column->byteSize();
|
2012-05-17 19:15:53 +00:00
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-08-14 00:49:30 +00:00
|
|
|
|
std::string Block::dumpNames() const
|
|
|
|
|
{
|
2016-12-21 00:18:11 +00:00
|
|
|
|
std::string res;
|
2011-08-14 00:49:30 +00:00
|
|
|
|
{
|
2016-12-21 00:18:11 +00:00
|
|
|
|
WriteBufferFromString out(res);
|
|
|
|
|
for (auto it = data.begin(); it != data.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
if (it != data.begin())
|
|
|
|
|
out << ", ";
|
|
|
|
|
out << it->name;
|
|
|
|
|
}
|
2011-08-14 00:49:30 +00:00
|
|
|
|
}
|
2016-12-21 00:18:11 +00:00
|
|
|
|
return res;
|
2011-08-14 00:49:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-12-05 12:47:05 +00:00
|
|
|
|
std::string Block::dumpStructure() const
|
|
|
|
|
{
|
2016-12-21 00:18:11 +00:00
|
|
|
|
std::string res;
|
2013-12-05 12:47:05 +00:00
|
|
|
|
{
|
2016-12-21 00:18:11 +00:00
|
|
|
|
WriteBufferFromString out(res);
|
|
|
|
|
for (auto it = data.begin(); it != data.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
if (it != data.begin())
|
|
|
|
|
out << ", ";
|
2015-07-27 15:51:37 +00:00
|
|
|
|
|
2016-12-21 00:18:11 +00:00
|
|
|
|
out << it->name << ' ' << it->type->getName();
|
2015-07-27 15:51:37 +00:00
|
|
|
|
|
2016-12-21 00:18:11 +00:00
|
|
|
|
if (it->column)
|
|
|
|
|
out << ' ' << it->column->getName() << ' ' << it->column->size();
|
|
|
|
|
else
|
|
|
|
|
out << " nullptr";
|
|
|
|
|
}
|
2013-12-05 12:47:05 +00:00
|
|
|
|
}
|
2016-12-21 00:18:11 +00:00
|
|
|
|
return res;
|
2013-12-05 12:47:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-09-19 03:34:23 +00:00
|
|
|
|
Block Block::cloneEmpty() const
|
|
|
|
|
{
|
|
|
|
|
Block res;
|
|
|
|
|
|
2015-04-09 02:10:06 +00:00
|
|
|
|
for (const auto & elem : data)
|
|
|
|
|
res.insert(elem.cloneEmpty());
|
2011-09-19 03:34:23 +00:00
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-02-13 20:37:30 +00:00
|
|
|
|
Block Block::sortColumns() const
|
|
|
|
|
{
|
|
|
|
|
Block sorted_block;
|
|
|
|
|
|
|
|
|
|
for (const auto & name : index_by_name)
|
2016-08-04 21:40:20 +00:00
|
|
|
|
sorted_block.insert(data[name.second]);
|
2015-02-13 20:37:30 +00:00
|
|
|
|
|
|
|
|
|
return sorted_block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-07-17 01:27:35 +00:00
|
|
|
|
ColumnsWithTypeAndName Block::getColumns() const
|
2013-06-04 13:34:46 +00:00
|
|
|
|
{
|
2015-07-17 01:27:35 +00:00
|
|
|
|
return ColumnsWithTypeAndName(data.begin(), data.end());
|
2013-06-04 13:34:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-11-06 02:29:13 +00:00
|
|
|
|
NamesAndTypesList Block::getColumnsList() const
|
|
|
|
|
{
|
|
|
|
|
NamesAndTypesList res;
|
|
|
|
|
|
2015-04-09 02:10:06 +00:00
|
|
|
|
for (const auto & elem : data)
|
|
|
|
|
res.push_back(NameAndTypePair(elem.name, elem.type));
|
2011-11-06 02:29:13 +00:00
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-08-02 14:26:04 +00:00
|
|
|
|
void Block::checkNestedArraysOffsets() const
|
|
|
|
|
{
|
|
|
|
|
/// Указатели на столбцы-массивы, для проверки равенства столбцов смещений во вложенных структурах данных
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using ArrayColumns = std::map<String, const ColumnArray *>;
|
2013-08-02 14:26:04 +00:00
|
|
|
|
ArrayColumns array_columns;
|
2014-06-25 00:17:51 +00:00
|
|
|
|
|
2015-04-09 02:10:06 +00:00
|
|
|
|
for (const auto & elem : data)
|
2013-08-02 14:26:04 +00:00
|
|
|
|
{
|
2016-08-24 16:02:34 +00:00
|
|
|
|
const IColumn * observed_col;
|
|
|
|
|
if (elem.column->isNullable())
|
|
|
|
|
{
|
|
|
|
|
const auto & nullable_col = static_cast<const ColumnNullable &>(*elem.column);
|
|
|
|
|
observed_col = nullable_col.getNestedColumn().get();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
observed_col = elem.column.get();
|
|
|
|
|
|
|
|
|
|
if (const ColumnArray * column_array = typeid_cast<const ColumnArray *>(observed_col))
|
2013-08-02 14:26:04 +00:00
|
|
|
|
{
|
2015-04-09 02:10:06 +00:00
|
|
|
|
String name = DataTypeNested::extractNestedTableName(elem.name);
|
2014-06-25 00:17:51 +00:00
|
|
|
|
|
2013-08-02 14:26:04 +00:00
|
|
|
|
ArrayColumns::const_iterator it = array_columns.find(name);
|
|
|
|
|
if (array_columns.end() == it)
|
|
|
|
|
array_columns[name] = column_array;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!it->second->hasEqualOffsets(*column_array))
|
|
|
|
|
throw Exception("Sizes of nested arrays do not match", ErrorCodes::SIZES_OF_ARRAYS_DOESNT_MATCH);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Block::optimizeNestedArraysOffsets()
|
|
|
|
|
{
|
|
|
|
|
/// Указатели на столбцы-массивы, для проверки равенства столбцов смещений во вложенных структурах данных
|
2016-05-28 10:35:44 +00:00
|
|
|
|
using ArrayColumns = std::map<String, ColumnArray *>;
|
2013-08-02 14:26:04 +00:00
|
|
|
|
ArrayColumns array_columns;
|
2014-06-25 00:17:51 +00:00
|
|
|
|
|
2015-04-09 02:10:06 +00:00
|
|
|
|
for (auto & elem : data)
|
2013-08-02 14:26:04 +00:00
|
|
|
|
{
|
2016-08-24 16:02:34 +00:00
|
|
|
|
IColumn * observed_col;
|
|
|
|
|
if (elem.column->isNullable())
|
|
|
|
|
{
|
|
|
|
|
auto & nullable_col = static_cast<ColumnNullable &>(*elem.column);
|
|
|
|
|
observed_col = nullable_col.getNestedColumn().get();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
observed_col = elem.column.get();
|
|
|
|
|
|
|
|
|
|
if (ColumnArray * column_array = typeid_cast<ColumnArray *>(observed_col))
|
2013-08-02 14:26:04 +00:00
|
|
|
|
{
|
2015-04-09 02:10:06 +00:00
|
|
|
|
String name = DataTypeNested::extractNestedTableName(elem.name);
|
2014-06-25 00:17:51 +00:00
|
|
|
|
|
2013-08-02 14:26:04 +00:00
|
|
|
|
ArrayColumns::const_iterator it = array_columns.find(name);
|
|
|
|
|
if (array_columns.end() == it)
|
|
|
|
|
array_columns[name] = column_array;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!it->second->hasEqualOffsets(*column_array))
|
|
|
|
|
throw Exception("Sizes of nested arrays do not match", ErrorCodes::SIZES_OF_ARRAYS_DOESNT_MATCH);
|
2014-06-25 00:17:51 +00:00
|
|
|
|
|
2013-08-02 14:26:04 +00:00
|
|
|
|
/// делаем так, чтобы столбцы смещений массивов внутри одной вложенной таблицы указывали в одно место
|
|
|
|
|
column_array->getOffsetsColumn() = it->second->getOffsetsColumn();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-06-21 23:27:26 +00:00
|
|
|
|
bool blocksHaveEqualStructure(const Block & lhs, const Block & rhs)
|
|
|
|
|
{
|
|
|
|
|
size_t columns = lhs.columns();
|
|
|
|
|
if (rhs.columns() != columns)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < columns; ++i)
|
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
const IDataType & lhs_type = *lhs.safeGetByPosition(i).type;
|
|
|
|
|
const IDataType & rhs_type = *rhs.safeGetByPosition(i).type;
|
2015-01-03 03:18:49 +00:00
|
|
|
|
|
2013-06-21 23:27:26 +00:00
|
|
|
|
if (lhs_type.getName() != rhs_type.getName())
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-21 00:18:11 +00:00
|
|
|
|
|
|
|
|
|
void getBlocksDifference(const Block & lhs, const Block & rhs, std::string & out_lhs_diff, std::string & out_rhs_diff)
|
2016-12-20 22:22:23 +00:00
|
|
|
|
{
|
|
|
|
|
/// Традиционная задача: наибольшая общая подпоследовательность (LCS).
|
2016-12-21 00:18:11 +00:00
|
|
|
|
/// Полагаем, что порядок важен. Если это когда-то станет не так, упростим: например, сделаем 2 set'а.
|
|
|
|
|
|
|
|
|
|
std::vector<std::vector<int>> lcs(lhs.columns() + 1);
|
|
|
|
|
for (auto & v : lcs)
|
|
|
|
|
v.resize(rhs.columns() + 1);
|
|
|
|
|
|
2016-12-20 22:22:23 +00:00
|
|
|
|
for (size_t i = 1; i <= lhs.columns(); ++i)
|
2016-12-21 00:18:11 +00:00
|
|
|
|
{
|
2016-12-20 22:22:23 +00:00
|
|
|
|
for (size_t j = 1; j <= rhs.columns(); ++j)
|
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
if (lhs.safeGetByPosition(i - 1) == rhs.safeGetByPosition(j - 1))
|
2016-12-21 00:18:11 +00:00
|
|
|
|
lcs[i][j] = lcs[i - 1][j - 1] + 1;
|
2016-12-20 22:22:23 +00:00
|
|
|
|
else
|
2016-12-21 00:18:11 +00:00
|
|
|
|
lcs[i][j] = std::max(lcs[i - 1][j], lcs[i][j - 1]);
|
2016-12-20 22:22:23 +00:00
|
|
|
|
}
|
2016-12-21 00:18:11 +00:00
|
|
|
|
}
|
2016-12-20 22:22:23 +00:00
|
|
|
|
|
|
|
|
|
/// Теперь идем обратно и собираем ответ.
|
2016-12-23 01:24:19 +00:00
|
|
|
|
ColumnsWithTypeAndName left_columns;
|
|
|
|
|
ColumnsWithTypeAndName right_columns;
|
2016-12-21 00:18:11 +00:00
|
|
|
|
size_t l = lhs.columns();
|
|
|
|
|
size_t r = rhs.columns();
|
2016-12-20 22:22:23 +00:00
|
|
|
|
while (l > 0 && r > 0)
|
|
|
|
|
{
|
2017-01-02 20:12:12 +00:00
|
|
|
|
if (lhs.safeGetByPosition(l - 1) == rhs.safeGetByPosition(r - 1))
|
2016-12-20 22:22:23 +00:00
|
|
|
|
{
|
|
|
|
|
/// Данный элемент в обеих последовательностях, значит, в diff не попадает.
|
|
|
|
|
--l;
|
|
|
|
|
--r;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/// Маленькая эвристика: чаще всего используется при получении разницы для (expected_block, actual_block).
|
|
|
|
|
/// Поэтому предпочтение будем отдавать полю, которое есть в левом блоке (expected_block), поэтому
|
|
|
|
|
/// в diff попадет столбец из actual_block.
|
2016-12-21 00:18:11 +00:00
|
|
|
|
if (lcs[l][r - 1] >= lcs[l - 1][r])
|
2017-01-02 20:12:12 +00:00
|
|
|
|
right_columns.push_back(rhs.safeGetByPosition(--r));
|
2016-12-20 22:22:23 +00:00
|
|
|
|
else
|
2017-01-02 20:12:12 +00:00
|
|
|
|
left_columns.push_back(lhs.safeGetByPosition(--l));
|
2016-12-20 22:22:23 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (l > 0)
|
2017-01-02 20:12:12 +00:00
|
|
|
|
left_columns.push_back(lhs.safeGetByPosition(--l));
|
2016-12-20 22:22:23 +00:00
|
|
|
|
while (r > 0)
|
2017-01-02 20:12:12 +00:00
|
|
|
|
right_columns.push_back(rhs.safeGetByPosition(--r));
|
2016-12-20 22:22:23 +00:00
|
|
|
|
|
2016-12-21 00:18:11 +00:00
|
|
|
|
WriteBufferFromString lhs_diff_writer(out_lhs_diff);
|
|
|
|
|
WriteBufferFromString rhs_diff_writer(out_rhs_diff);
|
|
|
|
|
|
2016-12-20 22:22:23 +00:00
|
|
|
|
for (auto it = left_columns.rbegin(); it != left_columns.rend(); ++it)
|
2016-12-23 01:24:19 +00:00
|
|
|
|
{
|
|
|
|
|
lhs_diff_writer << it->prettyPrint();
|
|
|
|
|
lhs_diff_writer << ", position: " << lhs.getPositionByName(it->name) << '\n';
|
|
|
|
|
}
|
2016-12-20 22:22:23 +00:00
|
|
|
|
for (auto it = right_columns.rbegin(); it != right_columns.rend(); ++it)
|
2016-12-23 01:24:19 +00:00
|
|
|
|
{
|
|
|
|
|
rhs_diff_writer << it->prettyPrint();
|
|
|
|
|
rhs_diff_writer << ", position: " << rhs.getPositionByName(it->name) << '\n';
|
|
|
|
|
}
|
2016-12-20 22:22:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-17 19:14:17 +00:00
|
|
|
|
|
|
|
|
|
void Block::clear()
|
|
|
|
|
{
|
2015-01-03 03:18:49 +00:00
|
|
|
|
info = BlockInfo();
|
2013-11-17 19:14:17 +00:00
|
|
|
|
data.clear();
|
|
|
|
|
index_by_name.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-30 20:54:39 +00:00
|
|
|
|
void Block::swap(Block & other) noexcept
|
2013-11-17 19:14:17 +00:00
|
|
|
|
{
|
2015-01-03 03:18:49 +00:00
|
|
|
|
std::swap(info, other.info);
|
2013-11-17 19:14:17 +00:00
|
|
|
|
data.swap(other.data);
|
|
|
|
|
index_by_name.swap(other.index_by_name);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-07 15:13:40 +00:00
|
|
|
|
|
|
|
|
|
void Block::unshareColumns()
|
|
|
|
|
{
|
|
|
|
|
std::unordered_set<void*> pointers;
|
|
|
|
|
|
|
|
|
|
for (auto & elem : data)
|
|
|
|
|
{
|
|
|
|
|
if (!pointers.insert(elem.column.get()).second)
|
|
|
|
|
{
|
|
|
|
|
elem.column = elem.column->clone();
|
|
|
|
|
}
|
|
|
|
|
else if (ColumnArray * arr = typeid_cast<ColumnArray *>(elem.column.get()))
|
|
|
|
|
{
|
|
|
|
|
ColumnPtr & offsets = arr->getOffsetsColumn();
|
|
|
|
|
if (!pointers.insert(offsets.get()).second)
|
|
|
|
|
offsets = offsets->clone();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-03-04 19:20:28 +00:00
|
|
|
|
}
|