<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright 2015 Cloudius Systems
 *
 * Modified by Cloudius Systems
 */

#ifndef CQL3_MAPS_HH
#define CQL3_MAPS_HH

#include "cql3/abstract_marker.hh"
#include "cql3/term.hh"
#include "operation.hh"
#include "update_parameters.hh"
#include "exceptions/exceptions.hh"
#include "cql3/cql3_type.hh"

namespace cql3 {

/**
 * Static helper methods and classes for maps.
 */
class maps {
private:
    maps() = delete;
public:
    static shared_ptr<column_specification> key_spec_of(column_specification& column) {
        return ::make_shared<column_specification>(column.ks_name, column.cf_name,
                ::make_shared<column_identifier>(sprint("key(%s)", *column.name), true),
                dynamic_pointer_cast<map_type_impl>(column.type)->get_keys_type());
    }

    static shared_ptr<column_specification> value_spec_of(column_specification& column) {
        return ::make_shared<column_specification>(column.ks_name, column.cf_name,
                ::make_shared<column_identifier>(sprint("value(%s)", *column.name), true),
                dynamic_pointer_cast<map_type_impl>(column.type)->get_values_type());
    }

    class literal : public term::raw {
    public:
        const std::vector<std::pair<::shared_ptr<term::raw>, ::shared_ptr<term::raw>>> entries;

        literal(const std::vector<std::pair<::shared_ptr<term::raw>, ::shared_ptr<term::raw>>>& entries_)
            : entries{entries_}
        { }

        virtual ::shared_ptr<term> prepare(const sstring& keyspace, ::shared_ptr<column_specification> receiver) override {
            validate_assignable_to(keyspace, *receiver);

            auto key_spec = maps::key_spec_of(*receiver);
            auto value_spec = maps::value_spec_of(*receiver);
            std::unordered_map<shared_ptr<term>, shared_ptr<term>> values;
            values.reserve(entries.size());
            bool all_terminal = true;
            for (auto&& entry : entries) {
                auto k = entry.first->prepare(keyspace, key_spec);
                auto v = entry.second->prepare(keyspace, value_spec);

                if (k->contains_bind_marker() || v->contains_bind_marker()) {
                    throw exceptions::invalid_request_exception(sprint("Invalid map literal for %s: bind variables are not supported inside collection literals", *receiver->name));
                }

                if (dynamic_pointer_cast<non_terminal>(k) || dynamic_pointer_cast<non_terminal>(v)) {
                    all_terminal = false;
                }

                values.emplace(k, v);
            }
            delayed_value value(static_pointer_cast<map_type_impl>(receiver->type)->get_keys_type()->as_less_comparator(), values);
            if (all_terminal) {
                return value.bind(query_options::DEFAULT);
            } else {
                return make_shared(std::move(value));
            }
        }

    private:
        void validate_assignable_to(const sstring& keyspace, column_specification& receiver) {
            if (!dynamic_pointer_cast<map_type_impl>(receiver.type)) {
                throw exceptions::invalid_request_exception(sprint("Invalid map literal for %s of type %s", *receiver.name, *receiver.type->as_cql3_type()));
            }
            auto&& key_spec = maps::key_spec_of(receiver);
            auto&& value_spec = maps::value_spec_of(receiver);
            for (auto&& entry : entries) {
                if (!is_assignable(entry.first->test_assignment(keyspace, key_spec))) {
                    throw exceptions::invalid_request_exception(sprint("Invalid map literal for %s: key %s is not of type %s", *receiver.name, *entry.first, *key_spec->type->as_cql3_type()));
                }
                if (!is_assignable(entry.second->test_assignment(keyspace, value_spec))) {
                    throw exceptions::invalid_request_exception(sprint("Invalid map literal for %s: value %s is not of type %s", *receiver.name, *entry.second, *value_spec->type->as_cql3_type()));
                }
            }
        }
    public:

        virtual assignment_testable::test_result test_assignment(const sstring& keyspace, ::shared_ptr<column_specification> receiver) override {
            throw std::runtime_error("not implemented");
#if 0
            if (!(receiver.type instanceof MapType))
                return AssignmentTestable.TestResult.NOT_ASSIGNABLE;

            // If there is no elements, we can't say it's an exact match (an empty map if fundamentally polymorphic).
            if (entries.isEmpty())
                return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;

            ColumnSpecification keySpec = Maps.keySpecOf(receiver);
            ColumnSpecification valueSpec = Maps.valueSpecOf(receiver);
            // It's an exact match if all are exact match, but is not assignable as soon as any is non assignable.
            AssignmentTestable.TestResult res = AssignmentTestable.TestResult.EXACT_MATCH;
            for (Pair<Term.Raw, Term.Raw> entry : entries)
            {
                AssignmentTestable.TestResult t1 = entry.left.testAssignment(keyspace, keySpec);
                AssignmentTestable.TestResult t2 = entry.right.testAssignment(keyspace, valueSpec);
                if (t1 == AssignmentTestable.TestResult.NOT_ASSIGNABLE || t2 == AssignmentTestable.TestResult.NOT_ASSIGNABLE)
                    return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
                if (t1 != AssignmentTestable.TestResult.EXACT_MATCH || t2 != AssignmentTestable.TestResult.EXACT_MATCH)
                    res = AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
            }
            return res;
#endif
        }

        virtual sstring to_string() const override {
            sstring result = "{";
            for (size_t i = 0; i < entries.size(); i++) {
                if (i > 0) {
                    result += ", ";
                }
                result += entries[i].first->to_string();
                result += ":";
                result += entries[i].second->to_string();
            }
            result += "}";
            return result;
        }
    };

    class value : public terminal, collection_terminal {
    public:
        std::map<bytes, bytes, serialized_compare> map;

        value(std::map<bytes, bytes, serialized_compare> map)
            : map(std::move(map)) {
        }

        static value from_serialized(bytes value, map_type type, 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: deserialize_for_native_protocol?!
                auto m = boost::any_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 { std::move(map) };
            } catch (marshal_exception& e) {
                throw exceptions::invalid_request_exception(e.why());
            }
        }
<commit_msg>cql3: use bytes_view when creating a map literal from the serialized form<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Copyright 2015 Cloudius Systems
 *
 * Modified by Cloudius Systems
 */

#ifndef CQL3_MAPS_HH
#define CQL3_MAPS_HH

#include "cql3/abstract_marker.hh"
#include "cql3/term.hh"
#include "operation.hh"
#include "update_parameters.hh"
#include "exceptions/exceptions.hh"
#include "cql3/cql3_type.hh"

namespace cql3 {

/**
 * Static helper methods and classes for maps.
 */
class maps {
private:
    maps() = delete;
public:
    static shared_ptr<column_specification> key_spec_of(column_specification& column) {
        return ::make_shared<column_specification>(column.ks_name, column.cf_name,
                ::make_shared<column_identifier>(sprint("key(%s)", *column.name), true),
                dynamic_pointer_cast<map_type_impl>(column.type)->get_keys_type());
    }

    static shared_ptr<column_specification> value_spec_of(column_specification& column) {
        return ::make_shared<column_specification>(column.ks_name, column.cf_name,
                ::make_shared<column_identifier>(sprint("value(%s)", *column.name), true),
                dynamic_pointer_cast<map_type_impl>(column.type)->get_values_type());
    }

    class literal : public term::raw {
    public:
        const std::vector<std::pair<::shared_ptr<term::raw>, ::shared_ptr<term::raw>>> entries;

        literal(const std::vector<std::pair<::shared_ptr<term::raw>, ::shared_ptr<term::raw>>>& entries_)
            : entries{entries_}
        { }

        virtual ::shared_ptr<term> prepare(const sstring& keyspace, ::shared_ptr<column_specification> receiver) override {
            validate_assignable_to(keyspace, *receiver);

            auto key_spec = maps::key_spec_of(*receiver);
            auto value_spec = maps::value_spec_of(*receiver);
            std::unordered_map<shared_ptr<term>, shared_ptr<term>> values;
            values.reserve(entries.size());
            bool all_terminal = true;
            for (auto&& entry : entries) {
                auto k = entry.first->prepare(keyspace, key_spec);
                auto v = entry.second->prepare(keyspace, value_spec);

                if (k->contains_bind_marker() || v->contains_bind_marker()) {
                    throw exceptions::invalid_request_exception(sprint("Invalid map literal for %s: bind variables are not supported inside collection literals", *receiver->name));
                }

                if (dynamic_pointer_cast<non_terminal>(k) || dynamic_pointer_cast<non_terminal>(v)) {
                    all_terminal = false;
                }

                values.emplace(k, v);
            }
            delayed_value value(static_pointer_cast<map_type_impl>(receiver->type)->get_keys_type()->as_less_comparator(), values);
            if (all_terminal) {
                return value.bind(query_options::DEFAULT);
            } else {
                return make_shared(std::move(value));
            }
        }

    private:
        void validate_assignable_to(const sstring& keyspace, column_specification& receiver) {
            if (!dynamic_pointer_cast<map_type_impl>(receiver.type)) {
                throw exceptions::invalid_request_exception(sprint("Invalid map literal for %s of type %s", *receiver.name, *receiver.type->as_cql3_type()));
            }
            auto&& key_spec = maps::key_spec_of(receiver);
            auto&& value_spec = maps::value_spec_of(receiver);
            for (auto&& entry : entries) {
                if (!is_assignable(entry.first->test_assignment(keyspace, key_spec))) {
                    throw exceptions::invalid_request_exception(sprint("Invalid map literal for %s: key %s is not of type %s", *receiver.name, *entry.first, *key_spec->type->as_cql3_type()));
                }
                if (!is_assignable(entry.second->test_assignment(keyspace, value_spec))) {
                    throw exceptions::invalid_request_exception(sprint("Invalid map literal for %s: value %s is not of type %s", *receiver.name, *entry.second, *value_spec->type->as_cql3_type()));
                }
            }
        }
    public:

        virtual assignment_testable::test_result test_assignment(const sstring& keyspace, ::shared_ptr<column_specification> receiver) override {
            throw std::runtime_error("not implemented");
#if 0
            if (!(receiver.type instanceof MapType))
                return AssignmentTestable.TestResult.NOT_ASSIGNABLE;

            // If there is no elements, we can't say it's an exact match (an empty map if fundamentally polymorphic).
            if (entries.isEmpty())
                return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;

            ColumnSpecification keySpec = Maps.keySpecOf(receiver);
            ColumnSpecification valueSpec = Maps.valueSpecOf(receiver);
            // It's an exact match if all are exact match, but is not assignable as soon as any is non assignable.
            AssignmentTestable.TestResult res = AssignmentTestable.TestResult.EXACT_MATCH;
            for (Pair<Term.Raw, Term.Raw> entry : entries)
            {
                AssignmentTestable.TestResult t1 = entry.left.testAssignment(keyspace, keySpec);
                AssignmentTestable.TestResult t2 = entry.right.testAssignment(keyspace, valueSpec);
                if (t1 == AssignmentTestable.TestResult.NOT_ASSIGNABLE || t2 == AssignmentTestable.TestResult.NOT_ASSIGNABLE)
                    return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
                if (t1 != AssignmentTestable.TestResult.EXACT_MATCH || t2 != AssignmentTestable.TestResult.EXACT_MATCH)
                    res = AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
            }
            return res;
#endif
        }

        virtual sstring to_string() const override {
            sstring result = "{";
            for (size_t i = 0; i < entries.size(); i++) {
                if (i > 0) {
                    result += ", ";
                }
                result += entries[i].first->to_string();
                result += ":";
                result += entries[i].second->to_string();
            }
            result += "}";
            return result;
        }
    };

    class value : public terminal, collection_terminal {
    public:
        std::map<bytes, bytes, serialized_compare> map;

        value(std::map<bytes, bytes, serialized_compare> map)
            : map(std::move(map)) {
        }

        static value from_serialized(bytes_view value, map_type type, 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: deserialize_for_native_protocol?!
                auto m = boost::any_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 { std::move(map) };
            } catch (marshal_exception& e) {
                throw exceptions::invalid_request_exception(e.why());
            }
        }

{'fraction_non_alphanumeric': 0.10731975784259769, 'fraction_numerical': 0.003363297254326423, 'mean_word_length': 2.5382951103418434, 'pattern_counts': {'":': 2, '<': 67, '<?xml version=': 0, '>': 119, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2583009', 'n_tokens_mistral': 4569, 'n_tokens_neox': 4406, 'n_words': 1057}