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 #include "sql_list.h" // Sql_alloc, List, List_iterator
24 #include "sql_cmd.h" // Sql_cmd
25 #include "sql_class.h" // Diagnostics_area
26 #include "sql_get_diagnostics.h" // Sql_cmd_get_diagnostics
27 #include "sp_rcontext.h" // sp_rcontext
28
29 /**
30 Execute this GET DIAGNOSTICS statement.
31
32 @param thd The current thread.
33
34 @remark Errors or warnings occurring during the execution of the GET
35 DIAGNOSTICS statement should not affect the Diagnostics Area
36 of a previous statement as the diagnostics information there
37 would be wiped out. Thus, in order to preserve the contents
38 of the Diagnostics Area from which information is being
39 retrieved, the GET DIAGNOSTICS statement is executed under
40 a separate Diagnostics Area. If any errors or warnings occur
41 during the execution of the GET DIAGNOSTICS statement, these
42 error or warnings (conditions) are appended to the list of
43 the original Diagnostics Area. The only exception to this is
44 fatal errors, which must always cause the statement to fail.
45
46 @retval false on success.
47 @retval true on error
48 */
49
50 bool
execute(THD * thd)51 Sql_cmd_get_diagnostics::execute(THD *thd)
52 {
53 bool rc;
54 Diagnostics_area new_stmt_da(false);
55 Diagnostics_area *first_da= thd->get_stmt_da();
56 const Diagnostics_area *second_da= thd->get_stacked_da();
57 DBUG_ENTER("Sql_cmd_get_diagnostics::execute");
58
59 /* Push new Diagnostics Area, execute statement and pop. */
60 thd->push_diagnostics_area(&new_stmt_da);
61 /*
62 Reset the condition counter.
63 This statement has just started and has not generated any conditions
64 on its own. However the condition counter will have been updated by
65 push_diagnostics_area() to match the number of conditions present in
66 first_da. It is therefore necessary to reset so we don't inherit the
67 old counter value.
68 */
69 new_stmt_da.reset_statement_cond_count();
70
71 if (m_info->get_which_da() == Diagnostics_information::STACKED_AREA)
72 {
73 // STACKED_AREA only allowed inside handlers
74 if (!thd->sp_runtime_ctx ||
75 !thd->sp_runtime_ctx->current_handler_frame())
76 {
77 my_error(ER_GET_STACKED_DA_WITHOUT_ACTIVE_HANDLER, MYF(ME_FATALERROR));
78 rc = true;
79 }
80 else
81 rc= m_info->aggregate(thd, second_da);
82 }
83 else
84 rc= m_info->aggregate(thd, first_da);
85 thd->pop_diagnostics_area();
86
87 /* Bail out early if statement succeeded. */
88 if (! rc)
89 {
90 thd->get_stmt_da()->set_ok_status(0, 0, NULL);
91 DBUG_RETURN(false);
92 }
93
94 /* Statement failed, retrieve the error information for propagation. */
95 uint sql_errno= new_stmt_da.mysql_errno();
96 const char *message= new_stmt_da.message_text();
97 const char *sqlstate= new_stmt_da.returned_sqlstate();
98
99 /* In case of a fatal error, set it into the original DA.*/
100 if (thd->is_fatal_error)
101 {
102 first_da->set_error_status(sql_errno, message, sqlstate);
103 DBUG_RETURN(true);
104 }
105
106 /* Otherwise, just append the new error as a exception condition. */
107 first_da->push_warning(thd, sql_errno, sqlstate,
108 Sql_condition::SL_ERROR,
109 message);
110
111 /* Appending might have failed. */
112 if (! (rc= thd->is_error()))
113 thd->get_stmt_da()->set_ok_status(0, 0, NULL);
114
115 DBUG_RETURN(rc);
116 }
117
118
119 /**
120 Set a value for this item.
121
122 @param thd The current thread.
123 @param value The obtained value.
124
125 @retval false on success.
126 @retval true on error.
127 */
128
129 bool
set_value(THD * thd,Item ** value)130 Diagnostics_information_item::set_value(THD *thd, Item **value)
131 {
132 bool rc;
133 Settable_routine_parameter *srp;
134 DBUG_ENTER("Diagnostics_information_item::set_value");
135
136 /* Get a settable reference to the target. */
137 srp= m_target->get_settable_routine_parameter();
138
139 DBUG_ASSERT(srp);
140
141 /* Set variable/parameter value. */
142 rc= srp->set_value(thd, thd->sp_runtime_ctx, value);
143
144 DBUG_RETURN(rc);
145 }
146
147
148 /**
149 Obtain statement information in the context of a given Diagnostics Area.
150
151 @param thd The current thread.
152 @param da The Diagnostics Area.
153
154 @retval false on success.
155 @retval true on error
156 */
157
158 bool
aggregate(THD * thd,const Diagnostics_area * da)159 Statement_information::aggregate(THD *thd, const Diagnostics_area *da)
160 {
161 bool rv= false;
162 Statement_information_item *stmt_info_item;
163 List_iterator<Statement_information_item> it(*m_items);
164 DBUG_ENTER("Statement_information::aggregate");
165
166 /*
167 Each specified target gets the value of each given
168 information item obtained from the Diagnostics Area.
169 */
170 while ((stmt_info_item= it++))
171 {
172 if ((rv= evaluate(thd, stmt_info_item, da)))
173 break;
174 }
175
176 DBUG_RETURN(rv);
177 }
178
179
180 /**
181 Obtain the value of this statement information item in the context of
182 a given Diagnostics Area.
183
184 @param thd The current thread.
185 @param da The Diagnostics Area.
186
187 @retval Item representing the value.
188 @retval NULL on error.
189 */
190
191 Item *
get_value(THD * thd,const Diagnostics_area * da)192 Statement_information_item::get_value(THD *thd, const Diagnostics_area *da)
193 {
194 Item *value= NULL;
195 DBUG_ENTER("Statement_information_item::get_value");
196
197 switch (m_name)
198 {
199 /*
200 The number of condition areas that have information. That is,
201 the number of errors and warnings within the Diagnostics Area.
202 */
203 case NUMBER:
204 {
205 ulong count= da->cond_count();
206 value= new (thd->mem_root) Item_uint(count);
207 break;
208 }
209 /*
210 Number that shows how many rows were directly affected by
211 a data-change statement (INSERT, UPDATE, DELETE, MERGE,
212 REPLACE, LOAD).
213 */
214 case ROW_COUNT:
215 value= new (thd->mem_root) Item_int(thd->get_row_count_func());
216 break;
217 }
218
219 DBUG_RETURN(value);
220 }
221
222
223 /**
224 Obtain condition information in the context of a given Diagnostics Area.
225
226 @param thd The current thread.
227 @param da The Diagnostics Area.
228
229 @retval false on success.
230 @retval true on error
231 */
232
233 bool
aggregate(THD * thd,const Diagnostics_area * da)234 Condition_information::aggregate(THD *thd, const Diagnostics_area *da)
235 {
236 bool rv= false;
237 longlong cond_number;
238 const Sql_condition *cond= NULL;
239 Condition_information_item *cond_info_item;
240 Diagnostics_area::Sql_condition_iterator it_conds= da->sql_conditions();
241 List_iterator_fast<Condition_information_item> it_items(*m_items);
242 DBUG_ENTER("Condition_information::aggregate");
243
244 /* Prepare the expression for evaluation. */
245 if (!m_cond_number_expr->fixed &&
246 m_cond_number_expr->fix_fields(thd, &m_cond_number_expr))
247 DBUG_RETURN(true);
248
249 cond_number= m_cond_number_expr->val_int();
250
251 /*
252 Limit to the number of available conditions. Diagnostics_area::warn_count()
253 is not used because it indicates the number of condition regardless of
254 @@max_error_count, which prevents conditions from being pushed, but not
255 counted.
256 */
257 if (cond_number < 1 || (ulonglong) cond_number > da->cond_count())
258 {
259 my_error(ER_DA_INVALID_CONDITION_NUMBER, MYF(0));
260 DBUG_RETURN(true);
261 }
262
263 /* Advance to the requested condition. */
264 while (cond_number--)
265 cond= it_conds++;
266
267 DBUG_ASSERT(cond);
268
269 /* Evaluate the requested information in the context of the condition. */
270 while ((cond_info_item= it_items++))
271 {
272 if ((rv= evaluate(thd, cond_info_item, cond)))
273 break;
274 }
275
276 DBUG_RETURN(rv);
277 }
278
279
280 /**
281 Create an UTF-8 string item to represent a condition item string.
282
283 @remark The string might not have a associated charset. For example,
284 this can be the case if the server does not or fails to process
285 the error message file.
286
287 @remark See "Design notes about Sql_condition::m_message_text." in sql_error.cc
288
289 @return Pointer to an string item, NULL on failure.
290 */
291
292 Item *
make_utf8_string_item(THD * thd,const String * str)293 Condition_information_item::make_utf8_string_item(THD *thd, const String *str)
294 {
295 /* Default is utf8 character set and utf8_general_ci collation. */
296 const CHARSET_INFO *to_cs= &my_charset_utf8_general_ci;
297 /* If a charset was not set, assume that no conversion is needed. */
298 const CHARSET_INFO *from_cs= str->charset() ? str->charset() : to_cs;
299 Item_string *item= new Item_string(str->ptr(), str->length(), from_cs);
300 /* If necessary, convert the string (ignoring errors), then copy it over. */
301 return item ? item->charset_converter(to_cs, false) : NULL;
302 }
303
304
305 /**
306 Obtain the value of this condition information item in the context of
307 a given condition.
308
309 @param thd The current thread.
310 @param da The Diagnostics Area.
311
312 @retval Item representing the value.
313 @retval NULL on error.
314 */
315
316 Item *
get_value(THD * thd,const Sql_condition * cond)317 Condition_information_item::get_value(THD *thd, const Sql_condition *cond)
318 {
319 String str;
320 Item *value= NULL;
321 DBUG_ENTER("Condition_information_item::get_value");
322
323 switch (m_name)
324 {
325 case CLASS_ORIGIN:
326 value= make_utf8_string_item(thd, &(cond->m_class_origin));
327 break;
328 case SUBCLASS_ORIGIN:
329 value= make_utf8_string_item(thd, &(cond->m_subclass_origin));
330 break;
331 case CONSTRAINT_CATALOG:
332 value= make_utf8_string_item(thd, &(cond->m_constraint_catalog));
333 break;
334 case CONSTRAINT_SCHEMA:
335 value= make_utf8_string_item(thd, &(cond->m_constraint_schema));
336 break;
337 case CONSTRAINT_NAME:
338 value= make_utf8_string_item(thd, &(cond->m_constraint_name));
339 break;
340 case CATALOG_NAME:
341 value= make_utf8_string_item(thd, &(cond->m_catalog_name));
342 break;
343 case SCHEMA_NAME:
344 value= make_utf8_string_item(thd, &(cond->m_schema_name));
345 break;
346 case TABLE_NAME:
347 value= make_utf8_string_item(thd, &(cond->m_table_name));
348 break;
349 case COLUMN_NAME:
350 value= make_utf8_string_item(thd, &(cond->m_column_name));
351 break;
352 case CURSOR_NAME:
353 value= make_utf8_string_item(thd, &(cond->m_cursor_name));
354 break;
355 case MESSAGE_TEXT:
356 value= make_utf8_string_item(thd, &(cond->m_message_text));
357 break;
358 case MYSQL_ERRNO:
359 value= new (thd->mem_root) Item_uint(cond->m_mysql_errno);
360 break;
361 case RETURNED_SQLSTATE:
362 str.set_ascii(cond->returned_sqlstate(), strlen(cond->returned_sqlstate()));
363 value= make_utf8_string_item(thd, &str);
364 break;
365 }
366
367 DBUG_RETURN(value);
368 }
369
370