| /** |
| * 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. |
| **/ |
| |
| #ifndef QUICKSTEP_TYPES_OPERATIONS_COMPARISONS_PATTERN_MATCHING_COMPARATORS_HPP_ |
| #define QUICKSTEP_TYPES_OPERATIONS_COMPARISONS_PATTERN_MATCHING_COMPARATORS_HPP_ |
| |
| #include <cstddef> |
| #include <string> |
| |
| #include "catalog/CatalogTypedefs.hpp" |
| #include "types/TypedValue.hpp" |
| #include "types/operations/comparisons/Comparison.hpp" |
| #include "types/port/strnlen.hpp" |
| |
| #include "re2/stringpiece.h" |
| #include "re2/re2.h" |
| |
| namespace quickstep { |
| |
| class ColumnVector; |
| class TupleIdSequence; |
| class ValueAccessor; |
| |
| /** \addtogroup Types |
| * @{ |
| */ |
| |
| /** |
| * @brief Base class for UncheckedComparators which does pattern matching. |
| **/ |
| template <bool is_like_pattern, bool is_negation, |
| bool left_nullable, bool right_nullable> |
| class PatternMatchingUncheckedComparator : public UncheckedComparator { |
| public: |
| /** |
| * @brief Constructor. |
| **/ |
| PatternMatchingUncheckedComparator(const std::size_t left_length, |
| const std::size_t right_length) |
| : left_length_(left_length), |
| right_length_(right_length) { |
| } |
| |
| inline bool compareDataPtrs(const void *left, |
| const void *right) const override { |
| return compareDataPtrsInl(left, right); |
| } |
| |
| inline bool compareDataPtrsInl(const void *left, |
| const void *right) const { |
| if ((left_nullable && (left == nullptr)) |
| || (right_nullable && (right == nullptr))) { |
| return false; |
| } |
| |
| const char* text = static_cast<const char*>(left); |
| const re2::StringPiece text_piece(text, strnlen(text, left_length_)); |
| |
| const char* pattern = static_cast<const char*>(right); |
| std::string regex_pattern; |
| re2::StringPiece pattern_piece; |
| int orig_pattern_len = strnlen(pattern, right_length_); |
| if (is_like_pattern) { |
| regex_pattern = transformLikeToRegex(pattern, orig_pattern_len); |
| pattern_piece.set(regex_pattern.c_str(), regex_pattern.size()); |
| } else { |
| pattern_piece.set(pattern, orig_pattern_len); |
| } |
| const re2::RE2 re2_pattern(pattern_piece); |
| return match(text_piece, re2_pattern); |
| } |
| |
| inline bool compareTypedValues(const TypedValue &left, |
| const TypedValue &right) const override { |
| return compareDataPtrsInl(left.getOutOfLineData(), right.getOutOfLineData()); |
| } |
| |
| inline bool compareTypedValueWithDataPtr(const TypedValue &left, |
| const void *right) const override { |
| return compareDataPtrsInl(left.getOutOfLineData(), right); |
| } |
| |
| inline bool compareDataPtrWithTypedValue(const void *left, |
| const TypedValue &right) const override { |
| return compareDataPtrsInl(left, right.getOutOfLineData()); |
| } |
| |
| TupleIdSequence* compareColumnVectors( |
| const ColumnVector &left, |
| const ColumnVector &right, |
| const TupleIdSequence *filter, |
| const TupleIdSequence *existence_bitmap) const override; |
| |
| TupleIdSequence* compareColumnVectorAndStaticValue( |
| const ColumnVector &left, |
| const TypedValue &right, |
| const TupleIdSequence *filter, |
| const TupleIdSequence *existence_bitmap) const override; |
| |
| TupleIdSequence* compareStaticValueAndColumnVector( |
| const TypedValue &left, |
| const ColumnVector &right, |
| const TupleIdSequence *filter, |
| const TupleIdSequence *existence_bitmap) const override; |
| |
| #ifdef QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION |
| TupleIdSequence* compareSingleValueAccessor( |
| ValueAccessor *accessor, |
| const attribute_id left_id, |
| const attribute_id right_id, |
| const TupleIdSequence *filter) const override; |
| |
| TupleIdSequence* compareValueAccessorAndStaticValue( |
| ValueAccessor *left_accessor, |
| const attribute_id left_id, |
| const TypedValue &right, |
| const TupleIdSequence *filter) const override; |
| |
| TupleIdSequence* compareStaticValueAndValueAccessor( |
| const TypedValue &left, |
| ValueAccessor *right_accessor, |
| const attribute_id right_id, |
| const TupleIdSequence *filter) const override; |
| |
| TupleIdSequence* compareColumnVectorAndValueAccessor( |
| const ColumnVector &left, |
| ValueAccessor *right_accessor, |
| const attribute_id right_id, |
| const TupleIdSequence *filter, |
| const TupleIdSequence *existence_bitmap) const override; |
| |
| TupleIdSequence* compareValueAccessorAndColumnVector( |
| ValueAccessor *left_accessor, |
| const attribute_id left_id, |
| const ColumnVector &right, |
| const TupleIdSequence *filter, |
| const TupleIdSequence *existence_bitmap) const override; |
| |
| TypedValue accumulateValueAccessor( |
| const TypedValue ¤t, |
| ValueAccessor *accessor, |
| const attribute_id value_accessor_id) const override; |
| #endif // QUICKSTEP_ENABLE_VECTOR_COPY_ELISION_SELECTION |
| |
| TypedValue accumulateColumnVector( |
| const TypedValue ¤t, |
| const ColumnVector &column_vector) const override; |
| |
| private: |
| /** |
| * @brief Checks whether the raw text matches pattern. |
| * |
| * @param text The raw text to be checked, must be not null. |
| * @param pattern The pattern to be matched against. |
| * |
| * @return Whether text matches pattern. |
| **/ |
| inline bool matchDataPtrWithPattern(const void *text, |
| const re2::RE2 &pattern) const { |
| const char* c_text = static_cast<const char*>(text); |
| const re2::StringPiece text_piece(c_text, strnlen(c_text, left_length_)); |
| return match(text_piece, pattern); |
| } |
| |
| /** |
| * @brief Checks whether text matches pattern. |
| * |
| * @param text The text to be checked. |
| * @param pattern The pattern to be matched against. |
| * |
| * @return Whether text matches pattern. |
| **/ |
| inline bool match(const re2::StringPiece &text, |
| const re2::RE2 &pattern) const { |
| if (is_negation) { |
| return !(re2::RE2::FullMatch(text, pattern)); |
| } else { |
| return re2::RE2::FullMatch(text, pattern); |
| } |
| } |
| |
| /** |
| * @brief Tranform a LIKE pattern to the corresponding regular expression |
| * pattern. |
| * |
| * @param like_pattern The original LIKE pattern. |
| * @param len The length of the LIKE pattern. |
| * |
| * @return The transformed regular expression pattern. |
| */ |
| inline std::string transformLikeToRegex(const char *like_pattern, |
| const std::size_t len) const { |
| std::string regex_pattern; |
| for (std::size_t i = 0; i < len; i++) { |
| char c = like_pattern[i]; |
| switch (c) { |
| case '_': |
| regex_pattern.append("(.|\n)"); |
| break; |
| case '%': |
| regex_pattern.append("(.|\n)*"); |
| break; |
| default: |
| // Escape special characters |
| if ((c < 'a' || c > 'z') |
| && (c < 'A' || c > 'Z') |
| && (c < '0' || c > '9') |
| && !(c & 128)) { |
| regex_pattern.push_back('\\'); |
| } |
| regex_pattern.push_back(c); |
| break; |
| } |
| } |
| return regex_pattern; |
| } |
| |
| const std::size_t left_length_; |
| const std::size_t right_length_; |
| }; |
| |
| /** @} */ |
| |
| } // namespace quickstep |
| |
| #endif // QUICKSTEP_TYPES_OPERATIONS_COMPARISONS_PATTERN_MATCHING_COMPARATORS_HPP_ |