MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
opt_trace-t.cc
Go to the documentation of this file.
1 /* Copyright (c) 2011, 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 as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
21 // First include (the generated) my_config.h, to get correct platform defines.
22 #include "my_config.h"
23 #include <gtest/gtest.h>
24 
25 #ifdef OPTIMIZER_TRACE
26 
27 #include <opt_trace.h>
28 #include <mysys_err.h> // for testing of OOM
29 #include "mysqld.h" // system_charset_info
30 #ifdef HAVE_SYS_WAIT_H
31 #include <sys/wait.h> // for WEXITSTATUS
32 #endif
33 
34 namespace opt_trace_unittest {
35 
36 const ulonglong all_features= Opt_trace_context::default_features;
37 
43 #define check_json_compliance(str, length) \
44  { \
45  SCOPED_TRACE(""); \
46  do_check_json_compliance(str, length); \
47  }
48 
58 void do_check_json_compliance(const char *str, size_t length)
59 {
60  return;
61  /*
62  Read from stdin, eliminate comments, parse as JSON. If invalid, an
63  exception is thrown by Python, uncaught, which produces a non-zero error
64  code.
65  */
66 #ifndef __WIN__
67  const char python_cmd[]=
68  "python -c \""
69  "import json, re, sys;"
70  "s= sys.stdin.read();"
71  "s= re.sub('/\\\\*[ A-Za-z_]* \\\\*/', '', s);"
72  "json.loads(s, 'utf-8')\"";
73  // Send the trace to this new process' stdin:
74  FILE *fd= popen(python_cmd, "w");
75  ASSERT_TRUE(NULL != fd);
76  ASSERT_NE(0U, length); // empty is not compliant
77  ASSERT_EQ(1U, fwrite(str, length, 1, fd));
78  int rc= pclose(fd);
79  rc= WEXITSTATUS(rc);
80  EXPECT_EQ(0, rc);
81 #endif
82 }
83 
84 extern "C"
85 void my_error_handler(uint error, const char *str, myf MyFlags);
86 
87 
88 class TraceContentTest : public ::testing::Test
89 {
90 public:
91  Opt_trace_context trace;
92  static bool oom;
93 protected:
94  static void SetUpTestCase()
95  {
96  system_charset_info= &my_charset_utf8_general_ci;
97  }
98  virtual void SetUp()
99  {
100  error_handler_hook= my_error_handler;
101  oom= false;
102  // Setting debug flags triggers enter/exit trace, so redirect to /dev/null
103  DBUG_SET("o," IF_WIN("NUL", "/dev/null"));
104  }
105 
106 };
107 bool TraceContentTest::oom;
108 
109 
110 void my_error_handler(uint error, const char *str, myf MyFlags)
111 {
112  const uint EE= static_cast<uint>(EE_OUTOFMEMORY);
113  EXPECT_EQ(EE, error);
114  if (error == EE)
115  TraceContentTest::oom= true;
116 }
117 
118 
119 
120 TEST_F(TraceContentTest, ConstructAndDestruct)
121 {
122 }
123 
124 
126 TEST_F(TraceContentTest, Empty)
127 {
128  ASSERT_FALSE(trace.start(true, false, false, false, -1, 1, ULONG_MAX,
129  all_features));
130  EXPECT_TRUE(trace.is_started());
131  EXPECT_TRUE(trace.support_I_S());
132  /*
133  Add at least an object to it. A really empty trace ("") is not
134  JSON-compliant, at least Python's JSON module raises an exception.
135  */
136  {
137  Opt_trace_object oto(&trace);
138  }
139  /* End trace */
140  trace.end();
141  /* And verify trace's content */
142  Opt_trace_iterator it(&trace);
143  /*
144  ASSERT here, because a failing EXPECT_FALSE would continue into
145  it.get_value() and segfault.
146  */
147  ASSERT_FALSE(it.at_end());
148  Opt_trace_info info;
149  it.get_value(&info);
150  const char expected[]= "{\n}";
151  EXPECT_STREQ(expected, info.trace_ptr);
152  EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
153  check_json_compliance(info.trace_ptr, info.trace_length);
154  EXPECT_EQ(0U, info.missing_bytes);
155  EXPECT_FALSE(info.missing_priv);
156  EXPECT_FALSE(oom);
157  /* Should be no more traces */
158  it.next();
159  ASSERT_TRUE(it.at_end());
160 }
161 
162 
164 TEST_F(TraceContentTest, NormalUsage)
165 {
166  ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
167  all_features));
168  {
169  Opt_trace_object oto(&trace);
170  oto.add_select_number(123456);
171  {
172  Opt_trace_array ota(&trace, "one array");
173  ota.add(200.4);
174  {
175  Opt_trace_object oto1(&trace);
176  oto1.add_alnum("one key", "one value").
177  add("another key", 100U);
178  }
179  ota.add_alnum("one string element");
180  ota.add(true);
181  ota.add_hex(12318421343459ULL);
182  }
183  oto.add("yet another key", -1000LL);
184  {
185  Opt_trace_array ota(&trace, "another array");
186  ota.add(1LL).add(2).add(3LL).add(4LL);
187  }
188  }
189  trace.end();
190  Opt_trace_iterator it(&trace);
191  ASSERT_FALSE(it.at_end());
192  Opt_trace_info info;
193  it.get_value(&info);
194  const char expected[]=
195  "{\n"
196  " \"select#\": 123456,\n"
197  " \"one array\": [\n"
198  " 200.4,\n"
199  " {\n"
200  " \"one key\": \"one value\",\n"
201  " \"another key\": 100\n"
202  " },\n"
203  " \"one string element\",\n"
204  " true,\n"
205  " 0x0b341b20dce3\n"
206  " ] /* one array */,\n"
207  " \"yet another key\": -1000,\n"
208  " \"another array\": [\n"
209  " 1,\n"
210  " 2,\n"
211  " 3,\n"
212  " 4\n"
213  " ] /* another array */\n"
214  "}";
215  EXPECT_STREQ(expected, info.trace_ptr);
216  EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
217  check_json_compliance(info.trace_ptr, info.trace_length);
218  EXPECT_EQ(0U, info.missing_bytes);
219  EXPECT_FALSE(info.missing_priv);
220  EXPECT_FALSE(oom);
221  it.next();
222  ASSERT_TRUE(it.at_end());
223 }
224 
225 
227 TEST_F(TraceContentTest, BuggyObject)
228 {
229  ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
230  all_features));
231  {
232  Opt_trace_object oto(&trace);
233  {
234  Opt_trace_array ota(&trace, "one array");
235  ota.add(200.4);
236  {
237  Opt_trace_object oto1(&trace);
238  oto1.add_alnum("one value"); // no key, which is wrong
239  oto1.add(326); // same
240  Opt_trace_object oto2(&trace); // same
241  }
242  ota.add_alnum("one string element");
243  ota.add(true);
244  }
245  oto.add("yet another key", -1000LL);
246  {
247  Opt_trace_array ota(&trace, "another array");
248  ota.add(1LL).add(2LL).add(3LL).add(4LL);
249  }
250  }
251  trace.end();
252  Opt_trace_iterator it(&trace);
253  ASSERT_FALSE(it.at_end());
254  Opt_trace_info info;
255  it.get_value(&info);
256  const char expected[]=
257  "{\n"
258  " \"one array\": [\n"
259  " 200.4,\n"
260  " {\n"
261  " \"unknown_key_1\": \"one value\",\n"
262  " \"unknown_key_2\": 326,\n"
263  " \"unknown_key_3\": {\n"
264  " }\n"
265  " },\n"
266  " \"one string element\",\n"
267  " true\n"
268  " ] /* one array */,\n"
269  " \"yet another key\": -1000,\n"
270  " \"another array\": [\n"
271  " 1,\n"
272  " 2,\n"
273  " 3,\n"
274  " 4\n"
275  " ] /* another array */\n"
276  "}";
277  EXPECT_STREQ(expected, info.trace_ptr);
278  EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
279  check_json_compliance(info.trace_ptr, info.trace_length);
280  EXPECT_EQ(0U, info.missing_bytes);
281  EXPECT_FALSE(info.missing_priv);
282  EXPECT_FALSE(oom);
283  it.next();
284  ASSERT_TRUE(it.at_end());
285 }
286 
287 
289 TEST_F(TraceContentTest, BuggyArray)
290 {
291  ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
292  all_features));
293  {
294  Opt_trace_object oto(&trace);
295  {
296  Opt_trace_array ota(&trace, "one array");
297  ota.add("superfluous key", 200.4); // key, which is wrong
298  ota.add("not necessary", 326); // same
299  Opt_trace_object oto2(&trace, "not needed"); // same
300  }
301  oto.add("yet another key", -1000LL);
302  {
303  Opt_trace_array ota(&trace, "another array");
304  ota.add(1LL).add(2LL).add(3LL).add(4LL);
305  }
306  }
307  trace.end();
308  Opt_trace_iterator it(&trace);
309  ASSERT_FALSE(it.at_end());
310  Opt_trace_info info;
311  it.get_value(&info);
312  const char expected[]=
313  "{\n"
314  " \"one array\": [\n"
315  " 200.4,\n"
316  " 326,\n"
317  " {\n"
318  " } /* not needed */\n"
319  " ] /* one array */,\n"
320  " \"yet another key\": -1000,\n"
321  " \"another array\": [\n"
322  " 1,\n"
323  " 2,\n"
324  " 3,\n"
325  " 4\n"
326  " ] /* another array */\n"
327  "}";
328  EXPECT_STREQ(expected, info.trace_ptr);
329  EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
330  check_json_compliance(info.trace_ptr, info.trace_length);
331  EXPECT_EQ(0U, info.missing_bytes);
332  EXPECT_FALSE(info.missing_priv);
333  EXPECT_FALSE(oom);
334  it.next();
335  ASSERT_TRUE(it.at_end());
336 }
337 
338 
340 TEST_F(TraceContentTest, DisableISWithObject)
341 {
342  ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
343  all_features));
344  {
345  Opt_trace_object oto(&trace);
346  {
347  Opt_trace_array ota(&trace, "one array");
348  ota.add(200.4);
349  {
350  Opt_trace_object oto1(&trace);
351  oto1.add_alnum("one key", "one value").
352  add("another key", 100LL);
353  Opt_trace_disable_I_S otd(&trace, true);
354  oto1.add("a third key", false);
355  Opt_trace_object oto2(&trace, "a fourth key");
356  oto2.add("key inside", 1LL);
357  /* don't disable... but above layer is stronger */
358  Opt_trace_disable_I_S otd2(&trace, false);
359  oto2.add("another key inside", 5LL);
360  // disabling should apply to substatements too:
361  ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
362  all_features));
363  {
364  Opt_trace_object oto3(&trace);
365  }
366  trace.end();
367  }
368  ota.add_alnum("one string element");
369  ota.add(true);
370  }
371  Opt_trace_disable_I_S otd2(&trace, false); // don't disable
372  oto.add("yet another key", -1000LL);
373  {
374  Opt_trace_array ota(&trace, "another array");
375  ota.add(1LL).add(2LL).add(3LL).add(4LL);
376  }
377  }
378  trace.end();
379  Opt_trace_iterator it(&trace);
380  ASSERT_FALSE(it.at_end());
381  Opt_trace_info info;
382  it.get_value(&info);
383  const char expected[]=
384  "{\n"
385  " \"one array\": [\n"
386  " 200.4,\n"
387  " {\n"
388  " \"one key\": \"one value\",\n"
389  " \"another key\": 100\n"
390  " },\n"
391  " \"one string element\",\n"
392  " true\n"
393  " ] /* one array */,\n"
394  " \"yet another key\": -1000,\n"
395  " \"another array\": [\n"
396  " 1,\n"
397  " 2,\n"
398  " 3,\n"
399  " 4\n"
400  " ] /* another array */\n"
401  "}";
402  EXPECT_STREQ(expected, info.trace_ptr);
403  EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
404  check_json_compliance(info.trace_ptr, info.trace_length);
405  EXPECT_EQ(0U, info.missing_bytes);
406  EXPECT_FALSE(info.missing_priv);
407  EXPECT_FALSE(oom);
408  it.next();
409  ASSERT_TRUE(it.at_end());
410 }
411 
412 
414 TEST_F(TraceContentTest, DisableISWithCall)
415 {
416  // Test that it disables even before any start()
417  trace.disable_I_S_for_this_and_children();
418  ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
419  all_features));
420  {
421  Opt_trace_object oto(&trace);
422  {
423  Opt_trace_array ota(&trace, "one array");
424  ota.add(200.4);
425  {
426  Opt_trace_object oto1(&trace);
427  oto1.add_alnum("one key", "one value").
428  add("another key", 100LL);
429  oto1.add("a third key", false);
430  Opt_trace_object oto2(&trace, "a fourth key");
431  oto2.add("key inside", 1LL);
432  // disabling should apply to substatements too:
433  ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
434  all_features));
435  {
436  Opt_trace_object oto3(&trace);
437  }
438  trace.end();
439  /* don't disable... but above layer is stronger */
440  Opt_trace_disable_I_S otd2(&trace, false);
441  oto2.add("another key inside", 5LL);
442  // disabling should apply to substatements too:
443  ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
444  all_features));
445  {
446  Opt_trace_object oto4(&trace);
447  }
448  trace.end();
449  }
450  ota.add_alnum("one string element");
451  ota.add(true);
452  }
453  oto.add("yet another key", -1000LL);
454  {
455  Opt_trace_array ota(&trace, "another array");
456  ota.add(1LL).add(2LL).add(3LL).add(4LL);
457  }
458  }
459  trace.end();
460  trace.restore_I_S();
461  Opt_trace_iterator it(&trace);
462  ASSERT_TRUE(it.at_end());
463 }
464 
465 
467 void make_one_trace(Opt_trace_context *trace, const char *name,
468  long offset, long limit)
469 {
470  ASSERT_FALSE(trace->start(true, false, true, false, offset, limit,
471  ULONG_MAX, all_features));
472  {
473  Opt_trace_object oto(trace);
474  oto.add(name, 0LL);
475  }
476  trace->end();
477 }
478 
479 
495 #define check(trace, names) { SCOPED_TRACE(""); do_check(&trace, names); }
496 
497 void do_check(Opt_trace_context *trace, const char **names)
498 {
499  Opt_trace_iterator it(trace);
500  Opt_trace_info info;
501  for (const char **name= names ; *name != NULL ; name++)
502  {
503  ASSERT_FALSE(it.at_end());
504  it.get_value(&info);
505  const size_t name_len= strlen(*name);
506  EXPECT_EQ(name_len + 11, info.trace_length);
507  EXPECT_EQ(0, strncmp(info.trace_ptr + 5, *name, name_len));
508  EXPECT_EQ(0U, info.missing_bytes);
509  it.next();
510  }
511  ASSERT_TRUE(it.at_end());
512 }
513 
514 
516 TEST_F(TraceContentTest, Offset)
517 {
518  make_one_trace(&trace, "100", -1 /* offset */, 1 /* limit */);
519  const char *expected_traces0[]= {"100", NULL};
520  check(trace, expected_traces0);
521  make_one_trace(&trace, "101", -1, 1);
522  /* 101 should have overwritten 100 */
523  const char *expected_traces1[]= {"101", NULL};
524  check(trace, expected_traces1);
525  make_one_trace(&trace, "102", -1, 1);
526  const char *expected_traces2[]= {"102", NULL};
527  check(trace, expected_traces2);
528  trace.reset();
529  const char *expected_traces_empty[]= {NULL};
530  check(trace, expected_traces_empty);
531  make_one_trace(&trace, "103", -3, 2);
532  make_one_trace(&trace, "104", -3, 2);
533  make_one_trace(&trace, "105", -3, 2);
534  make_one_trace(&trace, "106", -3, 2);
535  make_one_trace(&trace, "107", -3, 2);
536  make_one_trace(&trace, "108", -3, 2);
537  make_one_trace(&trace, "109", -3, 2);
538  const char *expected_traces3[]= {"107", "108", NULL};
539  check(trace, expected_traces3);
540  trace.reset();
541  check(trace, expected_traces_empty);
542  make_one_trace(&trace, "110", 3, 2);
543  make_one_trace(&trace, "111", 3, 2);
544  make_one_trace(&trace, "112", 3, 2);
545  make_one_trace(&trace, "113", 3, 2);
546  make_one_trace(&trace, "114", 3, 2);
547  make_one_trace(&trace, "115", 3, 2);
548  make_one_trace(&trace, "116", 3, 2);
549  const char *expected_traces10[]= {"113", "114", NULL};
550  check(trace, expected_traces10);
551  trace.reset();
552  check(trace, expected_traces_empty);
553  make_one_trace(&trace, "117", 0, 1);
554  make_one_trace(&trace, "118", 0, 1);
555  make_one_trace(&trace, "119", 0, 1);
556  const char *expected_traces17[]= {"117", NULL};
557  check(trace, expected_traces17);
558  trace.reset();
559  make_one_trace(&trace, "120", 0, 0);
560  make_one_trace(&trace, "121", 0, 0);
561  make_one_trace(&trace, "122", 0, 0);
562  const char *expected_traces20[]= {NULL};
563  check(trace, expected_traces20);
564  EXPECT_FALSE(oom);
565 }
566 
567 
569 TEST_F(TraceContentTest, MaxMemSize)
570 {
571  ASSERT_FALSE(trace.start(true, false, false, false, -1,
572  1, 1000 /* max_mem_size */, all_features));
573  /* make a "long" trace */
574  {
575  Opt_trace_object oto(&trace);
576  Opt_trace_array ota(&trace, "one array");
577  for (int i= 0; i < 100; i++)
578  {
579  ota.add_alnum("make it long");
580  }
581  }
582  trace.end();
583  Opt_trace_iterator it(&trace);
584  ASSERT_FALSE(it.at_end());
585  Opt_trace_info info;
586  it.get_value(&info);
587  const char expected[]=
588  "{\n"
589  " \"one array\": [\n"
590  " \"make it long\",\n"
591  " \"make it long\",\n"
592  ;
593  /*
594  Without truncation the trace would take:
595  2+17+3+1+20*100 = 2023
596  */
597  EXPECT_EQ(996U, info.trace_length);
598  EXPECT_EQ(1027U, info.missing_bytes); // 996+1027=2023
599  EXPECT_FALSE(info.missing_priv);
600  EXPECT_FALSE(oom);
601  EXPECT_EQ(0, strncmp(expected, info.trace_ptr, sizeof(expected) - 1));
602  it.next();
603  ASSERT_TRUE(it.at_end());
604 }
605 
606 
607 
609 TEST_F(TraceContentTest, MaxMemSize2)
610 {
611  ASSERT_FALSE(trace.start(true, false, false, false, -2,
612  2, 21 /* max_mem_size */, all_features));
613  /* make a "long" trace */
614  {
615  Opt_trace_object oto(&trace);
616  oto.add_alnum("some key1", "make it long");
617  }
618  trace.end();
619  /* A second similar trace */
620  ASSERT_FALSE(trace.start(true, false, false, false, -2,
621  2, 21, all_features));
622  {
623  Opt_trace_object oto(&trace);
624  oto.add_alnum("some key2", "make it long");
625  }
626  trace.end();
627  Opt_trace_iterator it(&trace);
628  ASSERT_FALSE(it.at_end());
629  Opt_trace_info info;
630  it.get_value(&info);
631  EXPECT_EQ(17U, info.trace_length);
632  EXPECT_EQ(16U, info.missing_bytes);
633  EXPECT_FALSE(info.missing_priv);
634  EXPECT_FALSE(oom);
635  it.next();
636  ASSERT_FALSE(it.at_end());
637  it.get_value(&info);
638  /* 2nd trace completely empty as first trace left no room */
639  EXPECT_EQ(0U, info.trace_length);
640  EXPECT_EQ(33U, info.missing_bytes);
641  it.next();
642  ASSERT_TRUE(it.at_end());
643  /*
644  3rd trace; the first one should automatically be purged, thus the 3rd
645  should have a bit of room.
646  */
647  ASSERT_FALSE(trace.start(true, false, false, false, -2,
648  2, 21, all_features));
649  {
650  Opt_trace_object oto(&trace);
651  oto.add_alnum("some key3", "make it long");
652  }
653  trace.end();
654  Opt_trace_iterator it2(&trace);
655  ASSERT_FALSE(it2.at_end());
656  it2.get_value(&info);
657  EXPECT_EQ(0U, info.trace_length);
658  EXPECT_EQ(33U, info.missing_bytes);
659  EXPECT_FALSE(info.missing_priv);
660  EXPECT_FALSE(oom);
661  it2.next();
662  it2.get_value(&info);
663  /*
664  3rd one had room. A bit less than first, because just reading the second
665  with the iterator has reallocated the second from 0 to 8 bytes...
666  */
667  EXPECT_EQ(14U, info.trace_length);
668  EXPECT_EQ(19U, info.missing_bytes);
669  EXPECT_FALSE(info.missing_priv);
670  it2.next();
671  ASSERT_TRUE(it2.at_end());
672 }
673 
674 
675 void open_object(uint count, Opt_trace_context *trace, bool simulate_oom)
676 {
677  if (count == 0)
678  return;
679  count--;
680  char key[4];
681  /*
682  Add 100 to always have a key of length 3, this matters to
683  TraceContentTest.Indent.
684  We could use just a fixed string, but it would cause an assertion failure
685  (due to invalid JSON, which itself is conceivable in case of OOM).
686  */
687  llstr(100 + count, key);
688  if (simulate_oom)
689  {
690  if (count == 90)
691  DBUG_SET("+d,opt_trace_oom_in_open_struct");
692  /*
693  Now we let 80 objects be created, so that one of them surely hits
694  re-allocation and OOM failure.
695  */
696  if (count == 10)
697  DBUG_SET("-d,opt_trace_oom_in_open_struct");
698  }
699  Opt_trace_object oto(trace, key);
700  open_object(count, trace, simulate_oom);
701 }
702 
703 
704 #ifndef DBUG_OFF
705 
707 TEST_F(TraceContentTest, OOMinBuffer)
708 {
709  ASSERT_FALSE(trace.start(true, false, false, false, -1, 1, ULONG_MAX,
710  all_features));
711  {
712  Opt_trace_object oto(&trace);
713  {
714  Opt_trace_array ota(&trace, "one array");
715  DBUG_SET("+d,opt_trace_oom_in_buffers");
716  for (int i= 0; i < 30; i++)
717  ota.add_alnum("_______________________________________________");
718  DBUG_SET("-d,opt_trace_oom_in_buffers");
719  }
720  }
721  trace.end();
722  Opt_trace_iterator it(&trace);
723  ASSERT_FALSE(it.at_end());
724  Opt_trace_info info;
725  it.get_value(&info);
726  EXPECT_EQ(0U, info.missing_bytes);
727  EXPECT_FALSE(info.missing_priv);
728  it.next();
729  ASSERT_TRUE(it.at_end());
730  EXPECT_TRUE(oom);
731 }
732 
733 
735 TEST_F(TraceContentTest, OOMinBookKeeping)
736 {
737  ASSERT_FALSE(trace.start(true, false, false, false, -1, 1, ULONG_MAX,
738  all_features));
739  {
740  Opt_trace_object oto(&trace);
741  open_object(100, &trace, true);
742  }
743  trace.end();
744  Opt_trace_iterator it(&trace);
745  ASSERT_FALSE(it.at_end());
746  Opt_trace_info info;
747  it.get_value(&info);
748  EXPECT_EQ(0U, info.missing_bytes);
749  EXPECT_FALSE(info.missing_priv);
750  it.next();
751  ASSERT_TRUE(it.at_end());
752  EXPECT_TRUE(oom);
753 }
754 
755 
757 TEST_F(TraceContentTest, OOMinPurge)
758 {
759  make_one_trace(&trace, "103", -3, 2);
760  make_one_trace(&trace, "104", -3, 2);
761  DBUG_SET("+d,opt_trace_oom_in_purge");
762  make_one_trace(&trace, "105", -3, 2);
763  make_one_trace(&trace, "106", -3, 2);
764  make_one_trace(&trace, "107", -3, 2);
765  make_one_trace(&trace, "108", -3, 2);
766  make_one_trace(&trace, "109", -3, 2);
767  make_one_trace(&trace, "110", -3, 2);
768  make_one_trace(&trace, "111", -3, 2);
769  make_one_trace(&trace, "112", -3, 2);
770  make_one_trace(&trace, "113", -3, 2);
771  make_one_trace(&trace, "114", -3, 2);
772  make_one_trace(&trace, "115", -3, 2);
773  make_one_trace(&trace, "116", -3, 2);
774  make_one_trace(&trace, "117", -3, 2);
775  make_one_trace(&trace, "118", -3, 2);
776  make_one_trace(&trace, "119", -3, 2);
777  make_one_trace(&trace, "120", -3, 2);
778  make_one_trace(&trace, "121", -3, 2);
779  make_one_trace(&trace, "122", -3, 2); // purge first fails here
780 
781  DBUG_SET("-d,opt_trace_oom_in_purge");
782  // 122 could not purge 119, so we should see 119 and 120
783  const char *expected_traces3[]= {"119", "120", NULL};
784  check(trace, expected_traces3);
785  EXPECT_TRUE(oom);
786 
787  // Back to normal:
788  oom= false;
789  make_one_trace(&trace, "123", -3, 2); // purge succeeds
790  const char *expected_traces4[]= {"121", "122", NULL};
791  check(trace, expected_traces4);
792  EXPECT_FALSE(oom);
793 }
794 
795 #endif // !DBUG_OFF
796 
797 
799 TEST_F(TraceContentTest, FilteringByFeature)
800 {
801  ASSERT_FALSE(trace.start(true, false, false, false, -1, 1, ULONG_MAX,
802  Opt_trace_context::MISC));
803  {
804  Opt_trace_object oto(&trace);
805  {
806  Opt_trace_array ota(&trace, "one array");
807  ota.add(200.4);
808  {
809  Opt_trace_object oto1(&trace, Opt_trace_context::GREEDY_SEARCH);
810  oto1.add_alnum("one key", "one value").
811  add("another key", 100LL);
812  Opt_trace_object oto2(&trace, "a fourth key",
813  Opt_trace_context::MISC);
814  oto2.add("another key inside", 5LL);
815  }
816  ota.add(true);
817  }
818  {
819  Opt_trace_object oto3(&trace, "key for oto3",
820  Opt_trace_context::GREEDY_SEARCH);
821  oto3.add("etc", 25);
822  }
823  oto.add("yet another key", -1000LL);
824  {
825  Opt_trace_array ota(&trace, "another array");
826  ota.add(1LL).add(2LL).add(3LL).add(4LL);
827  }
828  }
829  trace.end();
830  Opt_trace_iterator it(&trace);
831  ASSERT_FALSE(it.at_end());
832  Opt_trace_info info;
833  it.get_value(&info);
834  const char expected[]=
835  "{\n"
836  " \"one array\": [\n"
837  " 200.4,\n"
838  " \"...\",\n"
839  " true\n"
840  " ],\n"
841  " \"key for oto3\": \"...\",\n"
842  " \"yet another key\": -1000,\n"
843  " \"another array\": [\n"
844  " 1,\n"
845  " 2,\n"
846  " 3,\n"
847  " 4\n"
848  " ]\n"
849  "}";
850  EXPECT_STREQ(expected, info.trace_ptr);
851  EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
852  check_json_compliance(info.trace_ptr, info.trace_length);
853  EXPECT_EQ(0U, info.missing_bytes);
854  EXPECT_FALSE(info.missing_priv);
855  EXPECT_FALSE(oom);
856  it.next();
857  ASSERT_TRUE(it.at_end());
858 }
859 
860 
862 TEST_F(TraceContentTest, Escaping)
863 {
864  ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
865  all_features));
866  // All ASCII 0-127 chars are valid UTF8 encodings
867  char all_chars[130];
868  for (uint c= 0; c < sizeof(all_chars) - 2 ; c++)
869  all_chars[c]= c;
870  // Now a character with a two-byte code in utf8: ä
871  all_chars[128]= static_cast<char>(0xc3);
872  all_chars[129]= static_cast<char>(0xa4);
873  // all_chars is used both as query...
874  trace.set_query(all_chars, sizeof(all_chars), system_charset_info);
875  {
876  Opt_trace_object oto(&trace);
877  // ... and inside the trace:
878  oto.add_utf8("somekey", all_chars, sizeof(all_chars));
879  }
880  trace.end();
881  Opt_trace_iterator it(&trace);
882  ASSERT_FALSE(it.at_end());
883  Opt_trace_info info;
884  it.get_value(&info);
885  // we get the trace escaped, JSON-compliant:
886  const char expected[]=
887  "{\n"
888  " \"somekey\": \"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\u0008\\t\\n\\u000b\\u000c\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f !\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ä\"\n"
889  "}";
890  EXPECT_STREQ(expected, info.trace_ptr);
891  EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
892  check_json_compliance(info.trace_ptr, info.trace_length);
893  EXPECT_EQ(0U, info.missing_bytes);
894  EXPECT_FALSE(info.missing_priv);
895  EXPECT_FALSE(oom);
896  EXPECT_EQ(sizeof(all_chars), info.query_length);
897  // we get the query unescaped, verbatim, not 0-terminated:
898  EXPECT_EQ(0, memcmp(all_chars, info.query_ptr, sizeof(all_chars)));
899  EXPECT_EQ(system_charset_info, info.query_charset);
900  it.next();
901  ASSERT_TRUE(it.at_end());
902 }
903 
904 
906 TEST_F(TraceContentTest, NonUtf8)
907 {
908  ASSERT_FALSE(trace.start(true, false, true, false, -1, 1, ULONG_MAX,
909  all_features));
910  /*
911  A string which starts with invalid utf8 (the four first bytes are éèÄà in
912  latin1).
913  In utf8, the following holds
914  - E0->EF can only be the start of a 3-byte sequence
915  - C2->DF 2-byte
916  - ASCII a single-byte sequence
917  */
918  const char all_chars[]= "\xe9\xe8\xc4\xe0" "ABC";
919  // We declare a query in latin1
920  trace.set_query(all_chars, sizeof(all_chars), &my_charset_latin1);
921  {
922  Opt_trace_object oto(&trace);
923  /*
924  We pass the non-utf8-compliant string to add_utf8() (violating the
925  API). We get it back unchanged. The trace system could try to be robust,
926  detecting and sanitizing wrong characters (replacing them with '?'); but
927  it does not bother, as the MySQL Server normally does not violate the
928  API.
929  */
930  oto.add_utf8("somekey", all_chars, sizeof(all_chars) - 1);
931  }
932  trace.end();
933  Opt_trace_iterator it(&trace);
934  ASSERT_FALSE(it.at_end());
935  Opt_trace_info info;
936  it.get_value(&info);
937  // This is not UTF8-compliant and thus not JSON-compliant.
938  const char expected[]=
939  "{\n"
940  " \"somekey\": \"" "\xe9\xe8\xc4\xe0" "ABC\"\n"
941  "}";
942  EXPECT_STREQ(expected, info.trace_ptr);
943  EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
944  EXPECT_EQ(0U, info.missing_bytes);
945  EXPECT_FALSE(info.missing_priv);
946  EXPECT_FALSE(oom);
947  EXPECT_EQ(sizeof(all_chars), info.query_length);
948  // we get the query unescaped, verbatim, not 0-terminated:
949  EXPECT_EQ(0, memcmp(all_chars, info.query_ptr, sizeof(all_chars)));
950  it.next();
951  ASSERT_TRUE(it.at_end());
952 }
953 
954 
960 TEST_F(TraceContentTest, Indent)
961 {
962  ASSERT_FALSE(trace.start(true, false, false, false, -1, 1, ULONG_MAX,
963  all_features));
964  {
965  Opt_trace_object oto(&trace);
966  open_object(100, &trace, false);
967  }
968  trace.end();
969  Opt_trace_iterator it(&trace);
970  ASSERT_FALSE(it.at_end());
971  Opt_trace_info info;
972  it.get_value(&info);
973  /*
974  Formula for the expected size.
975  Before the Nth call to open_object(), indentation inside the innermost
976  empty object is noted I(N); so the relationship between the size before
977  Nth call and the size after Nth call is:
978  S(N+1) = S(N)
979  + I(N) (indentation before added '"xxx": {\n' )
980  + 9 (length of added '"xxx": {\n' )
981  + I(N) (indentation before added '}\n' )
982  + 2 (length of added '}\n' )
983  and the indentation is increased by two as we are one level deeper:
984  I(N+1) = I(N) + 2
985  With S(1) = 3 (length of '{\n}') and I(1) = 2.
986  So I(N) = 2 * N and
987  S(N+1) - S(N) = 11 + 4 * N
988  So S(N) = 3 + 11 * (N - 1) + 2 * N * (N - 1).
989  For 100 calls, the final size is S(101) = 21303.
990  Each call adds 10 non-space characters, so there should be
991  21303
992  - 10 * 100 (added non-spaces characters)
993  - 3 (non-spaces of initial object before first function call)
994  = 20300 spaces.
995  */
996  EXPECT_EQ(21303U, info.trace_length);
997  uint spaces= 0;
998  for (uint i= 0; i < info.trace_length; i++)
999  if (info.trace_ptr[i] == ' ')
1000  spaces++;
1001  EXPECT_EQ(20300U, spaces);
1002  check_json_compliance(info.trace_ptr, info.trace_length);
1003  EXPECT_EQ(0U, info.missing_bytes);
1004  EXPECT_FALSE(info.missing_priv);
1005  EXPECT_FALSE(oom);
1006  it.next();
1007  ASSERT_TRUE(it.at_end());
1008 }
1009 
1010 
1012 TEST_F(TraceContentTest, MissingPrivilege)
1013 {
1014  ASSERT_FALSE(trace.start(true, false, true, false, 0, 100, ULONG_MAX,
1015  all_features));
1016  {
1017  Opt_trace_object oto(&trace);
1018  {
1019  Opt_trace_array ota(&trace, "one array");
1020  ota.add(200.4);
1021  {
1022  Opt_trace_object oto1(&trace);
1023  oto1.add_alnum("one key", "one value").
1024  add("another key", 100LL);
1025  oto1.add("a third key", false);
1026  Opt_trace_object oto2(&trace, "a fourth key");
1027  oto2.add("key inside", 1LL);
1028  ASSERT_FALSE(trace.start(true, false, true, false, 0, 100, ULONG_MAX,
1029  all_features));
1030  {
1031  Opt_trace_object oto3(&trace);
1032  trace.missing_privilege();
1033  ASSERT_FALSE(trace.start(true, false, true, false, 0, 100,
1034  ULONG_MAX, all_features));
1035  {
1036  Opt_trace_object oto4(&trace);
1037  oto4.add_alnum("in4","key4");
1038  }
1039  trace.end();
1040  }
1041  trace.end(); // this should restore I_S support
1042  // so this should be visible
1043  oto2.add("another key inside", 5LL);
1044  // and this new sub statement too:
1045  ASSERT_FALSE(trace.start(true, false, true, false, 0, 100, ULONG_MAX,
1046  all_features));
1047  {
1048  Opt_trace_object oto5(&trace);
1049  oto5.add("in5", true);
1050  }
1051  trace.end();
1052  }
1053  ota.add_alnum("one string element");
1054  ota.add(true);
1055  }
1056  oto.add("yet another key", -1000LL);
1057  {
1058  Opt_trace_array ota(&trace, "another array");
1059  ota.add(1LL).add(2LL).add(3LL).add(4LL);
1060  }
1061  }
1062  trace.end();
1063  Opt_trace_iterator it(&trace);
1064  ASSERT_FALSE(it.at_end());
1065  Opt_trace_info info;
1066  it.get_value(&info);
1067  const char expected[]=
1068  "{\n"
1069  " \"one array\": [\n"
1070  " 200.4,\n"
1071  " {\n"
1072  " \"one key\": \"one value\",\n"
1073  " \"another key\": 100,\n"
1074  " \"a third key\": false,\n"
1075  " \"a fourth key\": {\n"
1076  " \"key inside\": 1,\n"
1077  " \"another key inside\": 5\n"
1078  " } /* a fourth key */\n"
1079  " },\n"
1080  " \"one string element\",\n"
1081  " true\n"
1082  " ] /* one array */,\n"
1083  " \"yet another key\": -1000,\n"
1084  " \"another array\": [\n"
1085  " 1,\n"
1086  " 2,\n"
1087  " 3,\n"
1088  " 4\n"
1089  " ] /* another array */\n"
1090  "}";
1091  EXPECT_STREQ(expected, info.trace_ptr);
1092  EXPECT_EQ(sizeof(expected) - 1, info.trace_length);
1093  check_json_compliance(info.trace_ptr, info.trace_length);
1094  EXPECT_EQ(0U, info.missing_bytes);
1095  EXPECT_FALSE(info.missing_priv);
1096  EXPECT_FALSE(oom);
1097  it.next();
1098  ASSERT_FALSE(it.at_end());
1099  // Now the substatement with a missing privilege
1100  it.get_value(&info);
1101  const char expected2[]= ""; // because of missing privilege...
1102  EXPECT_STREQ(expected2, info.trace_ptr);
1103  EXPECT_EQ(sizeof(expected2) - 1, info.trace_length);
1104  EXPECT_EQ(0U, info.missing_bytes);
1105  EXPECT_TRUE(info.missing_priv); // ... tested here.
1106  it.next();
1107  ASSERT_FALSE(it.at_end());
1108  // And now the last substatement, visible
1109  it.get_value(&info);
1110  const char expected3[]=
1111  "{\n"
1112  " \"in5\": true\n"
1113  "}";
1114  EXPECT_STREQ(expected3, info.trace_ptr);
1115  EXPECT_EQ(sizeof(expected3) - 1, info.trace_length);
1116  check_json_compliance(info.trace_ptr, info.trace_length);
1117  EXPECT_EQ(0U, info.missing_bytes);
1118  EXPECT_FALSE(info.missing_priv);
1119  it.next();
1120  ASSERT_TRUE(it.at_end());
1121 }
1122 
1123 
1125 TEST_F(TraceContentTest, MissingPrivilege2)
1126 {
1127  /*
1128  Ask for neither I_S not debug output, and no
1129  missing_privilege() support
1130  */
1131  ASSERT_FALSE(trace.start(false, false, true, false, 0, 100, ULONG_MAX,
1132  all_features));
1133  EXPECT_FALSE(trace.is_started());
1134  trace.end();
1135  /*
1136  Ask for neither I_S not debug output, but ask that
1137  missing_privilege() is supported.
1138  */
1139  ASSERT_FALSE(trace.start(false, true, true, false, 0, 100, ULONG_MAX,
1140  all_features));
1141  EXPECT_TRUE(trace.is_started());
1142  trace.missing_privilege();
1143  // This above should make the substatement below not be traced:
1144  ASSERT_FALSE(trace.start(true, false, true, false, 0, 100, ULONG_MAX,
1145  all_features));
1146  {
1147  Opt_trace_object oto5(&trace);
1148  oto5.add("in5", true);
1149  }
1150  trace.end();
1151  trace.end();
1152  Opt_trace_iterator it(&trace);
1153  ASSERT_TRUE(it.at_end());
1154 }
1155 
1156 
1162 TEST_F(TraceContentTest, NoOptTraceStmt)
1163 {
1164  ASSERT_FALSE(trace.start(false, false, false, false, -1, 1, ULONG_MAX,
1165  all_features));
1166  EXPECT_FALSE(trace.is_started());
1167  // one substatement:
1168  ASSERT_FALSE(trace.start(false, false, false, false, -1, 1, ULONG_MAX,
1169  all_features));
1170  EXPECT_FALSE(trace.is_started());
1171  // another one deeper nested:
1172  ASSERT_FALSE(trace.start(false, false, false, false, -1, 1, ULONG_MAX,
1173  all_features));
1174  EXPECT_FALSE(trace.is_started());
1175  trace.end();
1176  trace.end();
1177  trace.end();
1178 }
1179 
1180 } // namespace
1181 
1182 #endif // OPTIMIZER_TRACE