mirror of
https://github.com/scylladb/scylladb.git
synced 2026-04-22 01:20:39 +00:00
To prepare a user-defined type, we need to look up its name in the keyspace. While we get the keyspace name as an argument to prepare(), it is useless without the database instance. Fix the problem by passing a database reference along with the keyspace. This precolates through the class structure, so most cql3 raw types end up receiving this treatment. Origin gets along without it by using a singleton. We can't do this due to sharding (we could use a thread-local instance, but that's ugly too). Hopefully the transition to a visitor will clean this up.
328 lines
12 KiB
C++
328 lines
12 KiB
C++
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/*
|
|
* Copyright 2015 Cloudius Systems
|
|
*
|
|
* Modified by Cloudius Systems
|
|
*/
|
|
|
|
#include "cql3/selection/selection.hh"
|
|
#include "cql3/selection/selector_factories.hh"
|
|
#include "cql3/result_set.hh"
|
|
|
|
namespace cql3 {
|
|
|
|
namespace selection {
|
|
|
|
selection::selection(schema_ptr schema,
|
|
std::vector<const column_definition*> columns,
|
|
std::vector<::shared_ptr<column_specification>> metadata_,
|
|
bool collect_timestamps,
|
|
bool collect_TTLs)
|
|
: _schema(std::move(schema))
|
|
, _columns(std::move(columns))
|
|
, _metadata(::make_shared<metadata>(std::move(metadata_)))
|
|
, _collect_timestamps(collect_timestamps)
|
|
, _collect_TTLs(collect_TTLs)
|
|
, _contains_static_columns(std::any_of(_columns.begin(), _columns.end(), std::mem_fn(&column_definition::is_static)))
|
|
{ }
|
|
|
|
query::partition_slice::option_set selection::get_query_options() {
|
|
query::partition_slice::option_set opts;
|
|
|
|
opts.set_if<query::partition_slice::option::send_timestamp_and_ttl>(_collect_timestamps || _collect_TTLs);
|
|
|
|
opts.set_if<query::partition_slice::option::send_partition_key>(
|
|
std::any_of(_columns.begin(), _columns.end(),
|
|
std::mem_fn(&column_definition::is_partition_key)));
|
|
|
|
opts.set_if<query::partition_slice::option::send_clustering_key>(
|
|
std::any_of(_columns.begin(), _columns.end(),
|
|
std::mem_fn(&column_definition::is_clustering_key)));
|
|
|
|
return opts;
|
|
}
|
|
|
|
// Special cased selection for when no function is used (this save some allocations).
|
|
class simple_selection : public selection {
|
|
private:
|
|
const bool _is_wildcard;
|
|
public:
|
|
static ::shared_ptr<simple_selection> make(schema_ptr schema, std::vector<const column_definition*> columns, bool is_wildcard) {
|
|
std::vector<::shared_ptr<column_specification>> metadata;
|
|
metadata.reserve(columns.size());
|
|
for (auto&& col : columns) {
|
|
metadata.emplace_back(col->column_specification);
|
|
}
|
|
return ::make_shared<simple_selection>(schema, std::move(columns), std::move(metadata), is_wildcard);
|
|
}
|
|
|
|
/*
|
|
* In theory, even a simple selection could have multiple time the same column, so we
|
|
* could filter those duplicate out of columns. But since we're very unlikely to
|
|
* get much duplicate in practice, it's more efficient not to bother.
|
|
*/
|
|
simple_selection(schema_ptr schema, std::vector<const column_definition*> columns,
|
|
std::vector<::shared_ptr<column_specification>> metadata, bool is_wildcard)
|
|
: selection(schema, std::move(columns), std::move(metadata), false, false)
|
|
, _is_wildcard(is_wildcard)
|
|
{ }
|
|
|
|
virtual bool is_wildcard() const override { return _is_wildcard; }
|
|
virtual bool is_aggregate() const override { return false; }
|
|
protected:
|
|
class simple_selectors : public selectors {
|
|
private:
|
|
std::vector<bytes_opt> _current;
|
|
public:
|
|
virtual void reset() override {
|
|
_current.clear();
|
|
}
|
|
|
|
virtual std::vector<bytes_opt> get_output_row(serialization_format sf) override {
|
|
return std::move(_current);
|
|
}
|
|
|
|
virtual void add_input_row(serialization_format sf, result_set_builder& rs) override {
|
|
_current = std::move(*rs.current);
|
|
}
|
|
|
|
virtual bool is_aggregate() {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
std::unique_ptr<selectors> new_selectors() {
|
|
return std::make_unique<simple_selectors>();
|
|
}
|
|
};
|
|
|
|
class selection_with_processing : public selection {
|
|
private:
|
|
::shared_ptr<selector_factories> _factories;
|
|
public:
|
|
selection_with_processing(schema_ptr schema, std::vector<const column_definition*> columns,
|
|
std::vector<::shared_ptr<column_specification>> metadata, ::shared_ptr<selector_factories> factories)
|
|
: selection(schema, std::move(columns), std::move(metadata),
|
|
factories->contains_write_time_selector_factory(),
|
|
factories->contains_ttl_selector_factory())
|
|
, _factories(std::move(factories))
|
|
{
|
|
if (_factories->does_aggregation() && !_factories->contains_only_aggregate_functions()) {
|
|
throw exceptions::invalid_request_exception("the select clause must either contains only aggregates or none");
|
|
}
|
|
}
|
|
|
|
virtual bool uses_function(const sstring& ks_name, const sstring& function_name) const override {
|
|
return _factories->uses_function(ks_name, function_name);
|
|
}
|
|
|
|
virtual uint32_t add_column_for_ordering(const column_definition& c) override {
|
|
uint32_t index = selection::add_column_for_ordering(c);
|
|
_factories->add_selector_for_ordering(c, index);
|
|
return index;
|
|
}
|
|
|
|
virtual bool is_aggregate() const override {
|
|
return _factories->contains_only_aggregate_functions();
|
|
}
|
|
protected:
|
|
class selectors_with_processing : public selectors {
|
|
private:
|
|
::shared_ptr<selector_factories> _factories;
|
|
std::vector<::shared_ptr<selector>> _selectors;
|
|
public:
|
|
selectors_with_processing(::shared_ptr<selector_factories> factories)
|
|
: _factories(std::move(factories))
|
|
, _selectors(_factories->new_instances())
|
|
{ }
|
|
|
|
virtual void reset() override {
|
|
for (auto&& s : _selectors) {
|
|
s->reset();
|
|
}
|
|
}
|
|
|
|
virtual bool is_aggregate() override {
|
|
return _factories->contains_only_aggregate_functions();
|
|
}
|
|
|
|
virtual std::vector<bytes_opt> get_output_row(serialization_format sf) override {
|
|
std::vector<bytes_opt> output_row;
|
|
output_row.reserve(_selectors.size());
|
|
for (auto&& s : _selectors) {
|
|
output_row.emplace_back(s->get_output(sf));
|
|
}
|
|
return output_row;
|
|
}
|
|
|
|
virtual void add_input_row(serialization_format sf, result_set_builder& rs) {
|
|
for (auto&& s : _selectors) {
|
|
s->add_input(sf, rs);
|
|
}
|
|
}
|
|
};
|
|
|
|
std::unique_ptr<selectors> new_selectors() {
|
|
return std::make_unique<selectors_with_processing>(_factories);
|
|
}
|
|
};
|
|
|
|
::shared_ptr<selection> selection::wildcard(schema_ptr schema) {
|
|
return simple_selection::make(schema, column_definition::vectorize(schema->all_columns_in_select_order()), true);
|
|
}
|
|
|
|
::shared_ptr<selection> selection::for_columns(schema_ptr schema, std::vector<const column_definition*> columns) {
|
|
return simple_selection::make(schema, std::move(columns), false);
|
|
}
|
|
|
|
uint32_t selection::add_column_for_ordering(const column_definition& c) {
|
|
_columns.push_back(&c);
|
|
_metadata->add_non_serialized_column(c.column_specification);
|
|
return _columns.size() - 1;
|
|
}
|
|
|
|
::shared_ptr<selection> selection::from_selectors(database& db, schema_ptr schema, const std::vector<::shared_ptr<raw_selector>>& raw_selectors) {
|
|
std::vector<const column_definition*> defs;
|
|
|
|
::shared_ptr<selector_factories> factories =
|
|
selector_factories::create_factories_and_collect_column_definitions(
|
|
raw_selector::to_selectables(raw_selectors, schema), db, schema, defs);
|
|
|
|
auto metadata = collect_metadata(schema, raw_selectors, *factories);
|
|
if (processes_selection(raw_selectors)) {
|
|
return ::make_shared<selection_with_processing>(schema, std::move(defs), std::move(metadata), std::move(factories));
|
|
} else {
|
|
return ::make_shared<simple_selection>(schema, std::move(defs), std::move(metadata), false);
|
|
}
|
|
}
|
|
|
|
std::vector<::shared_ptr<column_specification>>
|
|
selection::collect_metadata(schema_ptr schema, const std::vector<::shared_ptr<raw_selector>>& raw_selectors,
|
|
const selector_factories& factories) {
|
|
std::vector<::shared_ptr<column_specification>> r;
|
|
r.reserve(raw_selectors.size());
|
|
auto i = raw_selectors.begin();
|
|
for (auto&& factory : factories) {
|
|
::shared_ptr<column_specification> col_spec = factory->get_column_specification(schema);
|
|
::shared_ptr<column_identifier> alias = (*i++)->alias;
|
|
r.push_back(alias ? col_spec->with_alias(alias) : col_spec);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
result_set_builder::result_set_builder(selection& s, db_clock::time_point now, serialization_format sf)
|
|
: _result_set(std::make_unique<result_set>(::make_shared<metadata>(*(s.get_result_metadata()))))
|
|
, _selectors(s.new_selectors())
|
|
, _now(now)
|
|
, _serialization_format(sf)
|
|
{
|
|
if (s._collect_timestamps) {
|
|
_timestamps.resize(s._columns.size(), 0);
|
|
}
|
|
if (s._collect_TTLs) {
|
|
_ttls.resize(s._columns.size(), 0);
|
|
}
|
|
}
|
|
|
|
void result_set_builder::add_empty() {
|
|
current->emplace_back();
|
|
if (!_timestamps.empty()) {
|
|
_timestamps[current->size() - 1] = api::min_timestamp;
|
|
}
|
|
if (!_ttls.empty()) {
|
|
_ttls[current->size() - 1] = -1;
|
|
}
|
|
}
|
|
|
|
void result_set_builder::add(bytes_opt value) {
|
|
current->emplace_back(std::move(value));
|
|
}
|
|
|
|
void result_set_builder::add(const column_definition& def, const query::result_atomic_cell_view& c) {
|
|
current->emplace_back(get_value(def.type, c));
|
|
if (!_timestamps.empty()) {
|
|
_timestamps[current->size() - 1] = c.timestamp();
|
|
}
|
|
if (!_ttls.empty()) {
|
|
gc_clock::duration ttl(-1);
|
|
auto maybe_ttl = c.ttl();
|
|
if (maybe_ttl) {
|
|
ttl = *maybe_ttl - to_gc_clock(_now);
|
|
}
|
|
_ttls[current->size() - 1] = ttl.count();
|
|
}
|
|
}
|
|
|
|
void result_set_builder::add(const column_definition& def, collection_mutation::view c) {
|
|
auto&& ctype = static_cast<collection_type_impl*>(def.type.get());
|
|
current->emplace_back(ctype->to_value(c, _serialization_format));
|
|
// timestamps, ttls meaningless for collections
|
|
}
|
|
|
|
void result_set_builder::new_row() {
|
|
if (current) {
|
|
_selectors->add_input_row(_serialization_format, *this);
|
|
if (!_selectors->is_aggregate()) {
|
|
_result_set->add_row(_selectors->get_output_row(_serialization_format));
|
|
_selectors->reset();
|
|
}
|
|
current->clear();
|
|
} else {
|
|
// FIXME: we use optional<> here because we don't have an end_row() signal
|
|
// instead, !current means that new_row has never been called, so this
|
|
// call to new_row() does not end a previous row.
|
|
current.emplace();
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<result_set> result_set_builder::build() {
|
|
if (current) {
|
|
_selectors->add_input_row(_serialization_format, *this);
|
|
_result_set->add_row(_selectors->get_output_row(_serialization_format));
|
|
_selectors->reset();
|
|
current = std::experimental::nullopt;
|
|
}
|
|
if (_result_set->empty() && _selectors->is_aggregate()) {
|
|
_result_set->add_row(_selectors->get_output_row(_serialization_format));
|
|
}
|
|
return std::move(_result_set);
|
|
}
|
|
|
|
api::timestamp_type result_set_builder::timestamp_of(size_t idx) {
|
|
return _timestamps[idx];
|
|
}
|
|
|
|
int32_t result_set_builder::ttl_of(size_t idx) {
|
|
return _ttls[idx];
|
|
}
|
|
|
|
bytes_opt result_set_builder::get_value(data_type t, query::result_atomic_cell_view c) {
|
|
if (t->is_counter()) {
|
|
fail(unimplemented::cause::COUNTERS);
|
|
#if 0
|
|
ByteBufferUtil.bytes(CounterContext.instance().total(c.value()))
|
|
#endif
|
|
}
|
|
return {to_bytes(c.value())};
|
|
}
|
|
|
|
}
|
|
|
|
} |