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