1 /* Copyright (c) 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include "my_config.h"
24 #include <gmock/gmock.h>
25 #include <gtest/gtest.h>
26
27 #include <string>
28
29 #include "item.h"
30 #include "item_cmpfunc.h"
31 #include "sql_class.h"
32 #include "test_utils.h"
33
34 namespace item_func_regex_unittest {
35
36 using my_testing::Server_initializer;
37
38 static const char *substrings[2] = {
39 "Folder=RootObject="
40 "Operating System-WinWinServerLocalAdminis-trator1-ABCDEFGHI01-adminimm",
41 "tasktype=ReconcileTask"};
42
43 static const char *wild_like = "%";
44 static const char *wild_rlike = ".*";
45 static const char escape[] = "\\";
46
make_like_pattern()47 static std::string make_like_pattern() {
48 return std::string(wild_like) + substrings[0] + wild_like + substrings[1] +
49 wild_like;
50 }
51
make_rlike_pattern()52 static std::string make_rlike_pattern() {
53 return std::string(wild_rlike) + substrings[0] + wild_rlike + substrings[1] +
54 wild_rlike;
55 }
56
make_matched_string()57 static std::string make_matched_string() {
58 return std::string("hello") + substrings[0] + "42" + substrings[1] +
59 "goodbye";
60 }
61
init_collation(const char * name)62 CHARSET_INFO *init_collation(const char *name) {
63 MY_CHARSET_LOADER loader;
64 my_charset_loader_init_mysys(&loader);
65 return my_collation_get_by_name(&loader, name, MYF(0));
66 }
67
make_string_item(std::string * str)68 Item_string *make_string_item(std::string *str) {
69 CHARSET_INFO *cs = init_collation("ascii_general_ci");
70 return new Item_string(str->c_str(), str->length(), cs);
71 }
72
73 class LikeVSRlikeTest : public ::testing::Test {
74 protected:
SetUp()75 virtual void SetUp() {
76 initializer.SetUp();
77
78 dummy_string = "this is a dummy string";
79 like_pattern = make_like_pattern();
80 rlike_pattern = make_rlike_pattern();
81 match_string = make_matched_string();
82
83 dummy_subject_item = make_string_item(&dummy_string);
84 match_subject_item = make_string_item(&match_string);
85 like_pattern_item = make_string_item(&like_pattern);
86 rlike_pattern_item = make_string_item(&rlike_pattern);
87 it_escape = new Item_string(STRING_WITH_LEN(escape), &my_charset_latin1);
88 }
TearDown()89 virtual void TearDown() { initializer.TearDown(); }
90
thd()91 THD *thd() { return initializer.thd(); }
92
93 std::string dummy_string;
94 std::string like_pattern;
95 std::string rlike_pattern;
96 std::string match_string;
97
98 Server_initializer initializer;
99 Item_string *dummy_subject_item;
100 Item_string *match_subject_item;
101 Item_string *like_pattern_item;
102 Item_string *rlike_pattern_item;
103 Item_string *it_escape;
104 };
105
106 // "dummy text" LIKE "pattern with three %"
107 // "matching text" LIKE "pattern with three %"
TEST_F(LikeVSRlikeTest,SimpleLike)108 TEST_F(LikeVSRlikeTest, SimpleLike) {
109 Item_func_like *like_item = new Item_func_like(
110 dummy_subject_item, like_pattern_item, it_escape, false);
111 EXPECT_EQ(0, like_item->fix_fields(thd(), NULL));
112 EXPECT_EQ(0, like_item->val_int());
113
114 like_item = new Item_func_like(match_subject_item, like_pattern_item,
115 it_escape, false);
116 EXPECT_EQ(0, like_item->fix_fields(thd(), NULL));
117 EXPECT_EQ(1, like_item->val_int());
118 }
119
120 // "dummy text" REGEXP "pattern with three .*"
121 // "matching text" REGEXP "pattern with three .*"
TEST_F(LikeVSRlikeTest,SimpleRLike)122 TEST_F(LikeVSRlikeTest, SimpleRLike) {
123 POS pos;
124 Item *like_item =
125 new Item_func_regex(pos, dummy_subject_item, rlike_pattern_item);
126 EXPECT_EQ(0, like_item->fix_fields(thd(), NULL));
127 EXPECT_EQ(0, like_item->val_int());
128 like_item->cleanup();
129
130 like_item = new Item_func_regex(pos, match_subject_item, rlike_pattern_item);
131 EXPECT_EQ(0, like_item->fix_fields(thd(), NULL));
132 EXPECT_EQ(1, like_item->val_int());
133 like_item->cleanup();
134 }
135
136 /*
137 To benchmark:
138 make item_func_rlike-t
139 ./unittest/gunit/item_func_rlike-t --disable-tap-output
140
141 googletest reports total time in milliseconds,
142 and we do num_iterations = 1000000;
143 so translation to ns/iter is trivial.
144 */
145
146 // Do each algorithm this many times. Increase value for benchmarking!
147 // static const size_t num_iterations = 1000000;
148 static const size_t num_iterations = 1;
149
TEST_F(LikeVSRlikeTest,BM_LikeNoMatch)150 TEST_F(LikeVSRlikeTest, BM_LikeNoMatch) {
151 Item_func_like *like_item = new Item_func_like(
152 dummy_subject_item, like_pattern_item, it_escape, false);
153 EXPECT_EQ(0, like_item->fix_fields(thd(), NULL));
154 for (size_t i = 0; i < num_iterations; ++i) {
155 EXPECT_EQ(0, like_item->val_int());
156 }
157 }
158
TEST_F(LikeVSRlikeTest,BM_LikeWithMatch)159 TEST_F(LikeVSRlikeTest, BM_LikeWithMatch) {
160 Item_func_like *like_item = new Item_func_like(
161 match_subject_item, like_pattern_item, it_escape, false);
162 EXPECT_EQ(0, like_item->fix_fields(thd(), NULL));
163 for (size_t i = 0; i < num_iterations; ++i) {
164 EXPECT_EQ(1, like_item->val_int());
165 }
166 }
167
TEST_F(LikeVSRlikeTest,BM_RlikeNoMatch)168 TEST_F(LikeVSRlikeTest, BM_RlikeNoMatch) {
169 POS pos;
170 Item *like_item =
171 new Item_func_regex(pos, dummy_subject_item, rlike_pattern_item);
172 EXPECT_EQ(0, like_item->fix_fields(thd(), NULL));
173 for (size_t i = 0; i < num_iterations; ++i) {
174 EXPECT_EQ(0, like_item->val_int());
175 }
176 like_item->cleanup();
177 }
178
TEST_F(LikeVSRlikeTest,BM_RlikeWithMatch)179 TEST_F(LikeVSRlikeTest, BM_RlikeWithMatch) {
180 POS pos;
181 Item *like_item =
182 new Item_func_regex(pos, match_subject_item, rlike_pattern_item);
183 EXPECT_EQ(0, like_item->fix_fields(thd(), NULL));
184 for (size_t i = 0; i < num_iterations; ++i) {
185 EXPECT_EQ(1, like_item->val_int());
186 }
187 like_item->cleanup();
188 }
189
190 } // namespace item_func_regex_unittest
191