1 /* Copyright (c) 2008, 2015, 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_priv.h"
24 #include "sp_head.h"
25 #include "sp_pcontext.h"
26 #include "sp_rcontext.h"
27 #include "sql_signal.h"
28 
29 /*
30   The parser accepts any error code (desired)
31   The runtime internally supports any error code (desired)
32   The client server protocol is limited to 16 bits error codes (restriction)
33   Enforcing the 65535 limit in the runtime until the protocol can change.
34 */
35 #define MAX_MYSQL_ERRNO UINT_MAX16
36 
37 const LEX_STRING Diag_condition_item_names[]=
38 {
39   { C_STRING_WITH_LEN("CLASS_ORIGIN") },
40   { C_STRING_WITH_LEN("SUBCLASS_ORIGIN") },
41   { C_STRING_WITH_LEN("CONSTRAINT_CATALOG") },
42   { C_STRING_WITH_LEN("CONSTRAINT_SCHEMA") },
43   { C_STRING_WITH_LEN("CONSTRAINT_NAME") },
44   { C_STRING_WITH_LEN("CATALOG_NAME") },
45   { C_STRING_WITH_LEN("SCHEMA_NAME") },
46   { C_STRING_WITH_LEN("TABLE_NAME") },
47   { C_STRING_WITH_LEN("COLUMN_NAME") },
48   { C_STRING_WITH_LEN("CURSOR_NAME") },
49   { C_STRING_WITH_LEN("MESSAGE_TEXT") },
50   { C_STRING_WITH_LEN("MYSQL_ERRNO") },
51 
52   { C_STRING_WITH_LEN("CONDITION_IDENTIFIER") },
53   { C_STRING_WITH_LEN("CONDITION_NUMBER") },
54   { C_STRING_WITH_LEN("CONNECTION_NAME") },
55   { C_STRING_WITH_LEN("MESSAGE_LENGTH") },
56   { C_STRING_WITH_LEN("MESSAGE_OCTET_LENGTH") },
57   { C_STRING_WITH_LEN("PARAMETER_MODE") },
58   { C_STRING_WITH_LEN("PARAMETER_NAME") },
59   { C_STRING_WITH_LEN("PARAMETER_ORDINAL_POSITION") },
60   { C_STRING_WITH_LEN("RETURNED_SQLSTATE") },
61   { C_STRING_WITH_LEN("ROUTINE_CATALOG") },
62   { C_STRING_WITH_LEN("ROUTINE_NAME") },
63   { C_STRING_WITH_LEN("ROUTINE_SCHEMA") },
64   { C_STRING_WITH_LEN("SERVER_NAME") },
65   { C_STRING_WITH_LEN("SPECIFIC_NAME") },
66   { C_STRING_WITH_LEN("TRIGGER_CATALOG") },
67   { C_STRING_WITH_LEN("TRIGGER_NAME") },
68   { C_STRING_WITH_LEN("TRIGGER_SCHEMA") }
69 };
70 
Set_signal_information(const Set_signal_information & set)71 Set_signal_information::Set_signal_information(
72   const Set_signal_information& set)
73 {
74   memcpy(m_item, set.m_item, sizeof(m_item));
75 }
76 
clear()77 void Set_signal_information::clear()
78 {
79   memset(m_item, 0, sizeof(m_item));
80 }
81 
assign_defaults(Sql_condition * cond,bool set_level_code,Sql_condition::enum_warning_level level,int sqlcode)82 void Sql_cmd_common_signal::assign_defaults(
83                                     Sql_condition *cond,
84                                     bool set_level_code,
85                                     Sql_condition::enum_warning_level level,
86                                     int sqlcode)
87 {
88   if (set_level_code)
89   {
90     cond->m_level= level;
91     cond->m_sql_errno= sqlcode;
92   }
93   if (! cond->get_message_text())
94     cond->set_builtin_message_text(ER(sqlcode));
95 }
96 
eval_defaults(THD * thd,Sql_condition * cond)97 void Sql_cmd_common_signal::eval_defaults(THD *thd, Sql_condition *cond)
98 {
99   DBUG_ASSERT(cond);
100 
101   const char* sqlstate;
102   bool set_defaults= (m_cond != 0);
103 
104   if (set_defaults)
105   {
106     /*
107       SIGNAL is restricted in sql_yacc.yy to only signal SQLSTATE conditions.
108     */
109     DBUG_ASSERT(m_cond->type == sp_condition_value::SQLSTATE);
110     sqlstate= m_cond->sql_state;
111     cond->set_sqlstate(sqlstate);
112   }
113   else
114     sqlstate= cond->get_sqlstate();
115 
116   DBUG_ASSERT(sqlstate);
117   /* SQLSTATE class "00": illegal, rejected in the parser. */
118   DBUG_ASSERT((sqlstate[0] != '0') || (sqlstate[1] != '0'));
119 
120   if ((sqlstate[0] == '0') && (sqlstate[1] == '1'))
121   {
122     /* SQLSTATE class "01": warning. */
123     assign_defaults(cond, set_defaults,
124                     Sql_condition::WARN_LEVEL_WARN, ER_SIGNAL_WARN);
125   }
126   else if ((sqlstate[0] == '0') && (sqlstate[1] == '2'))
127   {
128     /* SQLSTATE class "02": not found. */
129     assign_defaults(cond, set_defaults,
130                     Sql_condition::WARN_LEVEL_ERROR, ER_SIGNAL_NOT_FOUND);
131   }
132   else
133   {
134     /* other SQLSTATE classes : error. */
135     assign_defaults(cond, set_defaults,
136                     Sql_condition::WARN_LEVEL_ERROR, ER_SIGNAL_EXCEPTION);
137   }
138 }
139 
assign_fixed_string(MEM_ROOT * mem_root,CHARSET_INFO * dst_cs,size_t max_char,String * dst,const String * src)140 static bool assign_fixed_string(MEM_ROOT *mem_root,
141                                 CHARSET_INFO *dst_cs,
142                                 size_t max_char,
143                                 String *dst,
144                                 const String* src)
145 {
146   bool truncated;
147   size_t numchars;
148   const CHARSET_INFO *src_cs;
149   const char* src_str;
150   const char* src_end;
151   size_t src_len;
152   size_t to_copy;
153   char* dst_str;
154   size_t dst_len;
155   size_t dst_copied;
156   uint32 dummy_offset;
157 
158   src_str= src->ptr();
159   if (src_str == NULL)
160   {
161     dst->set((const char*) NULL, 0, dst_cs);
162     return false;
163   }
164 
165   src_cs= src->charset();
166   src_len= src->length();
167   src_end= src_str + src_len;
168   numchars= src_cs->cset->numchars(src_cs, src_str, src_end);
169 
170   if (numchars <= max_char)
171   {
172     to_copy= src->length();
173     truncated= false;
174   }
175   else
176   {
177     numchars= max_char;
178     to_copy= dst_cs->cset->charpos(dst_cs, src_str, src_end, numchars);
179     truncated= true;
180   }
181 
182   if (String::needs_conversion(to_copy, src_cs, dst_cs, & dummy_offset))
183   {
184     dst_len= numchars * dst_cs->mbmaxlen;
185     dst_str= (char*) alloc_root(mem_root, dst_len + 1);
186     if (dst_str)
187     {
188       const char* well_formed_error_pos;
189       const char* cannot_convert_error_pos;
190       const char* from_end_pos;
191 
192       dst_copied= well_formed_copy_nchars(dst_cs, dst_str, dst_len,
193                                           src_cs, src_str, src_len,
194                                           numchars,
195                                           & well_formed_error_pos,
196                                           & cannot_convert_error_pos,
197                                           & from_end_pos);
198       DBUG_ASSERT(dst_copied <= dst_len);
199       dst_len= dst_copied; /* In case the copy truncated the data */
200       dst_str[dst_copied]= '\0';
201     }
202   }
203   else
204   {
205     dst_len= to_copy;
206     dst_str= (char*) alloc_root(mem_root, dst_len + 1);
207     if (dst_str)
208     {
209       memcpy(dst_str, src_str, to_copy);
210       dst_str[to_copy]= '\0';
211     }
212   }
213   dst->set(dst_str, dst_len, dst_cs);
214 
215   return truncated;
216 }
217 
assign_condition_item(MEM_ROOT * mem_root,const char * name,THD * thd,Item * set,String * ci)218 static int assign_condition_item(MEM_ROOT *mem_root, const char* name, THD *thd,
219                                  Item *set, String *ci)
220 {
221   char str_buff[(64+1)*4]; /* Room for a null terminated UTF8 String 64 */
222   String str_value(str_buff, sizeof(str_buff), & my_charset_utf8_bin);
223   String *str;
224   bool truncated;
225 
226   DBUG_ENTER("assign_condition_item");
227 
228   if (set->is_null())
229   {
230     thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR, name, "NULL");
231     DBUG_RETURN(1);
232   }
233 
234   str= set->val_str(& str_value);
235   truncated= assign_fixed_string(mem_root, & my_charset_utf8_bin, 64, ci, str);
236   if (truncated)
237   {
238     if (thd->is_strict_mode())
239     {
240       thd->raise_error_printf(ER_COND_ITEM_TOO_LONG, name);
241       DBUG_RETURN(1);
242     }
243 
244     thd->raise_warning_printf(WARN_COND_ITEM_TRUNCATED, name);
245   }
246 
247   DBUG_RETURN(0);
248 }
249 
250 
eval_signal_informations(THD * thd,Sql_condition * cond)251 int Sql_cmd_common_signal::eval_signal_informations(THD *thd, Sql_condition *cond)
252 {
253   struct cond_item_map
254   {
255     enum enum_diag_condition_item_name m_item;
256     String Sql_condition::*m_member;
257   };
258 
259   static cond_item_map map[]=
260   {
261     { DIAG_CLASS_ORIGIN, & Sql_condition::m_class_origin },
262     { DIAG_SUBCLASS_ORIGIN, & Sql_condition::m_subclass_origin },
263     { DIAG_CONSTRAINT_CATALOG, & Sql_condition::m_constraint_catalog },
264     { DIAG_CONSTRAINT_SCHEMA, & Sql_condition::m_constraint_schema },
265     { DIAG_CONSTRAINT_NAME, & Sql_condition::m_constraint_name },
266     { DIAG_CATALOG_NAME, & Sql_condition::m_catalog_name },
267     { DIAG_SCHEMA_NAME, & Sql_condition::m_schema_name },
268     { DIAG_TABLE_NAME, & Sql_condition::m_table_name },
269     { DIAG_COLUMN_NAME, & Sql_condition::m_column_name },
270     { DIAG_CURSOR_NAME, & Sql_condition::m_cursor_name }
271   };
272 
273   Item *set;
274   String str_value;
275   String *str;
276   int i;
277   uint j;
278   int result= 1;
279   enum enum_diag_condition_item_name item_enum;
280   String *member;
281   const LEX_STRING *name;
282 
283   DBUG_ENTER("Sql_cmd_common_signal::eval_signal_informations");
284 
285   for (i= FIRST_DIAG_SET_PROPERTY;
286        i <= LAST_DIAG_SET_PROPERTY;
287        i++)
288   {
289     set= m_set_signal_information.m_item[i];
290     if (set)
291     {
292       if (! set->fixed)
293       {
294         if (set->fix_fields(thd, & set))
295           goto end;
296         m_set_signal_information.m_item[i]= set;
297       }
298     }
299   }
300 
301   /*
302     Generically assign all the UTF8 String 64 condition items
303     described in the map.
304   */
305   for (j= 0; j < array_elements(map); j++)
306   {
307     item_enum= map[j].m_item;
308     set= m_set_signal_information.m_item[item_enum];
309     if (set != NULL)
310     {
311       member= & (cond->* map[j].m_member);
312       name= & Diag_condition_item_names[item_enum];
313       if (assign_condition_item(cond->m_mem_root, name->str, thd, set, member))
314         goto end;
315     }
316   }
317 
318   /*
319     Assign the remaining attributes.
320   */
321 
322   set= m_set_signal_information.m_item[DIAG_MESSAGE_TEXT];
323   if (set != NULL)
324   {
325     if (set->is_null())
326     {
327       thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR,
328                               "MESSAGE_TEXT", "NULL");
329       goto end;
330     }
331     /*
332       Enforce that SET MESSAGE_TEXT = <value> evaluates the value
333       as VARCHAR(128) CHARACTER SET UTF8.
334     */
335     bool truncated;
336     String utf8_text;
337     str= set->val_str(& str_value);
338     truncated= assign_fixed_string(thd->mem_root, & my_charset_utf8_bin, 128,
339                                    & utf8_text, str);
340     if (truncated)
341     {
342       if (thd->is_strict_mode())
343       {
344         thd->raise_error_printf(ER_COND_ITEM_TOO_LONG,
345                                 "MESSAGE_TEXT");
346         goto end;
347       }
348 
349       thd->raise_warning_printf(WARN_COND_ITEM_TRUNCATED,
350                                 "MESSAGE_TEXT");
351     }
352 
353     /*
354       See the comments
355        "Design notes about Sql_condition::m_message_text."
356       in file sql_error.cc
357     */
358     String converted_text;
359     converted_text.set_charset(error_message_charset_info);
360     converted_text.append(utf8_text.ptr(), utf8_text.length(),
361                           utf8_text.charset());
362     cond->set_builtin_message_text(converted_text.c_ptr_safe());
363   }
364 
365   set= m_set_signal_information.m_item[DIAG_MYSQL_ERRNO];
366   if (set != NULL)
367   {
368     if (set->is_null())
369     {
370       thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR,
371                               "MYSQL_ERRNO", "NULL");
372       goto end;
373     }
374     longlong code= set->val_int();
375     if ((code <= 0) || (code > MAX_MYSQL_ERRNO))
376     {
377       str= set->val_str(& str_value);
378       thd->raise_error_printf(ER_WRONG_VALUE_FOR_VAR,
379                               "MYSQL_ERRNO", str->c_ptr_safe());
380       goto end;
381     }
382     cond->m_sql_errno= (int) code;
383   }
384 
385   /*
386     The various item->val_xxx() methods don't return an error code,
387     but flag thd in case of failure.
388   */
389   if (! thd->is_error())
390     result= 0;
391 
392 end:
393   for (i= FIRST_DIAG_SET_PROPERTY;
394        i <= LAST_DIAG_SET_PROPERTY;
395        i++)
396   {
397     set= m_set_signal_information.m_item[i];
398     if (set)
399     {
400       if (set->fixed)
401         set->cleanup();
402     }
403   }
404 
405   DBUG_RETURN(result);
406 }
407 
raise_condition(THD * thd,Sql_condition * cond)408 bool Sql_cmd_common_signal::raise_condition(THD *thd, Sql_condition *cond)
409 {
410   bool result= TRUE;
411 
412   DBUG_ENTER("Sql_cmd_common_signal::raise_condition");
413 
414   DBUG_ASSERT(thd->lex->query_tables == NULL);
415 
416   eval_defaults(thd, cond);
417   if (eval_signal_informations(thd, cond))
418     DBUG_RETURN(result);
419 
420   /* SIGNAL should not signal WARN_LEVEL_NOTE */
421   DBUG_ASSERT((cond->m_level == Sql_condition::WARN_LEVEL_WARN) ||
422               (cond->m_level == Sql_condition::WARN_LEVEL_ERROR));
423 
424   Sql_condition *raised= NULL;
425   raised= thd->raise_condition(cond->get_sql_errno(),
426                                cond->get_sqlstate(),
427                                cond->get_level(),
428                                cond->get_message_text());
429   if (raised)
430     raised->copy_opt_attributes(cond);
431 
432   if (cond->m_level == Sql_condition::WARN_LEVEL_WARN)
433   {
434     my_ok(thd);
435     result= FALSE;
436   }
437 
438   DBUG_RETURN(result);
439 }
440 
execute(THD * thd)441 bool Sql_cmd_signal::execute(THD *thd)
442 {
443   bool result= TRUE;
444   Sql_condition cond(thd->mem_root);
445 
446   DBUG_ENTER("Sql_cmd_signal::execute");
447 
448   /*
449     WL#2110 SIGNAL specification says:
450 
451       When SIGNAL is executed, it has five effects, in the following order:
452 
453         (1) First, the diagnostics area is completely cleared. So if the
454         SIGNAL is in a DECLARE HANDLER then any pending errors or warnings
455         are gone. So is 'row count'.
456 
457     This has roots in the SQL standard specification for SIGNAL.
458   */
459 
460   thd->get_stmt_da()->reset_diagnostics_area();
461   thd->set_row_count_func(0);
462   thd->get_stmt_da()->clear_warning_info(thd->query_id);
463 
464   result= raise_condition(thd, &cond);
465 
466   DBUG_RETURN(result);
467 }
468 
469 
470 /**
471   Execute RESIGNAL SQL-statement.
472 
473   @param thd Thread context.
474 
475   @return Error status
476   @retval true  in case of error
477   @retval false on success
478 */
479 
execute(THD * thd)480 bool Sql_cmd_resignal::execute(THD *thd)
481 {
482   Diagnostics_area *da= thd->get_stmt_da();
483   const sp_rcontext::Sql_condition_info *signaled;
484 
485   DBUG_ENTER("Sql_cmd_resignal::execute");
486 
487   // This is a way to force sql_conditions from the current Warning_info to be
488   // passed to the caller's Warning_info.
489   da->set_warning_info_id(thd->query_id);
490 
491   if (! thd->sp_runtime_ctx ||
492       ! (signaled= thd->sp_runtime_ctx->raised_condition()))
493   {
494     thd->raise_error(ER_RESIGNAL_WITHOUT_ACTIVE_HANDLER);
495     DBUG_RETURN(true);
496   }
497 
498   Sql_condition signaled_err(thd->mem_root);
499   signaled_err.set(signaled->sql_errno,
500                    signaled->sql_state,
501                    signaled->level,
502                    signaled->message);
503 
504 
505   if (m_cond) // RESIGNAL with signal_value.
506   {
507     query_cache_abort(&thd->query_cache_tls);
508 
509     /* Keep handled conditions. */
510     da->unmark_sql_conditions_from_removal();
511 
512     /* Check if the old condition still exists. */
513     if (da->has_sql_condition(signaled->message, strlen(signaled->message)))
514     {
515       /* Make room for the new RESIGNAL condition. */
516       da->reserve_space(thd, 1);
517     }
518     else
519     {
520       /* Make room for old condition + the new RESIGNAL condition. */
521       da->reserve_space(thd, 2);
522 
523       da->push_warning(thd, &signaled_err);
524     }
525   }
526 
527   DBUG_RETURN(raise_condition(thd, &signaled_err));
528 }
529