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