~vadim-tk/percona-server/flushing-algo

« back to all changes in this revision

Viewing changes to sql/sql_signal.cc

  • Committer: root
  • Date: 2011-10-29 01:34:40 UTC
  • Revision ID: root@hppro1.office.percona.com-20111029013440-qhnf4jk8kdjcf4e0
Initial import

Show diffs side-by-side

added added

removed removed

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