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