/* * 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 columns, std::vector<::shared_ptr> metadata_, bool collect_timestamps, bool collect_TTLs) : _schema(std::move(schema)) , _columns(std::move(columns)) , _metadata(::make_shared(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(_collect_timestamps || _collect_TTLs); opts.set_if( std::any_of(_columns.begin(), _columns.end(), std::mem_fn(&column_definition::is_partition_key))); opts.set_if( 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 make(schema_ptr schema, std::vector columns, bool is_wildcard) { std::vector<::shared_ptr> metadata; metadata.reserve(columns.size()); for (auto&& col : columns) { metadata.emplace_back(col->column_specification); } return ::make_shared(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 columns, std::vector<::shared_ptr> 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 _current; public: virtual void reset() override { _current.clear(); } virtual std::vector 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 new_selectors() { return std::make_unique(); } }; class selection_with_processing : public selection { private: ::shared_ptr _factories; public: selection_with_processing(schema_ptr schema, std::vector columns, std::vector<::shared_ptr> metadata, ::shared_ptr 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 _factories; std::vector<::shared_ptr> _selectors; public: selectors_with_processing(::shared_ptr 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 get_output_row(serialization_format sf) override { std::vector 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 new_selectors() { return std::make_unique(_factories); } }; ::shared_ptr selection::wildcard(schema_ptr schema) { return simple_selection::make(schema, column_definition::vectorize(schema->all_columns_in_select_order()), true); } ::shared_ptr selection::for_columns(schema_ptr schema, std::vector 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::from_selectors(database& db, schema_ptr schema, const std::vector<::shared_ptr>& raw_selectors) { std::vector defs; ::shared_ptr 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(schema, std::move(defs), std::move(metadata), std::move(factories)); } else { return ::make_shared(schema, std::move(defs), std::move(metadata), false); } } std::vector<::shared_ptr> selection::collect_metadata(schema_ptr schema, const std::vector<::shared_ptr>& raw_selectors, const selector_factories& factories) { std::vector<::shared_ptr> r; r.reserve(raw_selectors.size()); auto i = raw_selectors.begin(); for (auto&& factory : factories) { ::shared_ptr col_spec = factory->get_column_specification(schema); ::shared_ptr 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(::make_shared(*(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(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_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())}; } } }