Merge "Query result set comparison support"

Pekka says:

"This series adds comparison operators for query result sets that are
needed by schema merging code. The operators are implemented using a
newly added "data_value" type that encodes the type of the value."
This commit is contained in:
Avi Kivity
2015-05-27 12:38:20 +03:00
3 changed files with 77 additions and 21 deletions

View File

@@ -29,7 +29,7 @@ void result_set_builder::accept_new_row(const clustering_key& key, const result_
auto static_cells = deserialize(static_row, true);
auto regular_cells = deserialize(row, false);
std::unordered_map<sstring, boost::any> cells;
std::unordered_map<sstring, data_value> cells;
cells.insert(_pkey_cells.begin(), _pkey_cells.end());
cells.insert(ckey_cells.begin(), ckey_cells.end());
cells.insert(static_cells.begin(), static_cells.end());
@@ -42,7 +42,7 @@ void result_set_builder::accept_new_row(const query::result_row_view &static_row
auto static_cells = deserialize(static_row, true);
auto regular_cells = deserialize(row, false);
std::unordered_map<sstring, boost::any> cells;
std::unordered_map<sstring, data_value> cells;
cells.insert(_pkey_cells.begin(), _pkey_cells.end());
cells.insert(static_cells.begin(), static_cells.end());
cells.insert(regular_cells.begin(), regular_cells.end());
@@ -54,34 +54,34 @@ void result_set_builder::accept_partition_end(const result_row_view& static_row)
_pkey_cells.clear();
}
std::unordered_map<sstring, boost::any>
std::unordered_map<sstring, data_value>
result_set_builder::deserialize(const partition_key& key)
{
std::unordered_map<sstring, boost::any> cells;
std::unordered_map<sstring, data_value> cells;
auto i = key.begin(*_schema);
for (auto&& col : _schema->partition_key_columns()) {
cells.emplace(col.name_as_text(), col.type->deserialize(*i));
cells.emplace(col.name_as_text(), col.type->deserialize_value(*i));
++i;
}
return cells;
}
std::unordered_map<sstring, boost::any>
std::unordered_map<sstring, data_value>
result_set_builder::deserialize(const clustering_key& key)
{
std::unordered_map<sstring, boost::any> cells;
std::unordered_map<sstring, data_value> cells;
auto i = key.begin(*_schema);
for (auto&& col : _schema->clustering_key_columns()) {
cells.emplace(col.name_as_text(), col.type->deserialize(*i));
cells.emplace(col.name_as_text(), col.type->deserialize_value(*i));
++i;
}
return cells;
}
std::unordered_map<sstring, boost::any>
std::unordered_map<sstring, data_value>
result_set_builder::deserialize(const result_row_view& row, bool is_static)
{
std::unordered_map<sstring, boost::any> cells;
std::unordered_map<sstring, data_value> cells;
auto i = row.iterator();
auto columns = is_static ? _schema->static_columns() : _schema->regular_columns();
for (auto &&col : columns) {
@@ -89,14 +89,14 @@ result_set_builder::deserialize(const result_row_view& row, bool is_static)
auto cell = i.next_atomic_cell();
if (cell) {
auto view = cell.value();
cells.emplace(col.name_as_text(), col.type->deserialize(view.value()));
cells.emplace(col.name_as_text(), col.type->deserialize_value(view.value()));
}
} else {
auto cell = i.next_collection_cell();
if (cell) {
auto ctype = static_pointer_cast<const collection_type_impl>(col.type);
auto view = cell.value();
cells.emplace(col.name_as_text(), ctype->deserialize(view.data, serialization_format::internal()));
cells.emplace(col.name_as_text(), ctype->deserialize_value(view.data, serialization_format::internal()));
}
}
}

View File

@@ -29,9 +29,9 @@ public:
// including regular column cells, partition keys, as well as static values.
class result_set_row {
schema_ptr _schema;
std::unordered_map<sstring, boost::any> _cells;
std::unordered_map<sstring, data_value> _cells;
public:
result_set_row(schema_ptr schema, std::unordered_map<sstring, boost::any>&& cells)
result_set_row(schema_ptr schema, std::unordered_map<sstring, data_value>&& cells)
: _schema{schema}
, _cells{std::move(cells)}
{ }
@@ -43,10 +43,11 @@ public:
if (it == _cells.end()) {
throw no_such_column(column_name);
}
if (it->second.empty()) {
auto&& value = it->second.value();
if (value.empty()) {
return std::experimental::nullopt;
}
return std::experimental::optional<T>{boost::any_cast<T>(it->second)};
return std::experimental::optional<T>{boost::any_cast<T>(value)};
}
template<typename T>
T get_nonnull(const sstring& column_name) const throw (no_such_column, null_column_value) {
@@ -56,8 +57,18 @@ public:
}
throw null_column_value(column_name);
}
friend inline bool operator==(const result_set_row& x, const result_set_row& y);
friend inline bool operator!=(const result_set_row& x, const result_set_row& y);
};
inline bool operator==(const result_set_row& x, const result_set_row& y) {
return x._schema == y._schema && x._cells == y._cells;
}
inline bool operator!=(const result_set_row& x, const result_set_row& y) {
return !(x == y);
}
// Result set is an in-memory representation of query results in
// deserialized format. To obtain a result set, use the result_set_builder
// class as a visitor to query_result::consume() function.
@@ -76,15 +87,20 @@ public:
}
return _rows[idx];
}
friend inline bool operator==(const result_set& x, const result_set& y);
};
inline bool operator==(const result_set& x, const result_set& y) {
return x._rows == y._rows;
}
// Result set builder is passed as a visitor to query_result::consume()
// function. You can call the build() method to obtain a result set that
// contains cells from the visited results.
class result_set_builder {
schema_ptr _schema;
std::vector<result_set_row> _rows;
std::unordered_map<sstring, boost::any> _pkey_cells;
std::unordered_map<sstring, data_value> _pkey_cells;
public:
result_set_builder(schema_ptr schema);
lw_shared_ptr<result_set> build() const;
@@ -94,9 +110,9 @@ public:
void accept_new_row(const result_row_view &static_row, const result_row_view &row);
void accept_partition_end(const result_row_view& static_row);
private:
std::unordered_map<sstring, boost::any> deserialize(const partition_key& key);
std::unordered_map<sstring, boost::any> deserialize(const clustering_key& key);
std::unordered_map<sstring, boost::any> deserialize(const result_row_view& row, bool is_static);
std::unordered_map<sstring, data_value> deserialize(const partition_key& key);
std::unordered_map<sstring, data_value> deserialize(const clustering_key& key);
std::unordered_map<sstring, data_value> deserialize(const result_row_view& row, bool is_static);
};
}

View File

@@ -169,6 +169,28 @@ inline int32_t compare_unsigned(bytes_view v1, bytes_view v2) {
return (int32_t) (v1.size() - v2.size());
}
class abstract_type;
using data_type = shared_ptr<const abstract_type>;
class data_value {
boost::any _value;
data_type _type;
public:
data_value(boost::any&& value, data_type type)
: _value{std::move(value)}
, _type{type}
{ }
const boost::any& value() const {
return _value;
}
data_type type() const {
return _type;
}
friend inline bool operator==(const data_value& x, const data_value& y);
friend inline bool operator!=(const data_value& x, const data_value& y);
};
class serialized_compare;
class abstract_type : public enable_shared_from_this<abstract_type> {
@@ -198,6 +220,9 @@ public:
}
}
virtual boost::any deserialize(bytes_view v) const = 0;
data_value deserialize_value(bytes_view v) const {
return data_value{deserialize(v), shared_from_this()};
};
virtual void validate(bytes_view v) const {
// FIXME
}
@@ -246,6 +271,9 @@ public:
virtual boost::any compose(const bytes& v) const {
return deserialize(v);
}
data_value compose_value(const bytes& v) const {
return deserialize_value(v);
}
bytes decompose(const boost::any& value) const {
bytes b(bytes::initialized_later(), serialized_size(value));
auto i = b.begin();
@@ -284,7 +312,16 @@ public:
friend class list_type_impl;
};
using data_type = shared_ptr<const abstract_type>;
inline bool operator==(const data_value& x, const data_value& y)
{
return x._type == y._type && x._type->decompose(x._value) == y._type->decompose(y._value);
}
inline bool operator!=(const data_value& x, const data_value& y)
{
return !(x == y);
}
using bytes_view_opt = std::experimental::optional<bytes_view>;
static inline
@@ -394,6 +431,9 @@ public:
collection_mutation::one merge(collection_mutation::view a, collection_mutation::view b) const;
virtual void serialize(const boost::any& value, bytes::iterator& out, serialization_format sf) const = 0;
virtual boost::any deserialize(bytes_view v, serialization_format sf) const = 0;
data_value deserialize_value(bytes_view v, serialization_format sf) const {
return data_value{deserialize(v, sf), shared_from_this()};
}
bytes_opt reserialize(serialization_format from, serialization_format to, bytes_view_opt v) const;
};