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