Compare commits
10 Commits
scylla-4.4
...
add_alter_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fcb349b026 | ||
|
|
28c558af95 | ||
|
|
83b47ae394 | ||
|
|
391d1f2b21 | ||
|
|
137a8a0161 | ||
|
|
c473cb4a2d | ||
|
|
98fac66361 | ||
|
|
2cbeb3678f | ||
|
|
d61e1fd174 | ||
|
|
f31ac0a8ca |
33
.github/workflows/pages.yml
vendored
33
.github/workflows/pages.yml
vendored
@@ -1,33 +0,0 @@
|
||||
name: "CI Docs"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- 'docs/**'
|
||||
jobs:
|
||||
release:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
LATEST_VERSION: master
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.7
|
||||
- name: Build docs
|
||||
run: |
|
||||
export PATH=$PATH:~/.local/bin
|
||||
cd docs
|
||||
make multiversion
|
||||
- name: Deploy
|
||||
run : ./docs/_utils/deploy.sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -25,5 +25,3 @@ tags
|
||||
testlog
|
||||
test/*/*.reject
|
||||
.vscode
|
||||
docs/_build
|
||||
docs/poetry.lock
|
||||
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,6 +1,6 @@
|
||||
[submodule "seastar"]
|
||||
path = seastar
|
||||
url = ../scylla-seastar
|
||||
url = ../seastar
|
||||
ignore = dirty
|
||||
[submodule "swagger-ui"]
|
||||
path = swagger-ui
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
# Contributing
|
||||
|
||||
## Asking questions or requesting help
|
||||
# Asking questions or requesting help
|
||||
|
||||
Use the [ScyllaDB user mailing list](https://groups.google.com/forum/#!forum/scylladb-users) or the [Slack workspace](http://slack.scylladb.com) for general questions and help.
|
||||
|
||||
## Reporting an issue
|
||||
# Reporting an issue
|
||||
|
||||
Please use the [Issue Tracker](https://github.com/scylladb/scylla/issues/) to report issues. Fill in as much information as you can in the issue template, especially for performance problems.
|
||||
|
||||
## Contributing Code to Scylla
|
||||
# Contributing Code to Scylla
|
||||
|
||||
To contribute code to Scylla, you need to sign the [Contributor License Agreement](https://www.scylladb.com/open-source/contributor-agreement/) and send your changes as [patches](https://github.com/scylladb/scylla/wiki/Formatting-and-sending-patches) to the [mailing list](https://groups.google.com/forum/#!forum/scylladb-dev). We don't accept pull requests on GitHub.
|
||||
|
||||
@@ -78,7 +78,10 @@ and the current compatibility of this feature as well as Scylla-specific extensi
|
||||
|
||||
## Documentation
|
||||
|
||||
Documentation can be found [here](https://scylla.docs.scylladb.com).
|
||||
Documentation can be found in [./docs](./docs) and on the
|
||||
[wiki](https://github.com/scylladb/scylla/wiki). There is currently no clear
|
||||
definition of what goes where, so when looking for something be sure to check
|
||||
both.
|
||||
Seastar documentation can be found [here](http://docs.seastar.io/master/index.html).
|
||||
User documentation can be found [here](https://docs.scylladb.com/).
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
PRODUCT=scylla
|
||||
VERSION=4.4.rc2
|
||||
VERSION=4.4.dev
|
||||
|
||||
if test -f version
|
||||
then
|
||||
|
||||
@@ -129,8 +129,7 @@ future<std::string> get_key_from_roles(cql3::query_processor& qp, std::string us
|
||||
auth::meta::roles_table::qualified_name, auth::meta::roles_table::role_col_name);
|
||||
|
||||
auto cl = auth::password_authenticator::consistency_for_user(username);
|
||||
auto& timeout = auth::internal_distributed_timeout_config();
|
||||
return qp.execute_internal(query, cl, timeout, {sstring(username)}, true).then_wrapped([username = std::move(username)] (future<::shared_ptr<cql3::untyped_result_set>> f) {
|
||||
return qp.execute_internal(query, cl, auth::internal_distributed_query_state(), {sstring(username)}, true).then_wrapped([username = std::move(username)] (future<::shared_ptr<cql3::untyped_result_set>> f) {
|
||||
auto res = f.get0();
|
||||
auto salted_hash = std::optional<sstring>();
|
||||
if (res->empty()) {
|
||||
|
||||
@@ -159,40 +159,23 @@ static bool check_NE(const rjson::value* v1, const rjson::value& v2) {
|
||||
}
|
||||
|
||||
// Check if two JSON-encoded values match with the BEGINS_WITH relation
|
||||
bool check_BEGINS_WITH(const rjson::value* v1, const rjson::value& v2,
|
||||
bool v1_from_query, bool v2_from_query) {
|
||||
bool bad = false;
|
||||
if (!v1 || !v1->IsObject() || v1->MemberCount() != 1) {
|
||||
if (v1_from_query) {
|
||||
throw api_error::validation("begins_with() encountered malformed argument");
|
||||
} else {
|
||||
bad = true;
|
||||
}
|
||||
} else if (v1->MemberBegin()->name != "S" && v1->MemberBegin()->name != "B") {
|
||||
if (v1_from_query) {
|
||||
throw api_error::validation(format("begins_with supports only string or binary type, got: {}", *v1));
|
||||
} else {
|
||||
bad = true;
|
||||
}
|
||||
}
|
||||
static bool check_BEGINS_WITH(const rjson::value* v1, const rjson::value& v2) {
|
||||
// BEGINS_WITH requires that its single operand (v2) be a string or
|
||||
// binary - otherwise it's a validation error. However, problems with
|
||||
// the stored attribute (v1) will just return false (no match).
|
||||
if (!v2.IsObject() || v2.MemberCount() != 1) {
|
||||
if (v2_from_query) {
|
||||
throw api_error::validation("begins_with() encountered malformed argument");
|
||||
} else {
|
||||
bad = true;
|
||||
}
|
||||
} else if (v2.MemberBegin()->name != "S" && v2.MemberBegin()->name != "B") {
|
||||
if (v2_from_query) {
|
||||
throw api_error::validation(format("begins_with() supports only string or binary type, got: {}", v2));
|
||||
} else {
|
||||
bad = true;
|
||||
}
|
||||
throw api_error::validation(format("BEGINS_WITH operator encountered malformed AttributeValue: {}", v2));
|
||||
}
|
||||
if (bad) {
|
||||
auto it2 = v2.MemberBegin();
|
||||
if (it2->name != "S" && it2->name != "B") {
|
||||
throw api_error::validation(format("BEGINS_WITH operator requires String or Binary type in AttributeValue, got {}", it2->name));
|
||||
}
|
||||
|
||||
|
||||
if (!v1 || !v1->IsObject() || v1->MemberCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
auto it1 = v1->MemberBegin();
|
||||
auto it2 = v2.MemberBegin();
|
||||
if (it1->name != it2->name) {
|
||||
return false;
|
||||
}
|
||||
@@ -296,38 +279,24 @@ static bool check_NOT_NULL(const rjson::value* val) {
|
||||
return val != nullptr;
|
||||
}
|
||||
|
||||
// Only types S, N or B (string, number or bytes) may be compared by the
|
||||
// various comparion operators - lt, le, gt, ge, and between.
|
||||
static bool check_comparable_type(const rjson::value& v) {
|
||||
if (!v.IsObject() || v.MemberCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
const rjson::value& type = v.MemberBegin()->name;
|
||||
return type == "S" || type == "N" || type == "B";
|
||||
}
|
||||
|
||||
// Check if two JSON-encoded values match with cmp.
|
||||
template <typename Comparator>
|
||||
bool check_compare(const rjson::value* v1, const rjson::value& v2, const Comparator& cmp,
|
||||
bool v1_from_query, bool v2_from_query) {
|
||||
bool bad = false;
|
||||
if (!v1 || !check_comparable_type(*v1)) {
|
||||
if (v1_from_query) {
|
||||
throw api_error::validation(format("{} allow only the types String, Number, or Binary", cmp.diagnostic));
|
||||
}
|
||||
bad = true;
|
||||
bool check_compare(const rjson::value* v1, const rjson::value& v2, const Comparator& cmp) {
|
||||
if (!v2.IsObject() || v2.MemberCount() != 1) {
|
||||
throw api_error::validation(
|
||||
format("{} requires a single AttributeValue of type String, Number, or Binary",
|
||||
cmp.diagnostic));
|
||||
}
|
||||
if (!check_comparable_type(v2)) {
|
||||
if (v2_from_query) {
|
||||
throw api_error::validation(format("{} allow only the types String, Number, or Binary", cmp.diagnostic));
|
||||
}
|
||||
bad = true;
|
||||
const auto& kv2 = *v2.MemberBegin();
|
||||
if (kv2.name != "S" && kv2.name != "N" && kv2.name != "B") {
|
||||
throw api_error::validation(
|
||||
format("{} requires a single AttributeValue of type String, Number, or Binary",
|
||||
cmp.diagnostic));
|
||||
}
|
||||
if (bad) {
|
||||
if (!v1 || !v1->IsObject() || v1->MemberCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
const auto& kv1 = *v1->MemberBegin();
|
||||
const auto& kv2 = *v2.MemberBegin();
|
||||
if (kv1.name != kv2.name) {
|
||||
return false;
|
||||
}
|
||||
@@ -341,8 +310,7 @@ bool check_compare(const rjson::value* v1, const rjson::value& v2, const Compara
|
||||
if (kv1.name == "B") {
|
||||
return cmp(base64_decode(kv1.value), base64_decode(kv2.value));
|
||||
}
|
||||
// cannot reach here, as check_comparable_type() verifies the type is one
|
||||
// of the above options.
|
||||
clogger.error("check_compare panic: LHS type equals RHS type, but one is in {N,S,B} while the other isn't");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -373,71 +341,56 @@ struct cmp_gt {
|
||||
static constexpr const char* diagnostic = "GT operator";
|
||||
};
|
||||
|
||||
// True if v is between lb and ub, inclusive. Throws or returns false
|
||||
// (depending on bounds_from_query parameter) if lb > ub.
|
||||
// True if v is between lb and ub, inclusive. Throws if lb > ub.
|
||||
template <typename T>
|
||||
static bool check_BETWEEN(const T& v, const T& lb, const T& ub, bool bounds_from_query) {
|
||||
static bool check_BETWEEN(const T& v, const T& lb, const T& ub) {
|
||||
if (cmp_lt()(ub, lb)) {
|
||||
if (bounds_from_query) {
|
||||
throw api_error::validation(
|
||||
format("BETWEEN operator requires lower_bound <= upper_bound, but {} > {}", lb, ub));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
throw api_error::validation(
|
||||
format("BETWEEN operator requires lower_bound <= upper_bound, but {} > {}", lb, ub));
|
||||
}
|
||||
return cmp_ge()(v, lb) && cmp_le()(v, ub);
|
||||
}
|
||||
|
||||
static bool check_BETWEEN(const rjson::value* v, const rjson::value& lb, const rjson::value& ub,
|
||||
bool v_from_query, bool lb_from_query, bool ub_from_query) {
|
||||
if ((v && v_from_query && !check_comparable_type(*v)) ||
|
||||
(lb_from_query && !check_comparable_type(lb)) ||
|
||||
(ub_from_query && !check_comparable_type(ub))) {
|
||||
throw api_error::validation("between allow only the types String, Number, or Binary");
|
||||
|
||||
}
|
||||
if (!v || !v->IsObject() || v->MemberCount() != 1 ||
|
||||
!lb.IsObject() || lb.MemberCount() != 1 ||
|
||||
!ub.IsObject() || ub.MemberCount() != 1) {
|
||||
static bool check_BETWEEN(const rjson::value* v, const rjson::value& lb, const rjson::value& ub) {
|
||||
if (!v) {
|
||||
return false;
|
||||
}
|
||||
if (!v->IsObject() || v->MemberCount() != 1) {
|
||||
throw api_error::validation(format("BETWEEN operator encountered malformed AttributeValue: {}", *v));
|
||||
}
|
||||
if (!lb.IsObject() || lb.MemberCount() != 1) {
|
||||
throw api_error::validation(format("BETWEEN operator encountered malformed AttributeValue: {}", lb));
|
||||
}
|
||||
if (!ub.IsObject() || ub.MemberCount() != 1) {
|
||||
throw api_error::validation(format("BETWEEN operator encountered malformed AttributeValue: {}", ub));
|
||||
}
|
||||
|
||||
const auto& kv_v = *v->MemberBegin();
|
||||
const auto& kv_lb = *lb.MemberBegin();
|
||||
const auto& kv_ub = *ub.MemberBegin();
|
||||
bool bounds_from_query = lb_from_query && ub_from_query;
|
||||
if (kv_lb.name != kv_ub.name) {
|
||||
if (bounds_from_query) {
|
||||
throw api_error::validation(
|
||||
throw api_error::validation(
|
||||
format("BETWEEN operator requires the same type for lower and upper bound; instead got {} and {}",
|
||||
kv_lb.name, kv_ub.name));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (kv_v.name != kv_lb.name) { // Cannot compare different types, so v is NOT between lb and ub.
|
||||
return false;
|
||||
}
|
||||
if (kv_v.name == "N") {
|
||||
const char* diag = "BETWEEN operator";
|
||||
return check_BETWEEN(unwrap_number(*v, diag), unwrap_number(lb, diag), unwrap_number(ub, diag), bounds_from_query);
|
||||
return check_BETWEEN(unwrap_number(*v, diag), unwrap_number(lb, diag), unwrap_number(ub, diag));
|
||||
}
|
||||
if (kv_v.name == "S") {
|
||||
return check_BETWEEN(std::string_view(kv_v.value.GetString(), kv_v.value.GetStringLength()),
|
||||
std::string_view(kv_lb.value.GetString(), kv_lb.value.GetStringLength()),
|
||||
std::string_view(kv_ub.value.GetString(), kv_ub.value.GetStringLength()),
|
||||
bounds_from_query);
|
||||
std::string_view(kv_ub.value.GetString(), kv_ub.value.GetStringLength()));
|
||||
}
|
||||
if (kv_v.name == "B") {
|
||||
return check_BETWEEN(base64_decode(kv_v.value), base64_decode(kv_lb.value), base64_decode(kv_ub.value), bounds_from_query);
|
||||
return check_BETWEEN(base64_decode(kv_v.value), base64_decode(kv_lb.value), base64_decode(kv_ub.value));
|
||||
}
|
||||
if (v_from_query) {
|
||||
throw api_error::validation(
|
||||
format("BETWEEN operator requires AttributeValueList elements to be of type String, Number, or Binary; instead got {}",
|
||||
throw api_error::validation(
|
||||
format("BETWEEN operator requires AttributeValueList elements to be of type String, Number, or Binary; instead got {}",
|
||||
kv_lb.name));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify one Expect condition on one attribute (whose content is "got")
|
||||
@@ -484,19 +437,19 @@ static bool verify_expected_one(const rjson::value& condition, const rjson::valu
|
||||
return check_NE(got, (*attribute_value_list)[0]);
|
||||
case comparison_operator_type::LT:
|
||||
verify_operand_count(attribute_value_list, exact_size(1), *comparison_operator);
|
||||
return check_compare(got, (*attribute_value_list)[0], cmp_lt{}, false, true);
|
||||
return check_compare(got, (*attribute_value_list)[0], cmp_lt{});
|
||||
case comparison_operator_type::LE:
|
||||
verify_operand_count(attribute_value_list, exact_size(1), *comparison_operator);
|
||||
return check_compare(got, (*attribute_value_list)[0], cmp_le{}, false, true);
|
||||
return check_compare(got, (*attribute_value_list)[0], cmp_le{});
|
||||
case comparison_operator_type::GT:
|
||||
verify_operand_count(attribute_value_list, exact_size(1), *comparison_operator);
|
||||
return check_compare(got, (*attribute_value_list)[0], cmp_gt{}, false, true);
|
||||
return check_compare(got, (*attribute_value_list)[0], cmp_gt{});
|
||||
case comparison_operator_type::GE:
|
||||
verify_operand_count(attribute_value_list, exact_size(1), *comparison_operator);
|
||||
return check_compare(got, (*attribute_value_list)[0], cmp_ge{}, false, true);
|
||||
return check_compare(got, (*attribute_value_list)[0], cmp_ge{});
|
||||
case comparison_operator_type::BEGINS_WITH:
|
||||
verify_operand_count(attribute_value_list, exact_size(1), *comparison_operator);
|
||||
return check_BEGINS_WITH(got, (*attribute_value_list)[0], false, true);
|
||||
return check_BEGINS_WITH(got, (*attribute_value_list)[0]);
|
||||
case comparison_operator_type::IN:
|
||||
verify_operand_count(attribute_value_list, nonempty(), *comparison_operator);
|
||||
return check_IN(got, *attribute_value_list);
|
||||
@@ -508,8 +461,7 @@ static bool verify_expected_one(const rjson::value& condition, const rjson::valu
|
||||
return check_NOT_NULL(got);
|
||||
case comparison_operator_type::BETWEEN:
|
||||
verify_operand_count(attribute_value_list, exact_size(2), *comparison_operator);
|
||||
return check_BETWEEN(got, (*attribute_value_list)[0], (*attribute_value_list)[1],
|
||||
false, true, true);
|
||||
return check_BETWEEN(got, (*attribute_value_list)[0], (*attribute_value_list)[1]);
|
||||
case comparison_operator_type::CONTAINS:
|
||||
{
|
||||
verify_operand_count(attribute_value_list, exact_size(1), *comparison_operator);
|
||||
@@ -621,8 +573,7 @@ static bool calculate_primitive_condition(const parsed::primitive_condition& con
|
||||
// Shouldn't happen unless we have a bug in the parser
|
||||
throw std::logic_error(format("Wrong number of values {} in BETWEEN primitive_condition", cond._values.size()));
|
||||
}
|
||||
return check_BETWEEN(&calculated_values[0], calculated_values[1], calculated_values[2],
|
||||
cond._values[0].is_constant(), cond._values[1].is_constant(), cond._values[2].is_constant());
|
||||
return check_BETWEEN(&calculated_values[0], calculated_values[1], calculated_values[2]);
|
||||
case parsed::primitive_condition::type::IN:
|
||||
return check_IN(calculated_values);
|
||||
case parsed::primitive_condition::type::VALUE:
|
||||
@@ -653,17 +604,13 @@ static bool calculate_primitive_condition(const parsed::primitive_condition& con
|
||||
case parsed::primitive_condition::type::NE:
|
||||
return check_NE(&calculated_values[0], calculated_values[1]);
|
||||
case parsed::primitive_condition::type::GT:
|
||||
return check_compare(&calculated_values[0], calculated_values[1], cmp_gt{},
|
||||
cond._values[0].is_constant(), cond._values[1].is_constant());
|
||||
return check_compare(&calculated_values[0], calculated_values[1], cmp_gt{});
|
||||
case parsed::primitive_condition::type::GE:
|
||||
return check_compare(&calculated_values[0], calculated_values[1], cmp_ge{},
|
||||
cond._values[0].is_constant(), cond._values[1].is_constant());
|
||||
return check_compare(&calculated_values[0], calculated_values[1], cmp_ge{});
|
||||
case parsed::primitive_condition::type::LT:
|
||||
return check_compare(&calculated_values[0], calculated_values[1], cmp_lt{},
|
||||
cond._values[0].is_constant(), cond._values[1].is_constant());
|
||||
return check_compare(&calculated_values[0], calculated_values[1], cmp_lt{});
|
||||
case parsed::primitive_condition::type::LE:
|
||||
return check_compare(&calculated_values[0], calculated_values[1], cmp_le{},
|
||||
cond._values[0].is_constant(), cond._values[1].is_constant());
|
||||
return check_compare(&calculated_values[0], calculated_values[1], cmp_le{});
|
||||
default:
|
||||
// Shouldn't happen unless we have a bug in the parser
|
||||
throw std::logic_error(format("Unknown type {} in primitive_condition object", (int)(cond._op)));
|
||||
|
||||
@@ -52,7 +52,6 @@ bool verify_expected(const rjson::value& req, const rjson::value* previous_item)
|
||||
bool verify_condition(const rjson::value& condition, bool require_all, const rjson::value* previous_item);
|
||||
|
||||
bool check_CONTAINS(const rjson::value* v1, const rjson::value& v2);
|
||||
bool check_BEGINS_WITH(const rjson::value* v1, const rjson::value& v2, bool v1_from_query, bool v2_from_query);
|
||||
|
||||
bool verify_condition_expression(
|
||||
const parsed::condition_expression& condition_expression,
|
||||
|
||||
@@ -59,9 +59,6 @@ public:
|
||||
static api_error invalid_signature(std::string msg) {
|
||||
return api_error("InvalidSignatureException", std::move(msg));
|
||||
}
|
||||
static api_error missing_authentication_token(std::string msg) {
|
||||
return api_error("MissingAuthenticationTokenException", std::move(msg));
|
||||
}
|
||||
static api_error unrecognized_client(std::string msg) {
|
||||
return api_error("UnrecognizedClientException", std::move(msg));
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
#include "schema.hh"
|
||||
#include "alternator/tags_extension.hh"
|
||||
#include "alternator/rmw_operation.hh"
|
||||
#include <seastar/core/coroutine.hh>
|
||||
|
||||
#include <boost/range/adaptors.hpp>
|
||||
|
||||
logging::logger elogger("alternator-executor");
|
||||
@@ -220,7 +220,7 @@ static std::tuple<bool, std::string_view, std::string_view> try_get_internal_tab
|
||||
std::string_view ks_name = table_name.substr(0, delim);
|
||||
table_name.remove_prefix(ks_name.size() + 1);
|
||||
// Only internal keyspaces can be accessed to avoid leakage
|
||||
if (!is_internal_keyspace(ks_name)) {
|
||||
if (!is_internal_keyspace(sstring(ks_name))) {
|
||||
return {false, "", ""};
|
||||
}
|
||||
return {true, ks_name, table_name};
|
||||
@@ -476,8 +476,8 @@ future<executor::request_return_type> executor::delete_table(client_state& clien
|
||||
return make_ready_future<request_return_type>(api_error::resource_not_found(
|
||||
format("Requested resource not found: Table: {} not found", table_name)));
|
||||
}
|
||||
return _mm.announce_column_family_drop(keyspace_name, table_name, service::migration_manager::drop_views::yes).then([this, keyspace_name] {
|
||||
return _mm.announce_keyspace_drop(keyspace_name);
|
||||
return _mm.announce_column_family_drop(keyspace_name, table_name, false, service::migration_manager::drop_views::yes).then([this, keyspace_name] {
|
||||
return _mm.announce_keyspace_drop(keyspace_name, false);
|
||||
}).then([table_name = std::move(table_name)] {
|
||||
// FIXME: need more attributes?
|
||||
rjson::value table_description = rjson::empty_object();
|
||||
@@ -704,48 +704,52 @@ static void update_tags_map(const rjson::value& tags, std::map<sstring, sstring>
|
||||
static future<> update_tags(service::migration_manager& mm, schema_ptr schema, std::map<sstring, sstring>&& tags_map) {
|
||||
schema_builder builder(schema);
|
||||
builder.add_extension(tags_extension::NAME, ::make_shared<tags_extension>(std::move(tags_map)));
|
||||
return mm.announce_column_family_update(builder.build(), false, std::vector<view_ptr>());
|
||||
return mm.announce_column_family_update(builder.build(), false, std::vector<view_ptr>(), false);
|
||||
}
|
||||
|
||||
future<executor::request_return_type> executor::tag_resource(client_state& client_state, service_permit permit, rjson::value request) {
|
||||
_stats.api_operations.tag_resource++;
|
||||
|
||||
const rjson::value* arn = rjson::find(request, "ResourceArn");
|
||||
if (!arn || !arn->IsString()) {
|
||||
co_return api_error::access_denied("Incorrect resource identifier");
|
||||
}
|
||||
schema_ptr schema = get_table_from_arn(_proxy, rjson::to_string_view(*arn));
|
||||
std::map<sstring, sstring> tags_map = get_tags_of_table(schema);
|
||||
const rjson::value* tags = rjson::find(request, "Tags");
|
||||
if (!tags || !tags->IsArray()) {
|
||||
co_return api_error::validation("Cannot parse tags");
|
||||
}
|
||||
if (tags->Size() < 1) {
|
||||
co_return api_error::validation("The number of tags must be at least 1") ;
|
||||
}
|
||||
update_tags_map(*tags, tags_map, update_tags_action::add_tags);
|
||||
co_await update_tags(_mm, schema, std::move(tags_map));
|
||||
co_return json_string("");
|
||||
return seastar::async([this, &client_state, request = std::move(request)] () mutable -> request_return_type {
|
||||
const rjson::value* arn = rjson::find(request, "ResourceArn");
|
||||
if (!arn || !arn->IsString()) {
|
||||
return api_error::access_denied("Incorrect resource identifier");
|
||||
}
|
||||
schema_ptr schema = get_table_from_arn(_proxy, rjson::to_string_view(*arn));
|
||||
std::map<sstring, sstring> tags_map = get_tags_of_table(schema);
|
||||
const rjson::value* tags = rjson::find(request, "Tags");
|
||||
if (!tags || !tags->IsArray()) {
|
||||
return api_error::validation("Cannot parse tags");
|
||||
}
|
||||
if (tags->Size() < 1) {
|
||||
return api_error::validation("The number of tags must be at least 1") ;
|
||||
}
|
||||
update_tags_map(*tags, tags_map, update_tags_action::add_tags);
|
||||
update_tags(_mm, schema, std::move(tags_map)).get();
|
||||
return json_string("");
|
||||
});
|
||||
}
|
||||
|
||||
future<executor::request_return_type> executor::untag_resource(client_state& client_state, service_permit permit, rjson::value request) {
|
||||
_stats.api_operations.untag_resource++;
|
||||
|
||||
const rjson::value* arn = rjson::find(request, "ResourceArn");
|
||||
if (!arn || !arn->IsString()) {
|
||||
co_return api_error::access_denied("Incorrect resource identifier");
|
||||
}
|
||||
const rjson::value* tags = rjson::find(request, "TagKeys");
|
||||
if (!tags || !tags->IsArray()) {
|
||||
co_return api_error::validation(format("Cannot parse tag keys"));
|
||||
}
|
||||
return seastar::async([this, &client_state, request = std::move(request)] () -> request_return_type {
|
||||
const rjson::value* arn = rjson::find(request, "ResourceArn");
|
||||
if (!arn || !arn->IsString()) {
|
||||
return api_error::access_denied("Incorrect resource identifier");
|
||||
}
|
||||
const rjson::value* tags = rjson::find(request, "TagKeys");
|
||||
if (!tags || !tags->IsArray()) {
|
||||
return api_error::validation(format("Cannot parse tag keys"));
|
||||
}
|
||||
|
||||
schema_ptr schema = get_table_from_arn(_proxy, rjson::to_string_view(*arn));
|
||||
schema_ptr schema = get_table_from_arn(_proxy, rjson::to_string_view(*arn));
|
||||
|
||||
std::map<sstring, sstring> tags_map = get_tags_of_table(schema);
|
||||
update_tags_map(*tags, tags_map, update_tags_action::delete_tags);
|
||||
co_await update_tags(_mm, schema, std::move(tags_map));
|
||||
co_return json_string("");
|
||||
std::map<sstring, sstring> tags_map = get_tags_of_table(schema);
|
||||
update_tags_map(*tags, tags_map, update_tags_action::delete_tags);
|
||||
update_tags(_mm, schema, std::move(tags_map)).get();
|
||||
return json_string("");
|
||||
});
|
||||
}
|
||||
|
||||
future<executor::request_return_type> executor::list_tags_of_resource(client_state& client_state, service_permit permit, rjson::value request) {
|
||||
@@ -981,7 +985,7 @@ future<executor::request_return_type> executor::create_table(client_state& clien
|
||||
return create_keyspace(keyspace_name).handle_exception_type([] (exceptions::already_exists_exception&) {
|
||||
// Ignore the fact that the keyspace may already exist. See discussion in #6340
|
||||
}).then([this, table_name, request = std::move(request), schema, view_builders = std::move(view_builders), tags_map = std::move(tags_map)] () mutable {
|
||||
return futurize_invoke([&] { return _mm.announce_new_column_family(schema); }).then([this, table_info = std::move(request), schema, view_builders = std::move(view_builders), tags_map = std::move(tags_map)] () mutable {
|
||||
return futurize_invoke([&] { return _mm.announce_new_column_family(schema, false); }).then([this, table_info = std::move(request), schema, view_builders = std::move(view_builders), tags_map = std::move(tags_map)] () mutable {
|
||||
return parallel_for_each(std::move(view_builders), [this, schema] (schema_builder builder) {
|
||||
return _mm.announce_new_view(view_ptr(builder.build()));
|
||||
}).then([this, table_info = std::move(table_info), schema, tags_map = std::move(tags_map)] () mutable {
|
||||
@@ -1237,16 +1241,10 @@ mutation put_or_delete_item::build(schema_ptr schema, api::timestamp_type ts) co
|
||||
return m;
|
||||
}
|
||||
|
||||
// The DynamoDB API doesn't let the client control the server's timeout, so
|
||||
// we have a global default_timeout() for Alternator requests. The value of
|
||||
// default_timeout is overwritten by main.cc based on the
|
||||
// "alternator_timeout_in_ms" configuration parameter.
|
||||
db::timeout_clock::duration executor::s_default_timeout = 10s;
|
||||
void executor::set_default_timeout(db::timeout_clock::duration timeout) {
|
||||
s_default_timeout = timeout;
|
||||
}
|
||||
// The DynamoDB API doesn't let the client control the server's timeout.
|
||||
// Let's pick something reasonable:
|
||||
db::timeout_clock::time_point executor::default_timeout() {
|
||||
return db::timeout_clock::now() + s_default_timeout;
|
||||
return db::timeout_clock::now() + 10s;
|
||||
}
|
||||
|
||||
static future<std::unique_ptr<rjson::value>> get_previous_item(
|
||||
@@ -2247,30 +2245,19 @@ update_item_operation::apply(std::unique_ptr<rjson::value> previous_item, api::t
|
||||
rjson::value v1 = calculate_value(base, calculate_value_caller::UpdateExpression, previous_item.get());
|
||||
rjson::value v2 = calculate_value(addition, calculate_value_caller::UpdateExpression, previous_item.get());
|
||||
rjson::value result;
|
||||
// An ADD can be used to create a new attribute (when
|
||||
// v1.IsNull()) or to add to a pre-existing attribute:
|
||||
if (v1.IsNull()) {
|
||||
std::string v2_type = get_item_type_string(v2);
|
||||
if (v2_type == "N" || v2_type == "SS" || v2_type == "NS" || v2_type == "BS") {
|
||||
result = v2;
|
||||
} else {
|
||||
throw api_error::validation(format("An operand in the update expression has an incorrect data type: {}", v2));
|
||||
std::string v1_type = get_item_type_string(v1);
|
||||
if (v1_type == "N") {
|
||||
if (get_item_type_string(v2) != "N") {
|
||||
throw api_error::validation(format("Incorrect operand type for operator or function. Expected {}: {}", v1_type, rjson::print(v2)));
|
||||
}
|
||||
result = number_add(v1, v2);
|
||||
} else if (v1_type == "SS" || v1_type == "NS" || v1_type == "BS") {
|
||||
if (get_item_type_string(v2) != v1_type) {
|
||||
throw api_error::validation(format("Incorrect operand type for operator or function. Expected {}: {}", v1_type, rjson::print(v2)));
|
||||
}
|
||||
result = set_sum(v1, v2);
|
||||
} else {
|
||||
std::string v1_type = get_item_type_string(v1);
|
||||
if (v1_type == "N") {
|
||||
if (get_item_type_string(v2) != "N") {
|
||||
throw api_error::validation(format("Incorrect operand type for operator or function. Expected {}: {}", v1_type, rjson::print(v2)));
|
||||
}
|
||||
result = number_add(v1, v2);
|
||||
} else if (v1_type == "SS" || v1_type == "NS" || v1_type == "BS") {
|
||||
if (get_item_type_string(v2) != v1_type) {
|
||||
throw api_error::validation(format("Incorrect operand type for operator or function. Expected {}: {}", v1_type, rjson::print(v2)));
|
||||
}
|
||||
result = set_sum(v1, v2);
|
||||
} else {
|
||||
throw api_error::validation(format("An operand in the update expression has an incorrect data type: {}", v1));
|
||||
}
|
||||
throw api_error::validation(format("An operand in the update expression has an incorrect data type: {}", v1));
|
||||
}
|
||||
do_update(to_bytes(column_name), result);
|
||||
},
|
||||
@@ -2801,7 +2788,7 @@ static rjson::value encode_paging_state(const schema& schema, const service::pag
|
||||
for (const column_definition& cdef : schema.partition_key_columns()) {
|
||||
rjson::set_with_string_name(last_evaluated_key, std::string_view(cdef.name_as_text()), rjson::empty_object());
|
||||
rjson::value& key_entry = last_evaluated_key[cdef.name_as_text()];
|
||||
rjson::set_with_string_name(key_entry, type_to_string(cdef.type), json_key_column_value(*exploded_pk_it, cdef));
|
||||
rjson::set_with_string_name(key_entry, type_to_string(cdef.type), rjson::parse(to_json_string(*cdef.type, *exploded_pk_it)));
|
||||
++exploded_pk_it;
|
||||
}
|
||||
auto ck = paging_state.get_clustering_key();
|
||||
@@ -2811,7 +2798,7 @@ static rjson::value encode_paging_state(const schema& schema, const service::pag
|
||||
for (const column_definition& cdef : schema.clustering_key_columns()) {
|
||||
rjson::set_with_string_name(last_evaluated_key, std::string_view(cdef.name_as_text()), rjson::empty_object());
|
||||
rjson::value& key_entry = last_evaluated_key[cdef.name_as_text()];
|
||||
rjson::set_with_string_name(key_entry, type_to_string(cdef.type), json_key_column_value(*exploded_ck_it, cdef));
|
||||
rjson::set_with_string_name(key_entry, type_to_string(cdef.type), rjson::parse(to_json_string(*cdef.type, *exploded_ck_it)));
|
||||
++exploded_ck_it;
|
||||
}
|
||||
}
|
||||
@@ -2858,12 +2845,12 @@ static future<executor::request_return_type> do_query(service::storage_proxy& pr
|
||||
auto query_state_ptr = std::make_unique<service::query_state>(client_state, trace_state, std::move(permit));
|
||||
|
||||
command->slice.options.set<query::partition_slice::option::allow_short_read>();
|
||||
auto query_options = std::make_unique<cql3::query_options>(cl, infinite_timeout_config, std::vector<cql3::raw_value>{});
|
||||
auto query_options = std::make_unique<cql3::query_options>(cl, std::vector<cql3::raw_value>{});
|
||||
query_options = std::make_unique<cql3::query_options>(std::move(query_options), std::move(paging_state));
|
||||
auto p = service::pager::query_pagers::pager(schema, selection, *query_state_ptr, *query_options, command, std::move(partition_ranges), nullptr);
|
||||
|
||||
return p->fetch_page(limit, gc_clock::now(), executor::default_timeout()).then(
|
||||
[p = std::move(p), schema, cql_stats, partition_slice = std::move(partition_slice),
|
||||
[p, schema, cql_stats, partition_slice = std::move(partition_slice),
|
||||
selection = std::move(selection), query_state_ptr = std::move(query_state_ptr),
|
||||
attrs_to_get = std::move(attrs_to_get),
|
||||
query_options = std::move(query_options),
|
||||
@@ -3549,7 +3536,7 @@ future<> executor::create_keyspace(std::string_view keyspace_name) {
|
||||
}
|
||||
auto opts = get_network_topology_options(rf);
|
||||
auto ksm = keyspace_metadata::new_keyspace(keyspace_name_str, "org.apache.cassandra.locator.NetworkTopologyStrategy", std::move(opts), true);
|
||||
return _mm.announce_new_keyspace(ksm, api::new_timestamp());
|
||||
return _mm.announce_new_keyspace(ksm, api::new_timestamp(), false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -121,10 +121,6 @@ public:
|
||||
|
||||
static sstring table_name(const schema&);
|
||||
static db::timeout_clock::time_point default_timeout();
|
||||
static void set_default_timeout(db::timeout_clock::duration timeout);
|
||||
private:
|
||||
static db::timeout_clock::duration s_default_timeout;
|
||||
public:
|
||||
static schema_ptr find_table(service::storage_proxy&, const rjson::value& request);
|
||||
|
||||
private:
|
||||
|
||||
@@ -603,8 +603,52 @@ std::unordered_map<std::string_view, function_handler_type*> function_handlers {
|
||||
}
|
||||
rjson::value v1 = calculate_value(f._parameters[0], caller, previous_item);
|
||||
rjson::value v2 = calculate_value(f._parameters[1], caller, previous_item);
|
||||
return to_bool_json(check_BEGINS_WITH(v1.IsNull() ? nullptr : &v1, v2,
|
||||
f._parameters[0].is_constant(), f._parameters[1].is_constant()));
|
||||
// TODO: There's duplication here with check_BEGINS_WITH().
|
||||
// But unfortunately, the two functions differ a bit.
|
||||
|
||||
// If one of v1 or v2 is malformed or has an unsupported type
|
||||
// (not B or S), what we do depends on whether it came from
|
||||
// the user's query (is_constant()), or the item. Unsupported
|
||||
// values in the query result in an error, but if they are in
|
||||
// the item, we silently return false (no match).
|
||||
bool bad = false;
|
||||
if (!v1.IsObject() || v1.MemberCount() != 1) {
|
||||
bad = true;
|
||||
if (f._parameters[0].is_constant()) {
|
||||
throw api_error::validation(format("{}: begins_with() encountered malformed AttributeValue: {}", caller, v1));
|
||||
}
|
||||
} else if (v1.MemberBegin()->name != "S" && v1.MemberBegin()->name != "B") {
|
||||
bad = true;
|
||||
if (f._parameters[0].is_constant()) {
|
||||
throw api_error::validation(format("{}: begins_with() supports only string or binary in AttributeValue: {}", caller, v1));
|
||||
}
|
||||
}
|
||||
if (!v2.IsObject() || v2.MemberCount() != 1) {
|
||||
bad = true;
|
||||
if (f._parameters[1].is_constant()) {
|
||||
throw api_error::validation(format("{}: begins_with() encountered malformed AttributeValue: {}", caller, v2));
|
||||
}
|
||||
} else if (v2.MemberBegin()->name != "S" && v2.MemberBegin()->name != "B") {
|
||||
bad = true;
|
||||
if (f._parameters[1].is_constant()) {
|
||||
throw api_error::validation(format("{}: begins_with() supports only string or binary in AttributeValue: {}", caller, v2));
|
||||
}
|
||||
}
|
||||
bool ret = false;
|
||||
if (!bad) {
|
||||
auto it1 = v1.MemberBegin();
|
||||
auto it2 = v2.MemberBegin();
|
||||
if (it1->name == it2->name) {
|
||||
if (it2->name == "S") {
|
||||
std::string_view val1 = rjson::to_string_view(it1->value);
|
||||
std::string_view val2 = rjson::to_string_view(it2->value);
|
||||
ret = val1.starts_with(val2);
|
||||
} else /* it2->name == "B" */ {
|
||||
ret = base64_begins_with(rjson::to_string_view(it1->value), rjson::to_string_view(it2->value));
|
||||
}
|
||||
}
|
||||
}
|
||||
return to_bool_json(ret);
|
||||
}
|
||||
},
|
||||
{"contains", [] (calculate_value_caller caller, const rjson::value* previous_item, const parsed::value::function_call& f) {
|
||||
|
||||
@@ -189,7 +189,7 @@ future<> server::verify_signature(const request& req) {
|
||||
}
|
||||
auto authorization_it = req._headers.find("Authorization");
|
||||
if (authorization_it == req._headers.end()) {
|
||||
throw api_error::missing_authentication_token("Authorization header is mandatory for signature verification");
|
||||
throw api_error::invalid_signature("Authorization header is mandatory for signature verification");
|
||||
}
|
||||
std::string host = host_it->second;
|
||||
std::vector<std::string_view> credentials_raw = split(authorization_it->second, ' ');
|
||||
|
||||
@@ -2925,10 +2925,6 @@
|
||||
"id":"toppartitions_query_results",
|
||||
"description":"nodetool toppartitions query results",
|
||||
"properties":{
|
||||
"read_cardinality":{
|
||||
"type":"long",
|
||||
"description":"Number of the unique operations in the sample set"
|
||||
},
|
||||
"read":{
|
||||
"type":"array",
|
||||
"items":{
|
||||
@@ -2936,10 +2932,6 @@
|
||||
},
|
||||
"description":"Read results"
|
||||
},
|
||||
"write_cardinality":{
|
||||
"type":"long",
|
||||
"description":"Number of the unique operations in the sample set"
|
||||
},
|
||||
"write":{
|
||||
"type":"array",
|
||||
"items":{
|
||||
|
||||
@@ -148,30 +148,6 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"path":"/gossiper/force_remove_endpoint/{addr}",
|
||||
"operations":[
|
||||
{
|
||||
"method":"POST",
|
||||
"summary":"Force remove an endpoint from gossip",
|
||||
"type":"void",
|
||||
"nickname":"force_remove_endpoint",
|
||||
"produces":[
|
||||
"application/json"
|
||||
],
|
||||
"parameters":[
|
||||
{
|
||||
"name":"addr",
|
||||
"description":"The endpoint address",
|
||||
"required":true,
|
||||
"allowMultiple":false,
|
||||
"type":"string",
|
||||
"paramType":"path"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
return res;
|
||||
});
|
||||
|
||||
cf::get_column_family.set(r, [&ctx] (std::unique_ptr<request> req){
|
||||
cf::get_column_family.set(r, [&ctx] (const_req req){
|
||||
vector<cf::column_family_info> res;
|
||||
for (auto i: ctx.db.local().get_column_families_mapping()) {
|
||||
cf::column_family_info info;
|
||||
@@ -319,7 +319,7 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
info.type = "ColumnFamilies";
|
||||
res.push_back(info);
|
||||
}
|
||||
return make_ready_future<json::json_return_type>(json::stream_object(std::move(res)));
|
||||
return res;
|
||||
});
|
||||
|
||||
cf::get_column_family_name_keyspace.set(r, [&ctx] (const_req req){
|
||||
@@ -656,7 +656,7 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
cf::get_bloom_filter_disk_space_used.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf(ctx, req->param["name"], uint64_t(0), [] (column_family& cf) {
|
||||
return std::accumulate(cf.get_sstables()->begin(), cf.get_sstables()->end(), uint64_t(0), [](uint64_t s, auto& sst) {
|
||||
return s + sst->filter_size();
|
||||
return sst->filter_size();
|
||||
});
|
||||
}, std::plus<uint64_t>());
|
||||
});
|
||||
@@ -664,7 +664,7 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
cf::get_all_bloom_filter_disk_space_used.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf(ctx, uint64_t(0), [] (column_family& cf) {
|
||||
return std::accumulate(cf.get_sstables()->begin(), cf.get_sstables()->end(), uint64_t(0), [](uint64_t s, auto& sst) {
|
||||
return s + sst->filter_size();
|
||||
return sst->filter_size();
|
||||
});
|
||||
}, std::plus<uint64_t>());
|
||||
});
|
||||
@@ -672,7 +672,7 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
cf::get_bloom_filter_off_heap_memory_used.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf(ctx, req->param["name"], uint64_t(0), [] (column_family& cf) {
|
||||
return std::accumulate(cf.get_sstables()->begin(), cf.get_sstables()->end(), uint64_t(0), [](uint64_t s, auto& sst) {
|
||||
return s + sst->filter_memory_size();
|
||||
return sst->filter_memory_size();
|
||||
});
|
||||
}, std::plus<uint64_t>());
|
||||
});
|
||||
@@ -680,7 +680,7 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
cf::get_all_bloom_filter_off_heap_memory_used.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf(ctx, uint64_t(0), [] (column_family& cf) {
|
||||
return std::accumulate(cf.get_sstables()->begin(), cf.get_sstables()->end(), uint64_t(0), [](uint64_t s, auto& sst) {
|
||||
return s + sst->filter_memory_size();
|
||||
return sst->filter_memory_size();
|
||||
});
|
||||
}, std::plus<uint64_t>());
|
||||
});
|
||||
@@ -688,7 +688,7 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
cf::get_index_summary_off_heap_memory_used.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf(ctx, req->param["name"], uint64_t(0), [] (column_family& cf) {
|
||||
return std::accumulate(cf.get_sstables()->begin(), cf.get_sstables()->end(), uint64_t(0), [](uint64_t s, auto& sst) {
|
||||
return s + sst->get_summary().memory_footprint();
|
||||
return sst->get_summary().memory_footprint();
|
||||
});
|
||||
}, std::plus<uint64_t>());
|
||||
});
|
||||
@@ -696,7 +696,7 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
cf::get_all_index_summary_off_heap_memory_used.set(r, [&ctx] (std::unique_ptr<request> req) {
|
||||
return map_reduce_cf(ctx, uint64_t(0), [] (column_family& cf) {
|
||||
return std::accumulate(cf.get_sstables()->begin(), cf.get_sstables()->end(), uint64_t(0), [](uint64_t s, auto& sst) {
|
||||
return s + sst->get_summary().memory_footprint();
|
||||
return sst->get_summary().memory_footprint();
|
||||
});
|
||||
}, std::plus<uint64_t>());
|
||||
});
|
||||
@@ -991,9 +991,6 @@ void set_column_family(http_context& ctx, routes& r) {
|
||||
apilog.debug("toppartitions query: processing results");
|
||||
cf::toppartitions_query_results results;
|
||||
|
||||
results.read_cardinality = topk_results.read.size();
|
||||
results.write_cardinality = topk_results.write.size();
|
||||
|
||||
for (auto& d: topk_results.read.top(q.list_size())) {
|
||||
cf::toppartitions_record r;
|
||||
r.partition = sstring(d.item);
|
||||
|
||||
@@ -66,13 +66,6 @@ void set_gossiper(http_context& ctx, routes& r) {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
});
|
||||
|
||||
httpd::gossiper_json::force_remove_endpoint.set(r, [](std::unique_ptr<request> req) {
|
||||
gms::inet_address ep(req->param["addr"]);
|
||||
return gms::get_local_gossiper().force_remove_endpoint(ep).then([] {
|
||||
return make_ready_future<json::json_return_type>(json_void());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ static future<> create_metadata_table_if_missing_impl(
|
||||
b.set_uuid(uuid);
|
||||
schema_ptr table = b.build();
|
||||
return ignore_existing([&mm, table = std::move(table)] () {
|
||||
return mm.announce_new_column_family(table);
|
||||
return mm.announce_new_column_family(table, false);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ future<> wait_for_schema_agreement(::service::migration_manager& mm, const datab
|
||||
});
|
||||
}
|
||||
|
||||
const timeout_config& internal_distributed_timeout_config() noexcept {
|
||||
::service::query_state& internal_distributed_query_state() noexcept {
|
||||
#ifdef DEBUG
|
||||
// Give the much slower debug tests more headroom for completing auth queries.
|
||||
static const auto t = 30s;
|
||||
@@ -116,7 +116,9 @@ const timeout_config& internal_distributed_timeout_config() noexcept {
|
||||
static const auto t = 5s;
|
||||
#endif
|
||||
static const timeout_config tc{t, t, t, t, t, t, t};
|
||||
return tc;
|
||||
static thread_local ::service::client_state cs(::service::client_state::internal_tag{}, tc);
|
||||
static thread_local ::service::query_state qs(cs, empty_service_permit());
|
||||
return qs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "log.hh"
|
||||
#include "seastarx.hh"
|
||||
#include "utils/exponential_backoff_retry.hh"
|
||||
#include "service/query_state.hh"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
@@ -87,6 +88,6 @@ future<> wait_for_schema_agreement(::service::migration_manager&, const database
|
||||
///
|
||||
/// Time-outs for internal, non-local CQL queries.
|
||||
///
|
||||
const timeout_config& internal_distributed_timeout_config() noexcept;
|
||||
::service::query_state& internal_distributed_query_state() noexcept;
|
||||
|
||||
}
|
||||
|
||||
@@ -103,7 +103,6 @@ future<bool> default_authorizer::any_granted() const {
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::LOCAL_ONE,
|
||||
infinite_timeout_config,
|
||||
{},
|
||||
true).then([this](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
return !results->empty();
|
||||
@@ -116,8 +115,7 @@ future<> default_authorizer::migrate_legacy_metadata() const {
|
||||
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::LOCAL_ONE,
|
||||
infinite_timeout_config).then([this](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
db::consistency_level::LOCAL_ONE).then([this](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
return do_for_each(*results, [this](const cql3::untyped_result_set_row& row) {
|
||||
return do_with(
|
||||
row.get_as<sstring>("username"),
|
||||
@@ -197,7 +195,6 @@ default_authorizer::authorize(const role_or_anonymous& maybe_role, const resourc
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::LOCAL_ONE,
|
||||
infinite_timeout_config,
|
||||
{*maybe_role.name, r.name()}).then([](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
if (results->empty()) {
|
||||
return permissions::NONE;
|
||||
@@ -226,7 +223,7 @@ default_authorizer::modify(
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::ONE,
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{permissions::to_strings(set), sstring(role_name), resource.name()}).discard_result();
|
||||
});
|
||||
}
|
||||
@@ -251,7 +248,7 @@ future<std::vector<permission_details>> default_authorizer::list_all() const {
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::ONE,
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{},
|
||||
true).then([](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
std::vector<permission_details> all_details;
|
||||
@@ -278,7 +275,7 @@ future<> default_authorizer::revoke_all(std::string_view role_name) const {
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::ONE,
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{sstring(role_name)}).discard_result().handle_exception([role_name](auto ep) {
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
@@ -298,7 +295,6 @@ future<> default_authorizer::revoke_all(const resource& resource) const {
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::LOCAL_ONE,
|
||||
infinite_timeout_config,
|
||||
{resource.name()}).then_wrapped([this, resource](future<::shared_ptr<cql3::untyped_result_set>> f) {
|
||||
try {
|
||||
auto res = f.get0();
|
||||
@@ -315,7 +311,6 @@ future<> default_authorizer::revoke_all(const resource& resource) const {
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::LOCAL_ONE,
|
||||
infinite_timeout_config,
|
||||
{r.get_as<sstring>(ROLE_NAME), resource.name()}).discard_result().handle_exception(
|
||||
[resource](auto ep) {
|
||||
try {
|
||||
|
||||
@@ -66,6 +66,7 @@ constexpr std::string_view password_authenticator_name("org.apache.cassandra.aut
|
||||
|
||||
// name of the hash column.
|
||||
static constexpr std::string_view SALTED_HASH = "salted_hash";
|
||||
static constexpr std::string_view OPTIONS = "options";
|
||||
static constexpr std::string_view DEFAULT_USER_NAME = meta::DEFAULT_SUPERUSER_NAME;
|
||||
static const sstring DEFAULT_USER_PASSWORD = sstring(meta::DEFAULT_SUPERUSER_NAME);
|
||||
|
||||
@@ -114,7 +115,7 @@ future<> password_authenticator::migrate_legacy_metadata() const {
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::QUORUM,
|
||||
internal_distributed_timeout_config()).then([this](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
internal_distributed_query_state()).then([this](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
return do_for_each(*results, [this](const cql3::untyped_result_set_row& row) {
|
||||
auto username = row.get_as<sstring>("username");
|
||||
auto salted_hash = row.get_as<sstring>(SALTED_HASH);
|
||||
@@ -122,7 +123,7 @@ future<> password_authenticator::migrate_legacy_metadata() const {
|
||||
return _qp.execute_internal(
|
||||
update_row_query(),
|
||||
consistency_for_user(username),
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{std::move(salted_hash), username}).discard_result();
|
||||
}).finally([results] {});
|
||||
}).then([] {
|
||||
@@ -139,7 +140,7 @@ future<> password_authenticator::create_default_if_missing() const {
|
||||
return _qp.execute_internal(
|
||||
update_row_query(),
|
||||
db::consistency_level::QUORUM,
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{passwords::hash(DEFAULT_USER_PASSWORD, rng_for_salt), DEFAULT_USER_NAME}).then([](auto&&) {
|
||||
plogger.info("Created default superuser authentication record.");
|
||||
});
|
||||
@@ -203,11 +204,11 @@ bool password_authenticator::require_authentication() const {
|
||||
}
|
||||
|
||||
authentication_option_set password_authenticator::supported_options() const {
|
||||
return authentication_option_set{authentication_option::password};
|
||||
return authentication_option_set{authentication_option::password, authentication_option::options};
|
||||
}
|
||||
|
||||
authentication_option_set password_authenticator::alterable_options() const {
|
||||
return authentication_option_set{authentication_option::password};
|
||||
return authentication_option_set{authentication_option::password, authentication_option::options};
|
||||
}
|
||||
|
||||
future<authenticated_user> password_authenticator::authenticate(
|
||||
@@ -236,7 +237,7 @@ future<authenticated_user> password_authenticator::authenticate(
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
consistency_for_user(username),
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{username},
|
||||
true);
|
||||
}).then_wrapped([=](future<::shared_ptr<cql3::untyped_result_set>> f) {
|
||||
@@ -262,21 +263,46 @@ future<authenticated_user> password_authenticator::authenticate(
|
||||
});
|
||||
}
|
||||
|
||||
future<> password_authenticator::maybe_update_custom_options(std::string_view role_name, const authentication_options& options) const {
|
||||
static const sstring query = format("UPDATE {} SET {} = ? WHERE {} = ?",
|
||||
meta::roles_table::qualified_name,
|
||||
OPTIONS,
|
||||
meta::roles_table::role_col_name);
|
||||
|
||||
if (!options.options) {
|
||||
return make_ready_future<>();
|
||||
}
|
||||
|
||||
std::vector<std::pair<data_value, data_value>> entries;
|
||||
for (const auto& entry : *options.options) {
|
||||
entries.push_back({data_value(entry.first), data_value(entry.second)});
|
||||
}
|
||||
auto map_value = make_map_value(map_type_impl::get_instance(utf8_type, utf8_type, false), entries);
|
||||
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
consistency_for_user(role_name),
|
||||
internal_distributed_query_state(),
|
||||
{std::move(map_value), sstring(role_name)}).discard_result();
|
||||
}
|
||||
|
||||
future<> password_authenticator::create(std::string_view role_name, const authentication_options& options) const {
|
||||
if (!options.password) {
|
||||
return make_ready_future<>();
|
||||
return maybe_update_custom_options(role_name, options);
|
||||
}
|
||||
|
||||
return _qp.execute_internal(
|
||||
update_row_query(),
|
||||
consistency_for_user(role_name),
|
||||
internal_distributed_timeout_config(),
|
||||
{passwords::hash(*options.password, rng_for_salt), sstring(role_name)}).discard_result();
|
||||
internal_distributed_query_state(),
|
||||
{passwords::hash(*options.password, rng_for_salt), sstring(role_name)}).discard_result().then([this, role_name, &options] {
|
||||
return maybe_update_custom_options(role_name, options);
|
||||
});
|
||||
}
|
||||
|
||||
future<> password_authenticator::alter(std::string_view role_name, const authentication_options& options) const {
|
||||
if (!options.password) {
|
||||
return make_ready_future<>();
|
||||
return maybe_update_custom_options(role_name, options);
|
||||
}
|
||||
|
||||
static const sstring query = format("UPDATE {} SET {} = ? WHERE {} = ?",
|
||||
@@ -287,8 +313,10 @@ future<> password_authenticator::alter(std::string_view role_name, const authent
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
consistency_for_user(role_name),
|
||||
internal_distributed_timeout_config(),
|
||||
{passwords::hash(*options.password, rng_for_salt), sstring(role_name)}).discard_result();
|
||||
internal_distributed_query_state(),
|
||||
{passwords::hash(*options.password, rng_for_salt), sstring(role_name)}).discard_result().then([this, role_name, &options] {
|
||||
return maybe_update_custom_options(role_name, options);
|
||||
}).discard_result();
|
||||
}
|
||||
|
||||
future<> password_authenticator::drop(std::string_view name) const {
|
||||
@@ -299,12 +327,27 @@ future<> password_authenticator::drop(std::string_view name) const {
|
||||
|
||||
return _qp.execute_internal(
|
||||
query, consistency_for_user(name),
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{sstring(name)}).discard_result();
|
||||
}
|
||||
|
||||
future<custom_options> password_authenticator::query_custom_options(std::string_view role_name) const {
|
||||
return make_ready_future<custom_options>();
|
||||
static const sstring query = format("SELECT {} FROM {} WHERE {} = ?",
|
||||
OPTIONS,
|
||||
meta::roles_table::qualified_name,
|
||||
meta::roles_table::role_col_name);
|
||||
|
||||
return _qp.execute_internal(
|
||||
query, consistency_for_user(role_name),
|
||||
internal_distributed_query_state(),
|
||||
{sstring(role_name)}).then([](::shared_ptr<cql3::untyped_result_set> rs) {
|
||||
custom_options opts;
|
||||
const auto& row = rs->one();
|
||||
if (row.has(OPTIONS)) {
|
||||
row.get_map_data<sstring, sstring>(OPTIONS, std::inserter(opts, opts.end()), utf8_type, utf8_type);
|
||||
}
|
||||
return opts;
|
||||
});
|
||||
}
|
||||
|
||||
const resource_set& password_authenticator::protected_resources() const {
|
||||
|
||||
@@ -94,6 +94,8 @@ public:
|
||||
virtual ::shared_ptr<sasl_challenge> new_sasl_challenge() const override;
|
||||
|
||||
private:
|
||||
future<> maybe_update_custom_options(std::string_view role_name, const authentication_options& options) const;
|
||||
|
||||
bool legacy_metadata_exists() const;
|
||||
|
||||
future<> migrate_legacy_metadata() const;
|
||||
|
||||
@@ -43,7 +43,8 @@ std::string_view creation_query() {
|
||||
" can_login boolean,"
|
||||
" is_superuser boolean,"
|
||||
" member_of set<text>,"
|
||||
" salted_hash text"
|
||||
" salted_hash text,"
|
||||
" options frozen<map<text, text>>,"
|
||||
")",
|
||||
qualified_name,
|
||||
role_col_name);
|
||||
@@ -68,14 +69,13 @@ future<bool> default_role_row_satisfies(
|
||||
return qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::ONE,
|
||||
infinite_timeout_config,
|
||||
{meta::DEFAULT_SUPERUSER_NAME},
|
||||
true).then([&qp, &p](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
if (results->empty()) {
|
||||
return qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::QUORUM,
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{meta::DEFAULT_SUPERUSER_NAME},
|
||||
true).then([&p](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
if (results->empty()) {
|
||||
@@ -100,7 +100,7 @@ future<bool> any_nondefault_role_row_satisfies(
|
||||
return qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::QUORUM,
|
||||
internal_distributed_timeout_config()).then([&p](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
internal_distributed_query_state()).then([&p](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
if (results->empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ future<> service::create_keyspace_if_missing(::service::migration_manager& mm) c
|
||||
|
||||
// We use min_timestamp so that default keyspace metadata will loose with any manual adjustments.
|
||||
// See issue #2129.
|
||||
return mm.announce_new_keyspace(ksm, api::min_timestamp);
|
||||
return mm.announce_new_keyspace(ksm, api::min_timestamp, false);
|
||||
}
|
||||
|
||||
return make_ready_future<>();
|
||||
@@ -210,7 +210,6 @@ future<bool> service::has_existing_legacy_users() const {
|
||||
return _qp.execute_internal(
|
||||
default_user_query,
|
||||
db::consistency_level::ONE,
|
||||
infinite_timeout_config,
|
||||
{meta::DEFAULT_SUPERUSER_NAME},
|
||||
true).then([this](auto results) {
|
||||
if (!results->empty()) {
|
||||
@@ -220,7 +219,6 @@ future<bool> service::has_existing_legacy_users() const {
|
||||
return _qp.execute_internal(
|
||||
default_user_query,
|
||||
db::consistency_level::QUORUM,
|
||||
infinite_timeout_config,
|
||||
{meta::DEFAULT_SUPERUSER_NAME},
|
||||
true).then([this](auto results) {
|
||||
if (!results->empty()) {
|
||||
@@ -229,8 +227,7 @@ future<bool> service::has_existing_legacy_users() const {
|
||||
|
||||
return _qp.execute_internal(
|
||||
all_users_query,
|
||||
db::consistency_level::QUORUM,
|
||||
infinite_timeout_config).then([](auto results) {
|
||||
db::consistency_level::QUORUM).then([](auto results) {
|
||||
return make_ready_future<bool>(!results->empty());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -86,7 +86,7 @@ static future<std::optional<record>> find_record(cql3::query_processor& qp, std:
|
||||
return qp.execute_internal(
|
||||
query,
|
||||
consistency_for_role(role_name),
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{sstring(role_name)},
|
||||
true).then([](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
if (results->empty()) {
|
||||
@@ -165,7 +165,7 @@ future<> standard_role_manager::create_default_role_if_missing() const {
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::QUORUM,
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{meta::DEFAULT_SUPERUSER_NAME}).then([](auto&&) {
|
||||
log.info("Created default superuser role '{}'.", meta::DEFAULT_SUPERUSER_NAME);
|
||||
return make_ready_future<>();
|
||||
@@ -192,7 +192,7 @@ future<> standard_role_manager::migrate_legacy_metadata() const {
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::QUORUM,
|
||||
internal_distributed_timeout_config()).then([this](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
internal_distributed_query_state()).then([this](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
return do_for_each(*results, [this](const cql3::untyped_result_set_row& row) {
|
||||
role_config config;
|
||||
config.is_superuser = row.get_or<bool>("super", false);
|
||||
@@ -253,7 +253,7 @@ future<> standard_role_manager::create_or_replace(std::string_view role_name, co
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
consistency_for_role(role_name),
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{sstring(role_name), c.is_superuser, c.can_login},
|
||||
true).discard_result();
|
||||
}
|
||||
@@ -296,7 +296,7 @@ standard_role_manager::alter(std::string_view role_name, const role_config_updat
|
||||
build_column_assignments(u),
|
||||
meta::roles_table::role_col_name),
|
||||
consistency_for_role(role_name),
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{sstring(role_name)}).discard_result();
|
||||
});
|
||||
}
|
||||
@@ -315,7 +315,7 @@ future<> standard_role_manager::drop(std::string_view role_name) const {
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
consistency_for_role(role_name),
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{sstring(role_name)}).then([this, role_name](::shared_ptr<cql3::untyped_result_set> members) {
|
||||
return parallel_for_each(
|
||||
members->begin(),
|
||||
@@ -354,7 +354,7 @@ future<> standard_role_manager::drop(std::string_view role_name) const {
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
consistency_for_role(role_name),
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{sstring(role_name)}).discard_result();
|
||||
};
|
||||
|
||||
@@ -381,7 +381,7 @@ standard_role_manager::modify_membership(
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
consistency_for_role(grantee_name),
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{role_set{sstring(role_name)}, sstring(grantee_name)}).discard_result();
|
||||
};
|
||||
|
||||
@@ -392,7 +392,7 @@ standard_role_manager::modify_membership(
|
||||
format("INSERT INTO {} (role, member) VALUES (?, ?)",
|
||||
meta::role_members_table::qualified_name),
|
||||
consistency_for_role(role_name),
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{sstring(role_name), sstring(grantee_name)}).discard_result();
|
||||
|
||||
case membership_change::remove:
|
||||
@@ -400,7 +400,7 @@ standard_role_manager::modify_membership(
|
||||
format("DELETE FROM {} WHERE role = ? AND member = ?",
|
||||
meta::role_members_table::qualified_name),
|
||||
consistency_for_role(role_name),
|
||||
internal_distributed_timeout_config(),
|
||||
internal_distributed_query_state(),
|
||||
{sstring(role_name), sstring(grantee_name)}).discard_result();
|
||||
}
|
||||
|
||||
@@ -503,7 +503,7 @@ future<role_set> standard_role_manager::query_all() const {
|
||||
return _qp.execute_internal(
|
||||
query,
|
||||
db::consistency_level::QUORUM,
|
||||
internal_distributed_timeout_config()).then([](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
internal_distributed_query_state()).then([](::shared_ptr<cql3::untyped_result_set> results) {
|
||||
role_set roles;
|
||||
|
||||
std::transform(
|
||||
|
||||
40
bytes.hh
40
bytes.hh
@@ -28,7 +28,6 @@
|
||||
#include <iosfwd>
|
||||
#include <functional>
|
||||
#include "utils/mutable_view.hh"
|
||||
#include <xxhash.h>
|
||||
|
||||
using bytes = basic_sstring<int8_t, uint32_t, 31, false>;
|
||||
using bytes_view = std::basic_string_view<int8_t>;
|
||||
@@ -36,10 +35,6 @@ using bytes_mutable_view = basic_mutable_view<bytes_view::value_type>;
|
||||
using bytes_opt = std::optional<bytes>;
|
||||
using sstring_view = std::string_view;
|
||||
|
||||
inline bytes to_bytes(bytes&& b) {
|
||||
return std::move(b);
|
||||
}
|
||||
|
||||
inline sstring_view to_sstring_view(bytes_view view) {
|
||||
return {reinterpret_cast<const char*>(view.data()), view.size()};
|
||||
}
|
||||
@@ -48,6 +43,17 @@ inline bytes_view to_bytes_view(sstring_view view) {
|
||||
return {reinterpret_cast<const int8_t*>(view.data()), view.size()};
|
||||
}
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
struct hash<bytes_view> {
|
||||
size_t operator()(bytes_view v) const {
|
||||
return hash<sstring_view>()({reinterpret_cast<const char*>(v.begin()), v.size()});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
struct fmt_hex {
|
||||
bytes_view& v;
|
||||
fmt_hex(bytes_view& v) noexcept : v(v) {}
|
||||
@@ -88,30 +94,6 @@ struct appending_hash<bytes_view> {
|
||||
}
|
||||
};
|
||||
|
||||
struct bytes_view_hasher : public hasher {
|
||||
XXH64_state_t _state;
|
||||
bytes_view_hasher(uint64_t seed = 0) noexcept {
|
||||
XXH64_reset(&_state, seed);
|
||||
}
|
||||
void update(const char* ptr, size_t length) noexcept {
|
||||
XXH64_update(&_state, ptr, length);
|
||||
}
|
||||
size_t finalize() {
|
||||
return static_cast<size_t>(XXH64_digest(&_state));
|
||||
}
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<bytes_view> {
|
||||
size_t operator()(bytes_view v) const {
|
||||
bytes_view_hasher h;
|
||||
appending_hash<bytes_view>{}(h, v);
|
||||
return h.finalize();
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
inline int32_t compare_unsigned(bytes_view v1, bytes_view v2) {
|
||||
auto size = std::min(v1.size(), v2.size());
|
||||
if (size) {
|
||||
|
||||
@@ -461,7 +461,7 @@ void cache_flat_mutation_reader::maybe_add_to_cache(const clustering_row& cr) {
|
||||
cr.cells().prepare_hash(*_schema, column_kind::regular_column);
|
||||
}
|
||||
auto new_entry = alloc_strategy_unique_ptr<rows_entry>(
|
||||
current_allocator().construct<rows_entry>(*_schema, cr.key(), cr.as_deletable_row()));
|
||||
current_allocator().construct<rows_entry>(*_schema, cr.key(), cr.tomb(), cr.marker(), cr.cells()));
|
||||
new_entry->set_continuous(false);
|
||||
auto it = _next_row.iterators_valid() ? _next_row.get_iterator_in_latest_version()
|
||||
: mp.clustered_rows().lower_bound(cr.key(), less);
|
||||
|
||||
15
cdc/log.cc
15
cdc/log.cc
@@ -220,7 +220,7 @@ public:
|
||||
auto new_log_schema = create_log_schema(new_schema, log_schema ? std::make_optional(log_schema->id()) : std::nullopt);
|
||||
|
||||
auto log_mut = log_schema
|
||||
? db::schema_tables::make_update_table_mutations(db, keyspace.metadata(), log_schema, new_log_schema, timestamp, false)
|
||||
? db::schema_tables::make_update_table_mutations(keyspace.metadata(), log_schema, new_log_schema, timestamp, false)
|
||||
: db::schema_tables::make_create_table_mutations(keyspace.metadata(), new_log_schema, timestamp)
|
||||
;
|
||||
|
||||
@@ -579,6 +579,11 @@ db_context::builder& db_context::builder::with_migration_notifier(service::migra
|
||||
return *this;
|
||||
}
|
||||
|
||||
db_context::builder& db_context::builder::with_token_metadata(const locator::token_metadata& token_metadata) {
|
||||
_token_metadata = token_metadata;
|
||||
return *this;
|
||||
}
|
||||
|
||||
db_context::builder& db_context::builder::with_cdc_metadata(cdc::metadata& cdc_metadata) {
|
||||
_cdc_metadata = cdc_metadata;
|
||||
return *this;
|
||||
@@ -588,6 +593,7 @@ db_context db_context::builder::build() {
|
||||
return db_context{
|
||||
_proxy,
|
||||
_migration_notifier ? _migration_notifier->get() : service::get_local_storage_service().get_migration_notifier(),
|
||||
_token_metadata ? _token_metadata->get() : service::get_local_storage_service().get_token_metadata(),
|
||||
_cdc_metadata ? _cdc_metadata->get() : service::get_local_storage_service().get_cdc_metadata(),
|
||||
};
|
||||
}
|
||||
@@ -1291,13 +1297,6 @@ struct process_change_visitor {
|
||||
_clustering_row_states, _generate_delta_values);
|
||||
visit_row_cells(v);
|
||||
|
||||
if (_enable_updating_state) {
|
||||
// #7716: if there are no regular columns, our visitor would not have visited any cells,
|
||||
// hence it would not have created a row_state for this row. In effect, postimage wouldn't be produced.
|
||||
// Ensure that the row state exists.
|
||||
_clustering_row_states.try_emplace(ckey);
|
||||
}
|
||||
|
||||
_builder.set_operation(log_ck, v._cdc_op);
|
||||
_builder.set_ttl(log_ck, v._ttl_column);
|
||||
}
|
||||
|
||||
@@ -100,16 +100,19 @@ public:
|
||||
struct db_context final {
|
||||
service::storage_proxy& _proxy;
|
||||
service::migration_notifier& _migration_notifier;
|
||||
const locator::token_metadata& _token_metadata;
|
||||
cdc::metadata& _cdc_metadata;
|
||||
|
||||
class builder final {
|
||||
service::storage_proxy& _proxy;
|
||||
std::optional<std::reference_wrapper<service::migration_notifier>> _migration_notifier;
|
||||
std::optional<std::reference_wrapper<const locator::token_metadata>> _token_metadata;
|
||||
std::optional<std::reference_wrapper<cdc::metadata>> _cdc_metadata;
|
||||
public:
|
||||
builder(service::storage_proxy& proxy);
|
||||
|
||||
builder& with_migration_notifier(service::migration_notifier& migration_notifier);
|
||||
builder& with_token_metadata(const locator::token_metadata& token_metadata);
|
||||
builder& with_cdc_metadata(cdc::metadata&);
|
||||
|
||||
db_context build();
|
||||
|
||||
@@ -67,8 +67,8 @@ public:
|
||||
int operator()(const clustering_key_prefix& p1, int32_t w1, const clustering_key_prefix& p2, int32_t w2) const {
|
||||
auto type = _s.get().clustering_key_prefix_type();
|
||||
auto res = prefix_equality_tri_compare(type->types().begin(),
|
||||
type->begin(p1.representation()), type->end(p1.representation()),
|
||||
type->begin(p2.representation()), type->end(p2.representation()),
|
||||
type->begin(p1), type->end(p1),
|
||||
type->begin(p2), type->end(p2),
|
||||
::tri_compare);
|
||||
if (res) {
|
||||
return res;
|
||||
|
||||
@@ -136,4 +136,4 @@ collection_mutation merge(const abstract_type&, collection_mutation_view, collec
|
||||
collection_mutation difference(const abstract_type&, collection_mutation_view, collection_mutation_view);
|
||||
|
||||
// Serializes the given collection of cells to a sequence of bytes ready to be sent over the CQL protocol.
|
||||
bytes_ostream serialize_for_cql(const abstract_type&, collection_mutation_view, cql_serialization_format);
|
||||
bytes serialize_for_cql(const abstract_type&, collection_mutation_view, cql_serialization_format);
|
||||
|
||||
106
compound.hh
106
compound.hh
@@ -73,19 +73,12 @@ private:
|
||||
* <len(value1)><value1><len(value2)><value2>...<len(value_n)><value_n>
|
||||
*
|
||||
*/
|
||||
template<typename RangeOfSerializedComponents, FragmentedMutableView Out>
|
||||
static void serialize_value(RangeOfSerializedComponents&& values, Out out) {
|
||||
template<typename RangeOfSerializedComponents, typename CharOutputIterator>
|
||||
static void serialize_value(RangeOfSerializedComponents&& values, CharOutputIterator& out) {
|
||||
for (auto&& val : values) {
|
||||
assert(val.size() <= std::numeric_limits<size_type>::max());
|
||||
write<size_type>(out, size_type(val.size()));
|
||||
using val_type = std::remove_cvref_t<decltype(val)>;
|
||||
if constexpr (FragmentedView<val_type>) {
|
||||
write_fragmented(out, val);
|
||||
} else if constexpr (std::same_as<val_type, managed_bytes>) {
|
||||
write_fragmented(out, managed_bytes_view(val));
|
||||
} else {
|
||||
write_fragmented(out, single_fragmented_view(val));
|
||||
}
|
||||
out = std::copy(val.begin(), val.end(), out);
|
||||
}
|
||||
}
|
||||
template <typename RangeOfSerializedComponents>
|
||||
@@ -97,27 +90,25 @@ private:
|
||||
return len;
|
||||
}
|
||||
public:
|
||||
managed_bytes serialize_single(managed_bytes&& v) const {
|
||||
return serialize_value({std::move(v)});
|
||||
}
|
||||
managed_bytes serialize_single(bytes&& v) const {
|
||||
bytes serialize_single(bytes&& v) const {
|
||||
return serialize_value({std::move(v)});
|
||||
}
|
||||
template<typename RangeOfSerializedComponents>
|
||||
static managed_bytes serialize_value(RangeOfSerializedComponents&& values) {
|
||||
static bytes serialize_value(RangeOfSerializedComponents&& values) {
|
||||
auto size = serialized_size(values);
|
||||
if (size > std::numeric_limits<size_type>::max()) {
|
||||
throw std::runtime_error(format("Key size too large: {:d} > {:d}", size, std::numeric_limits<size_type>::max()));
|
||||
}
|
||||
managed_bytes b(managed_bytes::initialized_later(), size);
|
||||
serialize_value(values, managed_bytes_mutable_view(b));
|
||||
bytes b(bytes::initialized_later(), size);
|
||||
auto i = b.begin();
|
||||
serialize_value(values, i);
|
||||
return b;
|
||||
}
|
||||
template<typename T>
|
||||
static managed_bytes serialize_value(std::initializer_list<T> values) {
|
||||
static bytes serialize_value(std::initializer_list<T> values) {
|
||||
return serialize_value(boost::make_iterator_range(values.begin(), values.end()));
|
||||
}
|
||||
managed_bytes serialize_optionals(const std::vector<bytes_opt>& values) const {
|
||||
bytes serialize_optionals(const std::vector<bytes_opt>& values) const {
|
||||
return serialize_value(values | boost::adaptors::transformed([] (const bytes_opt& bo) -> bytes_view {
|
||||
if (!bo) {
|
||||
throw std::logic_error("attempted to create key component from empty optional");
|
||||
@@ -125,7 +116,7 @@ public:
|
||||
return *bo;
|
||||
}));
|
||||
}
|
||||
managed_bytes serialize_value_deep(const std::vector<data_value>& values) const {
|
||||
bytes serialize_value_deep(const std::vector<data_value>& values) const {
|
||||
// TODO: Optimize
|
||||
std::vector<bytes> partial;
|
||||
partial.reserve(values.size());
|
||||
@@ -136,26 +127,25 @@ public:
|
||||
}
|
||||
return serialize_value(partial);
|
||||
}
|
||||
managed_bytes decompose_value(const value_type& values) const {
|
||||
bytes decompose_value(const value_type& values) const {
|
||||
return serialize_value(values);
|
||||
}
|
||||
class iterator {
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = const managed_bytes_view;
|
||||
using value_type = const bytes_view;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = const value_type*;
|
||||
using reference = const value_type&;
|
||||
using pointer = const bytes_view*;
|
||||
using reference = const bytes_view&;
|
||||
private:
|
||||
managed_bytes_view _v;
|
||||
managed_bytes_view _current;
|
||||
size_t _remaining = 0;
|
||||
bytes_view _v;
|
||||
bytes_view _current;
|
||||
private:
|
||||
void read_current() {
|
||||
_remaining = _v.size_bytes();
|
||||
size_type len;
|
||||
{
|
||||
if (_v.empty()) {
|
||||
_v = bytes_view(nullptr, 0);
|
||||
return;
|
||||
}
|
||||
len = read_simple<size_type>(_v);
|
||||
@@ -163,16 +153,15 @@ public:
|
||||
throw_with_backtrace<marshal_exception>(format("compound_type iterator - not enough bytes, expected {:d}, got {:d}", len, _v.size()));
|
||||
}
|
||||
}
|
||||
_current = _v.prefix(len);
|
||||
_v.remove_prefix(_current.size_bytes());
|
||||
_current = bytes_view(_v.begin(), len);
|
||||
_v.remove_prefix(len);
|
||||
}
|
||||
public:
|
||||
struct end_iterator_tag {};
|
||||
iterator(const managed_bytes_view& v) : _v(v) {
|
||||
iterator(const bytes_view& v) : _v(v) {
|
||||
read_current();
|
||||
}
|
||||
iterator(end_iterator_tag, const managed_bytes_view& v) : _v() {}
|
||||
iterator() {}
|
||||
iterator(end_iterator_tag, const bytes_view& v) : _v(nullptr, 0) {}
|
||||
iterator& operator++() {
|
||||
read_current();
|
||||
return *this;
|
||||
@@ -184,40 +173,29 @@ public:
|
||||
}
|
||||
const value_type& operator*() const { return _current; }
|
||||
const value_type* operator->() const { return &_current; }
|
||||
bool operator==(const iterator& i) const { return _remaining == i._remaining; }
|
||||
bool operator!=(const iterator& i) const { return _v.begin() != i._v.begin(); }
|
||||
bool operator==(const iterator& i) const { return _v.begin() == i._v.begin(); }
|
||||
};
|
||||
static iterator begin(managed_bytes_view v) {
|
||||
static iterator begin(const bytes_view& v) {
|
||||
return iterator(v);
|
||||
}
|
||||
static iterator end(managed_bytes_view v) {
|
||||
static iterator end(const bytes_view& v) {
|
||||
return iterator(typename iterator::end_iterator_tag(), v);
|
||||
}
|
||||
static boost::iterator_range<iterator> components(managed_bytes_view v) {
|
||||
static boost::iterator_range<iterator> components(const bytes_view& v) {
|
||||
return { begin(v), end(v) };
|
||||
}
|
||||
value_type deserialize_value(managed_bytes_view v) const {
|
||||
value_type deserialize_value(bytes_view v) const {
|
||||
std::vector<bytes> result;
|
||||
result.reserve(_types.size());
|
||||
std::transform(begin(v), end(v), std::back_inserter(result), [] (auto&& v) {
|
||||
return to_bytes(v);
|
||||
return bytes(v.begin(), v.end());
|
||||
});
|
||||
return result;
|
||||
}
|
||||
bool less(managed_bytes_view b1, managed_bytes_view b2) const {
|
||||
return with_linearized(b1, [&] (bytes_view bv1) {
|
||||
return with_linearized(b2, [&] (bytes_view bv2) {
|
||||
return less(bv1, bv2);
|
||||
});
|
||||
});
|
||||
}
|
||||
bool less(bytes_view b1, bytes_view b2) const {
|
||||
return compare(b1, b2) < 0;
|
||||
}
|
||||
size_t hash(managed_bytes_view v) const{
|
||||
return with_linearized(v, [&] (bytes_view v) {
|
||||
return hash(v);
|
||||
});
|
||||
}
|
||||
size_t hash(bytes_view v) const {
|
||||
if (_byte_order_equal) {
|
||||
return std::hash<bytes_view>()(v);
|
||||
@@ -230,13 +208,6 @@ public:
|
||||
}
|
||||
return h;
|
||||
}
|
||||
int compare(managed_bytes_view b1, managed_bytes_view b2) const {
|
||||
return with_linearized(b1, [&] (bytes_view bv1) {
|
||||
return with_linearized(b2, [&] (bytes_view bv2) {
|
||||
return compare(bv1, bv2);
|
||||
});
|
||||
});
|
||||
}
|
||||
int compare(bytes_view b1, bytes_view b2) const {
|
||||
if (_byte_order_comparable) {
|
||||
if (_is_reversed) {
|
||||
@@ -251,21 +222,15 @@ public:
|
||||
});
|
||||
}
|
||||
// Retruns true iff given prefix has no missing components
|
||||
bool is_full(managed_bytes_view v) const {
|
||||
bool is_full(bytes_view v) const {
|
||||
assert(AllowPrefixes == allow_prefixes::yes);
|
||||
return std::distance(begin(v), end(v)) == (ssize_t)_types.size();
|
||||
}
|
||||
bool is_empty(managed_bytes_view v) const {
|
||||
return v.empty();
|
||||
}
|
||||
bool is_empty(const managed_bytes& v) const {
|
||||
return v.empty();
|
||||
}
|
||||
bool is_empty(bytes_view v) const {
|
||||
return begin(v) == end(v);
|
||||
}
|
||||
void validate(managed_bytes_view v) const {
|
||||
std::vector<managed_bytes_view> values(begin(v), end(v));
|
||||
void validate(bytes_view v) const {
|
||||
std::vector<bytes_view> values(begin(v), end(v));
|
||||
if (AllowPrefixes == allow_prefixes::no && values.size() < _types.size()) {
|
||||
throw marshal_exception(fmt::format("compound::validate(): non-prefixable compound cannot be a prefix"));
|
||||
}
|
||||
@@ -278,13 +243,6 @@ public:
|
||||
_types[i]->validate(values[i], cql_serialization_format::internal());
|
||||
}
|
||||
}
|
||||
bool equal(managed_bytes_view v1, managed_bytes_view v2) const {
|
||||
return with_linearized(v1, [&] (bytes_view bv1) {
|
||||
return with_linearized(v2, [&] (bytes_view bv2) {
|
||||
return equal(bv1, bv2);
|
||||
});
|
||||
});
|
||||
}
|
||||
bool equal(bytes_view v1, bytes_view v2) const {
|
||||
if (_byte_order_equal) {
|
||||
return compare_unsigned(v1, v2) == 0;
|
||||
|
||||
@@ -54,9 +54,9 @@ template <typename CompoundType>
|
||||
class legacy_compound_view {
|
||||
static_assert(!CompoundType::is_prefixable, "Legacy view not defined for prefixes");
|
||||
CompoundType& _type;
|
||||
managed_bytes_view _packed;
|
||||
bytes_view _packed;
|
||||
public:
|
||||
legacy_compound_view(CompoundType& c, managed_bytes_view packed)
|
||||
legacy_compound_view(CompoundType& c, bytes_view packed)
|
||||
: _type(c)
|
||||
, _packed(packed)
|
||||
{ }
|
||||
@@ -147,18 +147,18 @@ public:
|
||||
{ }
|
||||
|
||||
// @k1 and @k2 must be serialized using @type, which was passed to the constructor.
|
||||
int operator()(managed_bytes_view k1, managed_bytes_view k2) const {
|
||||
int operator()(bytes_view k1, bytes_view k2) const {
|
||||
if (_type.is_singular()) {
|
||||
return compare_unsigned(*_type.begin(k1), *_type.begin(k2));
|
||||
}
|
||||
return lexicographical_tri_compare(
|
||||
_type.begin(k1), _type.end(k1),
|
||||
_type.begin(k2), _type.end(k2),
|
||||
[] (const managed_bytes_view& c1, const managed_bytes_view& c2) -> int {
|
||||
[] (const bytes_view& c1, const bytes_view& c2) -> int {
|
||||
if (c1.size() != c2.size() || !c1.size()) {
|
||||
return c1.size() < c2.size() ? -1 : c1.size() ? 1 : 0;
|
||||
}
|
||||
return compare_unsigned(c1, c2);
|
||||
return memcmp(c1.begin(), c2.begin(), c1.size());
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -188,7 +188,7 @@ public:
|
||||
// @packed is assumed to be serialized using supplied @type.
|
||||
template <typename CompoundType>
|
||||
static inline
|
||||
bytes to_legacy(CompoundType& type, managed_bytes_view packed) {
|
||||
bytes to_legacy(CompoundType& type, bytes_view packed) {
|
||||
legacy_compound_view<CompoundType> lv(type, packed);
|
||||
bytes legacy_form(bytes::initialized_later(), lv.size());
|
||||
std::copy(lv.begin(), lv.end(), legacy_form.begin());
|
||||
@@ -264,12 +264,6 @@ private:
|
||||
static void write_value(Value&& val, CharOutputIterator& out) {
|
||||
out = std::copy(val.begin(), val.end(), out);
|
||||
}
|
||||
template<typename CharOutputIterator>
|
||||
static void write_value(managed_bytes_view val, CharOutputIterator& out) {
|
||||
for (bytes_view frag : fragment_range(val)) {
|
||||
out = std::copy(frag.begin(), frag.end(), out);
|
||||
}
|
||||
}
|
||||
template <typename CharOutputIterator>
|
||||
static void write_value(const data_value& val, CharOutputIterator& out) {
|
||||
val.serialize(out);
|
||||
@@ -411,7 +405,6 @@ public:
|
||||
iterator(end_iterator_tag) : _v(nullptr, 0) {}
|
||||
|
||||
public:
|
||||
iterator() : iterator(end_iterator_tag()) {}
|
||||
iterator& operator++() {
|
||||
read_current();
|
||||
return *this;
|
||||
|
||||
18
configure.py
18
configure.py
@@ -59,9 +59,6 @@ i18n_xlat = {
|
||||
}
|
||||
|
||||
python3_dependencies = subprocess.run('./install-dependencies.sh --print-python3-runtime-packages', shell=True, capture_output=True, encoding='utf-8').stdout.strip()
|
||||
node_exporter_filename = subprocess.run('./install-dependencies.sh --print-node-exporter-filename', shell=True, capture_output=True, encoding='utf-8').stdout.strip()
|
||||
node_exporter_dirname = os.path.basename(node_exporter_filename).rstrip('.tar.gz')
|
||||
|
||||
|
||||
def pkgname(name):
|
||||
if name in i18n_xlat:
|
||||
@@ -265,7 +262,7 @@ modes = {
|
||||
'stack-usage-threshold': 1024*13,
|
||||
},
|
||||
'dev': {
|
||||
'cxxflags': '-O1 -DDEVEL -DSEASTAR_ENABLE_ALLOC_FAILURE_INJECTION -DSCYLLA_ENABLE_ERROR_INJECTION',
|
||||
'cxxflags': '-O1 -DSEASTAR_ENABLE_ALLOC_FAILURE_INJECTION -DSCYLLA_ENABLE_ERROR_INJECTION',
|
||||
'cxx_ld_flags': '',
|
||||
'stack-usage-threshold': 1024*21,
|
||||
},
|
||||
@@ -332,7 +329,6 @@ scylla_tests = set([
|
||||
'test/boost/gossip_test',
|
||||
'test/boost/gossiping_property_file_snitch_test',
|
||||
'test/boost/hash_test',
|
||||
'test/boost/hashers_test',
|
||||
'test/boost/idl_test',
|
||||
'test/boost/imr_test',
|
||||
'test/boost/input_stream_test',
|
||||
@@ -348,7 +344,6 @@ scylla_tests = set([
|
||||
'test/boost/estimated_histogram_test',
|
||||
'test/boost/logalloc_test',
|
||||
'test/boost/managed_vector_test',
|
||||
'test/boost/managed_bytes_test',
|
||||
'test/boost/intrusive_array_test',
|
||||
'test/boost/map_difference_test',
|
||||
'test/boost/memtable_test',
|
||||
@@ -455,7 +450,6 @@ apps = set([
|
||||
'scylla',
|
||||
'test/tools/cql_repl',
|
||||
'tools/scylla-types',
|
||||
'tools/scylla-sstable-index',
|
||||
])
|
||||
|
||||
tests = scylla_tests | perf_tests | raft_tests
|
||||
@@ -581,7 +575,6 @@ scylla_core = (['database.cc',
|
||||
'sstables/mp_row_consumer.cc',
|
||||
'sstables/sstables.cc',
|
||||
'sstables/sstables_manager.cc',
|
||||
'sstables/sstable_set.cc',
|
||||
'sstables/mx/writer.cc',
|
||||
'sstables/kl/writer.cc',
|
||||
'sstables/sstable_version.cc',
|
||||
@@ -989,7 +982,6 @@ deps = {
|
||||
'test/tools/cql_repl': idls + ['test/tools/cql_repl.cc'] + scylla_core + scylla_tests_generic_dependencies,
|
||||
#FIXME: we don't need all of scylla_core here, only the types module, need to modularize scylla_core.
|
||||
'tools/scylla-types': idls + ['tools/scylla-types.cc'] + scylla_core,
|
||||
'tools/scylla-sstable-index': idls + ['tools/scylla-sstable-index.cc'] + scylla_core,
|
||||
}
|
||||
|
||||
pure_boost_tests = set([
|
||||
@@ -1009,7 +1001,6 @@ pure_boost_tests = set([
|
||||
'test/boost/dynamic_bitset_test',
|
||||
'test/boost/enum_option_test',
|
||||
'test/boost/enum_set_test',
|
||||
'test/boost/hashers_test',
|
||||
'test/boost/idl_test',
|
||||
'test/boost/json_test',
|
||||
'test/boost/keys_test',
|
||||
@@ -1026,7 +1017,6 @@ pure_boost_tests = set([
|
||||
'test/boost/top_k_test',
|
||||
'test/boost/vint_serialization_test',
|
||||
'test/boost/bptree_test',
|
||||
'test/boost/utf8_test',
|
||||
'test/manual/streaming_histogram_test',
|
||||
])
|
||||
|
||||
@@ -1149,6 +1139,7 @@ warnings = [
|
||||
'-Wno-delete-non-abstract-non-virtual-dtor',
|
||||
'-Wno-unknown-attributes',
|
||||
'-Wno-braced-scalar-init',
|
||||
'-Wno-unused-value',
|
||||
'-Wno-range-loop-construct',
|
||||
'-Wno-unused-function',
|
||||
'-Wno-implicit-int-float-conversion',
|
||||
@@ -1807,7 +1798,7 @@ with open(buildfile_tmp, 'w') as f:
|
||||
f.write(textwrap.dedent('''\
|
||||
build $builddir/{mode}/iotune: copy $builddir/{mode}/seastar/apps/iotune/iotune
|
||||
''').format(**locals()))
|
||||
f.write('build $builddir/{mode}/dist/tar/{scylla_product}-package.tar.gz: package $builddir/{mode}/scylla $builddir/{mode}/iotune $builddir/SCYLLA-RELEASE-FILE $builddir/SCYLLA-VERSION-FILE $builddir/debian/debian $builddir/node_exporter | always\n'.format(**locals()))
|
||||
f.write('build $builddir/{mode}/dist/tar/{scylla_product}-package.tar.gz: package $builddir/{mode}/scylla $builddir/{mode}/iotune $builddir/SCYLLA-RELEASE-FILE $builddir/SCYLLA-VERSION-FILE $builddir/debian/debian | always\n'.format(**locals()))
|
||||
f.write(' mode = {mode}\n'.format(**locals()))
|
||||
f.write(f'build $builddir/dist/{mode}/redhat: rpmbuild $builddir/{mode}/dist/tar/{scylla_product}-package.tar.gz\n')
|
||||
f.write(f' mode = {mode}\n')
|
||||
@@ -1966,9 +1957,6 @@ with open(buildfile_tmp, 'w') as f:
|
||||
rule debian_files_gen
|
||||
command = ./dist/debian/debian_files_gen.py
|
||||
build $builddir/debian/debian: debian_files_gen | always
|
||||
rule extract_node_exporter
|
||||
command = tar -C build -xvpf {node_exporter_filename} && rm -rfv build/node_exporter && mv -v build/{node_exporter_dirname} build/node_exporter
|
||||
build $builddir/node_exporter: extract_node_exporter | always
|
||||
''').format(**globals()))
|
||||
|
||||
os.rename(buildfile_tmp, buildfile)
|
||||
|
||||
18
counters.cc
18
counters.cc
@@ -19,10 +19,16 @@
|
||||
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "service/storage_service.hh"
|
||||
#include "counters.hh"
|
||||
#include "mutation.hh"
|
||||
#include "combine.hh"
|
||||
|
||||
counter_id counter_id::local()
|
||||
{
|
||||
return counter_id(service::get_local_storage_service().get_local_id());
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const counter_id& id) {
|
||||
return os << id.to_uuid();
|
||||
}
|
||||
@@ -191,10 +197,10 @@ std::optional<atomic_cell> counter_cell_view::difference(atomic_cell_view a, ato
|
||||
}
|
||||
|
||||
|
||||
void transform_counter_updates_to_shards(mutation& m, const mutation* current_state, uint64_t clock_offset, utils::UUID local_id) {
|
||||
void transform_counter_updates_to_shards(mutation& m, const mutation* current_state, uint64_t clock_offset) {
|
||||
// FIXME: allow current_state to be frozen_mutation
|
||||
|
||||
auto transform_new_row_to_shards = [&s = *m.schema(), clock_offset, local_id] (column_kind kind, auto& cells) {
|
||||
auto transform_new_row_to_shards = [&s = *m.schema(), clock_offset] (column_kind kind, auto& cells) {
|
||||
cells.for_each_cell([&] (column_id id, atomic_cell_or_collection& ac_o_c) {
|
||||
auto& cdef = s.column_at(kind, id);
|
||||
auto acv = ac_o_c.as_atomic_cell(cdef);
|
||||
@@ -202,7 +208,7 @@ void transform_counter_updates_to_shards(mutation& m, const mutation* current_st
|
||||
return; // continue -- we are in lambda
|
||||
}
|
||||
auto delta = acv.counter_update_value();
|
||||
auto cs = counter_shard(counter_id(local_id), delta, clock_offset + 1);
|
||||
auto cs = counter_shard(counter_id::local(), delta, clock_offset + 1);
|
||||
ac_o_c = counter_cell_builder::from_single_shard(acv.timestamp(), cs);
|
||||
});
|
||||
};
|
||||
@@ -217,7 +223,7 @@ void transform_counter_updates_to_shards(mutation& m, const mutation* current_st
|
||||
|
||||
clustering_key::less_compare cmp(*m.schema());
|
||||
|
||||
auto transform_row_to_shards = [&s = *m.schema(), clock_offset, local_id] (column_kind kind, auto& transformee, auto& state) {
|
||||
auto transform_row_to_shards = [&s = *m.schema(), clock_offset] (column_kind kind, auto& transformee, auto& state) {
|
||||
std::deque<std::pair<column_id, counter_shard>> shards;
|
||||
state.for_each_cell([&] (column_id id, const atomic_cell_or_collection& ac_o_c) {
|
||||
auto& cdef = s.column_at(kind, id);
|
||||
@@ -226,7 +232,7 @@ void transform_counter_updates_to_shards(mutation& m, const mutation* current_st
|
||||
return; // continue -- we are in lambda
|
||||
}
|
||||
counter_cell_view::with_linearized(acv, [&] (counter_cell_view ccv) {
|
||||
auto cs = ccv.get_shard(counter_id(local_id));
|
||||
auto cs = ccv.local_shard();
|
||||
if (!cs) {
|
||||
return; // continue
|
||||
}
|
||||
@@ -247,7 +253,7 @@ void transform_counter_updates_to_shards(mutation& m, const mutation* current_st
|
||||
auto delta = acv.counter_update_value();
|
||||
|
||||
if (shards.empty() || shards.front().first > id) {
|
||||
auto cs = counter_shard(counter_id(local_id), delta, clock_offset + 1);
|
||||
auto cs = counter_shard(counter_id::local(), delta, clock_offset + 1);
|
||||
ac_o_c = counter_cell_builder::from_single_shard(acv.timestamp(), cs);
|
||||
} else {
|
||||
auto& cs = shards.front().second;
|
||||
|
||||
@@ -61,6 +61,8 @@ public:
|
||||
return !(*this == other);
|
||||
}
|
||||
public:
|
||||
static counter_id local();
|
||||
|
||||
// For tests.
|
||||
static counter_id generate_random() {
|
||||
return counter_id(utils::make_random_uuid());
|
||||
@@ -403,6 +405,11 @@ public:
|
||||
return *it;
|
||||
}
|
||||
|
||||
std::optional<counter_shard_view> local_shard() const {
|
||||
// TODO: consider caching local shard position
|
||||
return get_shard(counter_id::local());
|
||||
}
|
||||
|
||||
bool operator==(const basic_counter_cell_view& other) const {
|
||||
return timestamp() == other.timestamp() && boost::equal(shards(), other.shards());
|
||||
}
|
||||
@@ -444,7 +451,7 @@ struct counter_cell_mutable_view : basic_counter_cell_view<mutable_view::yes> {
|
||||
// Transforms mutation dst from counter updates to counter shards using state
|
||||
// stored in current_state.
|
||||
// If current_state is present it has to be in the same schema as dst.
|
||||
void transform_counter_updates_to_shards(mutation& dst, const mutation* current_state, uint64_t clock_offset, utils::UUID local_id);
|
||||
void transform_counter_updates_to_shards(mutation& dst, const mutation* current_state, uint64_t clock_offset);
|
||||
|
||||
template<>
|
||||
struct appending_hash<counter_shard_view> {
|
||||
|
||||
@@ -394,7 +394,6 @@ selectStatement returns [std::unique_ptr<raw::select_statement> expr]
|
||||
bool allow_filtering = false;
|
||||
bool is_json = false;
|
||||
bool bypass_cache = false;
|
||||
auto attrs = std::make_unique<cql3::attributes::raw>();
|
||||
}
|
||||
: K_SELECT (
|
||||
( K_JSON { is_json = true; } )?
|
||||
@@ -409,12 +408,11 @@ selectStatement returns [std::unique_ptr<raw::select_statement> expr]
|
||||
( K_LIMIT rows=intValue { limit = rows; } )?
|
||||
( K_ALLOW K_FILTERING { allow_filtering = true; } )?
|
||||
( K_BYPASS K_CACHE { bypass_cache = true; })?
|
||||
( usingClause[attrs] )?
|
||||
{
|
||||
auto params = make_lw_shared<raw::select_statement::parameters>(std::move(orderings), is_distinct, allow_filtering, is_json, bypass_cache);
|
||||
$expr = std::make_unique<raw::select_statement>(std::move(cf), std::move(params),
|
||||
std::move(sclause), std::move(wclause), std::move(limit), std::move(per_partition_limit),
|
||||
std::move(gbcolumns), std::move(attrs));
|
||||
std::move(gbcolumns));
|
||||
}
|
||||
;
|
||||
|
||||
@@ -523,7 +521,6 @@ usingClause[std::unique_ptr<cql3::attributes::raw>& attrs]
|
||||
usingClauseObjective[std::unique_ptr<cql3::attributes::raw>& attrs]
|
||||
: K_TIMESTAMP ts=intValue { attrs->timestamp = ts; }
|
||||
| K_TTL t=intValue { attrs->time_to_live = t; }
|
||||
| K_TIMEOUT to=term { attrs->timeout = to; }
|
||||
;
|
||||
|
||||
/**
|
||||
@@ -1764,7 +1761,6 @@ basic_unreserved_keyword returns [sstring str]
|
||||
| K_PER
|
||||
| K_PARTITION
|
||||
| K_GROUP
|
||||
| K_TIMEOUT
|
||||
) { $str = $k.text; }
|
||||
;
|
||||
|
||||
@@ -1920,8 +1916,6 @@ K_GROUP: G R O U P;
|
||||
|
||||
K_LIKE: L I K E;
|
||||
|
||||
K_TIMEOUT: T I M E O U T;
|
||||
|
||||
// Case-insensitive alpha characters
|
||||
fragment A: ('a'|'A');
|
||||
fragment B: ('b'|'B');
|
||||
|
||||
@@ -70,11 +70,11 @@ abstract_marker::raw::raw(int32_t bind_index)
|
||||
::shared_ptr<term> abstract_marker::raw::prepare(database& db, const sstring& keyspace, lw_shared_ptr<column_specification> receiver) const
|
||||
{
|
||||
if (receiver->type->is_collection()) {
|
||||
if (receiver->type->without_reversed().is_list()) {
|
||||
if (receiver->type->get_kind() == abstract_type::kind::list) {
|
||||
return ::make_shared<lists::marker>(_bind_index, receiver);
|
||||
} else if (receiver->type->without_reversed().is_set()) {
|
||||
} else if (receiver->type->get_kind() == abstract_type::kind::set) {
|
||||
return ::make_shared<sets::marker>(_bind_index, receiver);
|
||||
} else if (receiver->type->without_reversed().is_map()) {
|
||||
} else if (receiver->type->get_kind() == abstract_type::kind::map) {
|
||||
return ::make_shared<maps::marker>(_bind_index, receiver);
|
||||
}
|
||||
assert(0);
|
||||
|
||||
@@ -44,13 +44,12 @@
|
||||
namespace cql3 {
|
||||
|
||||
std::unique_ptr<attributes> attributes::none() {
|
||||
return std::unique_ptr<attributes>{new attributes{{}, {}, {}}};
|
||||
return std::unique_ptr<attributes>{new attributes{{}, {}}};
|
||||
}
|
||||
|
||||
attributes::attributes(::shared_ptr<term>&& timestamp, ::shared_ptr<term>&& time_to_live, ::shared_ptr<term>&& timeout)
|
||||
attributes::attributes(::shared_ptr<term>&& timestamp, ::shared_ptr<term>&& time_to_live)
|
||||
: _timestamp{std::move(timestamp)}
|
||||
, _time_to_live{std::move(time_to_live)}
|
||||
, _timeout{std::move(timeout)}
|
||||
{ }
|
||||
|
||||
bool attributes::is_timestamp_set() const {
|
||||
@@ -61,10 +60,6 @@ bool attributes::is_time_to_live_set() const {
|
||||
return bool(_time_to_live);
|
||||
}
|
||||
|
||||
bool attributes::is_timeout_set() const {
|
||||
return bool(_timeout);
|
||||
}
|
||||
|
||||
int64_t attributes::get_timestamp(int64_t now, const query_options& options) {
|
||||
if (!_timestamp) {
|
||||
return now;
|
||||
@@ -77,12 +72,14 @@ int64_t attributes::get_timestamp(int64_t now, const query_options& options) {
|
||||
if (tval.is_unset_value()) {
|
||||
return now;
|
||||
}
|
||||
return with_linearized(*tval, [&] (bytes_view val) {
|
||||
try {
|
||||
data_type_for<int64_t>()->validate(*tval, options.get_cql_serialization_format());
|
||||
data_type_for<int64_t>()->validate(val, options.get_cql_serialization_format());
|
||||
} catch (marshal_exception& e) {
|
||||
throw exceptions::invalid_request_exception("Invalid timestamp value");
|
||||
}
|
||||
return value_cast<int64_t>(data_type_for<int64_t>()->deserialize(*tval));
|
||||
return value_cast<int64_t>(data_type_for<int64_t>()->deserialize(val));
|
||||
});
|
||||
}
|
||||
|
||||
int32_t attributes::get_time_to_live(const query_options& options) {
|
||||
@@ -96,15 +93,16 @@ int32_t attributes::get_time_to_live(const query_options& options) {
|
||||
if (tval.is_unset_value()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto ttl = with_linearized(*tval, [&] (bytes_view val) {
|
||||
try {
|
||||
data_type_for<int32_t>()->validate(*tval, options.get_cql_serialization_format());
|
||||
data_type_for<int32_t>()->validate(val, options.get_cql_serialization_format());
|
||||
}
|
||||
catch (marshal_exception& e) {
|
||||
throw exceptions::invalid_request_exception("Invalid TTL value");
|
||||
}
|
||||
auto ttl = value_cast<int32_t>(data_type_for<int32_t>()->deserialize(*tval));
|
||||
|
||||
return value_cast<int32_t>(data_type_for<int32_t>()->deserialize(val));
|
||||
});
|
||||
if (ttl < 0) {
|
||||
throw exceptions::invalid_request_exception("A TTL must be greater or equal to 0");
|
||||
}
|
||||
@@ -117,25 +115,6 @@ int32_t attributes::get_time_to_live(const query_options& options) {
|
||||
return ttl;
|
||||
}
|
||||
|
||||
|
||||
db::timeout_clock::duration attributes::get_timeout(const query_options& options) const {
|
||||
auto timeout = _timeout->bind_and_get(options);
|
||||
if (timeout.is_null() || timeout.is_unset_value()) {
|
||||
throw exceptions::invalid_request_exception("Timeout value cannot be unset/null");
|
||||
}
|
||||
cql_duration duration = value_cast<cql_duration>(duration_type->deserialize(*timeout));
|
||||
if (duration.months || duration.days) {
|
||||
throw exceptions::invalid_request_exception("Timeout values cannot be expressed in days/months");
|
||||
}
|
||||
if (duration.nanoseconds % 1'000'000 != 0) {
|
||||
throw exceptions::invalid_request_exception("Timeout values cannot have granularity finer than milliseconds");
|
||||
}
|
||||
if (duration.nanoseconds < 0) {
|
||||
throw exceptions::invalid_request_exception("Timeout values must be non-negative");
|
||||
}
|
||||
return std::chrono::duration_cast<db::timeout_clock::duration>(std::chrono::nanoseconds(duration.nanoseconds));
|
||||
}
|
||||
|
||||
void attributes::collect_marker_specification(variable_specifications& bound_names) const {
|
||||
if (_timestamp) {
|
||||
_timestamp->collect_marker_specification(bound_names);
|
||||
@@ -143,16 +122,12 @@ void attributes::collect_marker_specification(variable_specifications& bound_nam
|
||||
if (_time_to_live) {
|
||||
_time_to_live->collect_marker_specification(bound_names);
|
||||
}
|
||||
if (_timeout) {
|
||||
_timeout->collect_marker_specification(bound_names);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<attributes> attributes::raw::prepare(database& db, const sstring& ks_name, const sstring& cf_name) const {
|
||||
auto ts = !timestamp ? ::shared_ptr<term>{} : timestamp->prepare(db, ks_name, timestamp_receiver(ks_name, cf_name));
|
||||
auto ttl = !time_to_live ? ::shared_ptr<term>{} : time_to_live->prepare(db, ks_name, time_to_live_receiver(ks_name, cf_name));
|
||||
auto to = !timeout ? ::shared_ptr<term>{} : timeout->prepare(db, ks_name, timeout_receiver(ks_name, cf_name));
|
||||
return std::unique_ptr<attributes>{new attributes{std::move(ts), std::move(ttl), std::move(to)}};
|
||||
return std::unique_ptr<attributes>{new attributes{std::move(ts), std::move(ttl)}};
|
||||
}
|
||||
|
||||
lw_shared_ptr<column_specification> attributes::raw::timestamp_receiver(const sstring& ks_name, const sstring& cf_name) const {
|
||||
@@ -163,8 +138,4 @@ lw_shared_ptr<column_specification> attributes::raw::time_to_live_receiver(const
|
||||
return make_lw_shared<column_specification>(ks_name, cf_name, ::make_shared<column_identifier>("[ttl]", true), data_type_for<int32_t>());
|
||||
}
|
||||
|
||||
lw_shared_ptr<column_specification> attributes::raw::timeout_receiver(const sstring& ks_name, const sstring& cf_name) const {
|
||||
return make_lw_shared<column_specification>(ks_name, cf_name, ::make_shared<column_identifier>("[timeout]", true), duration_type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -54,39 +54,31 @@ class attributes final {
|
||||
private:
|
||||
const ::shared_ptr<term> _timestamp;
|
||||
const ::shared_ptr<term> _time_to_live;
|
||||
const ::shared_ptr<term> _timeout;
|
||||
public:
|
||||
static std::unique_ptr<attributes> none();
|
||||
private:
|
||||
attributes(::shared_ptr<term>&& timestamp, ::shared_ptr<term>&& time_to_live, ::shared_ptr<term>&& timeout);
|
||||
attributes(::shared_ptr<term>&& timestamp, ::shared_ptr<term>&& time_to_live);
|
||||
public:
|
||||
bool is_timestamp_set() const;
|
||||
|
||||
bool is_time_to_live_set() const;
|
||||
|
||||
bool is_timeout_set() const;
|
||||
|
||||
int64_t get_timestamp(int64_t now, const query_options& options);
|
||||
|
||||
int32_t get_time_to_live(const query_options& options);
|
||||
|
||||
db::timeout_clock::duration get_timeout(const query_options& options) const;
|
||||
|
||||
void collect_marker_specification(variable_specifications& bound_names) const;
|
||||
|
||||
class raw final {
|
||||
public:
|
||||
::shared_ptr<term::raw> timestamp;
|
||||
::shared_ptr<term::raw> time_to_live;
|
||||
::shared_ptr<term::raw> timeout;
|
||||
|
||||
std::unique_ptr<attributes> prepare(database& db, const sstring& ks_name, const sstring& cf_name) const;
|
||||
private:
|
||||
lw_shared_ptr<column_specification> timestamp_receiver(const sstring& ks_name, const sstring& cf_name) const;
|
||||
|
||||
lw_shared_ptr<column_specification> time_to_live_receiver(const sstring& ks_name, const sstring& cf_name) const;
|
||||
|
||||
lw_shared_ptr<column_specification> timeout_receiver(const sstring& ks_name, const sstring& cf_name) const;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -192,12 +192,9 @@ public:
|
||||
|
||||
virtual ::shared_ptr<terminal> bind(const query_options& options) override {
|
||||
auto bytes = bind_and_get(options);
|
||||
if (bytes.is_null()) {
|
||||
if (!bytes) {
|
||||
return ::shared_ptr<terminal>{};
|
||||
}
|
||||
if (bytes.is_unset_value()) {
|
||||
return UNSET_VALUE;
|
||||
}
|
||||
return ::make_shared<constants::value>(std::move(cql3::raw_value::make_value(to_bytes(*bytes))));
|
||||
}
|
||||
};
|
||||
@@ -230,7 +227,9 @@ public:
|
||||
} else if (value.is_unset_value()) {
|
||||
return;
|
||||
}
|
||||
auto increment = value_cast<int64_t>(long_type->deserialize_value(*value));
|
||||
auto increment = with_linearized(*value, [] (bytes_view value_view) {
|
||||
return value_cast<int64_t>(long_type->deserialize_value(value_view));
|
||||
});
|
||||
m.set_cell(prefix, column, make_counter_update_cell(increment, params));
|
||||
}
|
||||
};
|
||||
@@ -245,7 +244,9 @@ public:
|
||||
} else if (value.is_unset_value()) {
|
||||
return;
|
||||
}
|
||||
auto increment = value_cast<int64_t>(long_type->deserialize_value(*value));
|
||||
auto increment = with_linearized(*value, [] (bytes_view value_view) {
|
||||
return value_cast<int64_t>(long_type->deserialize_value(value_view));
|
||||
});
|
||||
if (increment == std::numeric_limits<int64_t>::min()) {
|
||||
throw exceptions::invalid_request_exception(format("The negation of {:d} overflows supported counter precision (signed 8 bytes integer)", increment));
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include <fmt/ostream.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "cql3/constants.hh"
|
||||
#include "cql3/lists.hh"
|
||||
#include "cql3/tuples.hh"
|
||||
#include "index/secondary_index_manager.hh"
|
||||
@@ -44,8 +43,7 @@ using boost::adaptors::transformed;
|
||||
|
||||
namespace {
|
||||
|
||||
static
|
||||
bytes_opt do_get_value(const schema& schema,
|
||||
std::optional<atomic_cell_value_view> do_get_value(const schema& schema,
|
||||
const column_definition& cdef,
|
||||
const partition_key& key,
|
||||
const clustering_key_prefix& ckey,
|
||||
@@ -53,9 +51,9 @@ bytes_opt do_get_value(const schema& schema,
|
||||
gc_clock::time_point now) {
|
||||
switch (cdef.kind) {
|
||||
case column_kind::partition_key:
|
||||
return to_bytes(key.get_component(schema, cdef.component_index()));
|
||||
return atomic_cell_value_view(key.get_component(schema, cdef.component_index()));
|
||||
case column_kind::clustering_key:
|
||||
return to_bytes(ckey.get_component(schema, cdef.component_index()));
|
||||
return atomic_cell_value_view(ckey.get_component(schema, cdef.component_index()));
|
||||
default:
|
||||
auto cell = cells.find_cell(cdef.id);
|
||||
if (!cell) {
|
||||
@@ -63,7 +61,7 @@ bytes_opt do_get_value(const schema& schema,
|
||||
}
|
||||
assert(cdef.is_atomic());
|
||||
auto c = cell->as_atomic_cell(cdef);
|
||||
return c.is_dead(now) ? std::nullopt : bytes_opt(c.value().linearize());
|
||||
return c.is_dead(now) ? std::nullopt : std::optional<atomic_cell_value_view>(c.value());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,8 +138,9 @@ bytes_opt get_value_from_partition_slice(
|
||||
|
||||
/// Returns col's value from a mutation.
|
||||
bytes_opt get_value_from_mutation(const column_value& col, row_data_from_mutation data) {
|
||||
return do_get_value(
|
||||
const auto v = do_get_value(
|
||||
data.schema_, *col.col, data.partition_key_, data.clustering_key_, data.other_columns, data.now);
|
||||
return v ? v->linearize() : bytes_opt();
|
||||
}
|
||||
|
||||
/// Returns col's value from the fetched data.
|
||||
@@ -155,7 +154,7 @@ bytes_opt get_value(const column_value& col, const column_value_eval_bag& bag) {
|
||||
|
||||
/// Type for comparing results of get_value().
|
||||
const abstract_type* get_value_comparator(const column_definition* cdef) {
|
||||
return &cdef->type->without_reversed();
|
||||
return cdef->type->is_reversed() ? cdef->type->underlying_type().get() : cdef->type.get();
|
||||
}
|
||||
|
||||
/// Type for comparing results of get_value().
|
||||
@@ -356,12 +355,16 @@ bytes_opt next_value(query::result_row_view::iterator_type& iter, const column_d
|
||||
if (cdef->type->is_multi_cell()) {
|
||||
auto cell = iter.next_collection_cell();
|
||||
if (cell) {
|
||||
return linearized(*cell);
|
||||
return cell->with_linearized([] (bytes_view data) {
|
||||
return bytes(data.cbegin(), data.cend());
|
||||
});
|
||||
}
|
||||
} else {
|
||||
auto cell = iter.next_atomic_cell();
|
||||
if (cell) {
|
||||
return linearized(cell->value());
|
||||
return cell->value().with_linearized([] (bytes_view data) {
|
||||
return bytes(data.cbegin(), data.cend());
|
||||
});
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
@@ -565,8 +568,7 @@ const auto deref = boost::adaptors::transformed([] (const bytes_opt& b) { return
|
||||
|
||||
/// Returns possible values from t, which must be RHS of IN.
|
||||
value_list get_IN_values(
|
||||
const ::shared_ptr<term>& t, const query_options& options, const serialized_compare& comparator,
|
||||
sstring_view column_name) {
|
||||
const ::shared_ptr<term>& t, const query_options& options, const serialized_compare& comparator) {
|
||||
// RHS is prepared differently for different CQL cases. Cast it dynamically to discern which case this is.
|
||||
if (auto dv = dynamic_pointer_cast<lists::delayed_value>(t)) {
|
||||
// Case `a IN (1,2,3)`.
|
||||
@@ -576,11 +578,8 @@ value_list get_IN_values(
|
||||
return to_sorted_vector(std::move(result_range), comparator);
|
||||
} else if (auto mkr = dynamic_pointer_cast<lists::marker>(t)) {
|
||||
// Case `a IN ?`. Collect all list-element values.
|
||||
const auto val = mkr->bind(options);
|
||||
if (val == constants::UNSET_VALUE) {
|
||||
throw exceptions::invalid_request_exception(format("Invalid unset value for column {}", column_name));
|
||||
}
|
||||
return to_sorted_vector(static_pointer_cast<lists::value>(val)->get_elements() | non_null | deref, comparator);
|
||||
const auto val = static_pointer_cast<lists::value>(mkr->bind(options));
|
||||
return to_sorted_vector(val->get_elements() | non_null | deref, comparator);
|
||||
}
|
||||
throw std::logic_error(format("get_IN_values(single column) on invalid term {}", *t));
|
||||
}
|
||||
@@ -687,7 +686,7 @@ value_set possible_lhs_values(const column_definition* cdef, const expression& e
|
||||
return oper.op == oper_t::EQ ? value_set(value_list{*val})
|
||||
: to_range(oper.op, *val);
|
||||
} else if (oper.op == oper_t::IN) {
|
||||
return get_IN_values(oper.rhs, options, type->as_less_comparator(), cdef->name_as_text());
|
||||
return get_IN_values(oper.rhs, options, type->as_less_comparator());
|
||||
}
|
||||
throw std::logic_error(format("possible_lhs_values: unhandled operator {}", oper));
|
||||
},
|
||||
@@ -777,11 +776,9 @@ bool is_supported_by(const expression& expr, const secondary_index::index& idx)
|
||||
return idx.supports_expression(*col.col, oper.op);
|
||||
},
|
||||
[&] (const std::vector<column_value>& cvs) {
|
||||
if (cvs.size() == 1) {
|
||||
return idx.supports_expression(*cvs[0].col, oper.op);
|
||||
}
|
||||
// We don't use index table for multi-column restrictions, as it cannot avoid filtering.
|
||||
return false;
|
||||
return boost::algorithm::any_of(cvs, [&] (const column_value& c) {
|
||||
return idx.supports_expression(*c.col, oper.op);
|
||||
});
|
||||
},
|
||||
[&] (const token&) { return false; },
|
||||
}, oper.lhs);
|
||||
|
||||
@@ -219,7 +219,7 @@ struct aggregate_type_for<simple_date_native_type> {
|
||||
|
||||
template<>
|
||||
struct aggregate_type_for<timeuuid_native_type> {
|
||||
using type = timeuuid_native_type;
|
||||
using type = timeuuid_native_type::primary_type;
|
||||
};
|
||||
|
||||
template<>
|
||||
@@ -227,7 +227,6 @@ struct aggregate_type_for<time_native_type> {
|
||||
using type = time_native_type::primary_type;
|
||||
};
|
||||
|
||||
// WARNING: never invoke this on temporary values; it will return a dangling reference.
|
||||
template <typename Type>
|
||||
const Type& max_wrapper(const Type& t1, const Type& t2) {
|
||||
using std::max;
|
||||
@@ -242,10 +241,6 @@ inline const net::inet_address& max_wrapper(const net::inet_address& t1, const n
|
||||
return std::memcmp(t1.data(), t2.data(), len) >= 0 ? t1 : t2;
|
||||
}
|
||||
|
||||
inline const timeuuid_native_type& max_wrapper(const timeuuid_native_type& t1, const timeuuid_native_type& t2) {
|
||||
return t1.uuid.timestamp() > t2.uuid.timestamp() ? t1 : t2;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
class impl_max_function_for final : public aggregate_function::aggregate {
|
||||
std::optional<typename aggregate_type_for<Type>::type> _max{};
|
||||
@@ -328,7 +323,6 @@ make_max_function() {
|
||||
return make_shared<max_function_for<Type>>();
|
||||
}
|
||||
|
||||
// WARNING: never invoke this on temporary values; it will return a dangling reference.
|
||||
template <typename Type>
|
||||
const Type& min_wrapper(const Type& t1, const Type& t2) {
|
||||
using std::min;
|
||||
@@ -343,10 +337,6 @@ inline const net::inet_address& min_wrapper(const net::inet_address& t1, const n
|
||||
return std::memcmp(t1.data(), t2.data(), len) <= 0 ? t1 : t2;
|
||||
}
|
||||
|
||||
inline timeuuid_native_type min_wrapper(timeuuid_native_type t1, timeuuid_native_type t2) {
|
||||
return t1.uuid.timestamp() < t2.uuid.timestamp() ? t1 : t2;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
class impl_min_function_for final : public aggregate_function::aggregate {
|
||||
std::optional<typename aggregate_type_for<Type>::type> _min{};
|
||||
|
||||
@@ -40,7 +40,7 @@ lw_shared_ptr<column_specification>
|
||||
lists::value_spec_of(const column_specification& column) {
|
||||
return make_lw_shared<column_specification>(column.ks_name, column.cf_name,
|
||||
::make_shared<column_identifier>(format("value({})", *column.name), true),
|
||||
dynamic_cast<const list_type_impl&>(column.type->without_reversed()).get_elements_type());
|
||||
dynamic_pointer_cast<const list_type_impl>(column.type)->get_elements_type());
|
||||
}
|
||||
|
||||
lw_shared_ptr<column_specification>
|
||||
@@ -87,7 +87,7 @@ lists::literal::prepare(database& db, const sstring& keyspace, lw_shared_ptr<col
|
||||
|
||||
void
|
||||
lists::literal::validate_assignable_to(database& db, const sstring keyspace, const column_specification& receiver) const {
|
||||
if (!receiver.type->without_reversed().is_list()) {
|
||||
if (!dynamic_pointer_cast<const list_type_impl>(receiver.type)) {
|
||||
throw exceptions::invalid_request_exception(format("Invalid list literal for {} of type {}",
|
||||
*receiver.name, receiver.type->as_cql3_type()));
|
||||
}
|
||||
@@ -125,11 +125,18 @@ lists::literal::to_string() const {
|
||||
|
||||
lists::value
|
||||
lists::value::from_serialized(const fragmented_temporary_buffer::view& val, const list_type_impl& type, cql_serialization_format sf) {
|
||||
return with_linearized(val, [&] (bytes_view v) {
|
||||
return from_serialized(v, type, sf);
|
||||
});
|
||||
}
|
||||
|
||||
lists::value
|
||||
lists::value::from_serialized(bytes_view v, const list_type_impl& type, cql_serialization_format sf) {
|
||||
try {
|
||||
// Collections have this small hack that validate cannot be called on a serialized object,
|
||||
// but compose does the validation (so we're fine).
|
||||
// FIXME: deserializeForNativeProtocol()?!
|
||||
auto l = value_cast<list_type_impl::native_type>(type.deserialize(val, sf));
|
||||
auto l = value_cast<list_type_impl::native_type>(type.deserialize(v, sf));
|
||||
std::vector<bytes_opt> elements;
|
||||
elements.reserve(l.size());
|
||||
for (auto&& element : l) {
|
||||
@@ -220,15 +227,17 @@ lists::delayed_value::bind(const query_options& options) {
|
||||
::shared_ptr<terminal>
|
||||
lists::marker::bind(const query_options& options) {
|
||||
const auto& value = options.get_value_at(_bind_index);
|
||||
auto& ltype = dynamic_cast<const list_type_impl&>(_receiver->type->without_reversed());
|
||||
auto& ltype = static_cast<const list_type_impl&>(*_receiver->type);
|
||||
if (value.is_null()) {
|
||||
return nullptr;
|
||||
} else if (value.is_unset_value()) {
|
||||
return constants::UNSET_VALUE;
|
||||
} else {
|
||||
try {
|
||||
ltype.validate(*value, options.get_cql_serialization_format());
|
||||
return make_shared<lists::value>(value::from_serialized(*value, ltype, options.get_cql_serialization_format()));
|
||||
return with_linearized(*value, [&] (bytes_view v) {
|
||||
ltype.validate(v, options.get_cql_serialization_format());
|
||||
return make_shared<lists::value>(value::from_serialized(v, ltype, options.get_cql_serialization_format()));
|
||||
});
|
||||
} catch (marshal_exception& e) {
|
||||
throw exceptions::invalid_request_exception(
|
||||
format("Exception while binding column {:s}: {:s}", _receiver->name->to_cql_string(), e.what()));
|
||||
@@ -299,7 +308,9 @@ lists::setter_by_index::execute(mutation& m, const clustering_key_prefix& prefix
|
||||
return;
|
||||
}
|
||||
|
||||
auto idx = value_cast<int32_t>(data_type_for<int32_t>()->deserialize(*index));
|
||||
auto idx = with_linearized(*index, [] (bytes_view v) {
|
||||
return value_cast<int32_t>(data_type_for<int32_t>()->deserialize(v));
|
||||
});
|
||||
auto&& existing_list_opt = params.get_prefetched_list(m.key(), prefix, column);
|
||||
if (!existing_list_opt) {
|
||||
throw exceptions::invalid_request_exception("Attempted to set an element on a list which is null");
|
||||
|
||||
@@ -73,6 +73,7 @@ public:
|
||||
};
|
||||
|
||||
class value : public multi_item_terminal, collection_terminal {
|
||||
static value from_serialized(bytes_view v, const list_type_impl& type, cql_serialization_format sf);
|
||||
public:
|
||||
std::vector<bytes_opt> _elements;
|
||||
public:
|
||||
|
||||
30
cql3/maps.cc
30
cql3/maps.cc
@@ -55,14 +55,14 @@ lw_shared_ptr<column_specification>
|
||||
maps::key_spec_of(const column_specification& column) {
|
||||
return make_lw_shared<column_specification>(column.ks_name, column.cf_name,
|
||||
::make_shared<column_identifier>(format("key({})", *column.name), true),
|
||||
dynamic_cast<const map_type_impl&>(column.type->without_reversed()).get_keys_type());
|
||||
dynamic_pointer_cast<const map_type_impl>(column.type)->get_keys_type());
|
||||
}
|
||||
|
||||
lw_shared_ptr<column_specification>
|
||||
maps::value_spec_of(const column_specification& column) {
|
||||
return make_lw_shared<column_specification>(column.ks_name, column.cf_name,
|
||||
::make_shared<column_identifier>(format("value({})", *column.name), true),
|
||||
dynamic_cast<const map_type_impl&>(column.type->without_reversed()).get_values_type());
|
||||
dynamic_pointer_cast<const map_type_impl>(column.type)->get_values_type());
|
||||
}
|
||||
|
||||
::shared_ptr<term>
|
||||
@@ -88,9 +88,7 @@ maps::literal::prepare(database& db, const sstring& keyspace, lw_shared_ptr<colu
|
||||
|
||||
values.emplace(k, v);
|
||||
}
|
||||
delayed_value value(
|
||||
dynamic_cast<const map_type_impl&>(receiver->type->without_reversed()).get_keys_type()->as_less_comparator(),
|
||||
values);
|
||||
delayed_value value(static_pointer_cast<const map_type_impl>(receiver->type)->get_keys_type()->as_less_comparator(), values);
|
||||
if (all_terminal) {
|
||||
return value.bind(query_options::DEFAULT);
|
||||
} else {
|
||||
@@ -100,7 +98,7 @@ maps::literal::prepare(database& db, const sstring& keyspace, lw_shared_ptr<colu
|
||||
|
||||
void
|
||||
maps::literal::validate_assignable_to(database& db, const sstring& keyspace, const column_specification& receiver) const {
|
||||
if (!receiver.type->without_reversed().is_map()) {
|
||||
if (!dynamic_pointer_cast<const map_type_impl>(receiver.type)) {
|
||||
throw exceptions::invalid_request_exception(format("Invalid map literal for {} of type {}", *receiver.name, receiver.type->as_cql3_type()));
|
||||
}
|
||||
auto&& key_spec = maps::key_spec_of(receiver);
|
||||
@@ -160,13 +158,15 @@ maps::value::from_serialized(const fragmented_temporary_buffer::view& fragmented
|
||||
// Collections have this small hack that validate cannot be called on a serialized object,
|
||||
// but compose does the validation (so we're fine).
|
||||
// FIXME: deserialize_for_native_protocol?!
|
||||
auto m = value_cast<map_type_impl::native_type>(type.deserialize(fragmented_value, sf));
|
||||
return with_linearized(fragmented_value, [&] (bytes_view value) {
|
||||
auto m = value_cast<map_type_impl::native_type>(type.deserialize(value, sf));
|
||||
std::map<bytes, bytes, serialized_compare> map(type.get_keys_type()->as_less_comparator());
|
||||
for (auto&& e : m) {
|
||||
map.emplace(type.get_keys_type()->decompose(e.first),
|
||||
type.get_values_type()->decompose(e.second));
|
||||
}
|
||||
return maps::value { std::move(map) };
|
||||
});
|
||||
} catch (marshal_exception& e) {
|
||||
throw exceptions::invalid_request_exception(e.what());
|
||||
}
|
||||
@@ -263,16 +263,14 @@ maps::marker::bind(const query_options& options) {
|
||||
return constants::UNSET_VALUE;
|
||||
}
|
||||
try {
|
||||
_receiver->type->validate(*val, options.get_cql_serialization_format());
|
||||
with_linearized(*val, [&] (bytes_view value) {
|
||||
_receiver->type->validate(value, options.get_cql_serialization_format());
|
||||
});
|
||||
} catch (marshal_exception& e) {
|
||||
throw exceptions::invalid_request_exception(
|
||||
format("Exception while binding column {:s}: {:s}", _receiver->name->to_cql_string(), e.what()));
|
||||
}
|
||||
return ::make_shared<maps::value>(
|
||||
maps::value::from_serialized(
|
||||
*val,
|
||||
dynamic_cast<const map_type_impl&>(_receiver->type->without_reversed()),
|
||||
options.get_cql_serialization_format()));
|
||||
return ::make_shared<maps::value>(maps::value::from_serialized(*val, static_cast<const map_type_impl&>(*_receiver->type), options.get_cql_serialization_format()));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -307,12 +305,6 @@ maps::setter_by_key::execute(mutation& m, const clustering_key_prefix& prefix, c
|
||||
assert(column.type->is_multi_cell()); // "Attempted to set a value for a single key on a frozen map"m
|
||||
auto key = _k->bind_and_get(params._options);
|
||||
auto value = _t->bind_and_get(params._options);
|
||||
if (value.is_unset_value()) {
|
||||
return;
|
||||
}
|
||||
if (key.is_unset_value() || value.is_unset_value()) {
|
||||
throw invalid_request_exception("Invalid unset map key");
|
||||
}
|
||||
if (!key) {
|
||||
throw invalid_request_exception("Invalid null map key");
|
||||
}
|
||||
|
||||
@@ -42,22 +42,19 @@
|
||||
#include "cql3/cql_config.hh"
|
||||
#include "query_options.hh"
|
||||
#include "version.hh"
|
||||
#include "db/consistency_level_type.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
const cql_config default_cql_config;
|
||||
|
||||
thread_local const query_options::specific_options query_options::specific_options::DEFAULT{
|
||||
-1, {}, db::consistency_level::SERIAL, api::missing_timestamp};
|
||||
thread_local const query_options::specific_options query_options::specific_options::DEFAULT{-1, {}, {}, api::missing_timestamp};
|
||||
|
||||
thread_local query_options query_options::DEFAULT{default_cql_config,
|
||||
db::consistency_level::ONE, infinite_timeout_config, std::nullopt,
|
||||
db::consistency_level::ONE, std::nullopt,
|
||||
std::vector<cql3::raw_value_view>(), false, query_options::specific_options::DEFAULT, cql_serialization_format::latest()};
|
||||
|
||||
query_options::query_options(const cql_config& cfg,
|
||||
db::consistency_level consistency,
|
||||
const ::timeout_config& timeout_config,
|
||||
std::optional<std::vector<sstring_view>> names,
|
||||
std::vector<cql3::raw_value> values,
|
||||
std::vector<cql3::raw_value_view> value_views,
|
||||
@@ -66,7 +63,6 @@ query_options::query_options(const cql_config& cfg,
|
||||
cql_serialization_format sf)
|
||||
: _cql_config(cfg)
|
||||
, _consistency(consistency)
|
||||
, _timeout_config(timeout_config)
|
||||
, _names(std::move(names))
|
||||
, _values(std::move(values))
|
||||
, _value_views(value_views)
|
||||
@@ -78,7 +74,6 @@ query_options::query_options(const cql_config& cfg,
|
||||
|
||||
query_options::query_options(const cql_config& cfg,
|
||||
db::consistency_level consistency,
|
||||
const ::timeout_config& timeout_config,
|
||||
std::optional<std::vector<sstring_view>> names,
|
||||
std::vector<cql3::raw_value> values,
|
||||
bool skip_metadata,
|
||||
@@ -86,7 +81,6 @@ query_options::query_options(const cql_config& cfg,
|
||||
cql_serialization_format sf)
|
||||
: _cql_config(cfg)
|
||||
, _consistency(consistency)
|
||||
, _timeout_config(timeout_config)
|
||||
, _names(std::move(names))
|
||||
, _values(std::move(values))
|
||||
, _value_views()
|
||||
@@ -99,7 +93,6 @@ query_options::query_options(const cql_config& cfg,
|
||||
|
||||
query_options::query_options(const cql_config& cfg,
|
||||
db::consistency_level consistency,
|
||||
const ::timeout_config& timeout_config,
|
||||
std::optional<std::vector<sstring_view>> names,
|
||||
std::vector<cql3::raw_value_view> value_views,
|
||||
bool skip_metadata,
|
||||
@@ -107,7 +100,6 @@ query_options::query_options(const cql_config& cfg,
|
||||
cql_serialization_format sf)
|
||||
: _cql_config(cfg)
|
||||
, _consistency(consistency)
|
||||
, _timeout_config(timeout_config)
|
||||
, _names(std::move(names))
|
||||
, _values()
|
||||
, _value_views(std::move(value_views))
|
||||
@@ -117,12 +109,11 @@ query_options::query_options(const cql_config& cfg,
|
||||
{
|
||||
}
|
||||
|
||||
query_options::query_options(db::consistency_level cl, const ::timeout_config& timeout_config, std::vector<cql3::raw_value> values,
|
||||
query_options::query_options(db::consistency_level cl, std::vector<cql3::raw_value> values,
|
||||
specific_options options)
|
||||
: query_options(
|
||||
default_cql_config,
|
||||
cl,
|
||||
timeout_config,
|
||||
{},
|
||||
std::move(values),
|
||||
false,
|
||||
@@ -135,7 +126,6 @@ query_options::query_options(db::consistency_level cl, const ::timeout_config& t
|
||||
query_options::query_options(std::unique_ptr<query_options> qo, lw_shared_ptr<service::pager::paging_state> paging_state)
|
||||
: query_options(qo->_cql_config,
|
||||
qo->_consistency,
|
||||
qo->get_timeout_config(),
|
||||
std::move(qo->_names),
|
||||
std::move(qo->_values),
|
||||
std::move(qo->_value_views),
|
||||
@@ -148,7 +138,6 @@ query_options::query_options(std::unique_ptr<query_options> qo, lw_shared_ptr<se
|
||||
query_options::query_options(std::unique_ptr<query_options> qo, lw_shared_ptr<service::pager::paging_state> paging_state, int32_t page_size)
|
||||
: query_options(qo->_cql_config,
|
||||
qo->_consistency,
|
||||
qo->get_timeout_config(),
|
||||
std::move(qo->_names),
|
||||
std::move(qo->_values),
|
||||
std::move(qo->_value_views),
|
||||
@@ -160,7 +149,7 @@ query_options::query_options(std::unique_ptr<query_options> qo, lw_shared_ptr<se
|
||||
|
||||
query_options::query_options(std::vector<cql3::raw_value> values)
|
||||
: query_options(
|
||||
db::consistency_level::ONE, infinite_timeout_config, std::move(values))
|
||||
db::consistency_level::ONE, std::move(values))
|
||||
{}
|
||||
|
||||
void query_options::prepare(const std::vector<lw_shared_ptr<column_specification>>& specs)
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
#include "cql3/column_identifier.hh"
|
||||
#include "cql3/values.hh"
|
||||
#include "cql_serialization_format.hh"
|
||||
#include "timeout_config.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
@@ -75,7 +74,6 @@ public:
|
||||
private:
|
||||
const cql_config& _cql_config;
|
||||
const db::consistency_level _consistency;
|
||||
const timeout_config& _timeout_config;
|
||||
const std::optional<std::vector<sstring_view>> _names;
|
||||
std::vector<cql3::raw_value> _values;
|
||||
std::vector<cql3::raw_value_view> _value_views;
|
||||
@@ -109,7 +107,6 @@ public:
|
||||
|
||||
explicit query_options(const cql_config& cfg,
|
||||
db::consistency_level consistency,
|
||||
const timeout_config& timeouts,
|
||||
std::optional<std::vector<sstring_view>> names,
|
||||
std::vector<cql3::raw_value> values,
|
||||
bool skip_metadata,
|
||||
@@ -117,7 +114,6 @@ public:
|
||||
cql_serialization_format sf);
|
||||
explicit query_options(const cql_config& cfg,
|
||||
db::consistency_level consistency,
|
||||
const timeout_config& timeouts,
|
||||
std::optional<std::vector<sstring_view>> names,
|
||||
std::vector<cql3::raw_value> values,
|
||||
std::vector<cql3::raw_value_view> value_views,
|
||||
@@ -126,7 +122,6 @@ public:
|
||||
cql_serialization_format sf);
|
||||
explicit query_options(const cql_config& cfg,
|
||||
db::consistency_level consistency,
|
||||
const timeout_config& timeouts,
|
||||
std::optional<std::vector<sstring_view>> names,
|
||||
std::vector<cql3::raw_value_view> value_views,
|
||||
bool skip_metadata,
|
||||
@@ -158,13 +153,10 @@ public:
|
||||
|
||||
// forInternalUse
|
||||
explicit query_options(std::vector<cql3::raw_value> values);
|
||||
explicit query_options(db::consistency_level, const timeout_config& timeouts,
|
||||
std::vector<cql3::raw_value> values, specific_options options = specific_options::DEFAULT);
|
||||
explicit query_options(db::consistency_level, std::vector<cql3::raw_value> values, specific_options options = specific_options::DEFAULT);
|
||||
explicit query_options(std::unique_ptr<query_options>, lw_shared_ptr<service::pager::paging_state> paging_state);
|
||||
explicit query_options(std::unique_ptr<query_options>, lw_shared_ptr<service::pager::paging_state> paging_state, int32_t page_size);
|
||||
|
||||
const timeout_config& get_timeout_config() const { return _timeout_config; }
|
||||
|
||||
db::consistency_level get_consistency() const {
|
||||
return _consistency;
|
||||
}
|
||||
@@ -258,7 +250,7 @@ query_options::query_options(query_options&& o, std::vector<OneMutationDataRange
|
||||
std::vector<query_options> tmp;
|
||||
tmp.reserve(values_ranges.size());
|
||||
std::transform(values_ranges.begin(), values_ranges.end(), std::back_inserter(tmp), [this](auto& values_range) {
|
||||
return query_options(_cql_config, _consistency, _timeout_config, {}, std::move(values_range), _skip_metadata, _options, _cql_serialization_format);
|
||||
return query_options(_cql_config, _consistency, {}, std::move(values_range), _skip_metadata, _options, _cql_serialization_format);
|
||||
});
|
||||
_batch_options = std::move(tmp);
|
||||
}
|
||||
|
||||
@@ -619,7 +619,6 @@ query_options query_processor::make_internal_options(
|
||||
const statements::prepared_statement::checked_weak_ptr& p,
|
||||
const std::initializer_list<data_value>& values,
|
||||
db::consistency_level cl,
|
||||
const timeout_config& timeout_config,
|
||||
int32_t page_size) const {
|
||||
if (p->bound_names.size() != values.size()) {
|
||||
throw std::invalid_argument(
|
||||
@@ -643,11 +642,10 @@ query_options query_processor::make_internal_options(
|
||||
api::timestamp_type ts = api::missing_timestamp;
|
||||
return query_options(
|
||||
cl,
|
||||
timeout_config,
|
||||
bound_values,
|
||||
cql3::query_options::specific_options{page_size, std::move(paging_state), serial_consistency, ts});
|
||||
}
|
||||
return query_options(cl, timeout_config, bound_values);
|
||||
return query_options(cl, bound_values);
|
||||
}
|
||||
|
||||
statements::prepared_statement::checked_weak_ptr query_processor::prepare_internal(const sstring& query_string) {
|
||||
@@ -671,7 +669,7 @@ struct internal_query_state {
|
||||
::shared_ptr<internal_query_state> query_processor::create_paged_state(const sstring& query_string,
|
||||
const std::initializer_list<data_value>& values, int32_t page_size) {
|
||||
auto p = prepare_internal(query_string);
|
||||
auto opts = make_internal_options(p, values, db::consistency_level::ONE, infinite_timeout_config, page_size);
|
||||
auto opts = make_internal_options(p, values, db::consistency_level::ONE, page_size);
|
||||
::shared_ptr<internal_query_state> res = ::make_shared<internal_query_state>(
|
||||
internal_query_state{
|
||||
query_string,
|
||||
@@ -789,7 +787,16 @@ future<::shared_ptr<untyped_result_set>>
|
||||
query_processor::execute_internal(
|
||||
const sstring& query_string,
|
||||
db::consistency_level cl,
|
||||
const timeout_config& timeout_config,
|
||||
const std::initializer_list<data_value>& values,
|
||||
bool cache) {
|
||||
return execute_internal(query_string, cl, *_internal_state, values, cache);
|
||||
}
|
||||
|
||||
future<::shared_ptr<untyped_result_set>>
|
||||
query_processor::execute_internal(
|
||||
const sstring& query_string,
|
||||
db::consistency_level cl,
|
||||
service::query_state& query_state,
|
||||
const std::initializer_list<data_value>& values,
|
||||
bool cache) {
|
||||
|
||||
@@ -797,13 +804,13 @@ query_processor::execute_internal(
|
||||
log.trace("execute_internal: {}\"{}\" ({})", cache ? "(cached) " : "", query_string, ::join(", ", values));
|
||||
}
|
||||
if (cache) {
|
||||
return execute_with_params(prepare_internal(query_string), cl, timeout_config, values);
|
||||
return execute_with_params(prepare_internal(query_string), cl, query_state, values);
|
||||
} else {
|
||||
auto p = parse_statement(query_string)->prepare(_db, _cql_stats);
|
||||
p->statement->raw_cql_statement = query_string;
|
||||
p->statement->validate(_proxy, *_internal_state);
|
||||
auto checked_weak_ptr = p->checked_weak_from_this();
|
||||
return execute_with_params(std::move(checked_weak_ptr), cl, timeout_config, values).finally([p = std::move(p)] {});
|
||||
return execute_with_params(std::move(checked_weak_ptr), cl, query_state, values).finally([p = std::move(p)] {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -811,11 +818,11 @@ future<::shared_ptr<untyped_result_set>>
|
||||
query_processor::execute_with_params(
|
||||
statements::prepared_statement::checked_weak_ptr p,
|
||||
db::consistency_level cl,
|
||||
const timeout_config& timeout_config,
|
||||
service::query_state& query_state,
|
||||
const std::initializer_list<data_value>& values) {
|
||||
auto opts = make_internal_options(p, values, cl, timeout_config);
|
||||
return do_with(std::move(opts), [this, p = std::move(p)](auto & opts) {
|
||||
return p->statement->execute(_proxy, *_internal_state, opts).then([](auto msg) {
|
||||
auto opts = make_internal_options(p, values, cl);
|
||||
return do_with(std::move(opts), [this, &query_state, p = std::move(p)](auto & opts) {
|
||||
return p->statement->execute(_proxy, query_state, opts).then([](auto msg) {
|
||||
return make_ready_future<::shared_ptr<untyped_result_set>>(::make_shared<untyped_result_set>(msg));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -215,8 +215,7 @@ public:
|
||||
// creating namespaces, etc) is explicitly forbidden via this interface.
|
||||
future<::shared_ptr<untyped_result_set>>
|
||||
execute_internal(const sstring& query_string, const std::initializer_list<data_value>& values = { }) {
|
||||
return execute_internal(query_string, db::consistency_level::ONE,
|
||||
infinite_timeout_config, values, true);
|
||||
return execute_internal(query_string, db::consistency_level::ONE, values, true);
|
||||
}
|
||||
|
||||
statements::prepared_statement::checked_weak_ptr prepare_internal(const sstring& query);
|
||||
@@ -305,14 +304,19 @@ public:
|
||||
future<::shared_ptr<untyped_result_set>> execute_internal(
|
||||
const sstring& query_string,
|
||||
db::consistency_level,
|
||||
const timeout_config& timeout_config,
|
||||
const std::initializer_list<data_value>& = { },
|
||||
bool cache = false);
|
||||
future<::shared_ptr<untyped_result_set>> execute_internal(
|
||||
const sstring& query_string,
|
||||
db::consistency_level,
|
||||
service::query_state& query_state,
|
||||
const std::initializer_list<data_value>& = { },
|
||||
bool cache = false);
|
||||
|
||||
future<::shared_ptr<untyped_result_set>> execute_with_params(
|
||||
statements::prepared_statement::checked_weak_ptr p,
|
||||
db::consistency_level,
|
||||
const timeout_config& timeout_config,
|
||||
service::query_state& query_state,
|
||||
const std::initializer_list<data_value>& = { });
|
||||
|
||||
future<::shared_ptr<cql_transport::messages::result_message::prepared>>
|
||||
@@ -341,7 +345,6 @@ private:
|
||||
const statements::prepared_statement::checked_weak_ptr& p,
|
||||
const std::initializer_list<data_value>&,
|
||||
db::consistency_level,
|
||||
const timeout_config& timeout_config,
|
||||
int32_t page_size = -1) const;
|
||||
|
||||
future<::shared_ptr<cql_transport::messages::result_message>>
|
||||
|
||||
@@ -171,7 +171,8 @@ public:
|
||||
|
||||
virtual void merge_with(::shared_ptr<restriction> restriction) override {
|
||||
if (find_atom(restriction->expression, [] (const expr::binary_operator& b) {
|
||||
return std::holds_alternative<std::vector<expr::column_value>>(b.lhs);
|
||||
return std::holds_alternative<std::vector<expr::column_value>>(b.lhs)
|
||||
&& std::get<std::vector<expr::column_value>>(b.lhs).size() > 1;
|
||||
})) {
|
||||
throw exceptions::invalid_request_exception(
|
||||
"Mixing single column relations and multi column relations on clustering columns is not allowed");
|
||||
@@ -212,22 +213,30 @@ private:
|
||||
std::vector<range_type> compute_bounds(const query_options& options) const {
|
||||
std::vector<range_type> ranges;
|
||||
|
||||
static constexpr auto invalid_null_msg = std::is_same<ValueType, partition_key>::value
|
||||
? "Invalid null value for partition key part %s" : "Invalid null value for clustering key part %s";
|
||||
|
||||
// TODO: rewrite this to simply invoke possible_lhs_values on each clustering column, find the first
|
||||
// non-list, and take Cartesian product of that prefix. No need for to_range() and std::get() here.
|
||||
if (_restrictions->is_all_eq()) {
|
||||
if (_restrictions->size() == 1) {
|
||||
auto&& e = *restrictions().begin();
|
||||
const auto b = std::get<expr::binary_operator>(e.second->expression).rhs->bind_and_get(options);
|
||||
if (!b) {
|
||||
throw exceptions::invalid_request_exception(sprint(invalid_null_msg, e.first->name_as_text()));
|
||||
}
|
||||
return {range_type::make_singular(ValueType::from_single_value(*_schema, to_bytes(b)))};
|
||||
}
|
||||
std::vector<bytes> components;
|
||||
components.reserve(_restrictions->size());
|
||||
for (auto&& e : restrictions()) {
|
||||
const column_definition* def = e.first;
|
||||
assert(components.size() == _schema->position(*def));
|
||||
// Because _restrictions is all EQ, possible_lhs_values must return a list, not a range.
|
||||
const auto b = std::get<expr::value_list>(possible_lhs_values(e.first, e.second->expression, options));
|
||||
// Furthermore, this list is either a single element (when all RHSs are the same) or empty (when at
|
||||
// least two are different, so the restrictions cannot hold simultaneously -- ie, c=1 AND c=2).
|
||||
if (b.empty()) {
|
||||
return {};
|
||||
const auto b = std::get<expr::binary_operator>(e.second->expression).rhs->bind_and_get(options);
|
||||
if (!b) {
|
||||
throw exceptions::invalid_request_exception(sprint(invalid_null_msg, e.first->name_as_text()));
|
||||
}
|
||||
components.emplace_back(b.front());
|
||||
components.emplace_back(to_bytes(b));
|
||||
}
|
||||
return {range_type::make_singular(ValueType::from_exploded(*_schema, std::move(components)))};
|
||||
}
|
||||
@@ -315,7 +324,7 @@ public:
|
||||
std::vector<bytes_opt> res;
|
||||
for (const ValueType& r : src) {
|
||||
for (const auto& component : r.components()) {
|
||||
res.emplace_back(to_bytes(component));
|
||||
res.emplace_back(component);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
||||
@@ -108,9 +108,6 @@ public:
|
||||
return bytes_opt{};
|
||||
} else {
|
||||
const auto values = std::get<expr::value_list>(possible_lhs_values(&cdef, it->second->expression, options));
|
||||
if (values.empty()) {
|
||||
return bytes_opt{};
|
||||
}
|
||||
assert(values.size() == 1);
|
||||
return values.front();
|
||||
}
|
||||
@@ -122,7 +119,7 @@ public:
|
||||
* @param column_def the column definition
|
||||
* @return the restriction associated to the specified column
|
||||
*/
|
||||
::shared_ptr<single_column_restriction> get_restriction(const column_definition& column_def) const {
|
||||
::shared_ptr<restriction> get_restriction(const column_definition& column_def) const {
|
||||
auto i = _restrictions.find(&column_def);
|
||||
if (i == _restrictions.end()) {
|
||||
return {};
|
||||
|
||||
@@ -147,6 +147,7 @@ statement_restrictions::statement_restrictions(database& db,
|
||||
const std::vector<::shared_ptr<relation>>& where_clause,
|
||||
variable_specifications& bound_names,
|
||||
bool selects_only_static_columns,
|
||||
bool select_a_collection,
|
||||
bool for_view,
|
||||
bool allow_filtering)
|
||||
: statement_restrictions(schema, allow_filtering)
|
||||
@@ -226,11 +227,10 @@ statement_restrictions::statement_restrictions(database& db,
|
||||
}
|
||||
}
|
||||
|
||||
process_clustering_columns_restrictions(for_view, allow_filtering);
|
||||
process_clustering_columns_restrictions(select_a_collection, for_view, allow_filtering);
|
||||
|
||||
// Covers indexes on the first clustering column (among others).
|
||||
if (_is_key_range && _has_queriable_ck_index &&
|
||||
!dynamic_pointer_cast<multi_column_restriction>(_clustering_columns_restrictions)) {
|
||||
if (_is_key_range && _has_queriable_ck_index) {
|
||||
_uses_secondary_indexing = true;
|
||||
}
|
||||
|
||||
@@ -329,39 +329,20 @@ int statement_restrictions::score(const secondary_index::index& index) const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace cql3::restrictions;
|
||||
|
||||
/// If rs contains a restrictions_map of individual columns to their restrictions, returns it. Otherwise, returns null.
|
||||
const single_column_restrictions::restrictions_map* get_individual_restrictions_map(const restrictions* rs) {
|
||||
if (auto regular = dynamic_cast<const single_column_restrictions*>(rs)) {
|
||||
return ®ular->restrictions();
|
||||
} else if (auto partition = dynamic_cast<const single_column_partition_key_restrictions*>(rs)) {
|
||||
return &partition->restrictions();
|
||||
} else if (auto clustering = dynamic_cast<const single_column_clustering_key_restrictions*>(rs)) {
|
||||
return &clustering->restrictions();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
std::pair<std::optional<secondary_index::index>, ::shared_ptr<cql3::restrictions::restrictions>> statement_restrictions::find_idx(secondary_index::secondary_index_manager& sim) const {
|
||||
std::optional<secondary_index::index> chosen_index;
|
||||
int chosen_index_score = 0;
|
||||
::shared_ptr<cql3::restrictions::restrictions> chosen_index_restrictions;
|
||||
|
||||
for (const auto& index : sim.list_indexes()) {
|
||||
auto cdef = _schema->get_column_definition(to_bytes(index.target_column()));
|
||||
for (::shared_ptr<cql3::restrictions::restrictions> restriction : index_restrictions()) {
|
||||
if (auto rmap = get_individual_restrictions_map(restriction.get())) {
|
||||
const auto found = rmap->find(cdef);
|
||||
if (found != rmap->end() && is_supported_by(found->second->expression, index)
|
||||
&& score(index) > chosen_index_score) {
|
||||
chosen_index = index;
|
||||
chosen_index_score = score(index);
|
||||
chosen_index_restrictions = restriction;
|
||||
for (const auto& cdef : restriction->get_column_defs()) {
|
||||
if (index.depends_on(*cdef)) {
|
||||
if (score(index) > chosen_index_score) {
|
||||
chosen_index = index;
|
||||
chosen_index_score = score(index);
|
||||
chosen_index_restrictions = restriction;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -454,11 +435,15 @@ bool statement_restrictions::has_unrestricted_clustering_columns() const {
|
||||
return _clustering_columns_restrictions->has_unrestricted_components(*_schema);
|
||||
}
|
||||
|
||||
void statement_restrictions::process_clustering_columns_restrictions(bool for_view, bool allow_filtering) {
|
||||
void statement_restrictions::process_clustering_columns_restrictions(bool select_a_collection, bool for_view, bool allow_filtering) {
|
||||
if (!has_clustering_columns_restriction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clustering_key_restrictions_has_IN() && select_a_collection) {
|
||||
throw exceptions::invalid_request_exception(
|
||||
"Cannot restrict clustering columns by IN relations when a collection is selected by the query");
|
||||
}
|
||||
if (find_atom(_clustering_columns_restrictions->expression, expr::is_on_collection)
|
||||
&& !_has_queriable_ck_index && !allow_filtering) {
|
||||
throw exceptions::invalid_request_exception(
|
||||
|
||||
@@ -119,6 +119,7 @@ public:
|
||||
const std::vector<::shared_ptr<relation>>& where_clause,
|
||||
variable_specifications& bound_names,
|
||||
bool selects_only_static_columns,
|
||||
bool select_a_collection,
|
||||
bool for_view = false,
|
||||
bool allow_filtering = false);
|
||||
|
||||
@@ -216,9 +217,10 @@ private:
|
||||
* Processes the clustering column restrictions.
|
||||
*
|
||||
* @param has_queriable_index <code>true</code> if some of the queried data are indexed, <code>false</code> otherwise
|
||||
* @param select_a_collection <code>true</code> if the query should return a collection column
|
||||
* @throws InvalidRequestException if the request is invalid
|
||||
*/
|
||||
void process_clustering_columns_restrictions(bool for_view, bool allow_filtering);
|
||||
void process_clustering_columns_restrictions(bool select_a_collection, bool for_view, bool allow_filtering);
|
||||
|
||||
/**
|
||||
* Returns the <code>Restrictions</code> for the specified type of columns.
|
||||
|
||||
@@ -140,6 +140,21 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this selection contains a collection.
|
||||
*
|
||||
* @return <code>true</code> if this selection contains a collection, <code>false</code> otherwise.
|
||||
*/
|
||||
bool contains_a_collection() const {
|
||||
if (!_schema->has_multi_cell_collections()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::any_of(_columns.begin(), _columns.end(), [] (auto&& def) {
|
||||
return def->type->is_collection() && def->type->is_multi_cell();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the specified column.
|
||||
*
|
||||
|
||||
33
cql3/sets.cc
33
cql3/sets.cc
@@ -31,7 +31,7 @@ lw_shared_ptr<column_specification>
|
||||
sets::value_spec_of(const column_specification& column) {
|
||||
return make_lw_shared<column_specification>(column.ks_name, column.cf_name,
|
||||
::make_shared<column_identifier>(format("value({})", *column.name), true),
|
||||
dynamic_cast<const set_type_impl&>(column.type->without_reversed()).get_elements_type());
|
||||
dynamic_pointer_cast<const set_type_impl>(column.type)->get_elements_type());
|
||||
}
|
||||
|
||||
shared_ptr<term>
|
||||
@@ -74,8 +74,7 @@ sets::literal::prepare(database& db, const sstring& keyspace, lw_shared_ptr<colu
|
||||
|
||||
values.push_back(std::move(t));
|
||||
}
|
||||
auto compare = dynamic_cast<const set_type_impl&>(receiver->type->without_reversed())
|
||||
.get_elements_type()->as_less_comparator();
|
||||
auto compare = dynamic_pointer_cast<const set_type_impl>(receiver->type)->get_elements_type()->as_less_comparator();
|
||||
|
||||
auto value = ::make_shared<delayed_value>(compare, std::move(values));
|
||||
if (all_terminal) {
|
||||
@@ -87,7 +86,7 @@ sets::literal::prepare(database& db, const sstring& keyspace, lw_shared_ptr<colu
|
||||
|
||||
void
|
||||
sets::literal::validate_assignable_to(database& db, const sstring& keyspace, const column_specification& receiver) const {
|
||||
if (!receiver.type->without_reversed().is_set()) {
|
||||
if (!dynamic_pointer_cast<const set_type_impl>(receiver.type)) {
|
||||
// We've parsed empty maps as a set literal to break the ambiguity so
|
||||
// handle that case now
|
||||
if (dynamic_pointer_cast<const map_type_impl>(receiver.type) && _elements.empty()) {
|
||||
@@ -107,7 +106,7 @@ sets::literal::validate_assignable_to(database& db, const sstring& keyspace, con
|
||||
|
||||
assignment_testable::test_result
|
||||
sets::literal::test_assignment(database& db, const sstring& keyspace, const column_specification& receiver) const {
|
||||
if (!receiver.type->without_reversed().is_set()) {
|
||||
if (!dynamic_pointer_cast<const set_type_impl>(receiver.type)) {
|
||||
// We've parsed empty maps as a set literal to break the ambiguity so handle that case now
|
||||
if (dynamic_pointer_cast<const map_type_impl>(receiver.type) && _elements.empty()) {
|
||||
return assignment_testable::test_result::WEAKLY_ASSIGNABLE;
|
||||
@@ -138,12 +137,14 @@ sets::value::from_serialized(const fragmented_temporary_buffer::view& val, const
|
||||
// Collections have this small hack that validate cannot be called on a serialized object,
|
||||
// but compose does the validation (so we're fine).
|
||||
// FIXME: deserializeForNativeProtocol?!
|
||||
auto s = value_cast<set_type_impl::native_type>(type.deserialize(val, sf));
|
||||
return with_linearized(val, [&] (bytes_view v) {
|
||||
auto s = value_cast<set_type_impl::native_type>(type.deserialize(v, sf));
|
||||
std::set<bytes, serialized_compare> elements(type.get_elements_type()->as_less_comparator());
|
||||
for (auto&& element : s) {
|
||||
elements.insert(elements.end(), type.get_elements_type()->decompose(element));
|
||||
}
|
||||
return value(std::move(elements));
|
||||
});
|
||||
} catch (marshal_exception& e) {
|
||||
throw exceptions::invalid_request_exception(e.what());
|
||||
}
|
||||
@@ -225,11 +226,8 @@ sets::delayed_value::bind(const query_options& options) {
|
||||
|
||||
sets::marker::marker(int32_t bind_index, lw_shared_ptr<column_specification> receiver)
|
||||
: abstract_marker{bind_index, std::move(receiver)} {
|
||||
if (!_receiver->type->without_reversed().is_set()) {
|
||||
throw std::runtime_error(format("Receiver {} for set marker has wrong type: {}",
|
||||
_receiver->cf_name, _receiver->type->name()));
|
||||
assert(dynamic_cast<const set_type_impl*>(_receiver->type.get()));
|
||||
}
|
||||
}
|
||||
|
||||
::shared_ptr<terminal>
|
||||
sets::marker::bind(const query_options& options) {
|
||||
@@ -239,9 +237,11 @@ sets::marker::bind(const query_options& options) {
|
||||
} else if (value.is_unset_value()) {
|
||||
return constants::UNSET_VALUE;
|
||||
} else {
|
||||
auto& type = dynamic_cast<const set_type_impl&>(_receiver->type->without_reversed());
|
||||
auto& type = static_cast<const set_type_impl&>(*_receiver->type);
|
||||
try {
|
||||
type.validate(*value, options.get_cql_serialization_format());
|
||||
with_linearized(*value, [&] (bytes_view v) {
|
||||
type.validate(v, options.get_cql_serialization_format());
|
||||
});
|
||||
} catch (marshal_exception& e) {
|
||||
throw exceptions::invalid_request_exception(
|
||||
format("Exception while binding column {:s}: {:s}", _receiver->name->to_cql_string(), e.what()));
|
||||
@@ -284,7 +284,8 @@ void
|
||||
sets::adder::do_add(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params,
|
||||
shared_ptr<term> value, const column_definition& column) {
|
||||
auto set_value = dynamic_pointer_cast<sets::value>(std::move(value));
|
||||
auto& set_type = dynamic_cast<const set_type_impl&>(column.type->without_reversed());
|
||||
auto set_type = dynamic_cast<const set_type_impl*>(column.type.get());
|
||||
assert(set_type);
|
||||
if (column.type->is_multi_cell()) {
|
||||
if (!set_value || set_value->_elements.empty()) {
|
||||
return;
|
||||
@@ -294,10 +295,10 @@ sets::adder::do_add(mutation& m, const clustering_key_prefix& row_key, const upd
|
||||
collection_mutation_description mut;
|
||||
|
||||
for (auto&& e : set_value->_elements) {
|
||||
mut.cells.emplace_back(e, params.make_cell(*set_type.value_comparator(), bytes_view(), atomic_cell::collection_member::yes));
|
||||
mut.cells.emplace_back(e, params.make_cell(*set_type->value_comparator(), bytes_view(), atomic_cell::collection_member::yes));
|
||||
}
|
||||
|
||||
m.set_cell(row_key, column, mut.serialize(set_type));
|
||||
m.set_cell(row_key, column, mut.serialize(*set_type));
|
||||
} else if (set_value != nullptr) {
|
||||
// for frozen sets, we're overwriting the whole cell
|
||||
auto v = set_type_impl::serialize_partially_deserialized_form(
|
||||
@@ -314,7 +315,7 @@ sets::discarder::execute(mutation& m, const clustering_key_prefix& row_key, cons
|
||||
assert(column.type->is_multi_cell()); // "Attempted to remove items from a frozen set";
|
||||
|
||||
auto&& value = _t->bind(params._options);
|
||||
if (!value || value == constants::UNSET_VALUE) {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#include "db/system_keyspace.hh"
|
||||
#include "database.hh"
|
||||
|
||||
bool is_system_keyspace(std::string_view keyspace);
|
||||
bool is_system_keyspace(const sstring& keyspace);
|
||||
|
||||
cql3::statements::alter_keyspace_statement::alter_keyspace_statement(sstring name, ::shared_ptr<ks_prop_defs> attrs)
|
||||
: _name(name)
|
||||
@@ -91,10 +91,10 @@ void cql3::statements::alter_keyspace_statement::validate(service::storage_proxy
|
||||
}
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> cql3::statements::alter_keyspace_statement::announce_migration(service::storage_proxy& proxy) const {
|
||||
future<shared_ptr<cql_transport::event::schema_change>> cql3::statements::alter_keyspace_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const {
|
||||
auto old_ksm = proxy.get_db().local().find_keyspace(_name).metadata();
|
||||
const auto& tm = *proxy.get_token_metadata_ptr();
|
||||
return service::get_local_migration_manager().announce_keyspace_update(_attrs->as_ks_metadata_update(old_ksm, tm)).then([this] {
|
||||
return service::get_local_migration_manager().announce_keyspace_update(_attrs->as_ks_metadata_update(old_ksm, tm), is_local_only).then([this] {
|
||||
using namespace cql_transport;
|
||||
return ::make_shared<event::schema_change>(
|
||||
event::schema_change::change_type::UPDATED,
|
||||
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
|
||||
future<> check_access(service::storage_proxy& proxy, const service::client_state& state) const override;
|
||||
void validate(service::storage_proxy& proxy, const service::client_state& state) const override;
|
||||
future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
};
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ alter_table_statement::alter_table_statement(shared_ptr<cf_name> name,
|
||||
|
||||
future<> alter_table_statement::check_access(service::storage_proxy& proxy, const service::client_state& state) const {
|
||||
using cdt = auth::command_desc::type;
|
||||
return state.has_column_family_access(proxy.local_db(), keyspace(), column_family(), auth::permission::ALTER,
|
||||
return state.has_column_family_access(keyspace(), column_family(), auth::permission::ALTER,
|
||||
_type == type::opts ? cdt::ALTER_WITH_OPTS : cdt::OTHER);
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ void alter_table_statement::drop_column(const schema& schema, const table& cf, s
|
||||
}
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> alter_table_statement::announce_migration(service::storage_proxy& proxy) const
|
||||
future<shared_ptr<cql_transport::event::schema_change>> alter_table_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const
|
||||
{
|
||||
auto& db = proxy.get_db().local();
|
||||
auto s = validation::validate_column_family(db, keyspace(), column_family());
|
||||
@@ -396,7 +396,7 @@ future<shared_ptr<cql_transport::event::schema_change>> alter_table_statement::a
|
||||
break;
|
||||
}
|
||||
|
||||
return service::get_local_migration_manager().announce_column_family_update(cfm.build(), false, std::move(view_updates))
|
||||
return service::get_local_migration_manager().announce_column_family_update(cfm.build(), false, std::move(view_updates), is_local_only)
|
||||
.then([this] {
|
||||
using namespace cql_transport;
|
||||
return ::make_shared<event::schema_change>(
|
||||
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
|
||||
virtual future<> check_access(service::storage_proxy& proxy, const service::client_state& state) const override;
|
||||
virtual void validate(service::storage_proxy& proxy, const service::client_state& state) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
private:
|
||||
void add_column(const schema& schema, const table& cf, schema_builder& cfm, std::vector<view_ptr>& view_updates, const column_identifier& column_name, const cql3_type validator, const column_definition* def, bool is_static) const;
|
||||
|
||||
@@ -78,7 +78,7 @@ const sstring& alter_type_statement::keyspace() const
|
||||
return _name.get_keyspace();
|
||||
}
|
||||
|
||||
void alter_type_statement::do_announce_migration(database& db, ::keyspace& ks) const
|
||||
void alter_type_statement::do_announce_migration(database& db, ::keyspace& ks, bool is_local_only) const
|
||||
{
|
||||
auto&& all_types = ks.metadata()->user_types().get_all_types();
|
||||
auto to_update = all_types.find(_name.get_user_type_name());
|
||||
@@ -100,7 +100,7 @@ void alter_type_statement::do_announce_migration(database& db, ::keyspace& ks) c
|
||||
|
||||
// Now, we need to announce the type update to basically change it for new tables using this type,
|
||||
// but we also need to find all existing user types and CF using it and change them.
|
||||
service::get_local_migration_manager().announce_type_update(updated).get();
|
||||
service::get_local_migration_manager().announce_type_update(updated, is_local_only).get();
|
||||
|
||||
for (auto&& schema : ks.metadata()->cf_meta_data() | boost::adaptors::map_values) {
|
||||
auto cfm = schema_builder(schema);
|
||||
@@ -115,21 +115,21 @@ void alter_type_statement::do_announce_migration(database& db, ::keyspace& ks) c
|
||||
}
|
||||
if (modified) {
|
||||
if (schema->is_view()) {
|
||||
service::get_local_migration_manager().announce_view_update(view_ptr(cfm.build())).get();
|
||||
service::get_local_migration_manager().announce_view_update(view_ptr(cfm.build()), is_local_only).get();
|
||||
} else {
|
||||
service::get_local_migration_manager().announce_column_family_update(cfm.build(), false, {}).get();
|
||||
service::get_local_migration_manager().announce_column_family_update(cfm.build(), false, {}, is_local_only).get();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> alter_type_statement::announce_migration(service::storage_proxy& proxy) const
|
||||
future<shared_ptr<cql_transport::event::schema_change>> alter_type_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const
|
||||
{
|
||||
return seastar::async([this, &proxy] {
|
||||
return seastar::async([this, &proxy, is_local_only] {
|
||||
auto&& db = proxy.get_db().local();
|
||||
try {
|
||||
auto&& ks = db.find_keyspace(keyspace());
|
||||
do_announce_migration(db, ks);
|
||||
do_announce_migration(db, ks, is_local_only);
|
||||
using namespace cql_transport;
|
||||
return ::make_shared<event::schema_change>(
|
||||
event::schema_change::change_type::UPDATED,
|
||||
|
||||
@@ -63,14 +63,14 @@ public:
|
||||
|
||||
virtual const sstring& keyspace() const override;
|
||||
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
|
||||
class add_or_alter;
|
||||
class renames;
|
||||
protected:
|
||||
virtual user_type make_updated_type(database& db, user_type to_update) const = 0;
|
||||
private:
|
||||
void do_announce_migration(database& db, ::keyspace& ks) const;
|
||||
void do_announce_migration(database& db, ::keyspace& ks, bool is_local_only) const;
|
||||
};
|
||||
|
||||
class alter_type_statement::add_or_alter : public alter_type_statement {
|
||||
|
||||
@@ -60,10 +60,9 @@ alter_view_statement::alter_view_statement(::shared_ptr<cf_name> view_name, ::sh
|
||||
future<> alter_view_statement::check_access(service::storage_proxy& proxy, const service::client_state& state) const
|
||||
{
|
||||
try {
|
||||
const database& db = proxy.local_db();
|
||||
auto&& s = db.find_schema(keyspace(), column_family());
|
||||
auto&& s = proxy.get_db().local().find_schema(keyspace(), column_family());
|
||||
if (s->is_view()) {
|
||||
return state.has_column_family_access(db, keyspace(), s->view_info()->base_name(), auth::permission::ALTER);
|
||||
return state.has_column_family_access(keyspace(), s->view_info()->base_name(), auth::permission::ALTER);
|
||||
}
|
||||
} catch (const no_such_column_family& e) {
|
||||
// Will be validated afterwards.
|
||||
@@ -76,7 +75,7 @@ void alter_view_statement::validate(service::storage_proxy&, const service::clie
|
||||
// validated in announce_migration()
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> alter_view_statement::announce_migration(service::storage_proxy& proxy) const
|
||||
future<shared_ptr<cql_transport::event::schema_change>> alter_view_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const
|
||||
{
|
||||
auto&& db = proxy.get_db().local();
|
||||
schema_ptr schema = validation::validate_column_family(db, keyspace(), column_family());
|
||||
@@ -108,7 +107,7 @@ future<shared_ptr<cql_transport::event::schema_change>> alter_view_statement::an
|
||||
"the corresponding data in the parent table.");
|
||||
}
|
||||
|
||||
return service::get_local_migration_manager().announce_view_update(view_ptr(builder.build())).then([this] {
|
||||
return service::get_local_migration_manager().announce_view_update(view_ptr(builder.build()), is_local_only).then([this] {
|
||||
using namespace cql_transport;
|
||||
|
||||
return ::make_shared<event::schema_change>(
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
|
||||
virtual void validate(service::storage_proxy&, const service::client_state& state) const override;
|
||||
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
};
|
||||
|
||||
@@ -59,10 +59,6 @@ timeout_for_type(batch_statement::type t) {
|
||||
: &timeout_config::write_timeout;
|
||||
}
|
||||
|
||||
db::timeout_clock::duration batch_statement::get_timeout(const query_options& options) const {
|
||||
return _attrs->is_timeout_set() ? _attrs->get_timeout(options) : options.get_timeout_config().*get_timeout_config_selector();
|
||||
}
|
||||
|
||||
batch_statement::batch_statement(int bound_terms, type type_,
|
||||
std::vector<single_statement> statements,
|
||||
std::unique_ptr<attributes> attrs,
|
||||
@@ -290,7 +286,7 @@ future<shared_ptr<cql_transport::messages::result_message>> batch_statement::do_
|
||||
++_stats.batches;
|
||||
_stats.statements_in_batches += _statements.size();
|
||||
|
||||
auto timeout = db::timeout_clock::now() + get_timeout(options);
|
||||
auto timeout = db::timeout_clock::now() + query_state.get_client_state().get_timeout_config().*get_timeout_config_selector();
|
||||
return get_mutations(storage, options, timeout, local, now, query_state).then([this, &storage, &options, timeout, tr_state = query_state.get_trace_state(),
|
||||
permit = query_state.get_permit()] (std::vector<mutation> ms) mutable {
|
||||
return execute_without_conditions(storage, std::move(ms), options.get_consistency(), timeout, std::move(tr_state), std::move(permit));
|
||||
@@ -347,7 +343,7 @@ future<shared_ptr<cql_transport::messages::result_message>> batch_statement::exe
|
||||
schema_ptr schema;
|
||||
|
||||
db::timeout_clock::time_point now = db::timeout_clock::now();
|
||||
const timeout_config& cfg = options.get_timeout_config();
|
||||
const timeout_config& cfg = qs.get_client_state().get_timeout_config();
|
||||
auto batch_timeout = now + cfg.write_timeout; // Statement timeout.
|
||||
auto cas_timeout = now + cfg.cas_timeout; // Ballot contention timeout.
|
||||
auto read_timeout = now + cfg.read_timeout; // Query timeout.
|
||||
|
||||
@@ -170,8 +170,6 @@ private:
|
||||
service::storage_proxy& storage,
|
||||
const query_options& options,
|
||||
service::query_state& state) const;
|
||||
|
||||
db::timeout_clock::duration get_timeout(const query_options& options) const;
|
||||
public:
|
||||
// FIXME: no cql_statement::to_string() yet
|
||||
#if 0
|
||||
|
||||
@@ -157,7 +157,6 @@ void cf_prop_defs::validate(const database& db, const schema::extensions_map& sc
|
||||
}
|
||||
|
||||
validate_minimum_int(KW_DEFAULT_TIME_TO_LIVE, 0, DEFAULT_DEFAULT_TIME_TO_LIVE);
|
||||
validate_minimum_int(KW_PAXOSGRACESECONDS, 0, DEFAULT_GC_GRACE_SECONDS);
|
||||
|
||||
auto min_index_interval = get_int(KW_MIN_INDEX_INTERVAL, DEFAULT_MIN_INDEX_INTERVAL);
|
||||
auto max_index_interval = get_int(KW_MAX_INDEX_INTERVAL, DEFAULT_MAX_INDEX_INTERVAL);
|
||||
|
||||
@@ -59,11 +59,11 @@ std::unique_ptr<prepared_statement> create_function_statement::prepare(database&
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> create_function_statement::announce_migration(
|
||||
service::storage_proxy& proxy) const {
|
||||
service::storage_proxy& proxy, bool is_local_only) const {
|
||||
if (!_func) {
|
||||
return make_ready_future<::shared_ptr<cql_transport::event::schema_change>>();
|
||||
}
|
||||
return service::get_local_migration_manager().announce_new_function(_func).then([this] {
|
||||
return service::get_local_migration_manager().announce_new_function(_func, is_local_only).then([this] {
|
||||
return create_schema_change(*_func, true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace statements {
|
||||
class create_function_statement final : public create_function_statement_base {
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(
|
||||
service::storage_proxy& proxy) const override;
|
||||
service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
virtual void create(service::storage_proxy& proxy, functions::function* old) const override;
|
||||
sstring _language;
|
||||
sstring _body;
|
||||
|
||||
@@ -73,7 +73,7 @@ create_index_statement::create_index_statement(::shared_ptr<cf_name> name,
|
||||
|
||||
future<>
|
||||
create_index_statement::check_access(service::storage_proxy& proxy, const service::client_state& state) const {
|
||||
return state.has_column_family_access(proxy.local_db(), keyspace(), column_family(), auth::permission::ALTER);
|
||||
return state.has_column_family_access(keyspace(), column_family(), auth::permission::ALTER);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -271,7 +271,7 @@ void create_index_statement::validate_targets_for_multi_column_index(std::vector
|
||||
}
|
||||
|
||||
future<::shared_ptr<cql_transport::event::schema_change>>
|
||||
create_index_statement::announce_migration(service::storage_proxy& proxy) const {
|
||||
create_index_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const {
|
||||
auto& db = proxy.get_db().local();
|
||||
auto schema = db.find_schema(keyspace(), column_family());
|
||||
std::vector<::shared_ptr<index_target>> targets;
|
||||
@@ -310,7 +310,7 @@ create_index_statement::announce_migration(service::storage_proxy& proxy) const
|
||||
schema_builder builder{schema};
|
||||
builder.with_index(index);
|
||||
return service::get_local_migration_manager().announce_column_family_update(
|
||||
builder.build(), false, {}).then([this]() {
|
||||
builder.build(), false, {}, is_local_only).then([this]() {
|
||||
using namespace cql_transport;
|
||||
return ::make_shared<event::schema_change>(
|
||||
event::schema_change::change_type::UPDATED,
|
||||
|
||||
@@ -79,7 +79,7 @@ public:
|
||||
|
||||
future<> check_access(service::storage_proxy& proxy, const service::client_state& state) const override;
|
||||
void validate(service::storage_proxy&, const service::client_state& state) const override;
|
||||
future<::shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy&) const override;
|
||||
future<::shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy&, bool is_local_only) const override;
|
||||
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
private:
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
#include <regex>
|
||||
|
||||
bool is_system_keyspace(std::string_view keyspace);
|
||||
bool is_system_keyspace(const sstring& keyspace);
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
@@ -106,11 +106,11 @@ void create_keyspace_statement::validate(service::storage_proxy&, const service:
|
||||
#endif
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> create_keyspace_statement::announce_migration(service::storage_proxy& proxy) const
|
||||
future<shared_ptr<cql_transport::event::schema_change>> create_keyspace_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const
|
||||
{
|
||||
return make_ready_future<>().then([this, p = proxy.shared_from_this()] {
|
||||
return make_ready_future<>().then([this, p = proxy.shared_from_this(), is_local_only] {
|
||||
const auto& tm = *p->get_token_metadata_ptr();
|
||||
return service::get_local_migration_manager().announce_new_keyspace(_attrs->as_ks_metadata(_name, tm));
|
||||
return service::get_local_migration_manager().announce_new_keyspace(_attrs->as_ks_metadata(_name, tm), is_local_only);
|
||||
}).then_wrapped([this] (auto&& f) {
|
||||
try {
|
||||
f.get();
|
||||
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
*/
|
||||
virtual void validate(service::storage_proxy&, const service::client_state& state) const override;
|
||||
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
|
||||
|
||||
@@ -97,10 +97,10 @@ std::vector<column_definition> create_table_statement::get_columns() const
|
||||
return column_defs;
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> create_table_statement::announce_migration(service::storage_proxy& proxy) const {
|
||||
future<shared_ptr<cql_transport::event::schema_change>> create_table_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const {
|
||||
auto schema = get_cf_meta_data(proxy.get_db().local());
|
||||
return make_ready_future<>().then([this, schema = std::move(schema)] {
|
||||
return service::get_local_migration_manager().announce_new_column_family(std::move(schema));
|
||||
return make_ready_future<>().then([this, is_local_only, schema = std::move(schema)] {
|
||||
return service::get_local_migration_manager().announce_new_column_family(std::move(schema), is_local_only);
|
||||
}).then_wrapped([this] (auto&& f) {
|
||||
try {
|
||||
f.get();
|
||||
|
||||
@@ -102,7 +102,7 @@ public:
|
||||
|
||||
virtual void validate(service::storage_proxy&, const service::client_state& state) const override;
|
||||
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ inline user_type create_type_statement::create_type(database& db) const
|
||||
std::move(field_names), std::move(field_types), true /* multi cell */);
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> create_type_statement::announce_migration(service::storage_proxy& proxy) const
|
||||
future<shared_ptr<cql_transport::event::schema_change>> create_type_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const
|
||||
{
|
||||
auto&& db = proxy.get_db().local();
|
||||
|
||||
@@ -152,7 +152,7 @@ future<shared_ptr<cql_transport::event::schema_change>> create_type_statement::a
|
||||
|
||||
auto type = create_type(db);
|
||||
check_for_duplicate_names(type);
|
||||
return service::get_local_migration_manager().announce_new_type(type).then([this] {
|
||||
return service::get_local_migration_manager().announce_new_type(type, is_local_only).then([this] {
|
||||
using namespace cql_transport;
|
||||
|
||||
return ::make_shared<event::schema_change>(
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
|
||||
virtual const sstring& keyspace() const override;
|
||||
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ create_view_statement::create_view_statement(
|
||||
}
|
||||
|
||||
future<> create_view_statement::check_access(service::storage_proxy& proxy, const service::client_state& state) const {
|
||||
return state.has_column_family_access(proxy.local_db(), keyspace(), _base_name->get_column_family(), auth::permission::ALTER);
|
||||
return state.has_column_family_access(keyspace(), _base_name->get_column_family(), auth::permission::ALTER);
|
||||
}
|
||||
|
||||
void create_view_statement::validate(service::storage_proxy& proxy, const service::client_state& state) const {
|
||||
@@ -140,7 +140,7 @@ static bool validate_primary_key(
|
||||
return new_non_pk_column;
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> create_view_statement::announce_migration(service::storage_proxy& proxy) const {
|
||||
future<shared_ptr<cql_transport::event::schema_change>> create_view_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const {
|
||||
// We need to make sure that:
|
||||
// - primary key includes all columns in base table's primary key
|
||||
// - make sure that the select statement does not have anything other than columns
|
||||
@@ -225,7 +225,7 @@ future<shared_ptr<cql_transport::event::schema_change>> create_view_statement::a
|
||||
}
|
||||
|
||||
auto parameters = make_lw_shared<raw::select_statement::parameters>(raw::select_statement::parameters::orderings_type(), false, true);
|
||||
raw::select_statement raw_select(_base_name, std::move(parameters), _select_clause, _where_clause, nullptr, nullptr, {}, std::make_unique<cql3::attributes::raw>());
|
||||
raw::select_statement raw_select(_base_name, std::move(parameters), _select_clause, _where_clause, nullptr, nullptr, {});
|
||||
raw_select.prepare_keyspace(keyspace());
|
||||
raw_select.set_bound_variables({});
|
||||
|
||||
@@ -350,8 +350,8 @@ future<shared_ptr<cql_transport::event::schema_change>> create_view_statement::a
|
||||
auto where_clause_text = util::relations_to_where_clause(_where_clause);
|
||||
builder.with_view_info(schema->id(), schema->cf_name(), included.empty(), std::move(where_clause_text));
|
||||
|
||||
return make_ready_future<>().then([definition = view_ptr(builder.build())]() mutable {
|
||||
return service::get_local_migration_manager().announce_new_view(definition);
|
||||
return make_ready_future<>().then([definition = view_ptr(builder.build()), is_local_only]() mutable {
|
||||
return service::get_local_migration_manager().announce_new_view(definition, is_local_only);
|
||||
}).then_wrapped([this] (auto&& f) {
|
||||
try {
|
||||
f.get();
|
||||
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
// Functions we need to override to subclass schema_altering_statement
|
||||
virtual future<> check_access(service::storage_proxy& proxy, const service::client_state& state) const override;
|
||||
virtual void validate(service::storage_proxy&, const service::client_state& state) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
|
||||
// FIXME: continue here. See create_table_statement.hh and CreateViewStatement.java
|
||||
|
||||
@@ -33,7 +33,7 @@ std::unique_ptr<prepared_statement> drop_function_statement::prepare(database& d
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> drop_function_statement::announce_migration(
|
||||
service::storage_proxy& proxy) const {
|
||||
service::storage_proxy& proxy, bool is_local_only) const {
|
||||
if (!_func) {
|
||||
return make_ready_future<shared_ptr<cql_transport::event::schema_change>>();
|
||||
}
|
||||
@@ -41,7 +41,7 @@ future<shared_ptr<cql_transport::event::schema_change>> drop_function_statement:
|
||||
if (!user_func) {
|
||||
throw exceptions::invalid_request_exception(format("'{}' is not a user defined function", _func));
|
||||
}
|
||||
return service::get_local_migration_manager().announce_function_drop(user_func).then([this] {
|
||||
return service::get_local_migration_manager().announce_function_drop(user_func, is_local_only).then([this] {
|
||||
return create_schema_change(*_func, false);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace statements {
|
||||
class drop_function_statement final : public drop_function_statement_base {
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(
|
||||
service::storage_proxy& proxy) const override;
|
||||
service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
|
||||
public:
|
||||
drop_function_statement(functions::function_name name, std::vector<shared_ptr<cql3_type::raw>> arg_types,
|
||||
|
||||
@@ -70,7 +70,7 @@ future<> drop_index_statement::check_access(service::storage_proxy& proxy, const
|
||||
if (!cfm) {
|
||||
return make_ready_future<>();
|
||||
}
|
||||
return state.has_column_family_access(proxy.local_db(), cfm->ks_name(), cfm->cf_name(), auth::permission::ALTER);
|
||||
return state.has_column_family_access(cfm->ks_name(), cfm->cf_name(), auth::permission::ALTER);
|
||||
}
|
||||
|
||||
void drop_index_statement::validate(service::storage_proxy& proxy, const service::client_state& state) const
|
||||
@@ -86,7 +86,7 @@ void drop_index_statement::validate(service::storage_proxy& proxy, const service
|
||||
}
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> drop_index_statement::announce_migration(service::storage_proxy& proxy) const
|
||||
future<shared_ptr<cql_transport::event::schema_change>> drop_index_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const
|
||||
{
|
||||
auto cfm = lookup_indexed_table(proxy);
|
||||
if (!cfm) {
|
||||
@@ -95,7 +95,7 @@ future<shared_ptr<cql_transport::event::schema_change>> drop_index_statement::an
|
||||
++_cql_stats->secondary_index_drops;
|
||||
auto builder = schema_builder(cfm);
|
||||
builder.without_index(_index_name);
|
||||
return service::get_local_migration_manager().announce_column_family_update(builder.build(), false, {}).then([cfm] {
|
||||
return service::get_local_migration_manager().announce_column_family_update(builder.build(), false, {}, is_local_only).then([cfm] {
|
||||
// Dropping an index is akin to updating the CF
|
||||
// Note that we shouldn't call columnFamily() at this point because the index has been dropped and the call to lookupIndexedTable()
|
||||
// in that method would now throw.
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
|
||||
virtual void validate(service::storage_proxy&, const service::client_state& state) const override;
|
||||
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
private:
|
||||
|
||||
@@ -74,10 +74,10 @@ const sstring& drop_keyspace_statement::keyspace() const
|
||||
return _keyspace;
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> drop_keyspace_statement::announce_migration(service::storage_proxy& proxy) const
|
||||
future<shared_ptr<cql_transport::event::schema_change>> drop_keyspace_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const
|
||||
{
|
||||
return make_ready_future<>().then([this] {
|
||||
return service::get_local_migration_manager().announce_keyspace_drop(_keyspace);
|
||||
return make_ready_future<>().then([this, is_local_only] {
|
||||
return service::get_local_migration_manager().announce_keyspace_drop(_keyspace, is_local_only);
|
||||
}).then_wrapped([this] (auto&& f) {
|
||||
try {
|
||||
f.get();
|
||||
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
|
||||
virtual const sstring& keyspace() const override;
|
||||
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
};
|
||||
|
||||
@@ -58,7 +58,7 @@ future<> drop_table_statement::check_access(service::storage_proxy& proxy, const
|
||||
{
|
||||
// invalid_request_exception is only thrown synchronously.
|
||||
try {
|
||||
return state.has_column_family_access(proxy.local_db(), keyspace(), column_family(), auth::permission::DROP);
|
||||
return state.has_column_family_access(keyspace(), column_family(), auth::permission::DROP);
|
||||
} catch (exceptions::invalid_request_exception&) {
|
||||
if (!_if_exists) {
|
||||
throw;
|
||||
@@ -72,10 +72,10 @@ void drop_table_statement::validate(service::storage_proxy&, const service::clie
|
||||
// validated in announce_migration()
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> drop_table_statement::announce_migration(service::storage_proxy& proxy) const
|
||||
future<shared_ptr<cql_transport::event::schema_change>> drop_table_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const
|
||||
{
|
||||
return make_ready_future<>().then([this] {
|
||||
return service::get_local_migration_manager().announce_column_family_drop(keyspace(), column_family());
|
||||
return make_ready_future<>().then([this, is_local_only] {
|
||||
return service::get_local_migration_manager().announce_column_family_drop(keyspace(), column_family(), is_local_only);
|
||||
}).then_wrapped([this] (auto&& f) {
|
||||
try {
|
||||
f.get();
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
|
||||
virtual void validate(service::storage_proxy&, const service::client_state& state) const override;
|
||||
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
};
|
||||
|
||||
@@ -142,7 +142,7 @@ const sstring& drop_type_statement::keyspace() const
|
||||
return _name.get_keyspace();
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> drop_type_statement::announce_migration(service::storage_proxy& proxy) const
|
||||
future<shared_ptr<cql_transport::event::schema_change>> drop_type_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const
|
||||
{
|
||||
auto&& db = proxy.get_db().local();
|
||||
|
||||
@@ -157,7 +157,7 @@ future<shared_ptr<cql_transport::event::schema_change>> drop_type_statement::ann
|
||||
return make_ready_future<::shared_ptr<cql_transport::event::schema_change>>();
|
||||
}
|
||||
|
||||
return service::get_local_migration_manager().announce_type_drop(to_drop->second).then([this] {
|
||||
return service::get_local_migration_manager().announce_type_drop(to_drop->second, is_local_only).then([this] {
|
||||
using namespace cql_transport;
|
||||
|
||||
return ::make_shared<event::schema_change>(
|
||||
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
|
||||
virtual const sstring& keyspace() const override;
|
||||
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
};
|
||||
|
||||
@@ -58,10 +58,9 @@ drop_view_statement::drop_view_statement(::shared_ptr<cf_name> view_name, bool i
|
||||
future<> drop_view_statement::check_access(service::storage_proxy& proxy, const service::client_state& state) const
|
||||
{
|
||||
try {
|
||||
const database& db = proxy.local_db();
|
||||
auto&& s = db.find_schema(keyspace(), column_family());
|
||||
auto&& s = proxy.get_db().local().find_schema(keyspace(), column_family());
|
||||
if (s->is_view()) {
|
||||
return state.has_column_family_access(db, keyspace(), s->view_info()->base_name(), auth::permission::ALTER);
|
||||
return state.has_column_family_access(keyspace(), s->view_info()->base_name(), auth::permission::ALTER);
|
||||
}
|
||||
} catch (const no_such_column_family& e) {
|
||||
// Will be validated afterwards.
|
||||
@@ -74,10 +73,10 @@ void drop_view_statement::validate(service::storage_proxy&, const service::clien
|
||||
// validated in migration_manager::announce_view_drop()
|
||||
}
|
||||
|
||||
future<shared_ptr<cql_transport::event::schema_change>> drop_view_statement::announce_migration(service::storage_proxy& proxy) const
|
||||
future<shared_ptr<cql_transport::event::schema_change>> drop_view_statement::announce_migration(service::storage_proxy& proxy, bool is_local_only) const
|
||||
{
|
||||
return make_ready_future<>().then([this] {
|
||||
return service::get_local_migration_manager().announce_view_drop(keyspace(), column_family());
|
||||
return make_ready_future<>().then([this, is_local_only] {
|
||||
return service::get_local_migration_manager().announce_view_drop(keyspace(), column_family(), is_local_only);
|
||||
}).then_wrapped([this] (auto&& f) {
|
||||
try {
|
||||
f.get();
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
|
||||
virtual void validate(service::storage_proxy&, const service::client_state& state) const override;
|
||||
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const override;
|
||||
virtual future<shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const override;
|
||||
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override;
|
||||
};
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
#include "partition_slice_builder.hh"
|
||||
#include "cas_request.hh"
|
||||
|
||||
bool is_system_keyspace(std::string_view name);
|
||||
bool is_system_keyspace(const sstring& name);
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
@@ -74,10 +74,6 @@ modification_statement_timeout(const schema& s) {
|
||||
}
|
||||
}
|
||||
|
||||
db::timeout_clock::duration modification_statement::get_timeout(const query_options& options) const {
|
||||
return attrs->is_timeout_set() ? attrs->get_timeout(options) : options.get_timeout_config().*get_timeout_config_selector();
|
||||
}
|
||||
|
||||
modification_statement::modification_statement(statement_type type_, uint32_t bound_terms, schema_ptr schema_, std::unique_ptr<attributes> attrs_, cql_stats& stats_)
|
||||
: cql_statement_opt_metadata(modification_statement_timeout(*schema_))
|
||||
, type{type_}
|
||||
@@ -124,11 +120,10 @@ gc_clock::duration modification_statement::get_time_to_live(const query_options&
|
||||
}
|
||||
|
||||
future<> modification_statement::check_access(service::storage_proxy& proxy, const service::client_state& state) const {
|
||||
const database& db = proxy.local_db();
|
||||
auto f = state.has_column_family_access(db, keyspace(), column_family(), auth::permission::MODIFY);
|
||||
auto f = state.has_column_family_access(keyspace(), column_family(), auth::permission::MODIFY);
|
||||
if (has_conditions()) {
|
||||
f = f.then([this, &state, &db] {
|
||||
return state.has_column_family_access(db, keyspace(), column_family(), auth::permission::SELECT);
|
||||
f = f.then([this, &state] {
|
||||
return state.has_column_family_access(keyspace(), column_family(), auth::permission::SELECT);
|
||||
});
|
||||
}
|
||||
return f;
|
||||
@@ -291,7 +286,7 @@ modification_statement::do_execute(service::storage_proxy& proxy, service::query
|
||||
future<>
|
||||
modification_statement::execute_without_condition(service::storage_proxy& proxy, service::query_state& qs, const query_options& options) const {
|
||||
auto cl = options.get_consistency();
|
||||
auto timeout = db::timeout_clock::now() + get_timeout(options);
|
||||
auto timeout = db::timeout_clock::now() + qs.get_client_state().get_timeout_config().*get_timeout_config_selector();
|
||||
return get_mutations(proxy, options, timeout, false, options.get_timestamp(qs), qs).then([this, cl, timeout, &proxy, &qs] (auto mutations) {
|
||||
if (mutations.empty()) {
|
||||
return now();
|
||||
@@ -307,7 +302,7 @@ modification_statement::execute_with_condition(service::storage_proxy& proxy, se
|
||||
auto cl_for_learn = options.get_consistency();
|
||||
auto cl_for_paxos = options.check_serial_consistency();
|
||||
db::timeout_clock::time_point now = db::timeout_clock::now();
|
||||
const timeout_config& cfg = options.get_timeout_config();
|
||||
const timeout_config& cfg = qs.get_client_state().get_timeout_config();
|
||||
|
||||
auto statement_timeout = now + cfg.write_timeout; // All CAS networking operations run with write timeout.
|
||||
auto cas_timeout = now + cfg.cas_timeout; // When to give up due to contention.
|
||||
|
||||
@@ -298,9 +298,6 @@ protected:
|
||||
* @throws InvalidRequestException
|
||||
*/
|
||||
virtual void validate_where_clause_for_conditions() const;
|
||||
|
||||
db::timeout_clock::duration get_timeout(const query_options& options) const;
|
||||
|
||||
friend class raw::modification_statement;
|
||||
};
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
#include "cql3/selection/raw_selector.hh"
|
||||
#include "cql3/restrictions/statement_restrictions.hh"
|
||||
#include "cql3/result_set.hh"
|
||||
#include "cql3/attributes.hh"
|
||||
#include "exceptions/unrecognized_entity_exception.hh"
|
||||
#include "service/client_state.hh"
|
||||
#include <seastar/core/shared_ptr.hh>
|
||||
@@ -106,7 +105,6 @@ private:
|
||||
::shared_ptr<term::raw> _limit;
|
||||
::shared_ptr<term::raw> _per_partition_limit;
|
||||
std::vector<::shared_ptr<cql3::column_identifier::raw>> _group_by_columns;
|
||||
std::unique_ptr<cql3::attributes::raw> _attrs;
|
||||
public:
|
||||
select_statement(::shared_ptr<cf_name> cf_name,
|
||||
lw_shared_ptr<const parameters> parameters,
|
||||
@@ -114,8 +112,7 @@ public:
|
||||
std::vector<::shared_ptr<relation>> where_clause,
|
||||
::shared_ptr<term::raw> limit,
|
||||
::shared_ptr<term::raw> per_partition_limit,
|
||||
std::vector<::shared_ptr<cql3::column_identifier::raw>> group_by_columns,
|
||||
std::unique_ptr<cql3::attributes::raw> attrs);
|
||||
std::vector<::shared_ptr<cql3::column_identifier::raw>> group_by_columns);
|
||||
|
||||
virtual std::unique_ptr<prepared_statement> prepare(database& db, cql_stats& stats) override {
|
||||
return prepare(db, stats, false);
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
#include "gms/feature_service.hh"
|
||||
#include "transport/messages/result_message.hh"
|
||||
#include "unimplemented.hh"
|
||||
#include "concrete_types.hh"
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
@@ -105,6 +106,30 @@ future<> create_role_statement::grant_permissions_to_creator(const service::clie
|
||||
});
|
||||
}
|
||||
|
||||
static void validate_timeout_options(const auth::authentication_options& auth_options) {
|
||||
if (!auth_options.options) {
|
||||
return;
|
||||
}
|
||||
const auto& options = *auth_options.options;
|
||||
auto check_duration = [&] (const sstring& repr) {
|
||||
data_value v = duration_type->deserialize(duration_type->from_string(repr));
|
||||
cql_duration duration = static_pointer_cast<const duration_type_impl>(duration_type)->from_value(v);
|
||||
if (duration.months || duration.days) {
|
||||
throw exceptions::invalid_request_exception("Timeout values cannot be longer than 24h");
|
||||
}
|
||||
if (duration.nanoseconds % 1'000'000 != 0) {
|
||||
throw exceptions::invalid_request_exception("Timeout values must be expressed in millisecond granularity");
|
||||
}
|
||||
};
|
||||
|
||||
for (auto opt : {"read_timeout", "write_timeout"}) {
|
||||
auto it = options.find(opt);
|
||||
if (it != options.end()) {
|
||||
check_duration(it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void create_role_statement::validate(service::storage_proxy& p, const service::client_state&) const {
|
||||
validate_cluster_support(p);
|
||||
}
|
||||
@@ -137,9 +162,12 @@ create_role_statement::execute(service::storage_proxy&,
|
||||
[this, &state](const auth::role_config& config, const auth::authentication_options& authen_options) {
|
||||
const auto& cs = state.get_client_state();
|
||||
auto& as = *cs.get_auth_service();
|
||||
validate_timeout_options(authen_options);
|
||||
|
||||
return auth::create_role(as, _role, config, authen_options).then([this, &cs] {
|
||||
return grant_permissions_to_creator(cs);
|
||||
}).then([&state] () mutable {
|
||||
return state.get_client_state().update_per_role_params();
|
||||
}).then([] {
|
||||
return void_result_message();
|
||||
}).handle_exception_type([this](const auth::role_already_exists& e) {
|
||||
@@ -224,8 +252,9 @@ alter_role_statement::execute(service::storage_proxy&, service::query_state& sta
|
||||
extract_authentication_options(_options),
|
||||
[this, &state](const auth::role_config_update& update, const auth::authentication_options& authen_options) {
|
||||
auto& as = *state.get_client_state().get_auth_service();
|
||||
|
||||
return auth::alter_role(as, _role, update, authen_options).then([] {
|
||||
return auth::alter_role(as, _role, update, authen_options).then([&state] () mutable {
|
||||
return state.get_client_state().update_per_role_params();
|
||||
}).then([] {
|
||||
return void_result_message();
|
||||
}).handle_exception_type([](const auth::nonexistant_role& e) {
|
||||
return make_exception_future<result_message_ptr>(exceptions::invalid_request_exception(e.what()));
|
||||
|
||||
@@ -90,10 +90,10 @@ void schema_altering_statement::prepare_keyspace(const service::client_state& st
|
||||
}
|
||||
|
||||
future<::shared_ptr<messages::result_message>>
|
||||
schema_altering_statement::execute0(service::storage_proxy& proxy, service::query_state& state, const query_options& options) const {
|
||||
schema_altering_statement::execute0(service::storage_proxy& proxy, service::query_state& state, const query_options& options, bool is_local_only) const {
|
||||
// If an IF [NOT] EXISTS clause was used, this may not result in an actual schema change. To avoid doing
|
||||
// extra work in the drivers to handle schema changes, we return an empty message in this case. (CASSANDRA-7600)
|
||||
return announce_migration(proxy).then([this] (auto ce) {
|
||||
return announce_migration(proxy, is_local_only).then([this] (auto ce) {
|
||||
::shared_ptr<messages::result_message> result;
|
||||
if (!ce) {
|
||||
result = ::make_shared<messages::result_message::void_message>();
|
||||
@@ -120,7 +120,7 @@ schema_altering_statement::execute(service::storage_proxy& proxy, service::query
|
||||
}
|
||||
}
|
||||
|
||||
return execute0(proxy, state, options).then([this, &state, internal](::shared_ptr<messages::result_message> result) {
|
||||
return execute0(proxy, state, options, internal).then([this, &state, internal](::shared_ptr<messages::result_message> result) {
|
||||
auto permissions_granted_fut = internal
|
||||
? make_ready_future<>()
|
||||
: grant_permissions_to_creator(state.get_client_state());
|
||||
|
||||
@@ -65,7 +65,7 @@ private:
|
||||
const bool _is_column_family_level;
|
||||
|
||||
future<::shared_ptr<messages::result_message>>
|
||||
execute0(service::storage_proxy& proxy, service::query_state& state, const query_options& options) const;
|
||||
execute0(service::storage_proxy& proxy, service::query_state& state, const query_options& options, bool) const;
|
||||
protected:
|
||||
explicit schema_altering_statement(timeout_config_selector timeout_selector = &timeout_config::other_timeout);
|
||||
|
||||
@@ -87,7 +87,7 @@ protected:
|
||||
|
||||
virtual void prepare_keyspace(const service::client_state& state) override;
|
||||
|
||||
virtual future<::shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy) const = 0;
|
||||
virtual future<::shared_ptr<cql_transport::event::schema_change>> announce_migration(service::storage_proxy& proxy, bool is_local_only) const = 0;
|
||||
|
||||
virtual future<::shared_ptr<messages::result_message>>
|
||||
execute(service::storage_proxy& proxy, service::query_state& state, const query_options& options) const override;
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
#include "test/lib/select_statement_utils.hh"
|
||||
#include <boost/algorithm/cxx11/any_of.hpp>
|
||||
|
||||
bool is_system_keyspace(std::string_view name);
|
||||
bool is_system_keyspace(const sstring& name);
|
||||
|
||||
namespace cql3 {
|
||||
|
||||
@@ -138,8 +138,7 @@ select_statement::select_statement(schema_ptr schema,
|
||||
ordering_comparator_type ordering_comparator,
|
||||
::shared_ptr<term> limit,
|
||||
::shared_ptr<term> per_partition_limit,
|
||||
cql_stats& stats,
|
||||
std::unique_ptr<attributes> attrs)
|
||||
cql_stats& stats)
|
||||
: cql_statement(select_timeout(*restrictions))
|
||||
, _schema(schema)
|
||||
, _bound_terms(bound_terms)
|
||||
@@ -153,7 +152,6 @@ select_statement::select_statement(schema_ptr schema,
|
||||
, _ordering_comparator(std::move(ordering_comparator))
|
||||
, _stats(stats)
|
||||
, _ks_sel(::is_system_keyspace(schema->ks_name()) ? ks_selector::SYSTEM : ks_selector::NONSYSTEM)
|
||||
, _attrs(std::move(attrs))
|
||||
{
|
||||
_opts = _selection->get_query_options();
|
||||
_opts.set_if<query::partition_slice::option::bypass_cache>(_parameters->bypass_cache());
|
||||
@@ -161,10 +159,6 @@ select_statement::select_statement(schema_ptr schema,
|
||||
_opts.set_if<query::partition_slice::option::reversed>(_is_reversed);
|
||||
}
|
||||
|
||||
db::timeout_clock::duration select_statement::get_timeout(const query_options& options) const {
|
||||
return _attrs->is_timeout_set() ? _attrs->get_timeout(options) : options.get_timeout_config().*get_timeout_config_selector();
|
||||
}
|
||||
|
||||
::shared_ptr<const cql3::metadata> select_statement::get_result_metadata() const {
|
||||
// FIXME: COUNT needs special result metadata handling.
|
||||
return _selection->get_result_metadata();
|
||||
@@ -176,10 +170,9 @@ uint32_t select_statement::get_bound_terms() const {
|
||||
|
||||
future<> select_statement::check_access(service::storage_proxy& proxy, const service::client_state& state) const {
|
||||
try {
|
||||
const database& db = proxy.local_db();
|
||||
auto&& s = db.find_schema(keyspace(), column_family());
|
||||
auto&& s = proxy.get_db().local().find_schema(keyspace(), column_family());
|
||||
auto& cf_name = s->is_view() ? s->view_info()->base_name() : column_family();
|
||||
return state.has_column_family_access(db, keyspace(), cf_name, auth::permission::SELECT);
|
||||
return state.has_column_family_access(keyspace(), cf_name, auth::permission::SELECT);
|
||||
} catch (const no_such_column_family& e) {
|
||||
// Will be validated afterwards.
|
||||
return make_ready_future<>();
|
||||
@@ -259,9 +252,10 @@ uint64_t select_statement::do_get_limit(const query_options& options, ::shared_p
|
||||
if (val.is_unset_value()) {
|
||||
return default_limit;
|
||||
}
|
||||
return with_linearized(*val, [&] (bytes_view bv) {
|
||||
try {
|
||||
int32_type->validate(*val, options.get_cql_serialization_format());
|
||||
auto l = value_cast<int32_t>(int32_type->deserialize(*val));
|
||||
int32_type->validate(bv, options.get_cql_serialization_format());
|
||||
auto l = value_cast<int32_t>(int32_type->deserialize(bv));
|
||||
if (l <= 0) {
|
||||
throw exceptions::invalid_request_exception("LIMIT must be strictly positive");
|
||||
}
|
||||
@@ -269,6 +263,7 @@ uint64_t select_statement::do_get_limit(const query_options& options, ::shared_p
|
||||
} catch (const marshal_exception& e) {
|
||||
throw exceptions::invalid_request_exception("Invalid limit value");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool select_statement::needs_post_query_ordering() const {
|
||||
@@ -371,7 +366,7 @@ select_statement::do_execute(service::storage_proxy& proxy,
|
||||
}
|
||||
|
||||
command->slice.options.set<query::partition_slice::option::allow_short_read>();
|
||||
auto timeout_duration = get_timeout(options);
|
||||
auto timeout_duration = state.get_client_state().get_timeout_config().*get_timeout_config_selector();
|
||||
auto timeout = db::timeout_clock::now() + timeout_duration;
|
||||
auto p = service::pager::query_pagers::pager(_schema, _selection,
|
||||
state, options, command, std::move(key_ranges), restrictions_need_filtering ? _restrictions : nullptr);
|
||||
@@ -379,14 +374,14 @@ select_statement::do_execute(service::storage_proxy& proxy,
|
||||
if (aggregate || nonpaged_filtering) {
|
||||
return do_with(
|
||||
cql3::selection::result_set_builder(*_selection, now,
|
||||
options.get_cql_serialization_format(), *_group_by_cell_indices), std::move(p),
|
||||
[this, page_size, now, timeout, restrictions_need_filtering](auto& builder, std::unique_ptr<service::pager::query_pager>& p) {
|
||||
return do_until([&p] {return p->is_exhausted();},
|
||||
[&p, &builder, page_size, now, timeout] {
|
||||
options.get_cql_serialization_format(), *_group_by_cell_indices),
|
||||
[this, p, page_size, now, timeout, restrictions_need_filtering](auto& builder) {
|
||||
return do_until([p] {return p->is_exhausted();},
|
||||
[p, &builder, page_size, now, timeout] {
|
||||
return p->fetch_page(builder, page_size, now, timeout);
|
||||
}
|
||||
).then([this, &p, &builder, restrictions_need_filtering] {
|
||||
return builder.with_thread_if_needed([this, &p, &builder, restrictions_need_filtering] {
|
||||
).then([this, p, &builder, restrictions_need_filtering] {
|
||||
return builder.with_thread_if_needed([this, p, &builder, restrictions_need_filtering] {
|
||||
auto rs = builder.build();
|
||||
if (restrictions_need_filtering) {
|
||||
_stats.filtered_rows_read_total += p->stats().rows_read_total;
|
||||
@@ -407,7 +402,7 @@ select_statement::do_execute(service::storage_proxy& proxy,
|
||||
}
|
||||
|
||||
if (_selection->is_trivial() && !restrictions_need_filtering && !_per_partition_limit) {
|
||||
return p->fetch_page_generator(page_size, now, timeout, _stats).then([this, p = std::move(p)] (result_generator generator) {
|
||||
return p->fetch_page_generator(page_size, now, timeout, _stats).then([this, p] (result_generator generator) {
|
||||
auto meta = [&] () -> shared_ptr<const cql3::metadata> {
|
||||
if (!p->is_exhausted()) {
|
||||
auto meta = make_shared<metadata>(*_selection->get_result_metadata());
|
||||
@@ -425,7 +420,7 @@ select_statement::do_execute(service::storage_proxy& proxy,
|
||||
}
|
||||
|
||||
return p->fetch_page(page_size, now, timeout).then(
|
||||
[this, p = std::move(p), &options, now, restrictions_need_filtering](std::unique_ptr<cql3::result_set> rs) {
|
||||
[this, p, &options, now, restrictions_need_filtering](std::unique_ptr<cql3::result_set> rs) {
|
||||
|
||||
if (!p->is_exhausted()) {
|
||||
rs->get_metadata().set_paging_state(p->state());
|
||||
@@ -452,7 +447,7 @@ generate_base_key_from_index_pk(const partition_key& index_pk, const std::option
|
||||
return KeyType::make_empty();
|
||||
}
|
||||
|
||||
std::vector<managed_bytes_view> exploded_base_key;
|
||||
std::vector<bytes_view> exploded_base_key;
|
||||
exploded_base_key.reserve(base_columns.size());
|
||||
|
||||
for (const column_definition& base_col : base_columns) {
|
||||
@@ -518,7 +513,7 @@ indexed_table_select_statement::do_execute_base_query(
|
||||
lw_shared_ptr<const service::pager::paging_state> paging_state) const {
|
||||
using value_type = std::tuple<foreign_ptr<lw_shared_ptr<query::result>>, lw_shared_ptr<query::read_command>>;
|
||||
auto cmd = prepare_command_for_base_query(proxy, options, state, now, bool(paging_state));
|
||||
auto timeout = db::timeout_clock::now() + get_timeout(options);
|
||||
auto timeout = db::timeout_clock::now() + state.get_client_state().get_timeout_config().*get_timeout_config_selector();
|
||||
uint32_t queried_ranges_count = partition_ranges.size();
|
||||
service::query_ranges_to_vnodes_generator ranges_to_vnodes(proxy.get_token_metadata_ptr(), _schema, std::move(partition_ranges));
|
||||
|
||||
@@ -612,7 +607,7 @@ indexed_table_select_statement::do_execute_base_query(
|
||||
lw_shared_ptr<const service::pager::paging_state> paging_state) const {
|
||||
using value_type = std::tuple<foreign_ptr<lw_shared_ptr<query::result>>, lw_shared_ptr<query::read_command>>;
|
||||
auto cmd = prepare_command_for_base_query(proxy, options, state, now, bool(paging_state));
|
||||
auto timeout = db::timeout_clock::now() + get_timeout(options);
|
||||
auto timeout = db::timeout_clock::now() + state.get_client_state().get_timeout_config().*get_timeout_config_selector();
|
||||
|
||||
struct base_query_state {
|
||||
query::result_merger merger;
|
||||
@@ -694,7 +689,7 @@ select_statement::execute(service::storage_proxy& proxy,
|
||||
// is specified we need to get "limit" rows from each partition since there
|
||||
// is no way to tell which of these rows belong to the query result before
|
||||
// doing post-query ordering.
|
||||
auto timeout = db::timeout_clock::now() + get_timeout(options);
|
||||
auto timeout = db::timeout_clock::now() + state.get_client_state().get_timeout_config().*get_timeout_config_selector();
|
||||
if (needs_post_query_ordering() && _limit) {
|
||||
return do_with(std::forward<dht::partition_range_vector>(partition_ranges), [this, &proxy, &state, &options, cmd, timeout](auto& prs) {
|
||||
assert(cmd->partition_limit == query::max_partitions);
|
||||
@@ -797,9 +792,8 @@ primary_key_select_statement::primary_key_select_statement(schema_ptr schema, ui
|
||||
ordering_comparator_type ordering_comparator,
|
||||
::shared_ptr<term> limit,
|
||||
::shared_ptr<term> per_partition_limit,
|
||||
cql_stats &stats,
|
||||
std::unique_ptr<attributes> attrs)
|
||||
: select_statement{schema, bound_terms, parameters, selection, restrictions, group_by_cell_indices, is_reversed, ordering_comparator, limit, per_partition_limit, stats, std::move(attrs)}
|
||||
cql_stats &stats)
|
||||
: select_statement{schema, bound_terms, parameters, selection, restrictions, group_by_cell_indices, is_reversed, ordering_comparator, limit, per_partition_limit, stats}
|
||||
{
|
||||
if (_ks_sel == ks_selector::NONSYSTEM) {
|
||||
if (_restrictions->need_filtering() ||
|
||||
@@ -825,8 +819,7 @@ indexed_table_select_statement::prepare(database& db,
|
||||
ordering_comparator_type ordering_comparator,
|
||||
::shared_ptr<term> limit,
|
||||
::shared_ptr<term> per_partition_limit,
|
||||
cql_stats &stats,
|
||||
std::unique_ptr<attributes> attrs)
|
||||
cql_stats &stats)
|
||||
{
|
||||
auto& sim = db.find_column_family(schema).get_index_manager();
|
||||
auto [index_opt, used_index_restrictions] = restrictions->find_idx(sim);
|
||||
@@ -852,8 +845,7 @@ indexed_table_select_statement::prepare(database& db,
|
||||
stats,
|
||||
*index_opt,
|
||||
std::move(used_index_restrictions),
|
||||
view_schema,
|
||||
std::move(attrs));
|
||||
view_schema);
|
||||
|
||||
}
|
||||
|
||||
@@ -869,9 +861,8 @@ indexed_table_select_statement::indexed_table_select_statement(schema_ptr schema
|
||||
cql_stats &stats,
|
||||
const secondary_index::index& index,
|
||||
::shared_ptr<restrictions::restrictions> used_index_restrictions,
|
||||
schema_ptr view_schema,
|
||||
std::unique_ptr<attributes> attrs)
|
||||
: select_statement{schema, bound_terms, parameters, selection, restrictions, group_by_cell_indices, is_reversed, ordering_comparator, limit, per_partition_limit, stats, std::move(attrs)}
|
||||
schema_ptr view_schema)
|
||||
: select_statement{schema, bound_terms, parameters, selection, restrictions, group_by_cell_indices, is_reversed, ordering_comparator, limit, per_partition_limit, stats}
|
||||
, _index{index}
|
||||
, _used_index_restrictions(used_index_restrictions)
|
||||
, _view_schema(view_schema)
|
||||
@@ -887,7 +878,7 @@ indexed_table_select_statement::indexed_table_select_statement(schema_ptr schema
|
||||
|
||||
template<typename KeyType>
|
||||
requires (std::is_same_v<KeyType, partition_key> || std::is_same_v<KeyType, clustering_key_prefix>)
|
||||
static void append_base_key_to_index_ck(std::vector<managed_bytes_view>& exploded_index_ck, const KeyType& base_key, const column_definition& index_cdef) {
|
||||
static void append_base_key_to_index_ck(std::vector<bytes_view>& exploded_index_ck, const KeyType& base_key, const column_definition& index_cdef) {
|
||||
auto key_view = base_key.view();
|
||||
auto begin = key_view.begin();
|
||||
if ((std::is_same_v<KeyType, partition_key> && index_cdef.is_partition_key())
|
||||
@@ -942,7 +933,7 @@ lw_shared_ptr<const service::pager::paging_state> indexed_table_select_statement
|
||||
}
|
||||
}();
|
||||
|
||||
std::vector<managed_bytes_view> exploded_index_ck;
|
||||
std::vector<bytes_view> exploded_index_ck;
|
||||
exploded_index_ck.reserve(_view_schema->clustering_key_size());
|
||||
|
||||
bytes token_bytes;
|
||||
@@ -1244,7 +1235,7 @@ indexed_table_select_statement::read_posting_list(service::storage_proxy& proxy,
|
||||
|
||||
auto p = service::pager::query_pagers::pager(_view_schema, selection,
|
||||
state, options, cmd, std::move(partition_ranges), nullptr);
|
||||
return p->fetch_page(options.get_page_size(), now, timeout).then([p = std::move(p), &options, limit, now] (std::unique_ptr<cql3::result_set> rs) {
|
||||
return p->fetch_page(options.get_page_size(), now, timeout).then([p, &options, limit, now] (std::unique_ptr<cql3::result_set> rs) {
|
||||
rs->get_metadata().set_paging_state(p->state());
|
||||
return ::make_shared<cql_transport::messages::result_message::rows>(result(std::move(rs)));
|
||||
});
|
||||
@@ -1259,7 +1250,7 @@ indexed_table_select_statement::find_index_partition_ranges(service::storage_pro
|
||||
{
|
||||
using value_type = std::tuple<dht::partition_range_vector, lw_shared_ptr<const service::pager::paging_state>>;
|
||||
auto now = gc_clock::now();
|
||||
auto timeout = db::timeout_clock::now() + get_timeout(options);
|
||||
auto timeout = db::timeout_clock::now() + state.get_client_state().get_timeout_config().*get_timeout_config_selector();
|
||||
return read_posting_list(proxy, options, get_limit(options), state, now, timeout, false).then(
|
||||
[this, now, &options] (::shared_ptr<cql_transport::messages::result_message::rows> rows) {
|
||||
auto rs = cql3::untyped_result_set(rows);
|
||||
@@ -1300,7 +1291,7 @@ indexed_table_select_statement::find_index_clustering_rows(service::storage_prox
|
||||
{
|
||||
using value_type = std::tuple<std::vector<indexed_table_select_statement::primary_key>, lw_shared_ptr<const service::pager::paging_state>>;
|
||||
auto now = gc_clock::now();
|
||||
auto timeout = db::timeout_clock::now() + get_timeout(options);
|
||||
auto timeout = db::timeout_clock::now() + state.get_client_state().get_timeout_config().*get_timeout_config_selector();
|
||||
return read_posting_list(proxy, options, get_limit(options), state, now, timeout, true).then(
|
||||
[this, now, &options] (::shared_ptr<cql_transport::messages::result_message::rows> rows) {
|
||||
|
||||
@@ -1327,23 +1318,13 @@ indexed_table_select_statement::find_index_clustering_rows(service::storage_prox
|
||||
|
||||
namespace raw {
|
||||
|
||||
static void validate_attrs(const cql3::attributes::raw& attrs) {
|
||||
if (attrs.timestamp) {
|
||||
throw exceptions::invalid_request_exception("Specifying TIMESTAMP is not legal for SELECT statement");
|
||||
}
|
||||
if (attrs.time_to_live) {
|
||||
throw exceptions::invalid_request_exception("Specifying TTL is not legal for SELECT statement");
|
||||
}
|
||||
}
|
||||
|
||||
select_statement::select_statement(::shared_ptr<cf_name> cf_name,
|
||||
lw_shared_ptr<const parameters> parameters,
|
||||
std::vector<::shared_ptr<selection::raw_selector>> select_clause,
|
||||
std::vector<::shared_ptr<relation>> where_clause,
|
||||
::shared_ptr<term::raw> limit,
|
||||
::shared_ptr<term::raw> per_partition_limit,
|
||||
std::vector<::shared_ptr<cql3::column_identifier::raw>> group_by_columns,
|
||||
std::unique_ptr<attributes::raw> attrs)
|
||||
std::vector<::shared_ptr<cql3::column_identifier::raw>> group_by_columns)
|
||||
: cf_statement(std::move(cf_name))
|
||||
, _parameters(std::move(parameters))
|
||||
, _select_clause(std::move(select_clause))
|
||||
@@ -1351,10 +1332,7 @@ select_statement::select_statement(::shared_ptr<cf_name> cf_name,
|
||||
, _limit(std::move(limit))
|
||||
, _per_partition_limit(std::move(per_partition_limit))
|
||||
, _group_by_columns(std::move(group_by_columns))
|
||||
, _attrs(std::move(attrs))
|
||||
{
|
||||
validate_attrs(*_attrs);
|
||||
}
|
||||
{ }
|
||||
|
||||
void select_statement::maybe_jsonize_select_clause(database& db, schema_ptr schema) {
|
||||
// Fill wildcard clause with explicit column identifiers for as_json function
|
||||
@@ -1425,8 +1403,6 @@ std::unique_ptr<prepared_statement> select_statement::prepare(database& db, cql_
|
||||
auto group_by_cell_indices = ::make_shared<std::vector<size_t>>(prepare_group_by(*schema, *selection));
|
||||
|
||||
::shared_ptr<cql3::statements::select_statement> stmt;
|
||||
auto prepared_attrs = _attrs->prepare(db, keyspace(), column_family());
|
||||
prepared_attrs->collect_marker_specification(bound_names);
|
||||
if (restrictions->uses_secondary_indexing()) {
|
||||
stmt = indexed_table_select_statement::prepare(
|
||||
db,
|
||||
@@ -1440,8 +1416,7 @@ std::unique_ptr<prepared_statement> select_statement::prepare(database& db, cql_
|
||||
std::move(ordering_comparator),
|
||||
prepare_limit(db, bound_names, _limit),
|
||||
prepare_limit(db, bound_names, _per_partition_limit),
|
||||
stats,
|
||||
std::move(prepared_attrs));
|
||||
stats);
|
||||
} else {
|
||||
stmt = ::make_shared<cql3::statements::primary_key_select_statement>(
|
||||
schema,
|
||||
@@ -1454,8 +1429,7 @@ std::unique_ptr<prepared_statement> select_statement::prepare(database& db, cql_
|
||||
std::move(ordering_comparator),
|
||||
prepare_limit(db, bound_names, _limit),
|
||||
prepare_limit(db, bound_names, _per_partition_limit),
|
||||
stats,
|
||||
std::move(prepared_attrs));
|
||||
stats);
|
||||
}
|
||||
|
||||
auto partition_key_bind_indices = bound_names.get_partition_key_bind_indexes(*schema);
|
||||
@@ -1473,7 +1447,7 @@ select_statement::prepare_restrictions(database& db,
|
||||
{
|
||||
try {
|
||||
return ::make_shared<restrictions::statement_restrictions>(db, schema, statement_type::SELECT, std::move(_where_clause), bound_names,
|
||||
selection->contains_only_static_columns(), for_view, allow_filtering);
|
||||
selection->contains_only_static_columns(), selection->contains_a_collection(), for_view, allow_filtering);
|
||||
} catch (const exceptions::unrecognized_entity_exception& e) {
|
||||
if (contains_alias(e.entity)) {
|
||||
throw exceptions::invalid_request_exception(format("Aliases aren't allowed in the where clause ('{}')", e.relation_str));
|
||||
|
||||
@@ -96,7 +96,6 @@ protected:
|
||||
const ks_selector _ks_sel;
|
||||
bool _range_scan = false;
|
||||
bool _range_scan_no_bypass_cache = false;
|
||||
std::unique_ptr<cql3::attributes> _attrs;
|
||||
protected :
|
||||
virtual future<::shared_ptr<cql_transport::messages::result_message>> do_execute(service::storage_proxy& proxy,
|
||||
service::query_state& state, const query_options& options) const;
|
||||
@@ -112,8 +111,7 @@ public:
|
||||
ordering_comparator_type ordering_comparator,
|
||||
::shared_ptr<term> limit,
|
||||
::shared_ptr<term> per_partition_limit,
|
||||
cql_stats& stats,
|
||||
std::unique_ptr<cql3::attributes> attrs);
|
||||
cql_stats& stats);
|
||||
|
||||
virtual ::shared_ptr<const cql3::metadata> get_result_metadata() const override;
|
||||
virtual uint32_t get_bound_terms() const override;
|
||||
@@ -147,8 +145,6 @@ public:
|
||||
|
||||
bool has_group_by() const { return _group_by_cell_indices && !_group_by_cell_indices->empty(); }
|
||||
|
||||
db::timeout_clock::duration get_timeout(const query_options& options) const;
|
||||
|
||||
protected:
|
||||
uint64_t do_get_limit(const query_options& options, ::shared_ptr<term> limit, uint64_t default_limit) const;
|
||||
uint64_t get_limit(const query_options& options) const {
|
||||
@@ -175,8 +171,7 @@ public:
|
||||
ordering_comparator_type ordering_comparator,
|
||||
::shared_ptr<term> limit,
|
||||
::shared_ptr<term> per_partition_limit,
|
||||
cql_stats &stats,
|
||||
std::unique_ptr<cql3::attributes> attrs);
|
||||
cql_stats &stats);
|
||||
};
|
||||
|
||||
class indexed_table_select_statement : public select_statement {
|
||||
@@ -197,8 +192,7 @@ public:
|
||||
ordering_comparator_type ordering_comparator,
|
||||
::shared_ptr<term> limit,
|
||||
::shared_ptr<term> per_partition_limit,
|
||||
cql_stats &stats,
|
||||
std::unique_ptr<cql3::attributes> attrs);
|
||||
cql_stats &stats);
|
||||
|
||||
indexed_table_select_statement(schema_ptr schema,
|
||||
uint32_t bound_terms,
|
||||
@@ -213,8 +207,7 @@ public:
|
||||
cql_stats &stats,
|
||||
const secondary_index::index& index,
|
||||
::shared_ptr<restrictions::restrictions> used_index_restrictions,
|
||||
schema_ptr view_schema,
|
||||
std::unique_ptr<cql3::attributes> attrs);
|
||||
schema_ptr view_schema);
|
||||
|
||||
private:
|
||||
virtual future<::shared_ptr<cql_transport::messages::result_message>> do_execute(service::storage_proxy& proxy,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user