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