187 lines
7.2 KiB
C++
187 lines
7.2 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/statements/select_statement.hh"
|
|
#include "cql3/selection/selection.hh"
|
|
#include "core/shared_ptr.hh"
|
|
#include "query.hh"
|
|
|
|
namespace cql3 {
|
|
|
|
namespace statements {
|
|
|
|
const shared_ptr<select_statement::parameters> select_statement::_default_parameters = ::make_shared<select_statement::parameters>();
|
|
|
|
future<shared_ptr<transport::messages::result_message>>
|
|
select_statement::execute(service::storage_proxy& proxy, service::query_state& state, const query_options& options) {
|
|
auto cl = options.get_consistency();
|
|
|
|
validate_for_read(_schema->ks_name, cl);
|
|
|
|
int32_t limit = get_limit(options);
|
|
auto now = db_clock::now();
|
|
|
|
auto command = ::make_lw_shared<query::read_command>(_schema->ks_name, _schema->cf_name,
|
|
_restrictions->get_partition_key_ranges(options), make_partition_slice(options), limit);
|
|
|
|
int32_t page_size = options.get_page_size();
|
|
|
|
// An aggregation query will never be paged for the user, but we always page it internally to avoid OOM.
|
|
// If we user provided a page_size we'll use that to page internally (because why not), otherwise we use our default
|
|
// Note that if there are some nodes in the cluster with a version less than 2.0, we can't use paging (CASSANDRA-6707).
|
|
if (_selection->is_aggregate() && page_size <= 0) {
|
|
page_size = DEFAULT_COUNT_PAGE_SIZE;
|
|
}
|
|
|
|
warn(unimplemented::cause::PAGING);
|
|
return execute(proxy, command, state, options, now);
|
|
|
|
#if 0
|
|
if (page_size <= 0 || !command || !query_pagers::may_need_paging(command, page_size)) {
|
|
return execute(proxy, command, state, options, now);
|
|
}
|
|
|
|
auto pager = query_pagers::pager(command, cl, state.get_client_state(), options.get_paging_state());
|
|
|
|
if (selection->isAggregate()) {
|
|
return page_aggregate_query(pager, options, page_size, now);
|
|
}
|
|
|
|
// We can't properly do post-query ordering if we page (see #6722)
|
|
if (needs_post_query_ordering()) {
|
|
throw exceptions::invalid_request_exception(
|
|
"Cannot page queries with both ORDER BY and a IN restriction on the partition key;"
|
|
" you must either remove the ORDER BY or the IN and sort client side, or disable paging for this query");
|
|
}
|
|
|
|
return pager->fetch_page(page_size).then([this, pager, &options, limit, now] (auto page) {
|
|
auto msg = process_results(page, options, limit, now);
|
|
|
|
if (!pager->is_exhausted()) {
|
|
msg->result->metadata->set_has_more_pages(pager->state());
|
|
}
|
|
|
|
return msg;
|
|
});
|
|
#endif
|
|
}
|
|
|
|
future<shared_ptr<transport::messages::result_message>>
|
|
select_statement::execute(service::storage_proxy& proxy, lw_shared_ptr<query::read_command> cmd,
|
|
service::query_state& state, const query_options& options, db_clock::time_point now) {
|
|
return proxy.query(std::move(cmd), options.get_consistency())
|
|
.then([this, &options, now, cmd] (auto result) {
|
|
return this->process_results(std::move(result), cmd, options, now);
|
|
});
|
|
}
|
|
|
|
shared_ptr<transport::messages::result_message>
|
|
select_statement::process_results(foreign_ptr<lw_shared_ptr<query::result>> results, lw_shared_ptr<query::read_command> cmd,
|
|
const query_options& options, db_clock::time_point now) {
|
|
auto builder = _selection->make_result_set_builder(now, options.get_protocol_version());
|
|
|
|
auto add_value = [builder] (const column_definition& def, std::experimental::optional<atomic_cell_or_collection>& cell) {
|
|
if (!cell) {
|
|
builder->add_empty();
|
|
return;
|
|
}
|
|
|
|
if (def.type->is_multi_cell()) {
|
|
fail(unimplemented::cause::COLLECTIONS);
|
|
#if 0
|
|
List<Cell> cells = row.getMultiCellColumn(def.name);
|
|
ByteBuffer buffer = cells == null
|
|
? null
|
|
: ((CollectionType)def.type).serializeForNativeProtocol(cells, options.getProtocolVersion());
|
|
result.add(buffer);
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
builder->add(def, cell->as_atomic_cell());
|
|
};
|
|
|
|
for (auto&& e : results->partitions) {
|
|
// FIXME: deserialize into views
|
|
auto key = _schema->partition_key_type->deserialize_value(e.first);
|
|
auto& partition = e.second;
|
|
|
|
if (!partition.static_row.empty() && partition.rows.empty()
|
|
&& !_restrictions->uses_secondary_indexing()
|
|
&& _restrictions->has_no_clustering_columns_restriction()) {
|
|
builder->new_row();
|
|
uint32_t static_id = 0;
|
|
for (auto&& def : _selection->get_columns()) {
|
|
if (def->is_partition_key()) {
|
|
builder->add(key[def->component_index()]);
|
|
} else if (def->is_static()) {
|
|
add_value(*def, partition.static_row.cells[static_id++]);
|
|
} else {
|
|
builder->add_empty();
|
|
}
|
|
}
|
|
} else {
|
|
for (auto&& e : partition.rows) {
|
|
auto c_key = _schema->clustering_key_type->deserialize_value(e.first);
|
|
auto& cells = e.second.cells;
|
|
uint32_t static_id = 0;
|
|
uint32_t regular_id = 0;
|
|
|
|
builder->new_row();
|
|
for (auto&& def : _selection->get_columns()) {
|
|
switch (def->kind) {
|
|
case column_definition::column_kind::PARTITION:
|
|
builder->add(key[def->component_index()]);
|
|
break;
|
|
case column_definition::column_kind::CLUSTERING:
|
|
builder->add(c_key[def->component_index()]);
|
|
break;
|
|
case column_definition::column_kind::REGULAR:
|
|
add_value(*def, cells[regular_id++]);
|
|
break;
|
|
case column_definition::column_kind::STATIC:
|
|
add_value(*def, partition.static_row.cells[static_id++]);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto rs = builder->build();
|
|
if (needs_post_query_ordering()) {
|
|
rs->sort(_ordering_comparator);
|
|
}
|
|
if (_is_reversed) {
|
|
rs->reverse();
|
|
}
|
|
rs->trim(cmd->row_limit);
|
|
return ::make_shared<transport::messages::result_message::rows>(std::move(rs));
|
|
}
|
|
|
|
}
|
|
}
|