Short-circuit pattern matches for the following common sub cases : - starts_with, ends_with and is_substr
| 35 | // Short-circuit pattern matches for the following common sub cases : |
| 36 | // - starts_with, ends_with and is_substr |
| 37 | const FunctionNode LikeHolder::TryOptimize(const FunctionNode& node) { |
| 38 | // NOTE: avoid making those constants global to avoid compiling regexes at startup |
| 39 | // pre-compiled pattern for matching starts_with |
| 40 | static const RE2 starts_with_regex(R"(([^\.\*])*\.\*)"); |
| 41 | // pre-compiled pattern for matching ends_with |
| 42 | static const RE2 ends_with_regex(R"(\.\*([^\.\*])*)"); |
| 43 | // pre-compiled pattern for matching is_substr |
| 44 | static const RE2 is_substr_regex(R"(\.\*([^\.\*])*\.\*)"); |
| 45 | |
| 46 | static bool global_checked = false; |
| 47 | if (ARROW_PREDICT_FALSE(!global_checked)) { |
| 48 | if (ARROW_PREDICT_FALSE( |
| 49 | !(starts_with_regex.ok() && ends_with_regex.ok() && is_substr_regex.ok()))) { |
| 50 | return node; |
| 51 | } |
| 52 | global_checked = true; |
| 53 | } |
| 54 | |
| 55 | auto maybe_holder = Make(node); |
| 56 | if (maybe_holder.ok()) { |
| 57 | auto holder = *maybe_holder; |
| 58 | std::string& pattern = holder->pattern_; |
| 59 | auto literal_type = node.children().at(1)->return_type(); |
| 60 | |
| 61 | if (RE2::FullMatch(pattern, starts_with_regex)) { |
| 62 | auto prefix = pattern.substr(0, pattern.length() - 2); // trim .* |
| 63 | auto parsed_prefix = RemovePatternEscapeChars(node, prefix); |
| 64 | auto prefix_node = std::make_shared<LiteralNode>( |
| 65 | literal_type, LiteralHolder(parsed_prefix), false); |
| 66 | return FunctionNode("starts_with", {node.children().at(0), prefix_node}, |
| 67 | node.return_type()); |
| 68 | } else if (RE2::FullMatch(pattern, ends_with_regex)) { |
| 69 | auto suffix = pattern.substr(2); // skip .* |
| 70 | auto parsed_suffix = RemovePatternEscapeChars(node, suffix); |
| 71 | auto suffix_node = std::make_shared<LiteralNode>( |
| 72 | literal_type, LiteralHolder(parsed_suffix), false); |
| 73 | return FunctionNode("ends_with", {node.children().at(0), suffix_node}, |
| 74 | node.return_type()); |
| 75 | } else if (RE2::FullMatch(pattern, is_substr_regex)) { |
| 76 | auto substr = |
| 77 | pattern.substr(2, pattern.length() - 4); // trim starting and ending .* |
| 78 | auto parsed_substr = RemovePatternEscapeChars(node, substr); |
| 79 | auto substr_node = std::make_shared<LiteralNode>( |
| 80 | literal_type, LiteralHolder(parsed_substr), false); |
| 81 | return FunctionNode("is_substr", {node.children().at(0), substr_node}, |
| 82 | node.return_type()); |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | // Could not optimize, return original node. |
| 87 | return node; |
| 88 | } |
| 89 | |
| 90 | Result<std::shared_ptr<LikeHolder>> LikeHolder::Make(const FunctionNode& node) { |
| 91 | ARROW_RETURN_IF(node.children().size() != 2 && node.children().size() != 3, |
nothing calls this directly
no test coverage detected