1 /* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
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 Street, Fifth Floor, Boston, MA 02110-1301, USA */
22 
23 // First include (the generated) my_config.h, to get correct platform defines.
24 #include "my_config.h"
25 #include <gtest/gtest.h>
26 
27 #include "test_utils.h"
28 
29 #include "opt_range.cc"
30 
31 namespace opt_range_unittest {
32 
33 using my_testing::Server_initializer;
34 
35 class SelArgTest : public ::testing::Test
36 {
37 protected:
SelArgTest()38   SelArgTest()
39   {
40     memset(&m_opt_param, 0, sizeof(m_opt_param));
41   }
42 
SetUp()43   virtual void SetUp()
44   {
45     initializer.SetUp();
46     m_opt_param.thd= thd();
47     m_opt_param.mem_root= &m_alloc;
48     m_opt_param.current_table= 1<<0;
49     init_sql_alloc(&m_alloc, thd()->variables.range_alloc_block_size, 0);
50   }
51 
TearDown()52   virtual void TearDown()
53   {
54     initializer.TearDown();
55     free_root(&m_alloc, MYF(0));
56   }
57 
thd()58   THD *thd() { return initializer.thd(); }
59 
60   Server_initializer initializer;
61   MEM_ROOT           m_alloc;
62   RANGE_OPT_PARAM    m_opt_param;
63 };
64 
65 /*
66  Experiment with these to measure performance of
67    'new (thd->mem_root)' Foo vs. 'new Foo'.
68  With gcc 4.4.2 I see ~4% difference (in optimized mode).
69 */
70 const int num_iterations= 10;
71 const int num_allocs= 10;
72 
TEST_F(SelArgTest,AllocateExplicit)73 TEST_F(SelArgTest, AllocateExplicit)
74 {
75   for (int ix= 0; ix < num_iterations; ++ix)
76   {
77     free_root(thd()->mem_root, MYF(MY_KEEP_PREALLOC));
78     for (int ii= 0; ii < num_allocs; ++ii)
79       new (thd()->mem_root) SEL_ARG;
80   }
81 }
82 
TEST_F(SelArgTest,AllocateImplicit)83 TEST_F(SelArgTest, AllocateImplicit)
84 {
85   for (int ix= 0; ix < num_iterations; ++ix)
86   {
87     free_root(thd()->mem_root, MYF(MY_KEEP_PREALLOC));
88     for (int ii= 0; ii < num_allocs; ++ii)
89       new SEL_ARG;
90   }
91 }
92 
93 /*
94   We cannot do EXPECT_NE(NULL, get_mm_tree(...))
95   because of limits in google test.
96  */
97 const SEL_TREE *null_tree= NULL;
98 const SEL_ARG  *null_arg= NULL;
99 
100 
101 class Mock_field_long : public Field_long
102 {
103 public:
Mock_field_long(THD * thd,Item * item)104   Mock_field_long(THD *thd, Item *item)
105     : Field_long(0,                             // ptr_arg
106                  8,                             // len_arg
107                  NULL,                          // null_ptr_arg
108                  0,                             // null_bit_arg
109                  Field::NONE,                   // unireg_check_arg
110                  "field_name",                  // field_name_arg
111                  false,                         // zero_arg
112                  false)                         // unsigned_arg
113   {
114     m_table_name= "mock_table";
115     memset(static_cast<void*>(&m_share), 0, sizeof(m_share));
116     const char *foo= "mock_db";
117     m_share.db.str= const_cast<char*>(foo);
118     m_share.db.length= strlen(m_share.db.str);
119 
120     bitmap_init(&share_allset, 0, sizeof(my_bitmap_map), 0);
121     bitmap_set_above(&share_allset, 0, 1); //all bits 1
122     m_share.all_set= share_allset;
123 
124     memset(static_cast<void*>(&m_table), 0, sizeof(m_table));
125     m_table.s= &m_share;
126 
127     bitmap_init(&tbl_readset, 0, sizeof(my_bitmap_map), 0);
128     m_table.read_set= &tbl_readset;
129 
130     bitmap_init(&tbl_writeset, 0, sizeof(my_bitmap_map), 0);
131     m_table.write_set= &tbl_writeset;
132 
133     m_table.map= 1<<0;
134     m_table.in_use= thd;
135     this->table_name= &m_table_name;
136     this->table= &m_table;
137     this->ptr= (uchar*) alloc_root((thd->mem_root), KEY_LENGTH);
138     if (item)
139       item->save_in_field_no_warnings(this, true);
140   }
~Mock_field_long()141   ~Mock_field_long()
142   {
143     bitmap_free(&share_allset);
144     bitmap_free(&tbl_readset);
145     bitmap_free(&tbl_writeset);
146   }
147 
148   // #bytes to store the value - see Field_long::key_lenght()
149   static const int KEY_LENGTH= 4;
150   const char *m_table_name;
151   TABLE_SHARE m_share;
152   TABLE       m_table;
153   MY_BITMAP   share_allset;
154   MY_BITMAP   tbl_readset;
155   MY_BITMAP   tbl_writeset;
156 };
157 
158 
print_selarg_ranges(String * s,SEL_ARG * sel_arg,const KEY_PART_INFO * kpi)159 static void print_selarg_ranges(String *s, SEL_ARG *sel_arg,
160                                 const KEY_PART_INFO *kpi)
161 {
162   for (SEL_ARG *cur= sel_arg->first();
163        cur != &null_element;
164        cur= cur->right)
165   {
166     String current_range;
167     append_range(&current_range, kpi, cur->min_value, cur->max_value,
168                  cur->min_flag | cur->max_flag);
169 
170     if (s->length() > 0)
171       s->append(STRING_WITH_LEN("\n"));
172 
173     s->append(current_range);
174   }
175 }
176 
177 
TEST_F(SelArgTest,SimpleCond)178 TEST_F(SelArgTest, SimpleCond)
179 {
180   EXPECT_NE(null_tree, get_mm_tree(&m_opt_param, new Item_int(42)));
181 }
182 
183 
184 /*
185   TODO: Here we try to build a range, but a lot of mocking remains
186   before it works as intended. Currently get_mm_tree() returns NULL
187   because m_opt_param.key_parts and m_opt_param.key_parts_end have not
188   been setup.
189 */
TEST_F(SelArgTest,EqualCond)190 TEST_F(SelArgTest, EqualCond)
191 {
192   Mock_field_long field_long(thd(), NULL);
193   m_opt_param.table= &field_long.m_table;
194   SEL_TREE *tree= get_mm_tree(&m_opt_param,
195                               new Item_equal(new Item_int(42),
196                                              new Item_field(&field_long)));
197   EXPECT_EQ(null_tree, tree);
198 }
199 
200 
TEST_F(SelArgTest,SelArgOnevalue)201 TEST_F(SelArgTest, SelArgOnevalue)
202 {
203   Mock_field_long field_long7(thd(), new Item_int(7));
204 
205   KEY_PART_INFO kpi;
206   kpi.init_from_field(&field_long7);
207 
208   uchar range_val7[field_long7.KEY_LENGTH];
209   field_long7.get_key_image(range_val7, kpi.length, Field::itRAW);
210 
211   SEL_ARG sel_arg7(&field_long7, range_val7, range_val7);
212   String range_string;
213   print_selarg_ranges(&range_string, &sel_arg7, &kpi);
214   const char expected[]= "7 <= field_name <= 7";
215   EXPECT_STREQ(expected, range_string.c_ptr());
216 
217   sel_arg7.min_flag|= NO_MIN_RANGE;
218   range_string.length(0);
219   print_selarg_ranges(&range_string, &sel_arg7, &kpi);
220   const char expected2[]= "field_name <= 7";
221   EXPECT_STREQ(expected2, range_string.c_ptr());
222 
223   sel_arg7.max_flag= NEAR_MAX;
224   range_string.length(0);
225   print_selarg_ranges(&range_string, &sel_arg7, &kpi);
226   const char expected3[]= "field_name < 7";
227   EXPECT_STREQ(expected3, range_string.c_ptr());
228 
229   sel_arg7.min_flag= NEAR_MIN;
230   sel_arg7.max_flag= NO_MAX_RANGE;
231   range_string.length(0);
232   print_selarg_ranges(&range_string, &sel_arg7, &kpi);
233   const char expected4[]= "7 < field_name";
234   EXPECT_STREQ(expected4, range_string.c_ptr());
235 
236   sel_arg7.min_flag= 0;
237   range_string.length(0);
238   print_selarg_ranges(&range_string, &sel_arg7, &kpi);
239   const char expected5[]= "7 <= field_name";
240   EXPECT_STREQ(expected5, range_string.c_ptr());
241 }
242 
243 
TEST_F(SelArgTest,SelArgBetween)244 TEST_F(SelArgTest, SelArgBetween)
245 {
246   Mock_field_long field_long3(thd(), new Item_int(3));
247   Mock_field_long field_long5(thd(), new Item_int(5));
248 
249   KEY_PART_INFO kpi;
250   kpi.init_from_field(&field_long3);
251 
252   uchar range_val3[field_long3.KEY_LENGTH];
253   field_long3.get_key_image(range_val3, kpi.length, Field::itRAW);
254 
255   uchar range_val5[field_long5.KEY_LENGTH];
256   field_long5.get_key_image(range_val5, kpi.length, Field::itRAW);
257 
258   SEL_ARG sel_arg35(&field_long3, range_val3, range_val5);
259 
260   String range_string;
261   print_selarg_ranges(&range_string, &sel_arg35, &kpi);
262   const char expected[]= "3 <= field_name <= 5";
263   EXPECT_STREQ(expected, range_string.c_ptr());
264 
265   range_string.length(0);
266   sel_arg35.min_flag= NEAR_MIN;
267   print_selarg_ranges(&range_string, &sel_arg35, &kpi);
268   const char expected2[]= "3 < field_name <= 5";
269   EXPECT_STREQ(expected2, range_string.c_ptr());
270 
271   range_string.length(0);
272   sel_arg35.max_flag= NEAR_MAX;
273   print_selarg_ranges(&range_string, &sel_arg35, &kpi);
274   const char expected3[]= "3 < field_name < 5";
275   EXPECT_STREQ(expected3, range_string.c_ptr());
276 
277   range_string.length(0);
278   sel_arg35.min_flag= 0;
279   print_selarg_ranges(&range_string, &sel_arg35, &kpi);
280   const char expected4[]= "3 <= field_name < 5";
281   EXPECT_STREQ(expected4, range_string.c_ptr());
282 
283   range_string.length(0);
284   sel_arg35.min_flag= NO_MIN_RANGE;
285   sel_arg35.max_flag= 0;
286   print_selarg_ranges(&range_string, &sel_arg35, &kpi);
287   const char expected5[]= "field_name <= 5";
288   EXPECT_STREQ(expected5, range_string.c_ptr());
289 
290   range_string.length(0);
291   sel_arg35.min_flag= 0;
292   sel_arg35.max_flag= NO_MAX_RANGE;
293   print_selarg_ranges(&range_string, &sel_arg35, &kpi);
294   const char expected6[]= "3 <= field_name";
295   EXPECT_STREQ(expected6, range_string.c_ptr());
296 }
297 
TEST_F(SelArgTest,CopyMax)298 TEST_F(SelArgTest, CopyMax)
299 {
300   Mock_field_long field_long3(thd(), new Item_int(3));
301   Mock_field_long field_long5(thd(), new Item_int(5));
302 
303   KEY_PART_INFO kpi;
304   kpi.init_from_field(&field_long3);
305 
306   uchar range_val3[field_long3.KEY_LENGTH];
307   field_long3.get_key_image(range_val3, kpi.length, Field::itRAW);
308 
309   uchar range_val5[field_long5.KEY_LENGTH];
310   field_long5.get_key_image(range_val5, kpi.length, Field::itRAW);
311 
312   SEL_ARG sel_arg3(&field_long3, range_val3, range_val3);
313   sel_arg3.min_flag= NO_MIN_RANGE;
314   SEL_ARG sel_arg5(&field_long5, range_val5, range_val5);
315   sel_arg5.min_flag= NO_MIN_RANGE;
316 
317   String range_string;
318   print_selarg_ranges(&range_string, &sel_arg3, &kpi);
319   const char expected[]= "field_name <= 3";
320   EXPECT_STREQ(expected, range_string.c_ptr());
321 
322   range_string.length(0);
323   print_selarg_ranges(&range_string, &sel_arg5, &kpi);
324   const char expected2[]= "field_name <= 5";
325   EXPECT_STREQ(expected2, range_string.c_ptr());
326 
327   /*
328     Ranges now:
329                        -inf ----------------3-5----------- +inf
330     sel_arg3:          [-------------------->
331     sel_arg5:          [---------------------->
332     Below: merge these two ranges into sel_arg3 using copy_max()
333   */
334   bool full_range= sel_arg3.copy_max(&sel_arg5);
335   // The merged range does not cover all possible values
336   EXPECT_FALSE(full_range);
337 
338   range_string.length(0);
339   print_selarg_ranges(&range_string, &sel_arg3, &kpi);
340   const char expected3[]= "field_name <= 5";
341   EXPECT_STREQ(expected3, range_string.c_ptr());
342 
343   range_string.length(0);
344   sel_arg5.min_flag= 0;
345   sel_arg5.max_flag= NO_MAX_RANGE;
346   print_selarg_ranges(&range_string, &sel_arg5, &kpi);
347   const char expected4[]= "5 <= field_name";
348   EXPECT_STREQ(expected4, range_string.c_ptr());
349 
350   /*
351     Ranges now:
352                        -inf ----------------3-5----------- +inf
353     sel_arg3:          [---------------------->
354     sel_arg5:                                 <---------------]
355     Below: merge these two ranges into sel_arg3 using copy_max()
356   */
357 
358   full_range= sel_arg3.copy_max(&sel_arg5);
359   // The new range covers all possible values
360   EXPECT_TRUE(full_range);
361 
362   range_string.length(0);
363   print_selarg_ranges(&range_string, &sel_arg3, &kpi);
364   const char expected5[]= "field_name";
365   EXPECT_STREQ(expected5, range_string.c_ptr());
366 }
367 
TEST_F(SelArgTest,CopyMin)368 TEST_F(SelArgTest, CopyMin)
369 {
370   Mock_field_long field_long3(thd(), new Item_int(3));
371   Mock_field_long field_long5(thd(), new Item_int(5));
372 
373   KEY_PART_INFO kpi;
374   kpi.init_from_field(&field_long3);
375 
376   uchar range_val3[field_long3.KEY_LENGTH];
377   field_long3.get_key_image(range_val3, kpi.length, Field::itRAW);
378 
379   uchar range_val5[field_long5.KEY_LENGTH];
380   field_long5.get_key_image(range_val5, kpi.length, Field::itRAW);
381 
382   SEL_ARG sel_arg3(&field_long3, range_val3, range_val3);
383   sel_arg3.max_flag= NO_MAX_RANGE;
384   SEL_ARG sel_arg5(&field_long5, range_val5, range_val5);
385   sel_arg5.max_flag= NO_MAX_RANGE;
386 
387   String range_string;
388   print_selarg_ranges(&range_string, &sel_arg3, &kpi);
389   const char expected[]= "3 <= field_name";
390   EXPECT_STREQ(expected, range_string.c_ptr());
391 
392   range_string.length(0);
393   print_selarg_ranges(&range_string, &sel_arg5, &kpi);
394   const char expected2[]= "5 <= field_name";
395   EXPECT_STREQ(expected2, range_string.c_ptr());
396 
397   /*
398     Ranges now:
399                        -inf ----------------3-5----------- +inf
400     sel_arg3:                               <-----------------]
401     sel_arg5:                                 <---------------]
402     Below: merge these two ranges into sel_arg3 using copy_max()
403   */
404   bool full_range= sel_arg5.copy_min(&sel_arg3);
405   // The merged range does not cover all possible values
406   EXPECT_FALSE(full_range);
407 
408   range_string.length(0);
409   print_selarg_ranges(&range_string, &sel_arg5, &kpi);
410   const char expected3[]= "3 <= field_name";
411   EXPECT_STREQ(expected3, range_string.c_ptr());
412 
413   range_string.length(0);
414   sel_arg3.max_flag= 0;
415   sel_arg3.min_flag= NO_MIN_RANGE;
416   print_selarg_ranges(&range_string, &sel_arg3, &kpi);
417   const char expected4[]= "field_name <= 3";
418   EXPECT_STREQ(expected4, range_string.c_ptr());
419 
420   /*
421     Ranges now:
422                        -inf ----------------3-5----------- +inf
423     sel_arg3:          [-------------------->
424     sel_arg5:                               <-----------------]
425     Below: merge these two ranges into sel_arg5 using copy_min()
426   */
427 
428   full_range= sel_arg5.copy_min(&sel_arg3);
429   // The new range covers all possible values
430   EXPECT_TRUE(full_range);
431 
432   range_string.length(0);
433   print_selarg_ranges(&range_string, &sel_arg5, &kpi);
434   const char expected5[]= "field_name";
435   EXPECT_STREQ(expected5, range_string.c_ptr());
436 }
437 
438 
TEST_F(SelArgTest,KeyOr1)439 TEST_F(SelArgTest, KeyOr1)
440 {
441   Mock_field_long field_long3(thd(), new Item_int(3));
442   Mock_field_long field_long4(thd(), new Item_int(4));
443 
444   KEY_PART_INFO kpi;
445   kpi.init_from_field(&field_long3);
446 
447   uchar range_val3[field_long3.KEY_LENGTH];
448   field_long3.get_key_image(range_val3, kpi.length, Field::itRAW);
449 
450   uchar range_val4[field_long4.KEY_LENGTH];
451   field_long4.get_key_image(range_val4, kpi.length, Field::itRAW);
452 
453   SEL_ARG sel_arg_lt3(&field_long3, range_val3, range_val3);
454   sel_arg_lt3.part= 0;
455   sel_arg_lt3.min_flag= NO_MIN_RANGE;
456   sel_arg_lt3.max_flag= NEAR_MAX;
457 
458   SEL_ARG sel_arg_gt3(&field_long3, range_val3, range_val3);
459   sel_arg_gt3.part= 0;
460   sel_arg_gt3.min_flag= NEAR_MIN;
461   sel_arg_gt3.max_flag= NO_MAX_RANGE;
462 
463   SEL_ARG sel_arg_lt4(&field_long4, range_val4, range_val4);
464   sel_arg_lt4.part= 0;
465   sel_arg_lt4.min_flag= NO_MIN_RANGE;
466   sel_arg_lt4.max_flag= NEAR_MAX;
467 
468   String range_string;
469   print_selarg_ranges(&range_string, &sel_arg_lt3, &kpi);
470   const char expected_lt3[]= "field_name < 3";
471   EXPECT_STREQ(expected_lt3, range_string.c_ptr());
472 
473   range_string.length(0);
474   print_selarg_ranges(&range_string, &sel_arg_gt3, &kpi);
475   const char expected_gt3[]= "3 < field_name";
476   EXPECT_STREQ(expected_gt3, range_string.c_ptr());
477 
478   range_string.length(0);
479   print_selarg_ranges(&range_string, &sel_arg_lt4, &kpi);
480   const char expected_lt4[]= "field_name < 4";
481   EXPECT_STREQ(expected_lt4, range_string.c_ptr());
482 
483 
484   /*
485     Ranges now:
486                        -inf ----------------34----------- +inf
487     sel_arg_lt3:       [-------------------->
488     sel_arg_gt3:                             <---------------]
489     sel_arg_lt4:       [--------------------->
490   */
491 
492   SEL_ARG *tmp= key_or(NULL, &sel_arg_lt3, &sel_arg_gt3);
493 
494   /*
495     Ranges now:
496                        -inf ----------------34----------- +inf
497     tmp:               [--------------------><---------------]
498     sel_arg_lt4:       [--------------------->
499   */
500   range_string.length(0);
501   print_selarg_ranges(&range_string, tmp, &kpi);
502   const char expected_merged[]=
503     "field_name < 3\n"
504     "3 < field_name";
505   EXPECT_STREQ(expected_merged, range_string.c_ptr());
506 
507   SEL_ARG *tmp2= key_or(NULL, tmp, &sel_arg_lt4);
508   EXPECT_EQ(null_arg, tmp2);
509 }
510 
511 }
512 
513 
514