2010-03-12 20:44:25 +00:00
|
|
|
#include <iterator>
|
|
|
|
|
2010-03-04 19:20:28 +00:00
|
|
|
#include <DB/Core/Exception.h>
|
|
|
|
#include <DB/Core/ErrorCodes.h>
|
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
#include <DB/Core/Block.h>
|
|
|
|
|
2013-08-02 14:26:04 +00:00
|
|
|
#include <DB/Columns/ColumnArray.h>
|
|
|
|
#include <DB/DataTypes/DataTypeNested.h>
|
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2010-03-12 20:44:25 +00:00
|
|
|
|
|
|
|
Block::Block(const Block & other)
|
|
|
|
{
|
|
|
|
*this = other;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-28 16:09:42 +00:00
|
|
|
void Block::addDefaults(NamesAndTypesListPtr required_columns) {
|
|
|
|
for (NamesAndTypesList::const_iterator it = required_columns->begin(); it != required_columns->end(); ++it)
|
|
|
|
{
|
|
|
|
if (!this->has(it->first))
|
|
|
|
{
|
|
|
|
ColumnWithNameAndType col;
|
|
|
|
col.name = it->first;
|
|
|
|
col.type = it->second;
|
|
|
|
col.column = dynamic_cast<IColumnConst &>(*it->second->createConstColumn(
|
|
|
|
this->rows(), it->second->getDefault())).convertToFullColumn();
|
|
|
|
this->insert(col);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-12 20:44:25 +00:00
|
|
|
Block & Block::operator= (const Block & other)
|
|
|
|
{
|
|
|
|
data = other.data;
|
|
|
|
rebuildIndexByPosition();
|
2011-08-21 03:41:37 +00:00
|
|
|
index_by_name.clear();
|
2010-03-12 20:44:25 +00:00
|
|
|
|
|
|
|
for (IndexByName_t::const_iterator it = other.index_by_name.begin(); it != other.index_by_name.end(); ++it)
|
|
|
|
{
|
|
|
|
Container_t::iterator value = data.begin();
|
|
|
|
std::advance(value, std::distance(const_cast<Block&>(other).data.begin(), it->second));
|
|
|
|
index_by_name[it->first] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
void Block::rebuildIndexByPosition()
|
|
|
|
{
|
2010-03-04 19:20:28 +00:00
|
|
|
index_by_position.resize(data.size());
|
2010-03-01 16:59:51 +00:00
|
|
|
size_t pos = 0;
|
2010-03-04 19:20:28 +00:00
|
|
|
for (Container_t::iterator it = data.begin(); it != data.end(); ++it, ++pos)
|
2010-03-01 16:59:51 +00:00
|
|
|
index_by_position[pos] = it;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Block::insert(size_t position, const ColumnWithNameAndType & elem)
|
|
|
|
{
|
2012-09-20 19:14:37 +00:00
|
|
|
if (position > index_by_position.size())
|
2011-08-14 00:49:30 +00:00
|
|
|
throw Exception("Position out of bound in Block::insert(), max position = "
|
2013-06-21 20:34:19 +00:00
|
|
|
+ toString(index_by_position.size()), ErrorCodes::POSITION_OUT_OF_BOUND);
|
2012-09-20 19:14:37 +00:00
|
|
|
|
|
|
|
if (position == index_by_position.size())
|
|
|
|
{
|
|
|
|
insert(elem);
|
|
|
|
return;
|
|
|
|
}
|
2010-03-05 15:29:17 +00:00
|
|
|
|
2010-03-04 19:20:28 +00:00
|
|
|
Container_t::iterator it = data.insert(index_by_position[position], elem);
|
2010-03-01 16:59:51 +00:00
|
|
|
rebuildIndexByPosition();
|
|
|
|
index_by_name[elem.name] = it;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-05 15:29:17 +00:00
|
|
|
void Block::insert(const ColumnWithNameAndType & elem)
|
|
|
|
{
|
|
|
|
Container_t::iterator it = data.insert(data.end(), elem);
|
|
|
|
rebuildIndexByPosition();
|
2011-09-04 05:14:52 +00:00
|
|
|
index_by_name[elem.name] = it;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Block::insertUnique(const ColumnWithNameAndType & elem)
|
|
|
|
{
|
|
|
|
if (index_by_name.end() == index_by_name.find(elem.name))
|
|
|
|
insert(elem);
|
2010-03-05 15:29:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
void Block::erase(size_t position)
|
|
|
|
{
|
2010-03-05 15:29:17 +00:00
|
|
|
if (position >= index_by_position.size())
|
2011-08-14 00:49:30 +00:00
|
|
|
throw Exception("Position out of bound in Block::erase(), max position = "
|
2013-06-21 20:34:19 +00:00
|
|
|
+ toString(index_by_position.size()), ErrorCodes::POSITION_OUT_OF_BOUND);
|
2010-03-05 15:29:17 +00:00
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
Container_t::iterator it = index_by_position[position];
|
|
|
|
index_by_name.erase(index_by_name.find(it->name));
|
2010-03-04 19:20:28 +00:00
|
|
|
data.erase(it);
|
2010-03-01 16:59:51 +00:00
|
|
|
rebuildIndexByPosition();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-24 10:49:19 +00:00
|
|
|
void Block::erase(const String & name)
|
|
|
|
{
|
|
|
|
IndexByName_t::iterator index_it = index_by_name.find(name);
|
|
|
|
if (index_it == index_by_name.end())
|
|
|
|
throw Exception("No such name in Block::erase(): '"
|
|
|
|
+ name + "'", ErrorCodes::NOT_FOUND_COLUMN_IN_BLOCK);
|
|
|
|
|
|
|
|
Container_t::iterator it = index_it->second;
|
|
|
|
index_by_name.erase(index_it);
|
|
|
|
data.erase(it);
|
|
|
|
rebuildIndexByPosition();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-04 19:20:28 +00:00
|
|
|
ColumnWithNameAndType & Block::getByPosition(size_t position)
|
2010-03-01 16:59:51 +00:00
|
|
|
{
|
2011-08-21 03:41:37 +00:00
|
|
|
if (position >= index_by_position.size())
|
2013-06-21 20:34:19 +00:00
|
|
|
throw Exception("Position " + toString(position)
|
2011-09-05 00:32:22 +00:00
|
|
|
+ " is out of bound in Block::getByPosition(), max position = "
|
2013-06-21 20:34:19 +00:00
|
|
|
+ toString(index_by_position.size() - 1)
|
2011-09-05 00:32:22 +00:00
|
|
|
+ ", there are columns: " + dumpNames(), ErrorCodes::POSITION_OUT_OF_BOUND);
|
2011-08-21 03:41:37 +00:00
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
return *index_by_position[position];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-04 19:20:28 +00:00
|
|
|
const ColumnWithNameAndType & Block::getByPosition(size_t position) const
|
2010-03-01 16:59:51 +00:00
|
|
|
{
|
2011-08-21 03:41:37 +00:00
|
|
|
if (position >= index_by_position.size())
|
2013-06-21 20:34:19 +00:00
|
|
|
throw Exception("Position " + toString(position)
|
2011-09-05 00:32:22 +00:00
|
|
|
+ " is out of bound in Block::getByPosition(), max position = "
|
2013-06-21 20:34:19 +00:00
|
|
|
+ toString(index_by_position.size() - 1)
|
2011-09-05 00:32:22 +00:00
|
|
|
+ ", there are columns: " + dumpNames(), ErrorCodes::POSITION_OUT_OF_BOUND);
|
2011-08-21 03:41:37 +00:00
|
|
|
|
2010-03-01 16:59:51 +00:00
|
|
|
return *index_by_position[position];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-04 19:20:28 +00:00
|
|
|
ColumnWithNameAndType & Block::getByName(const std::string & name)
|
2010-03-01 16:59:51 +00:00
|
|
|
{
|
2011-08-21 03:41:37 +00:00
|
|
|
IndexByName_t::const_iterator it = index_by_name.find(name);
|
|
|
|
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);
|
|
|
|
|
|
|
|
return *it->second;
|
2010-03-01 16:59:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-04 19:20:28 +00:00
|
|
|
const ColumnWithNameAndType & Block::getByName(const std::string & name) const
|
2010-03-01 16:59:51 +00:00
|
|
|
{
|
2010-03-04 19:20:28 +00:00
|
|
|
IndexByName_t::const_iterator it = index_by_name.find(name);
|
|
|
|
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
|
|
|
|
|
|
|
return *it->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
IndexByName_t::const_iterator it = index_by_name.find(name);
|
|
|
|
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
|
|
|
|
|
|
|
return std::distance(const_cast<Container_t &>(data).begin(), it->second);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-04 19:20:28 +00:00
|
|
|
size_t Block::rows() const
|
|
|
|
{
|
|
|
|
size_t res = 0;
|
|
|
|
for (Container_t::const_iterator it = data.begin(); it != data.end(); ++it)
|
|
|
|
{
|
2010-03-12 18:25:35 +00:00
|
|
|
size_t size = it->column->size();
|
2010-03-04 19:20:28 +00:00
|
|
|
|
2010-03-18 20:32:35 +00:00
|
|
|
if (res != 0 && size != res)
|
2011-08-14 00:49:30 +00:00
|
|
|
throw Exception("Sizes of columns doesn't match: "
|
2013-06-21 20:34:19 +00:00
|
|
|
+ data.begin()->name + ": " + toString(res)
|
|
|
|
+ ", " + it->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
|
|
|
|
|
|
|
res = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
2010-03-01 16:59:51 +00:00
|
|
|
}
|
|
|
|
|
2010-03-04 19:20:28 +00:00
|
|
|
|
2013-06-08 20:19:29 +00:00
|
|
|
size_t Block::rowsInFirstColumn() const
|
|
|
|
{
|
|
|
|
if (data.empty() || data.front().column.isNull())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return data.front().column->size();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-04 19:20:28 +00:00
|
|
|
size_t Block::columns() const
|
|
|
|
{
|
|
|
|
return data.size();
|
2010-03-01 16:59:51 +00:00
|
|
|
}
|
|
|
|
|
2011-08-14 00:49:30 +00:00
|
|
|
|
2012-05-17 19:15:53 +00:00
|
|
|
size_t Block::bytes() const
|
|
|
|
{
|
|
|
|
size_t res = 0;
|
|
|
|
for (size_t i = 0; i < columns(); ++i)
|
|
|
|
res += getByPosition(i).column->byteSize();
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-08-14 00:49:30 +00:00
|
|
|
std::string Block::dumpNames() const
|
|
|
|
{
|
|
|
|
std::stringstream res;
|
|
|
|
for (Container_t::const_iterator it = data.begin(); it != data.end(); ++it)
|
|
|
|
{
|
|
|
|
if (it != data.begin())
|
|
|
|
res << ", ";
|
|
|
|
res << it->name;
|
|
|
|
}
|
|
|
|
return res.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-19 03:34:23 +00:00
|
|
|
Block Block::cloneEmpty() const
|
|
|
|
{
|
|
|
|
Block res;
|
|
|
|
|
|
|
|
for (Container_t::const_iterator it = data.begin(); it != data.end(); ++it)
|
|
|
|
res.insert(it->cloneEmpty());
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-04 13:34:46 +00:00
|
|
|
ColumnsWithNameAndType Block::getColumns() const
|
|
|
|
{
|
|
|
|
return ColumnsWithNameAndType(data.begin(), data.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-06 02:29:13 +00:00
|
|
|
NamesAndTypesList Block::getColumnsList() const
|
|
|
|
{
|
|
|
|
NamesAndTypesList res;
|
|
|
|
|
|
|
|
for (Container_t::const_iterator it = data.begin(); it != data.end(); ++it)
|
|
|
|
res.push_back(NameAndTypePair(it->name, it->type));
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-02 14:26:04 +00:00
|
|
|
void Block::checkNestedArraysOffsets() const
|
|
|
|
{
|
|
|
|
/// Указатели на столбцы-массивы, для проверки равенства столбцов смещений во вложенных структурах данных
|
|
|
|
typedef std::map<String, const ColumnArray *> ArrayColumns;
|
|
|
|
ArrayColumns array_columns;
|
|
|
|
|
|
|
|
for (Container_t::const_iterator it = data.begin(); it != data.end(); ++it)
|
|
|
|
{
|
|
|
|
const ColumnWithNameAndType & column = *it;
|
|
|
|
|
|
|
|
if (const ColumnArray * column_array = dynamic_cast<const ColumnArray *>(&*column.column))
|
|
|
|
{
|
|
|
|
String name = DataTypeNested::extractNestedTableName(column.name);
|
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
/// Указатели на столбцы-массивы, для проверки равенства столбцов смещений во вложенных структурах данных
|
|
|
|
typedef std::map<String, ColumnArray *> ArrayColumns;
|
|
|
|
ArrayColumns array_columns;
|
|
|
|
|
|
|
|
for (Container_t::iterator it = data.begin(); it != data.end(); ++it)
|
|
|
|
{
|
|
|
|
ColumnWithNameAndType & column = *it;
|
|
|
|
|
|
|
|
if (ColumnArray * column_array = dynamic_cast<ColumnArray *>(&*column.column))
|
|
|
|
{
|
|
|
|
String name = DataTypeNested::extractNestedTableName(column.name);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
/// делаем так, чтобы столбцы смещений массивов внутри одной вложенной таблицы указывали в одно место
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
const IDataType & lhs_type = *lhs.getByPosition(i).type;
|
|
|
|
const IDataType & rhs_type = *rhs.getByPosition(i).type;
|
|
|
|
|
|
|
|
if (lhs_type.getName() != rhs_type.getName())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-03-04 19:20:28 +00:00
|
|
|
}
|