MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
get_diagnostics-t.cc
1 /* Copyright (c) 2011, 2013, 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 
16 // First include (the generated) my_config.h, to get correct platform defines.
17 #include "my_config.h"
18 #include <gtest/gtest.h>
19 
20 #include "test_utils.h"
21 
22 #include "item.h"
23 #include "sql_get_diagnostics.h"
24 
25 namespace get_diagnostics_unittest {
26 
29 
30 class GetDiagnosticsTest : public ::testing::Test
31 {
32 protected:
33  virtual void SetUp() { initializer.SetUp(); }
34  virtual void TearDown() { initializer.TearDown(); }
35 
36  THD *thd() { return initializer.thd(); }
37 
38  Server_initializer initializer;
39 };
40 
41 
43 {
44 public:
45  void fail(const char *message)
46  {
47  FAIL() << message;
48  }
49 };
50 
51 
52 LEX_STRING var_name1= {C_STRING_WITH_LEN("var1")};
53 LEX_STRING var_name2= {C_STRING_WITH_LEN("var2")};
54 
55 
57 {
58 public:
59  MockDiagInfoItem(Item *target, int value)
60  : Diagnostics_information_item(target), m_value(value)
61  {}
62 
63  Item *get_value(THD *thd, const Diagnostics_area *da)
64  {
65  return new (thd->mem_root) Item_int(m_value);
66  }
67 
68 private:
69  int m_value;
70 };
71 
72 
74  private FailHelper
75 {
76 public:
78  : m_items(items)
79  {}
80 
81 protected:
82  bool aggregate(THD *thd, const Diagnostics_area *da)
83  {
84  bool rv= false;
85  MockDiagInfoItem *diag_info_item;
87 
88  while ((diag_info_item= it++))
89  {
90  if ((rv= evaluate(thd, diag_info_item, da)))
91  break;
92  }
93 
94  return rv;
95  }
96 
97  ~MockDiagInfo()
98  {
99  fail("MockDiagInfo destructor invoked.");
100  }
101 
102 private:
103  List<MockDiagInfoItem> *m_items;
104 };
105 
106 
107 // GET [CURRENT] DIAGNOSTICS @var1 = 1, @var2 = 2;
108 TEST_F(GetDiagnosticsTest, Cmd)
109 {
110  Item *var;
111  Sql_cmd *cmd;
112  MockDiagInfo *info;
113  MockDiagInfoItem *diag_info_item;
115  MEM_ROOT *mem_root= thd()->mem_root;
116 
117  // set var1 item
118  var= new (mem_root) Item_func_get_user_var(var_name1);
119  diag_info_item= new (mem_root) MockDiagInfoItem(var, 1);
120  EXPECT_FALSE(items.push_back(diag_info_item));
121 
122  // set var2 item
123  var= new (mem_root) Item_func_get_user_var(var_name2);
124  diag_info_item= new (mem_root) MockDiagInfoItem(var, 2);
125  EXPECT_FALSE(items.push_back(diag_info_item));
126 
127  // Information list and command
128  info= new (mem_root) MockDiagInfo(&items);
130  cmd= new (mem_root) Sql_cmd_get_diagnostics(info);
131 
132  EXPECT_FALSE(cmd->execute(thd()));
133  EXPECT_TRUE(thd()->get_stmt_da()->is_ok());
134 
135  // check var1 value
136  var= new (mem_root) Item_func_get_user_var(var_name1);
137  EXPECT_FALSE(var->fix_fields(thd(), &var));
138  EXPECT_EQ(1, var->val_int());
139 
140  // check var2 value
141  var= new (mem_root) Item_func_get_user_var(var_name2);
142  EXPECT_FALSE(var->fix_fields(thd(), &var));
143  EXPECT_EQ(2, var->val_int());
144 }
145 
146 
147 // Verifies death with a DBUG_ASSERT if target item is not settable.
148 // Google Test recommends DeathTest suffix for classes used in death tests.
149 typedef GetDiagnosticsTest GetDiagnosticsTestDeathTest;
150 
151 #if GTEST_HAS_DEATH_TEST && !defined(DBUG_OFF)
152 TEST_F(GetDiagnosticsTestDeathTest, DieWhenUnsettableItem)
153 {
154  Item *var;
155  Sql_cmd *cmd;
156  MockDiagInfo *info;
157  MockDiagInfoItem *diag_info_item;
159  MEM_ROOT *mem_root= thd()->mem_root;
160 
161  ::testing::FLAGS_gtest_death_test_style= "threadsafe";
162 
163  // Unsettable item
164  var= new (mem_root) Item_int(1);
165  diag_info_item= new (mem_root) MockDiagInfoItem(var, 1);
166  EXPECT_FALSE(items.push_back(diag_info_item));
167 
168  // Information list and command
169  info= new (mem_root) MockDiagInfo(&items);
170  info->set_which_da(Diagnostics_information::CURRENT_AREA);
171  cmd= new (mem_root) Sql_cmd_get_diagnostics(info);
172 
173  EXPECT_DEATH(cmd->execute(thd()), ".*Assertion.*srp.*");
174 }
175 #endif // GTEST_HAS_DEATH_TEST && !defined(DBUG_OFF)
176 
177 
179 {
180 public:
181  MockDiagInfoError(bool fatal_error)
182  : m_fatal_error(fatal_error)
183  {}
184 
185 protected:
186  bool aggregate(THD *thd, const Diagnostics_area *)
187  {
188  myf flag= m_fatal_error ? MYF(ME_FATALERROR) : MYF(0);
189  my_message_sql(ER_UNKNOWN_ERROR, "Unknown error", flag);
190  return thd->is_error();
191  }
192 
193 private:
194  bool m_fatal_error;
195 };
196 
197 
198 // GET DIAGNOSTICS itself causes an error.
199 TEST_F(GetDiagnosticsTest, Error)
200 {
201  Sql_cmd *cmd;
202  MockDiagInfoError *info;
203  MEM_ROOT *mem_root= thd()->mem_root;
204 
205  // Pre-existing warning
206  push_warning_printf(thd(), Sql_condition::WARN_LEVEL_WARN,
207  WARN_DATA_TRUNCATED, "Data truncated");
208 
209  // Simulate GET DIAGNOSTICS as a new command separated
210  // from the one that generated the warning
211  thd()->reset_for_next_command();
212 
213  // Error bound "information" and command
214  info= new (mem_root) MockDiagInfoError(false);
215  info->set_which_da(Diagnostics_information::CURRENT_AREA);
216  cmd= new (mem_root) Sql_cmd_get_diagnostics(info);
217 
218  initializer.set_expected_error(ER_UNKNOWN_ERROR);
219 
220  // Should succeed, not a fatal error
221  EXPECT_FALSE(cmd->execute(thd()));
222  EXPECT_TRUE(thd()->get_stmt_da()->is_ok());
223 
224  // New condition for the error
225  EXPECT_EQ(1U, thd()->get_stmt_da()->statement_warn_count());
226 
227  // Counted as a error
228  EXPECT_EQ(1U, thd()->get_stmt_da()->error_count());
229 
230  // Error is appended
231  EXPECT_EQ(2U, thd()->get_stmt_da()->warn_count());
232 }
233 
234 
235 // GET DIAGNOSTICS itself causes a fatal error.
236 TEST_F(GetDiagnosticsTest, FatalError)
237 {
238  Sql_cmd *cmd;
239  MockDiagInfoError *info;
240  MEM_ROOT *mem_root= thd()->mem_root;
241 
242  // Pre-existing warning
243  push_warning_printf(thd(), Sql_condition::WARN_LEVEL_WARN,
244  WARN_DATA_TRUNCATED, "Data truncated");
245 
246  // Simulate GET DIAGNOSTICS as a new command separated
247  // from the one that generated the warning
248  thd()->reset_for_next_command();
249 
250  // Error bound "information" and command
251  info= new (mem_root) MockDiagInfoError(true);
252  info->set_which_da(Diagnostics_information::CURRENT_AREA);
253  cmd= new (mem_root) Sql_cmd_get_diagnostics(info);
254 
255  initializer.set_expected_error(ER_UNKNOWN_ERROR);
256 
257  // Should not succeed due to a fatal error
258  EXPECT_TRUE(cmd->execute(thd()));
259  EXPECT_TRUE(thd()->get_stmt_da()->is_error());
260 
261  // No new condition for the error
262  EXPECT_EQ(0U, thd()->get_stmt_da()->error_count());
263 
264  // Fatal error is set, not appended
265  EXPECT_EQ(1U, thd()->get_stmt_da()->warn_count());
266 }
267 
268 
269 // GET [CURRENT] DIAGNOSTICS @var1 = NUMBER, @var2 = ROW_COUNT;
270 TEST_F(GetDiagnosticsTest, StatementInformation)
271 {
272  Item *var;
273  Sql_cmd *cmd;
274  Statement_information *info;
275  Statement_information_item *diag_info_item;
277  MEM_ROOT *mem_root= thd()->mem_root;
278 
279  // NUMBER = 1 warning
280  thd()->raise_warning(ER_UNKNOWN_ERROR);
281  // ROW_COUNT = 5
282  thd()->set_row_count_func(5U);
283 
284  // var1 will receive the value of NUMBER
285  var= new (mem_root) Item_func_get_user_var(var_name1);
286  diag_info_item= new (mem_root)
287  Statement_information_item(Statement_information_item::NUMBER, var);
288  EXPECT_FALSE(items.push_back(diag_info_item));
289 
290  // var2 will receive the value of ROW_COUNT
291  var= new (mem_root) Item_func_get_user_var(var_name2);
292  diag_info_item= new (mem_root)
293  Statement_information_item(Statement_information_item::ROW_COUNT, var);
294  EXPECT_FALSE(items.push_back(diag_info_item));
295 
296  // Information list and command
297  info= new (mem_root) Statement_information(&items);
299  cmd= new (mem_root) Sql_cmd_get_diagnostics(info);
300 
301  EXPECT_FALSE(cmd->execute(thd()));
302  EXPECT_TRUE(thd()->get_stmt_da()->is_ok());
303 
304  // check var1 value
305  var= new (mem_root) Item_func_get_user_var(var_name1);
306  EXPECT_FALSE(var->fix_fields(thd(), &var));
307  EXPECT_EQ(1U, var->val_uint());
308 
309  // check var2 value
310  var= new (mem_root) Item_func_get_user_var(var_name2);
311  EXPECT_FALSE(var->fix_fields(thd(), &var));
312  EXPECT_EQ(5U, var->val_int());
313 }
314 
315 
316 // GET DIAGNOSTICS CONDITION 1 @var1 = MYSQL_ERRNO, @var2 = MESSAGE_TEXT;
317 TEST_F(GetDiagnosticsTest, ConditionInformation)
318 {
319  Item *var;
320  String str;
321  Sql_cmd *cmd;
322  Condition_information *info;
323  Condition_information_item *diag_info_item;
325  MEM_ROOT *mem_root= thd()->mem_root;
326 
327  // Pre-existing error
328  my_message_sql(ER_UNKNOWN_ERROR, "Unknown error", MYF(0));
329 
330  // Simulate GET DIAGNOSTICS as a new command separated
331  // from the one that generated the error
332  thd()->reset_for_next_command();
333 
334  // var1 will receive the value of MYSQL_ERRNO
335  var= new (mem_root) Item_func_get_user_var(var_name1);
336  diag_info_item= new (mem_root)
337  Condition_information_item(Condition_information_item::MYSQL_ERRNO, var);
338  EXPECT_FALSE(items.push_back(diag_info_item));
339 
340  // var2 will receive the value of MESSAGE_TEXT
341  var= new (mem_root) Item_func_get_user_var(var_name2);
342  diag_info_item= new (mem_root)
343  Condition_information_item(Condition_information_item::MESSAGE_TEXT, var);
344  EXPECT_FALSE(items.push_back(diag_info_item));
345 
346  // condition number (1)
347  var= new (mem_root) Item_uint(1);
348 
349  // Information list and command
350  info= new (mem_root) Condition_information(var, &items);
352  cmd= new (mem_root) Sql_cmd_get_diagnostics(info);
353 
354  EXPECT_FALSE(cmd->execute(thd()));
355  EXPECT_TRUE(thd()->get_stmt_da()->is_ok());
356 
357  // check var1 value
358  var= new (mem_root) Item_func_get_user_var(var_name1);
359  EXPECT_FALSE(var->fix_fields(thd(), &var));
360  EXPECT_EQ(ulonglong (ER_UNKNOWN_ERROR), var->val_uint());
361 
362  // check var2 value
363  var= new (mem_root) Item_func_get_user_var(var_name2);
364  EXPECT_FALSE(var->fix_fields(thd(), &var));
365  EXPECT_EQ(&str, var->val_str(&str));
366  EXPECT_STREQ("Unknown error", str.c_ptr_safe());
367 }
368 
369 
370 Item *get_cond_info_item(THD *thd,
371  uint number,
373 {
374  Item *var;
375  Sql_cmd *cmd;
376  Condition_information *info;
377  Condition_information_item *diag_info_item;
379  MEM_ROOT *mem_root= thd->mem_root;
380  LEX_STRING var_name= {C_STRING_WITH_LEN("get_cond_info_item")};
381 
382  // Simulate GET DIAGNOSTICS as a new command
383  thd->reset_for_next_command();
384 
385  // var1 will receive the value of MYSQL_ERRNO
386  var= new (mem_root) Item_func_get_user_var(var_name);
387  diag_info_item= new (mem_root) Condition_information_item(name, var);
388  EXPECT_FALSE(items.push_back(diag_info_item));
389 
390  // condition number
391  var= new (mem_root) Item_uint(number);
392 
393  // Information list and command
394  info= new (mem_root) Condition_information(var, &items);
396  cmd= new (mem_root) Sql_cmd_get_diagnostics(info);
397 
398  EXPECT_FALSE(cmd->execute(thd));
399  EXPECT_TRUE(thd->get_stmt_da()->is_ok());
400 
401  // make a user var item
402  var= new (mem_root) Item_func_get_user_var(var_name);
403  EXPECT_FALSE(var->fix_fields(thd, &var));
404 
405  return var;
406 }
407 
408 
409 // GET DIAGNOSTICS CONDITION 1 @var = CLASS_ORIGIN;
410 // GET DIAGNOSTICS CONDITION 1 @var = SUBCLASS_ORIGIN;
411 TEST_F(GetDiagnosticsTest, ConditionInformationClassOrigin)
412 {
413  Item *var;
414  String str;
415 
416  // "MySQL" origin
417  push_warning_printf(thd(), Sql_condition::WARN_LEVEL_WARN,
418  ER_XAER_NOTA, "Unknown XID");
419 
420  // "ISO 9075" origin
421  push_warning_printf(thd(), Sql_condition::WARN_LEVEL_WARN,
422  ER_UNKNOWN_ERROR, "Unknown error");
423 
424  // Condition 1 CLASS_ORIGIN
425  var= get_cond_info_item(thd(), 1, Condition_information_item::CLASS_ORIGIN);
426  EXPECT_EQ(&str, var->val_str(&str));
427  EXPECT_STREQ("MySQL", str.c_ptr_safe());
428 
429  // Condition 1 SUBCLASS_ORIGIN
430  var= get_cond_info_item(thd(), 1, Condition_information_item::SUBCLASS_ORIGIN);
431  EXPECT_EQ(&str, var->val_str(&str));
432  EXPECT_STREQ("MySQL", str.c_ptr_safe());
433 
434  // Condition 2 CLASS_ORIGIN
435  var= get_cond_info_item(thd(), 2, Condition_information_item::CLASS_ORIGIN);
436  EXPECT_EQ(&str, var->val_str(&str));
437  EXPECT_STREQ("ISO 9075", str.c_ptr_safe());
438 
439  // Condition 2 CLASS_ORIGIN
440  var= get_cond_info_item(thd(), 2, Condition_information_item::SUBCLASS_ORIGIN);
441  EXPECT_EQ(&str, var->val_str(&str));
442  EXPECT_STREQ("ISO 9075", str.c_ptr_safe());
443 }
444 
445 
446 }