00001 /* Copyright (C) 2002 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 #include "mysql_priv.h" 00018 #ifdef USE_PRAGMA_IMPLEMENTATION 00019 #pragma implementation 00020 #endif 00021 #include "sp_head.h" 00022 #include "sp.h" 00023 #include "sp_pcontext.h" 00024 #include "sp_rcontext.h" 00025 #include "sp_cache.h" 00026 00027 /* 00028 Sufficient max length of printed destinations and frame offsets (all uints). 00029 */ 00030 #define SP_INSTR_UINT_MAXLEN 8 00031 #define SP_STMT_PRINT_MAXLEN 40 00032 00033 00034 #include <my_user.h> 00035 00036 Item_result 00037 sp_map_result_type(enum enum_field_types type) 00038 { 00039 switch (type) { 00040 case MYSQL_TYPE_TINY: 00041 case MYSQL_TYPE_SHORT: 00042 case MYSQL_TYPE_LONG: 00043 case MYSQL_TYPE_LONGLONG: 00044 case MYSQL_TYPE_INT24: 00045 return INT_RESULT; 00046 case MYSQL_TYPE_DECIMAL: 00047 case MYSQL_TYPE_NEWDECIMAL: 00048 return DECIMAL_RESULT; 00049 case MYSQL_TYPE_FLOAT: 00050 case MYSQL_TYPE_DOUBLE: 00051 return REAL_RESULT; 00052 default: 00053 return STRING_RESULT; 00054 } 00055 } 00056 00057 00058 Item::Type 00059 sp_map_item_type(enum enum_field_types type) 00060 { 00061 switch (type) { 00062 case MYSQL_TYPE_TINY: 00063 case MYSQL_TYPE_SHORT: 00064 case MYSQL_TYPE_LONG: 00065 case MYSQL_TYPE_LONGLONG: 00066 case MYSQL_TYPE_INT24: 00067 return Item::INT_ITEM; 00068 case MYSQL_TYPE_DECIMAL: 00069 case MYSQL_TYPE_NEWDECIMAL: 00070 return Item::DECIMAL_ITEM; 00071 case MYSQL_TYPE_FLOAT: 00072 case MYSQL_TYPE_DOUBLE: 00073 return Item::REAL_ITEM; 00074 default: 00075 return Item::STRING_ITEM; 00076 } 00077 } 00078 00079 00080 /* 00081 Return a string representation of the Item value. 00082 00083 NOTE: If the item has a string result type, the string is escaped 00084 according to its character set. 00085 00086 SYNOPSIS 00087 item a pointer to the Item 00088 str string buffer for representation of the value 00089 00090 RETURN 00091 NULL on error 00092 a pointer to valid a valid string on success 00093 */ 00094 00095 static String * 00096 sp_get_item_value(Item *item, String *str) 00097 { 00098 Item_result result_type= item->result_type(); 00099 00100 switch (item->result_type()) { 00101 case REAL_RESULT: 00102 case INT_RESULT: 00103 case DECIMAL_RESULT: 00104 return item->val_str(str); 00105 00106 case STRING_RESULT: 00107 { 00108 String *result= item->val_str(str); 00109 00110 if (!result) 00111 return NULL; 00112 00113 { 00114 char buf_holder[STRING_BUFFER_USUAL_SIZE]; 00115 String buf(buf_holder, sizeof(buf_holder), result->charset()); 00116 00117 /* We must reset length of the buffer, because of String specificity. */ 00118 buf.length(0); 00119 00120 buf.append('_'); 00121 buf.append(result->charset()->csname); 00122 if (result->charset()->escape_with_backslash_is_dangerous) 00123 buf.append(' '); 00124 append_query_string(result->charset(), result, &buf); 00125 str->copy(buf); 00126 00127 return str; 00128 } 00129 } 00130 00131 case ROW_RESULT: 00132 default: 00133 return NULL; 00134 } 00135 } 00136 00137 00138 /* 00139 SYNOPSIS 00140 sp_get_flags_for_command() 00141 00142 DESCRIPTION 00143 Returns a combination of: 00144 * sp_head::MULTI_RESULTS: added if the 'cmd' is a command that might 00145 result in multiple result sets being sent back. 00146 * sp_head::CONTAINS_DYNAMIC_SQL: added if 'cmd' is one of PREPARE, 00147 EXECUTE, DEALLOCATE. 00148 */ 00149 00150 uint 00151 sp_get_flags_for_command(LEX *lex) 00152 { 00153 uint flags; 00154 00155 switch (lex->sql_command) { 00156 case SQLCOM_SELECT: 00157 if (lex->result) 00158 { 00159 flags= 0; /* This is a SELECT with INTO clause */ 00160 break; 00161 } 00162 /* fallthrough */ 00163 case SQLCOM_ANALYZE: 00164 case SQLCOM_BACKUP_TABLE: 00165 case SQLCOM_OPTIMIZE: 00166 case SQLCOM_PRELOAD_KEYS: 00167 case SQLCOM_ASSIGN_TO_KEYCACHE: 00168 case SQLCOM_CHECKSUM: 00169 case SQLCOM_CHECK: 00170 case SQLCOM_HA_READ: 00171 case SQLCOM_SHOW_AUTHORS: 00172 case SQLCOM_SHOW_BINLOGS: 00173 case SQLCOM_SHOW_BINLOG_EVENTS: 00174 case SQLCOM_SHOW_CHARSETS: 00175 case SQLCOM_SHOW_COLLATIONS: 00176 case SQLCOM_SHOW_COLUMN_TYPES: 00177 case SQLCOM_SHOW_CONTRIBUTORS: 00178 case SQLCOM_SHOW_CREATE: 00179 case SQLCOM_SHOW_CREATE_DB: 00180 case SQLCOM_SHOW_CREATE_FUNC: 00181 case SQLCOM_SHOW_CREATE_PROC: 00182 case SQLCOM_SHOW_CREATE_EVENT: 00183 case SQLCOM_SHOW_DATABASES: 00184 case SQLCOM_SHOW_ERRORS: 00185 case SQLCOM_SHOW_FIELDS: 00186 case SQLCOM_SHOW_FUNC_CODE: 00187 case SQLCOM_SHOW_GRANTS: 00188 case SQLCOM_SHOW_ENGINE_STATUS: 00189 case SQLCOM_SHOW_ENGINE_LOGS: 00190 case SQLCOM_SHOW_ENGINE_MUTEX: 00191 case SQLCOM_SHOW_EVENTS: 00192 case SQLCOM_SHOW_KEYS: 00193 case SQLCOM_SHOW_MASTER_STAT: 00194 case SQLCOM_SHOW_NEW_MASTER: 00195 case SQLCOM_SHOW_OPEN_TABLES: 00196 case SQLCOM_SHOW_PRIVILEGES: 00197 case SQLCOM_SHOW_PROCESSLIST: 00198 case SQLCOM_SHOW_PROC_CODE: 00199 case SQLCOM_SHOW_SCHEDULER_STATUS: 00200 case SQLCOM_SHOW_SLAVE_HOSTS: 00201 case SQLCOM_SHOW_SLAVE_STAT: 00202 case SQLCOM_SHOW_STATUS: 00203 case SQLCOM_SHOW_STATUS_FUNC: 00204 case SQLCOM_SHOW_STATUS_PROC: 00205 case SQLCOM_SHOW_STORAGE_ENGINES: 00206 case SQLCOM_SHOW_TABLES: 00207 case SQLCOM_SHOW_VARIABLES: 00208 case SQLCOM_SHOW_WARNS: 00209 case SQLCOM_REPAIR: 00210 case SQLCOM_RESTORE_TABLE: 00211 flags= sp_head::MULTI_RESULTS; 00212 break; 00213 /* 00214 EXECUTE statement may return a result set, but doesn't have to. 00215 We can't, however, know it in advance, and therefore must add 00216 this statement here. This is ok, as is equivalent to a result-set 00217 statement within an IF condition. 00218 */ 00219 case SQLCOM_EXECUTE: 00220 flags= sp_head::MULTI_RESULTS | sp_head::CONTAINS_DYNAMIC_SQL; 00221 break; 00222 case SQLCOM_PREPARE: 00223 case SQLCOM_DEALLOCATE_PREPARE: 00224 flags= sp_head::CONTAINS_DYNAMIC_SQL; 00225 break; 00226 case SQLCOM_CREATE_TABLE: 00227 if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) 00228 flags= 0; 00229 else 00230 flags= sp_head::HAS_COMMIT_OR_ROLLBACK; 00231 break; 00232 case SQLCOM_DROP_TABLE: 00233 if (lex->drop_temporary) 00234 flags= 0; 00235 else 00236 flags= sp_head::HAS_COMMIT_OR_ROLLBACK; 00237 break; 00238 case SQLCOM_CREATE_INDEX: 00239 case SQLCOM_CREATE_DB: 00240 case SQLCOM_CREATE_VIEW: 00241 case SQLCOM_CREATE_TRIGGER: 00242 case SQLCOM_CREATE_USER: 00243 case SQLCOM_ALTER_TABLE: 00244 case SQLCOM_BEGIN: 00245 case SQLCOM_RENAME_TABLE: 00246 case SQLCOM_RENAME_USER: 00247 case SQLCOM_DROP_INDEX: 00248 case SQLCOM_DROP_DB: 00249 case SQLCOM_DROP_USER: 00250 case SQLCOM_DROP_VIEW: 00251 case SQLCOM_DROP_TRIGGER: 00252 case SQLCOM_TRUNCATE: 00253 case SQLCOM_COMMIT: 00254 case SQLCOM_ROLLBACK: 00255 case SQLCOM_LOAD: 00256 case SQLCOM_LOAD_MASTER_DATA: 00257 case SQLCOM_LOCK_TABLES: 00258 case SQLCOM_CREATE_PROCEDURE: 00259 case SQLCOM_CREATE_SPFUNCTION: 00260 case SQLCOM_ALTER_PROCEDURE: 00261 case SQLCOM_ALTER_FUNCTION: 00262 case SQLCOM_DROP_PROCEDURE: 00263 case SQLCOM_DROP_FUNCTION: 00264 case SQLCOM_CREATE_EVENT: 00265 case SQLCOM_ALTER_EVENT: 00266 case SQLCOM_DROP_EVENT: 00267 case SQLCOM_FLUSH: 00268 case SQLCOM_INSTALL_PLUGIN: 00269 case SQLCOM_UNINSTALL_PLUGIN: 00270 flags= sp_head::HAS_COMMIT_OR_ROLLBACK; 00271 break; 00272 default: 00273 flags= 0; 00274 break; 00275 } 00276 return flags; 00277 } 00278 00279 00280 /* 00281 Prepare an Item for evaluation (call of fix_fields). 00282 00283 SYNOPSIS 00284 sp_prepare_func_item() 00285 thd thread handler 00286 it_addr pointer on item refernce 00287 00288 RETURN 00289 NULL error 00290 prepared item 00291 */ 00292 00293 Item * 00294 sp_prepare_func_item(THD* thd, Item **it_addr) 00295 { 00296 DBUG_ENTER("sp_prepare_func_item"); 00297 it_addr= (*it_addr)->this_item_addr(thd, it_addr); 00298 00299 if (!(*it_addr)->fixed && 00300 ((*it_addr)->fix_fields(thd, it_addr) || 00301 (*it_addr)->check_cols(1))) 00302 { 00303 DBUG_PRINT("info", ("fix_fields() failed")); 00304 DBUG_RETURN(NULL); 00305 } 00306 DBUG_RETURN(*it_addr); 00307 } 00308 00309 00310 /* 00311 Evaluate an expression and store the result in the field. 00312 00313 SYNOPSIS 00314 sp_eval_expr() 00315 thd - current thread object 00316 expr_item - the root item of the expression 00317 result_field - the field to store the result 00318 00319 RETURN VALUES 00320 FALSE on success 00321 TRUE on error 00322 */ 00323 00324 bool 00325 sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) 00326 { 00327 Item *expr_item; 00328 00329 DBUG_ENTER("sp_eval_expr"); 00330 00331 if (!*expr_item_ptr) 00332 DBUG_RETURN(TRUE); 00333 00334 if (!(expr_item= sp_prepare_func_item(thd, expr_item_ptr))) 00335 DBUG_RETURN(TRUE); 00336 00337 bool err_status= FALSE; 00338 00339 /* 00340 Set THD flags to emit warnings/errors in case of overflow/type errors 00341 during saving the item into the field. 00342 00343 Save original values and restore them after save. 00344 */ 00345 00346 enum_check_fields save_count_cuted_fields= thd->count_cuted_fields; 00347 bool save_abort_on_warning= thd->abort_on_warning; 00348 bool save_no_trans_update= thd->no_trans_update; 00349 00350 thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; 00351 thd->abort_on_warning= 00352 thd->variables.sql_mode & 00353 (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES); 00354 thd->no_trans_update= 0; 00355 00356 /* Save the value in the field. Convert the value if needed. */ 00357 00358 expr_item->save_in_field(result_field, 0); 00359 00360 thd->count_cuted_fields= save_count_cuted_fields; 00361 thd->abort_on_warning= save_abort_on_warning; 00362 thd->no_trans_update= save_no_trans_update; 00363 00364 if (thd->net.report_error) 00365 { 00366 /* Return error status if something went wrong. */ 00367 err_status= TRUE; 00368 } 00369 00370 DBUG_RETURN(err_status); 00371 } 00372 00373 00374 /* 00375 * 00376 * sp_name 00377 * 00378 */ 00379 00380 void 00381 sp_name::init_qname(THD *thd) 00382 { 00383 m_sroutines_key.length= m_db.length + m_name.length + 2; 00384 if (!(m_sroutines_key.str= thd->alloc(m_sroutines_key.length + 1))) 00385 return; 00386 m_qname.length= m_sroutines_key.length - 1; 00387 m_qname.str= m_sroutines_key.str + 1; 00388 sprintf(m_qname.str, "%.*s.%.*s", 00389 m_db.length, (m_db.length ? m_db.str : ""), 00390 m_name.length, m_name.str); 00391 } 00392 00393 00394 /* 00395 Check that the name 'ident' is ok. It's assumed to be an 'ident' 00396 from the parser, so we only have to check length and trailing spaces. 00397 The former is a standard requirement (and 'show status' assumes a 00398 non-empty name), the latter is a mysql:ism as trailing spaces are 00399 removed by get_field(). 00400 00401 RETURN 00402 TRUE - bad name 00403 FALSE - name is ok 00404 */ 00405 00406 bool 00407 check_routine_name(LEX_STRING ident) 00408 { 00409 return (!ident.str || !ident.str[0] || ident.str[ident.length-1] == ' '); 00410 } 00411 00412 /* ------------------------------------------------------------------ */ 00413 00414 00415 /* 00416 * 00417 * sp_head 00418 * 00419 */ 00420 00421 void * 00422 sp_head::operator new(size_t size) 00423 { 00424 DBUG_ENTER("sp_head::operator new"); 00425 MEM_ROOT own_root; 00426 sp_head *sp; 00427 00428 init_alloc_root(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC); 00429 sp= (sp_head *) alloc_root(&own_root, size); 00430 sp->main_mem_root= own_root; 00431 DBUG_PRINT("info", ("mem_root 0x%lx", (ulong) &sp->mem_root)); 00432 DBUG_RETURN(sp); 00433 } 00434 00435 void 00436 sp_head::operator delete(void *ptr, size_t size) 00437 { 00438 DBUG_ENTER("sp_head::operator delete"); 00439 MEM_ROOT own_root; 00440 sp_head *sp= (sp_head *) ptr; 00441 00442 /* Make a copy of main_mem_root as free_root will free the sp */ 00443 own_root= sp->main_mem_root; 00444 DBUG_PRINT("info", ("mem_root 0x%lx moved to 0x%lx", 00445 (ulong) &sp->mem_root, (ulong) &own_root)); 00446 free_root(&own_root, MYF(0)); 00447 00448 DBUG_VOID_RETURN; 00449 } 00450 00451 00452 sp_head::sp_head() 00453 :Query_arena(&main_mem_root, INITIALIZED_FOR_SP), 00454 m_flags(0), m_recursion_level(0), m_next_cached_sp(0), 00455 m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this), 00456 m_cont_level(0) 00457 { 00458 const LEX_STRING str_reset= { NULL, 0 }; 00459 m_return_field_def.charset = NULL; 00460 /* 00461 FIXME: the only use case when name is NULL is events, and it should 00462 be rewritten soon. Remove the else part and replace 'if' with 00463 an assert when this is done. 00464 */ 00465 m_db= m_name= m_qname= str_reset; 00466 00467 extern byte * 00468 sp_table_key(const byte *ptr, uint *plen, my_bool first); 00469 DBUG_ENTER("sp_head::sp_head"); 00470 00471 m_backpatch.empty(); 00472 m_cont_backpatch.empty(); 00473 m_lex.empty(); 00474 hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); 00475 hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0); 00476 DBUG_VOID_RETURN; 00477 } 00478 00479 00480 void 00481 sp_head::init(LEX *lex) 00482 { 00483 DBUG_ENTER("sp_head::init"); 00484 00485 lex->spcont= m_pcont= new sp_pcontext(NULL); 00486 00487 /* 00488 Altough trg_table_fields list is used only in triggers we init for all 00489 types of stored procedures to simplify reset_lex()/restore_lex() code. 00490 */ 00491 lex->trg_table_fields.empty(); 00492 my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8); 00493 m_param_begin= m_param_end= m_body_begin= 0; 00494 m_qname.str= m_db.str= m_name.str= m_params.str= 00495 m_body.str= m_defstr.str= 0; 00496 m_qname.length= m_db.length= m_name.length= m_params.length= 00497 m_body.length= m_defstr.length= 0; 00498 m_return_field_def.charset= NULL; 00499 DBUG_VOID_RETURN; 00500 } 00501 00502 00503 void 00504 sp_head::init_sp_name(THD *thd, sp_name *spname) 00505 { 00506 DBUG_ENTER("sp_head::init_sp_name"); 00507 00508 /* Must be initialized in the parser. */ 00509 00510 DBUG_ASSERT(spname && spname->m_db.str && spname->m_db.length); 00511 00512 /* We have to copy strings to get them into the right memroot. */ 00513 00514 m_db.length= spname->m_db.length; 00515 m_db.str= strmake_root(thd->mem_root, spname->m_db.str, spname->m_db.length); 00516 00517 m_name.length= spname->m_name.length; 00518 m_name.str= strmake_root(thd->mem_root, spname->m_name.str, 00519 spname->m_name.length); 00520 00521 if (spname->m_qname.length == 0) 00522 spname->init_qname(thd); 00523 00524 m_qname.length= spname->m_qname.length; 00525 m_qname.str= strmake_root(thd->mem_root, spname->m_qname.str, 00526 m_qname.length); 00527 00528 DBUG_VOID_RETURN; 00529 } 00530 00531 00532 void 00533 sp_head::init_strings(THD *thd, LEX *lex) 00534 { 00535 DBUG_ENTER("sp_head::init_strings"); 00536 const uchar *endp; /* Used to trim the end */ 00537 /* During parsing, we must use thd->mem_root */ 00538 MEM_ROOT *root= thd->mem_root; 00539 00540 if (m_param_begin && m_param_end) 00541 { 00542 m_params.length= m_param_end - m_param_begin; 00543 m_params.str= strmake_root(root, 00544 (char *)m_param_begin, m_params.length); 00545 } 00546 00547 /* If ptr has overrun end_of_query then end_of_query is the end */ 00548 endp= (lex->ptr > lex->end_of_query ? lex->end_of_query : lex->ptr); 00549 /* 00550 Trim "garbage" at the end. This is sometimes needed with the 00551 "/ * ! VERSION... * /" wrapper in dump files. 00552 */ 00553 endp= skip_rear_comments(m_body_begin, endp); 00554 00555 m_body.length= endp - m_body_begin; 00556 m_body.str= strmake_root(root, (char *)m_body_begin, m_body.length); 00557 m_defstr.length= endp - lex->buf; 00558 m_defstr.str= strmake_root(root, (char *)lex->buf, m_defstr.length); 00559 DBUG_VOID_RETURN; 00560 } 00561 00562 00563 static TYPELIB * 00564 create_typelib(MEM_ROOT *mem_root, create_field *field_def, List<String> *src) 00565 { 00566 TYPELIB *result= NULL; 00567 CHARSET_INFO *cs= field_def->charset; 00568 DBUG_ENTER("create_typelib"); 00569 00570 if (src->elements) 00571 { 00572 result= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB)); 00573 result->count= src->elements; 00574 result->name= ""; 00575 if (!(result->type_names=(const char **) 00576 alloc_root(mem_root,(sizeof(char *)+sizeof(int))*(result->count+1)))) 00577 DBUG_RETURN(0); 00578 result->type_lengths= (uint*)(result->type_names + result->count+1); 00579 List_iterator<String> it(*src); 00580 String conv; 00581 for (uint i=0; i < result->count; i++) 00582 { 00583 uint32 dummy; 00584 uint length; 00585 String *tmp= it++; 00586 00587 if (String::needs_conversion(tmp->length(), tmp->charset(), 00588 cs, &dummy)) 00589 { 00590 uint cnv_errs; 00591 conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs); 00592 00593 length= conv.length(); 00594 result->type_names[i]= (char*) strmake_root(mem_root, conv.ptr(), 00595 length); 00596 } 00597 else 00598 { 00599 length= tmp->length(); 00600 result->type_names[i]= strmake_root(mem_root, tmp->ptr(), length); 00601 } 00602 00603 // Strip trailing spaces. 00604 length= cs->cset->lengthsp(cs, result->type_names[i], length); 00605 result->type_lengths[i]= length; 00606 ((uchar *)result->type_names[i])[length]= '\0'; 00607 } 00608 result->type_names[result->count]= 0; 00609 result->type_lengths[result->count]= 0; 00610 } 00611 DBUG_RETURN(result); 00612 } 00613 00614 00615 int 00616 sp_head::create(THD *thd) 00617 { 00618 DBUG_ENTER("sp_head::create"); 00619 int ret; 00620 00621 DBUG_PRINT("info", ("type: %d name: %s params: %s body: %s", 00622 m_type, m_name.str, m_params.str, m_body.str)); 00623 00624 #ifndef DBUG_OFF 00625 optimize(); 00626 { 00627 String s; 00628 sp_instr *i; 00629 uint ip= 0; 00630 while ((i = get_instr(ip))) 00631 { 00632 char buf[8]; 00633 00634 sprintf(buf, "%4u: ", ip); 00635 s.append(buf); 00636 i->print(&s); 00637 s.append('\n'); 00638 ip+= 1; 00639 } 00640 s.append('\0'); 00641 DBUG_PRINT("info", ("Code %s\n%s", m_qname.str, s.ptr())); 00642 } 00643 #endif 00644 00645 if (m_type == TYPE_ENUM_FUNCTION) 00646 ret= sp_create_function(thd, this); 00647 else 00648 ret= sp_create_procedure(thd, this); 00649 00650 DBUG_RETURN(ret); 00651 } 00652 00653 sp_head::~sp_head() 00654 { 00655 destroy(); 00656 delete m_next_cached_sp; 00657 if (m_thd) 00658 restore_thd_mem_root(m_thd); 00659 } 00660 00661 void 00662 sp_head::destroy() 00663 { 00664 sp_instr *i; 00665 LEX *lex; 00666 DBUG_ENTER("sp_head::destroy"); 00667 DBUG_PRINT("info", ("name: %s", m_name.str)); 00668 00669 for (uint ip = 0 ; (i = get_instr(ip)) ; ip++) 00670 delete i; 00671 delete_dynamic(&m_instr); 00672 m_pcont->destroy(); 00673 free_items(); 00674 00675 /* 00676 If we have non-empty LEX stack then we just came out of parser with 00677 error. Now we should delete all auxilary LEXes and restore original 00678 THD::lex (In this case sp_head::restore_thd_mem_root() was not called 00679 too, so m_thd points to the current thread context). 00680 It is safe to not update LEX::ptr because further query string parsing 00681 and execution will be stopped anyway. 00682 */ 00683 DBUG_ASSERT(m_lex.is_empty() || m_thd); 00684 while ((lex= (LEX *)m_lex.pop())) 00685 { 00686 lex_end(m_thd->lex); 00687 delete m_thd->lex; 00688 m_thd->lex= lex; 00689 } 00690 00691 hash_free(&m_sptabs); 00692 hash_free(&m_sroutines); 00693 DBUG_VOID_RETURN; 00694 } 00695 00696 00697 /* 00698 This is only used for result fields from functions (both during 00699 fix_length_and_dec() and evaluation). 00700 */ 00701 00702 Field * 00703 sp_head::create_result_field(uint field_max_length, const char *field_name, 00704 TABLE *table) 00705 { 00706 uint field_length; 00707 Field *field; 00708 00709 DBUG_ENTER("sp_head::create_result_field"); 00710 00711 field_length= !m_return_field_def.length ? 00712 field_max_length : m_return_field_def.length; 00713 00714 field= ::make_field(table->s, /* TABLE_SHARE ptr */ 00715 (char*) 0, /* field ptr */ 00716 field_length, /* field [max] length */ 00717 (uchar*) "", /* null ptr */ 00718 0, /* null bit */ 00719 m_return_field_def.pack_flag, 00720 m_return_field_def.sql_type, 00721 m_return_field_def.charset, 00722 m_return_field_def.geom_type, 00723 Field::NONE, /* unreg check */ 00724 m_return_field_def.interval, 00725 field_name ? field_name : (const char *) m_name.str); 00726 00727 if (field) 00728 field->init(table); 00729 00730 DBUG_RETURN(field); 00731 } 00732 00733 00734 int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) 00735 { 00736 return (int)((*a)->pos_in_query - (*b)->pos_in_query); 00737 } 00738 00739 00740 /* 00741 StoredRoutinesBinlogging 00742 This paragraph applies only to statement-based binlogging. Row-based 00743 binlogging does not need anything special like this. 00744 00745 Top-down overview: 00746 00747 1. Statements 00748 00749 Statements that have is_update_query(stmt) == TRUE are written into the 00750 binary log verbatim. 00751 Examples: 00752 UPDATE tbl SET tbl.x = spfunc_w_side_effects() 00753 UPDATE tbl SET tbl.x=1 WHERE spfunc_w_side_effect_that_returns_false(tbl.y) 00754 00755 Statements that have is_update_query(stmt) == FALSE (e.g. SELECTs) are not 00756 written into binary log. Instead we catch function calls the statement 00757 makes and write it into binary log separately (see #3). 00758 00759 2. PROCEDURE calls 00760 00761 CALL statements are not written into binary log. Instead 00762 * Any FUNCTION invocation (in SET, IF, WHILE, OPEN CURSOR and other SP 00763 instructions) is written into binlog separately. 00764 00765 * Each statement executed in SP is binlogged separately, according to rules 00766 in #1, with the exception that we modify query string: we replace uses 00767 of SP local variables with NAME_CONST('spvar_name', <spvar-value>) calls. 00768 This substitution is done in subst_spvars(). 00769 00770 3. FUNCTION calls 00771 00772 In sp_head::execute_function(), we check 00773 * If this function invocation is done from a statement that is written 00774 into the binary log. 00775 * If there were any attempts to write events to the binary log during 00776 function execution (grep for start_union_events and stop_union_events) 00777 00778 If the answers are No and Yes, we write the function call into the binary 00779 log as "SELECT spfunc(<param1value>, <param2value>, ...)" 00780 00781 00782 4. Miscellaneous issues. 00783 00784 4.1 User variables. 00785 00786 When we call mysql_bin_log.write() for an SP statement, thd->user_var_events 00787 must hold set<{var_name, value}> pairs for all user variables used during 00788 the statement execution. 00789 This set is produced by tracking user variable reads during statement 00790 execution. 00791 00792 Fo SPs, this has the following implications: 00793 1) thd->user_var_events may contain events from several SP statements and 00794 needs to be valid after exection of these statements was finished. In 00795 order to achieve that, we 00796 * Allocate user_var_events array elements on appropriate mem_root (grep 00797 for user_var_events_alloc). 00798 * Use is_query_in_union() to determine if user_var_event is created. 00799 00800 2) We need to empty thd->user_var_events after we have wrote a function 00801 call. This is currently done by making 00802 reset_dynamic(&thd->user_var_events); 00803 calls in several different places. (TODO cosider moving this into 00804 mysql_bin_log.write() function) 00805 */ 00806 00807 00808 /* 00809 Replace thd->query{_length} with a string that one can write to the binlog. 00810 00811 SYNOPSIS 00812 subst_spvars() 00813 thd Current thread. 00814 instr Instruction (we look for Item_splocal instances in 00815 instr->free_list) 00816 query_str Original query string 00817 00818 DESCRIPTION 00819 00820 The binlog-suitable string is produced by replacing references to SP local 00821 variables with NAME_CONST('sp_var_name', value) calls. 00822 00823 RETURN 00824 FALSE on success 00825 thd->query{_length} either has been appropriately replaced or there 00826 is no need for replacements. 00827 TRUE out of memory error. 00828 */ 00829 00830 static bool 00831 subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) 00832 { 00833 DBUG_ENTER("subst_spvars"); 00834 if (thd->prelocked_mode == NON_PRELOCKED && mysql_bin_log.is_open()) 00835 { 00836 Dynamic_array<Item_splocal*> sp_vars_uses; 00837 char *pbuf, *cur, buffer[512]; 00838 String qbuf(buffer, sizeof(buffer), &my_charset_bin); 00839 int prev_pos, res; 00840 00841 /* Find all instances of Item_splocal used in this statement */ 00842 for (Item *item= instr->free_list; item; item= item->next) 00843 { 00844 if (item->is_splocal()) 00845 { 00846 Item_splocal *item_spl= (Item_splocal*)item; 00847 if (item_spl->pos_in_query) 00848 sp_vars_uses.append(item_spl); 00849 } 00850 } 00851 if (!sp_vars_uses.elements()) 00852 DBUG_RETURN(FALSE); 00853 00854 /* Sort SP var refs by their occurences in the query */ 00855 sp_vars_uses.sort(cmp_splocal_locations); 00856 00857 /* 00858 Construct a statement string where SP local var refs are replaced 00859 with "NAME_CONST(name, value)" 00860 */ 00861 qbuf.length(0); 00862 cur= query_str->str; 00863 prev_pos= res= 0; 00864 for (Item_splocal **splocal= sp_vars_uses.front(); 00865 splocal < sp_vars_uses.back(); splocal++) 00866 { 00867 Item *val; 00868 00869 char str_buffer[STRING_BUFFER_USUAL_SIZE]; 00870 String str_value_holder(str_buffer, sizeof(str_buffer), 00871 &my_charset_latin1); 00872 String *str_value; 00873 00874 /* append the text between sp ref occurences */ 00875 res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos); 00876 prev_pos= (*splocal)->pos_in_query + (*splocal)->m_name.length; 00877 00878 /* append the spvar substitute */ 00879 res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('")); 00880 res|= qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length); 00881 res|= qbuf.append(STRING_WITH_LEN("',")); 00882 res|= (*splocal)->fix_fields(thd, (Item **) splocal); 00883 00884 if (res) 00885 break; 00886 00887 val= (*splocal)->this_item(); 00888 DBUG_PRINT("info", ("print %p", val)); 00889 str_value= sp_get_item_value(val, &str_value_holder); 00890 if (str_value) 00891 res|= qbuf.append(*str_value); 00892 else 00893 res|= qbuf.append(STRING_WITH_LEN("NULL")); 00894 res|= qbuf.append(')'); 00895 if (res) 00896 break; 00897 } 00898 res|= qbuf.append(cur + prev_pos, query_str->length - prev_pos); 00899 if (res) 00900 DBUG_RETURN(TRUE); 00901 00902 if (!(pbuf= thd->strmake(qbuf.ptr(), qbuf.length()))) 00903 DBUG_RETURN(TRUE); 00904 00905 thd->query= pbuf; 00906 thd->query_length= qbuf.length(); 00907 } 00908 DBUG_RETURN(FALSE); 00909 } 00910 00911 00912 /* 00913 Return appropriate error about recursion limit reaching 00914 00915 SYNOPSIS 00916 sp_head::recursion_level_error() 00917 thd Thread handle 00918 00919 NOTE 00920 For functions and triggers we return error about prohibited recursion. 00921 For stored procedures we return about reaching recursion limit. 00922 */ 00923 00924 void sp_head::recursion_level_error(THD *thd) 00925 { 00926 if (m_type == TYPE_ENUM_PROCEDURE) 00927 { 00928 my_error(ER_SP_RECURSION_LIMIT, MYF(0), 00929 thd->variables.max_sp_recursion_depth, 00930 m_name.str); 00931 } 00932 else 00933 my_error(ER_SP_NO_RECURSION, MYF(0)); 00934 } 00935 00936 00937 /* 00938 Execute the routine. The main instruction jump loop is there 00939 Assume the parameters already set. 00940 00941 RETURN 00942 FALSE on success 00943 TRUE on error 00944 00945 */ 00946 00947 bool 00948 sp_head::execute(THD *thd) 00949 { 00950 DBUG_ENTER("sp_head::execute"); 00951 char old_db_buf[NAME_LEN+1]; 00952 LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; 00953 bool dbchanged; 00954 sp_rcontext *ctx; 00955 bool err_status= FALSE; 00956 uint ip= 0; 00957 ulong save_sql_mode; 00958 bool save_abort_on_warning; 00959 Query_arena *old_arena; 00960 /* per-instruction arena */ 00961 MEM_ROOT execute_mem_root; 00962 Query_arena execute_arena(&execute_mem_root, INITIALIZED_FOR_SP), 00963 backup_arena; 00964 query_id_t old_query_id; 00965 TABLE *old_derived_tables; 00966 LEX *old_lex; 00967 Item_change_list old_change_list; 00968 String old_packet; 00969 00970 /* Use some extra margin for possible SP recursion and functions */ 00971 if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (char*)&old_packet)) 00972 DBUG_RETURN(TRUE); 00973 00974 /* init per-instruction memroot */ 00975 init_alloc_root(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0); 00976 00977 DBUG_ASSERT(!(m_flags & IS_INVOKED)); 00978 m_flags|= IS_INVOKED; 00979 m_first_instance->m_first_free_instance= m_next_cached_sp; 00980 if (m_next_cached_sp) 00981 { 00982 DBUG_PRINT("info", 00983 ("first free for 0x%lx ++: 0x%lx->0x%lx level: %lu flags %x", 00984 (ulong)m_first_instance, (ulong) this, 00985 (ulong) m_next_cached_sp, 00986 m_next_cached_sp->m_recursion_level, 00987 m_next_cached_sp->m_flags)); 00988 } 00989 /* 00990 Check that if there are not any instances after this one then 00991 pointer to the last instance points on this instance or if there are 00992 some instances after this one then recursion level of next instance 00993 greater then recursion level of current instance on 1 00994 */ 00995 DBUG_ASSERT((m_next_cached_sp == 0 && 00996 m_first_instance->m_last_cached_sp == this) || 00997 (m_recursion_level + 1 == m_next_cached_sp->m_recursion_level)); 00998 00999 if (m_db.length && 01000 (err_status= sp_use_new_db(thd, m_db, &old_db, 0, &dbchanged))) 01001 goto done; 01002 01003 if ((ctx= thd->spcont)) 01004 ctx->clear_handler(); 01005 thd->query_error= 0; 01006 old_arena= thd->stmt_arena; 01007 01008 /* 01009 We have to save/restore this info when we are changing call level to 01010 be able properly do close_thread_tables() in instructions. 01011 */ 01012 old_query_id= thd->query_id; 01013 old_derived_tables= thd->derived_tables; 01014 thd->derived_tables= 0; 01015 save_sql_mode= thd->variables.sql_mode; 01016 thd->variables.sql_mode= m_sql_mode; 01017 save_abort_on_warning= thd->abort_on_warning; 01018 thd->abort_on_warning= 01019 (m_sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)); 01020 01021 /* 01022 It is also more efficient to save/restore current thd->lex once when 01023 do it in each instruction 01024 */ 01025 old_lex= thd->lex; 01026 /* 01027 We should also save Item tree change list to avoid rollback something 01028 too early in the calling query. 01029 */ 01030 old_change_list= thd->change_list; 01031 thd->change_list.empty(); 01032 /* 01033 Cursors will use thd->packet, so they may corrupt data which was prepared 01034 for sending by upper level. OTOH cursors in the same routine can share this 01035 buffer safely so let use use routine-local packet instead of having own 01036 packet buffer for each cursor. 01037 01038 It is probably safe to use same thd->convert_buff everywhere. 01039 */ 01040 old_packet.swap(thd->packet); 01041 01042 /* 01043 Switch to per-instruction arena here. We can do it since we cleanup 01044 arena after every instruction. 01045 */ 01046 thd->set_n_backup_active_arena(&execute_arena, &backup_arena); 01047 01048 /* 01049 Save callers arena in order to store instruction results and out 01050 parameters in it later during sp_eval_func_item() 01051 */ 01052 thd->spcont->callers_arena= &backup_arena; 01053 01054 do 01055 { 01056 sp_instr *i; 01057 uint hip; // Handler ip 01058 01059 i = get_instr(ip); // Returns NULL when we're done. 01060 if (i == NULL) 01061 break; 01062 DBUG_PRINT("execute", ("Instruction %u", ip)); 01063 /* Don't change NOW() in FUNCTION or TRIGGER */ 01064 if (!thd->in_sub_stmt) 01065 thd->set_time(); // Make current_time() et al work 01066 01067 /* 01068 We have to set thd->stmt_arena before executing the instruction 01069 to store in the instruction free_list all new items, created 01070 during the first execution (for example expanding of '*' or the 01071 items made during other permanent subquery transformations). 01072 */ 01073 thd->stmt_arena= i; 01074 01075 /* 01076 Will write this SP statement into binlog separately 01077 (TODO: consider changing the condition to "not inside event union") 01078 */ 01079 if (thd->prelocked_mode == NON_PRELOCKED) 01080 thd->user_var_events_alloc= thd->mem_root; 01081 01082 err_status= i->execute(thd, &ip); 01083 01084 /* 01085 If this SP instruction have sent eof, it has caused no_send_error to be 01086 set. Clear it back to allow the next instruction to send error. (multi- 01087 statement execution code clears no_send_error between statements too) 01088 */ 01089 thd->net.no_send_error= 0; 01090 if (i->free_list) 01091 cleanup_items(i->free_list); 01092 01093 /* 01094 If we've set thd->user_var_events_alloc to mem_root of this SP 01095 statement, clean all the events allocated in it. 01096 */ 01097 if (thd->prelocked_mode == NON_PRELOCKED) 01098 { 01099 reset_dynamic(&thd->user_var_events); 01100 thd->user_var_events_alloc= NULL;//DEBUG 01101 } 01102 01103 /* we should cleanup free_list and memroot, used by instruction */ 01104 thd->cleanup_after_query(); 01105 free_root(&execute_mem_root, MYF(0)); 01106 01107 /* 01108 Check if an exception has occurred and a handler has been found 01109 Note: We have to check even if err_status == FALSE, since warnings (and 01110 some errors) don't return a non-zero value. We also have to check even 01111 if thd->killed != 0, since some errors return with this even when a 01112 handler has been found (e.g. "bad data"). 01113 */ 01114 if (ctx) 01115 { 01116 uint hf; 01117 01118 switch (ctx->found_handler(&hip, &hf)) { 01119 case SP_HANDLER_NONE: 01120 break; 01121 case SP_HANDLER_CONTINUE: 01122 thd->restore_active_arena(&execute_arena, &backup_arena); 01123 thd->set_n_backup_active_arena(&execute_arena, &backup_arena); 01124 ctx->push_hstack(ip); 01125 // Fall through 01126 default: 01127 ip= hip; 01128 err_status= FALSE; 01129 ctx->clear_handler(); 01130 ctx->enter_handler(hip); 01131 thd->clear_error(); 01132 thd->killed= THD::NOT_KILLED; 01133 continue; 01134 } 01135 } 01136 } while (!err_status && !thd->killed); 01137 01138 thd->restore_active_arena(&execute_arena, &backup_arena); 01139 01140 thd->spcont->pop_all_cursors(); // To avoid memory leaks after an error 01141 01142 /* Restore all saved */ 01143 old_packet.swap(thd->packet); 01144 DBUG_ASSERT(thd->change_list.is_empty()); 01145 thd->change_list= old_change_list; 01146 /* To avoid wiping out thd->change_list on old_change_list destruction */ 01147 old_change_list.empty(); 01148 thd->lex= old_lex; 01149 thd->query_id= old_query_id; 01150 DBUG_ASSERT(!thd->derived_tables); 01151 thd->derived_tables= old_derived_tables; 01152 thd->variables.sql_mode= save_sql_mode; 01153 thd->abort_on_warning= save_abort_on_warning; 01154 01155 thd->stmt_arena= old_arena; 01156 state= EXECUTED; 01157 01158 done: 01159 DBUG_PRINT("info", ("err_status: %d killed: %d query_error: %d", 01160 err_status, thd->killed, thd->query_error)); 01161 01162 if (thd->killed) 01163 err_status= TRUE; 01164 /* 01165 If the DB has changed, the pointer has changed too, but the 01166 original thd->db will then have been freed 01167 */ 01168 if (dbchanged) 01169 { 01170 /* 01171 No access check when changing back to where we came from. 01172 (It would generate an error from mysql_change_db() when old_db=="") 01173 */ 01174 if (! thd->killed) 01175 err_status|= mysql_change_db(thd, old_db.str, 1); 01176 } 01177 m_flags&= ~IS_INVOKED; 01178 DBUG_PRINT("info", 01179 ("first free for 0x%lx --: 0x%lx->0x%lx, level: %lu, flags %x", 01180 (ulong) m_first_instance, 01181 (ulong) m_first_instance->m_first_free_instance, 01182 (ulong) this, m_recursion_level, m_flags)); 01183 /* 01184 Check that we have one of following: 01185 01186 1) there are not free instances which means that this instance is last 01187 in the list of instances (pointer to the last instance point on it and 01188 ther are not other instances after this one in the list) 01189 01190 2) There are some free instances which mean that first free instance 01191 should go just after this one and recursion level of that free instance 01192 should be on 1 more then recursion level of this instance. 01193 */ 01194 DBUG_ASSERT((m_first_instance->m_first_free_instance == 0 && 01195 this == m_first_instance->m_last_cached_sp && 01196 m_next_cached_sp == 0) || 01197 (m_first_instance->m_first_free_instance != 0 && 01198 m_first_instance->m_first_free_instance == m_next_cached_sp && 01199 m_first_instance->m_first_free_instance->m_recursion_level == 01200 m_recursion_level + 1)); 01201 m_first_instance->m_first_free_instance= this; 01202 01203 DBUG_RETURN(err_status); 01204 } 01205 01206 01207 #ifndef NO_EMBEDDED_ACCESS_CHECKS 01208 /* 01209 set_routine_security_ctx() changes routine security context, and 01210 checks if there is an EXECUTE privilege in new context. If there is 01211 no EXECUTE privilege, it changes the context back and returns a 01212 error. 01213 01214 SYNOPSIS 01215 set_routine_security_ctx() 01216 thd thread handle 01217 sp stored routine to change the context for 01218 is_proc TRUE is procedure, FALSE if function 01219 save_ctx pointer to an old security context 01220 01221 RETURN 01222 TRUE if there was a error, and the context wasn't changed. 01223 FALSE if the context was changed. 01224 */ 01225 01226 bool 01227 set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc, 01228 Security_context **save_ctx) 01229 { 01230 *save_ctx= 0; 01231 if (sp_change_security_context(thd, sp, save_ctx)) 01232 return TRUE; 01233 01234 /* 01235 If we changed context to run as another user, we need to check the 01236 access right for the new context again as someone may have revoked 01237 the right to use the procedure from this user. 01238 01239 TODO: 01240 Cache if the definer has the right to use the object on the 01241 first usage and only reset the cache if someone does a GRANT 01242 statement that 'may' affect this. 01243 */ 01244 if (*save_ctx && 01245 check_routine_access(thd, EXECUTE_ACL, 01246 sp->m_db.str, sp->m_name.str, is_proc, FALSE)) 01247 { 01248 sp_restore_security_context(thd, *save_ctx); 01249 *save_ctx= 0; 01250 return TRUE; 01251 } 01252 01253 return FALSE; 01254 } 01255 #endif // ! NO_EMBEDDED_ACCESS_CHECKS 01256 01257 01258 /* 01259 Execute a trigger: 01260 - changes security context for triggers 01261 - switch to new memroot 01262 - call sp_head::execute 01263 - restore old memroot 01264 - restores security context 01265 01266 SYNOPSIS 01267 sp_head::execute_trigger() 01268 thd Thread handle 01269 db database name 01270 table table name 01271 grant_info GRANT_INFO structure to be filled with 01272 information about definer's privileges 01273 on subject table 01274 01275 RETURN 01276 FALSE on success 01277 TRUE on error 01278 */ 01279 01280 bool 01281 sp_head::execute_trigger(THD *thd, const char *db, const char *table, 01282 GRANT_INFO *grant_info) 01283 { 01284 sp_rcontext *octx = thd->spcont; 01285 sp_rcontext *nctx = NULL; 01286 bool err_status= FALSE; 01287 MEM_ROOT call_mem_root; 01288 Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP); 01289 Query_arena backup_arena; 01290 01291 DBUG_ENTER("sp_head::execute_trigger"); 01292 DBUG_PRINT("info", ("trigger %s", m_name.str)); 01293 01294 /* 01295 Prepare arena and memroot for objects which lifetime is whole 01296 duration of trigger call (sp_rcontext, it's tables and items, 01297 sp_cursor and Item_cache holders for case expressions). We can't 01298 use caller's arena/memroot for those objects because in this case 01299 some fixed amount of memory will be consumed for each trigger 01300 invocation and so statements which involve lot of them will hog 01301 memory. 01302 01303 TODO: we should create sp_rcontext once per command and reuse it 01304 on subsequent executions of a trigger. 01305 */ 01306 init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); 01307 thd->set_n_backup_active_arena(&call_arena, &backup_arena); 01308 01309 if (!(nctx= new sp_rcontext(m_pcont, 0, octx)) || 01310 nctx->init(thd)) 01311 { 01312 err_status= TRUE; 01313 goto err_with_cleanup; 01314 } 01315 01316 #ifndef DBUG_OFF 01317 nctx->sp= this; 01318 #endif 01319 01320 thd->spcont= nctx; 01321 01322 err_status= execute(thd); 01323 01324 err_with_cleanup: 01325 thd->restore_active_arena(&call_arena, &backup_arena); 01326 delete nctx; 01327 call_arena.free_items(); 01328 free_root(&call_mem_root, MYF(0)); 01329 thd->spcont= octx; 01330 01331 DBUG_RETURN(err_status); 01332 } 01333 01334 01335 /* 01336 Execute a function: 01337 - evaluate parameters 01338 - changes security context for SUID routines 01339 - switch to new memroot 01340 - call sp_head::execute 01341 - restore old memroot 01342 - evaluate the return value 01343 - restores security context 01344 01345 SYNOPSIS 01346 sp_head::execute_function() 01347 thd Thread handle 01348 argp Passed arguments (these are items from containing 01349 statement?) 01350 argcount Number of passed arguments. We need to check if this is 01351 correct. 01352 return_value_fld Save result here. 01353 01354 RETURN 01355 FALSE on success 01356 TRUE on error 01357 */ 01358 01359 bool 01360 sp_head::execute_function(THD *thd, Item **argp, uint argcount, 01361 Field *return_value_fld) 01362 { 01363 ulonglong binlog_save_options; 01364 bool need_binlog_call; 01365 uint arg_no; 01366 sp_rcontext *octx = thd->spcont; 01367 sp_rcontext *nctx = NULL; 01368 char buf[STRING_BUFFER_USUAL_SIZE]; 01369 String binlog_buf(buf, sizeof(buf), &my_charset_bin); 01370 bool err_status= FALSE; 01371 MEM_ROOT call_mem_root; 01372 Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP); 01373 Query_arena backup_arena; 01374 01375 DBUG_ENTER("sp_head::execute_function"); 01376 DBUG_PRINT("info", ("function %s", m_name.str)); 01377 01378 LINT_INIT(binlog_save_options); 01379 01380 /* 01381 Check that the function is called with all specified arguments. 01382 01383 If it is not, use my_error() to report an error, or it will not terminate 01384 the invoking query properly. 01385 */ 01386 if (argcount != m_pcont->context_var_count()) 01387 { 01388 /* 01389 Need to use my_error here, or it will not terminate the 01390 invoking query properly. 01391 */ 01392 my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), 01393 "FUNCTION", m_qname.str, m_pcont->context_var_count(), argcount); 01394 DBUG_RETURN(TRUE); 01395 } 01396 /* 01397 Prepare arena and memroot for objects which lifetime is whole 01398 duration of function call (sp_rcontext, it's tables and items, 01399 sp_cursor and Item_cache holders for case expressions). 01400 We can't use caller's arena/memroot for those objects because 01401 in this case some fixed amount of memory will be consumed for 01402 each function/trigger invocation and so statements which involve 01403 lot of them will hog memory. 01404 TODO: we should create sp_rcontext once per command and reuse 01405 it on subsequent executions of a function/trigger. 01406 */ 01407 init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); 01408 thd->set_n_backup_active_arena(&call_arena, &backup_arena); 01409 01410 if (!(nctx= new sp_rcontext(m_pcont, return_value_fld, octx)) || 01411 nctx->init(thd)) 01412 { 01413 thd->restore_active_arena(&call_arena, &backup_arena); 01414 err_status= TRUE; 01415 goto err_with_cleanup; 01416 } 01417 01418 /* 01419 We have to switch temporarily back to callers arena/memroot. 01420 Function arguments belong to the caller and so the may reference 01421 memory which they will allocate during calculation long after 01422 this function call will be finished (e.g. in Item::cleanup()). 01423 */ 01424 thd->restore_active_arena(&call_arena, &backup_arena); 01425 01426 #ifndef DBUG_OFF 01427 nctx->sp= this; 01428 #endif 01429 01430 /* Pass arguments. */ 01431 for (arg_no= 0; arg_no < argcount; arg_no++) 01432 { 01433 /* Arguments must be fixed in Item_func_sp::fix_fields */ 01434 DBUG_ASSERT(argp[arg_no]->fixed); 01435 01436 if ((err_status= nctx->set_variable(thd, arg_no, &(argp[arg_no])))) 01437 goto err_with_cleanup; 01438 } 01439 01440 /* 01441 If row-based binlogging, we don't need to binlog the function's call, let 01442 each substatement be binlogged its way. 01443 */ 01444 need_binlog_call= mysql_bin_log.is_open() && 01445 (thd->options & OPTION_BIN_LOG) && !thd->current_stmt_binlog_row_based; 01446 01447 /* 01448 Remember the original arguments for unrolled replication of functions 01449 before they are changed by execution. 01450 */ 01451 if (need_binlog_call) 01452 { 01453 binlog_buf.length(0); 01454 binlog_buf.append(STRING_WITH_LEN("SELECT ")); 01455 append_identifier(thd, &binlog_buf, m_name.str, m_name.length); 01456 binlog_buf.append('('); 01457 for (arg_no= 0; arg_no < argcount; arg_no++) 01458 { 01459 String str_value_holder; 01460 String *str_value; 01461 01462 if (arg_no) 01463 binlog_buf.append(','); 01464 01465 str_value= sp_get_item_value(nctx->get_item(arg_no), 01466 &str_value_holder); 01467 01468 if (str_value) 01469 binlog_buf.append(*str_value); 01470 else 01471 binlog_buf.append(STRING_WITH_LEN("NULL")); 01472 } 01473 binlog_buf.append(')'); 01474 } 01475 thd->spcont= nctx; 01476 01477 #ifndef NO_EMBEDDED_ACCESS_CHECKS 01478 Security_context *save_security_ctx; 01479 if (set_routine_security_ctx(thd, this, FALSE, &save_security_ctx)) 01480 { 01481 err_status= TRUE; 01482 goto err_with_cleanup; 01483 } 01484 #endif 01485 01486 if (need_binlog_call) 01487 { 01488 reset_dynamic(&thd->user_var_events); 01489 mysql_bin_log.start_union_events(thd); 01490 binlog_save_options= thd->options; 01491 thd->options&= ~OPTION_BIN_LOG; 01492 } 01493 01494 /* 01495 Switch to call arena/mem_root so objects like sp_cursor or 01496 Item_cache holders for case expressions can be allocated on it. 01497 01498 TODO: In future we should associate call arena/mem_root with 01499 sp_rcontext and allocate all these objects (and sp_rcontext 01500 itself) on it directly rather than juggle with arenas. 01501 */ 01502 thd->set_n_backup_active_arena(&call_arena, &backup_arena); 01503 01504 err_status= execute(thd); 01505 01506 thd->restore_active_arena(&call_arena, &backup_arena); 01507 01508 if (need_binlog_call) 01509 { 01510 mysql_bin_log.stop_union_events(thd); 01511 thd->options= binlog_save_options; 01512 if (thd->binlog_evt_union.unioned_events) 01513 { 01514 Query_log_event qinfo(thd, binlog_buf.ptr(), binlog_buf.length(), 01515 thd->binlog_evt_union.unioned_events_trans, FALSE); 01516 if (mysql_bin_log.write(&qinfo) && 01517 thd->binlog_evt_union.unioned_events_trans) 01518 { 01519 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, 01520 "Invoked ROUTINE modified a transactional table but MySQL " 01521 "failed to reflect this change in the binary log"); 01522 } 01523 reset_dynamic(&thd->user_var_events); 01524 } 01525 } 01526 01527 if (!err_status) 01528 { 01529 /* We need result only in function but not in trigger */ 01530 01531 if (!nctx->is_return_value_set()) 01532 { 01533 my_error(ER_SP_NORETURNEND, MYF(0), m_name.str); 01534 err_status= TRUE; 01535 } 01536 } 01537 01538 #ifndef NO_EMBEDDED_ACCESS_CHECKS 01539 sp_restore_security_context(thd, save_security_ctx); 01540 #endif 01541 01542 err_with_cleanup: 01543 delete nctx; 01544 call_arena.free_items(); 01545 free_root(&call_mem_root, MYF(0)); 01546 thd->spcont= octx; 01547 01548 DBUG_RETURN(err_status); 01549 } 01550 01551 01552 /* 01553 Execute a procedure. 01554 SYNOPSIS 01555 sp_head::execute_procedure() 01556 thd Thread handle 01557 args List of values passed as arguments. 01558 01559 DESCRIPTION 01560 01561 The function does the following steps: 01562 - Set all parameters 01563 - changes security context for SUID routines 01564 - call sp_head::execute 01565 - copy back values of INOUT and OUT parameters 01566 - restores security context 01567 01568 RETURN 01569 FALSE on success 01570 TRUE on error 01571 */ 01572 01573 bool 01574 sp_head::execute_procedure(THD *thd, List<Item> *args) 01575 { 01576 bool err_status= FALSE; 01577 uint params = m_pcont->context_var_count(); 01578 sp_rcontext *save_spcont, *octx; 01579 sp_rcontext *nctx = NULL; 01580 bool save_enable_slow_log= false; 01581 bool save_log_general= false; 01582 DBUG_ENTER("sp_head::execute_procedure"); 01583 DBUG_PRINT("info", ("procedure %s", m_name.str)); 01584 01585 if (args->elements != params) 01586 { 01587 my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "PROCEDURE", 01588 m_qname.str, params, args->elements); 01589 DBUG_RETURN(TRUE); 01590 } 01591 01592 save_spcont= octx= thd->spcont; 01593 if (! octx) 01594 { // Create a temporary old context 01595 if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) || 01596 octx->init(thd)) 01597 { 01598 delete octx; /* Delete octx if it was init() that failed. */ 01599 DBUG_RETURN(TRUE); 01600 } 01601 01602 #ifndef DBUG_OFF 01603 octx->sp= 0; 01604 #endif 01605 thd->spcont= octx; 01606 01607 /* set callers_arena to thd, for upper-level function to work */ 01608 thd->spcont->callers_arena= thd; 01609 } 01610 01611 if (!(nctx= new sp_rcontext(m_pcont, NULL, octx)) || 01612 nctx->init(thd)) 01613 { 01614 delete nctx; /* Delete nctx if it was init() that failed. */ 01615 thd->spcont= save_spcont; 01616 DBUG_RETURN(TRUE); 01617 } 01618 #ifndef DBUG_OFF 01619 nctx->sp= this; 01620 #endif 01621 01622 if (params > 0) 01623 { 01624 List_iterator<Item> it_args(*args); 01625 01626 DBUG_PRINT("info",(" %.*s: eval args", m_name.length, m_name.str)); 01627 01628 for (uint i= 0 ; i < params ; i++) 01629 { 01630 Item *arg_item= it_args++; 01631 01632 if (!arg_item) 01633 break; 01634 01635 sp_variable_t *spvar= m_pcont->find_variable(i); 01636 01637 if (!spvar) 01638 continue; 01639 01640 if (spvar->mode != sp_param_in) 01641 { 01642 Settable_routine_parameter *srp= 01643 arg_item->get_settable_routine_parameter(); 01644 01645 if (!srp) 01646 { 01647 my_error(ER_SP_NOT_VAR_ARG, MYF(0), i+1, m_qname.str); 01648 err_status= TRUE; 01649 break; 01650 } 01651 01652 srp->set_required_privilege(spvar->mode == sp_param_inout); 01653 } 01654 01655 if (spvar->mode == sp_param_out) 01656 { 01657 Item_null *null_item= new Item_null(); 01658 01659 if (!null_item || 01660 nctx->set_variable(thd, i, (struct Item **)&null_item)) 01661 { 01662 err_status= TRUE; 01663 break; 01664 } 01665 } 01666 else 01667 { 01668 if (nctx->set_variable(thd, i, it_args.ref())) 01669 { 01670 err_status= TRUE; 01671 break; 01672 } 01673 } 01674 } 01675 01676 /* 01677 Okay, got values for all arguments. Close tables that might be used by 01678 arguments evaluation. If arguments evaluation required prelocking mode, 01679 we'll leave it here. 01680 */ 01681 if (!thd->in_sub_stmt) 01682 close_thread_tables(thd, 0, 0); 01683 01684 DBUG_PRINT("info",(" %.*s: eval args done", m_name.length, m_name.str)); 01685 } 01686 if (!(m_flags & LOG_SLOW_STATEMENTS) && thd->enable_slow_log) 01687 { 01688 DBUG_PRINT("info", ("Disabling slow log for the execution")); 01689 save_enable_slow_log= true; 01690 thd->enable_slow_log= FALSE; 01691 } 01692 if (!(m_flags & LOG_GENERAL_LOG) && !(thd->options & OPTION_LOG_OFF)) 01693 { 01694 DBUG_PRINT("info", ("Disabling general log for the execution")); 01695 save_log_general= true; 01696 /* disable this bit */ 01697 thd->options |= OPTION_LOG_OFF; 01698 } 01699 thd->spcont= nctx; 01700 01701 #ifndef NO_EMBEDDED_ACCESS_CHECKS 01702 Security_context *save_security_ctx= 0; 01703 if (!err_status) 01704 err_status= set_routine_security_ctx(thd, this, TRUE, &save_security_ctx); 01705 #endif 01706 01707 if (!err_status) 01708 err_status= execute(thd); 01709 01710 if (save_log_general) 01711 thd->options &= ~OPTION_LOG_OFF; 01712 if (save_enable_slow_log) 01713 thd->enable_slow_log= true; 01714 /* 01715 In the case when we weren't able to employ reuse mechanism for 01716 OUT/INOUT paranmeters, we should reallocate memory. This 01717 allocation should be done on the arena which will live through 01718 all execution of calling routine. 01719 */ 01720 thd->spcont->callers_arena= octx->callers_arena; 01721 01722 if (!err_status && params > 0) 01723 { 01724 List_iterator<Item> it_args(*args); 01725 01726 /* 01727 Copy back all OUT or INOUT values to the previous frame, or 01728 set global user variables 01729 */ 01730 for (uint i= 0 ; i < params ; i++) 01731 { 01732 Item *arg_item= it_args++; 01733 01734 if (!arg_item) 01735 break; 01736 01737 sp_variable_t *spvar= m_pcont->find_variable(i); 01738 01739 if (spvar->mode == sp_param_in) 01740 continue; 01741 01742 Settable_routine_parameter *srp= 01743 arg_item->get_settable_routine_parameter(); 01744 01745 DBUG_ASSERT(srp); 01746 01747 if (srp->set_value(thd, octx, nctx->get_item_addr(i))) 01748 { 01749 err_status= TRUE; 01750 break; 01751 } 01752 } 01753 } 01754 01755 #ifndef NO_EMBEDDED_ACCESS_CHECKS 01756 if (save_security_ctx) 01757 sp_restore_security_context(thd, save_security_ctx); 01758 #endif 01759 01760 if (!save_spcont) 01761 delete octx; 01762 01763 delete nctx; 01764 thd->spcont= save_spcont; 01765 01766 DBUG_RETURN(err_status); 01767 } 01768 01769 01770 // Reset lex during parsing, before we parse a sub statement. 01771 void 01772 sp_head::reset_lex(THD *thd) 01773 { 01774 DBUG_ENTER("sp_head::reset_lex"); 01775 LEX *sublex; 01776 LEX *oldlex= thd->lex; 01777 my_lex_states state= oldlex->next_state; // Keep original next_state 01778 01779 (void)m_lex.push_front(oldlex); 01780 thd->lex= sublex= new st_lex; 01781 01782 /* Reset most stuff. The length arguments doesn't matter here. */ 01783 lex_start(thd, oldlex->buf, (ulong) (oldlex->end_of_query - oldlex->ptr)); 01784 01785 /* 01786 * next_state is normally the same (0), but it happens that we swap lex in 01787 * "mid-sentence", so we must restore it. 01788 */ 01789 sublex->next_state= state; 01790 /* We must reset ptr and end_of_query again */ 01791 sublex->ptr= oldlex->ptr; 01792 sublex->end_of_query= oldlex->end_of_query; 01793 sublex->tok_start= oldlex->tok_start; 01794 sublex->tok_end= oldlex->tok_end; 01795 sublex->yylineno= oldlex->yylineno; 01796 /* And keep the SP stuff too */ 01797 sublex->sphead= oldlex->sphead; 01798 sublex->spcont= oldlex->spcont; 01799 /* And trigger related stuff too */ 01800 sublex->trg_chistics= oldlex->trg_chistics; 01801 sublex->trg_table_fields.empty(); 01802 sublex->sp_lex_in_use= FALSE; 01803 01804 sublex->in_comment= oldlex->in_comment; 01805 01806 /* Reset type info. */ 01807 01808 sublex->charset= NULL; 01809 sublex->length= NULL; 01810 sublex->dec= NULL; 01811 sublex->interval_list.empty(); 01812 sublex->type= 0; 01813 01814 DBUG_VOID_RETURN; 01815 } 01816 01817 // Restore lex during parsing, after we have parsed a sub statement. 01818 void 01819 sp_head::restore_lex(THD *thd) 01820 { 01821 DBUG_ENTER("sp_head::restore_lex"); 01822 LEX *sublex= thd->lex; 01823 LEX *oldlex= (LEX *)m_lex.pop(); 01824 01825 if (! oldlex) 01826 return; // Nothing to restore 01827 01828 // Update some state in the old one first 01829 oldlex->ptr= sublex->ptr; 01830 oldlex->tok_end= sublex->tok_end; 01831 oldlex->next_state= sublex->next_state; 01832 oldlex->trg_table_fields.push_back(&sublex->trg_table_fields); 01833 01834 #ifdef HAVE_ROW_BASED_REPLICATION 01835 /* 01836 If this substatement needs row-based, the entire routine does too (we 01837 cannot switch from statement-based to row-based only for this 01838 substatement). 01839 */ 01840 if (sublex->binlog_row_based_if_mixed) 01841 m_flags|= BINLOG_ROW_BASED_IF_MIXED; 01842 #endif 01843 01844 /* 01845 Add routines which are used by statement to respective set for 01846 this routine. 01847 */ 01848 sp_update_sp_used_routines(&m_sroutines, &sublex->sroutines); 01849 /* 01850 Merge tables used by this statement (but not by its functions or 01851 procedures) to multiset of tables used by this routine. 01852 */ 01853 merge_table_list(thd, sublex->query_tables, sublex); 01854 if (! sublex->sp_lex_in_use) 01855 { 01856 lex_end(sublex); 01857 delete sublex; 01858 } 01859 thd->lex= oldlex; 01860 DBUG_VOID_RETURN; 01861 } 01862 01863 void 01864 sp_head::push_backpatch(sp_instr *i, sp_label_t *lab) 01865 { 01866 bp_t *bp= (bp_t *)sql_alloc(sizeof(bp_t)); 01867 01868 if (bp) 01869 { 01870 bp->lab= lab; 01871 bp->instr= i; 01872 (void)m_backpatch.push_front(bp); 01873 } 01874 } 01875 01876 void 01877 sp_head::backpatch(sp_label_t *lab) 01878 { 01879 bp_t *bp; 01880 uint dest= instructions(); 01881 List_iterator_fast<bp_t> li(m_backpatch); 01882 01883 while ((bp= li++)) 01884 { 01885 if (bp->lab == lab) 01886 bp->instr->backpatch(dest, lab->ctx); 01887 } 01888 } 01889 01890 /* 01891 Prepare an instance of create_field for field creation (fill all necessary 01892 attributes). 01893 01894 SYNOPSIS 01895 sp_head::fill_field_definition() 01896 thd [IN] Thread handle 01897 lex [IN] Yacc parsing context 01898 field_type [IN] Field type 01899 field_def [OUT] An instance of create_field to be filled 01900 01901 RETURN 01902 FALSE on success 01903 TRUE on error 01904 */ 01905 01906 bool 01907 sp_head::fill_field_definition(THD *thd, LEX *lex, 01908 enum enum_field_types field_type, 01909 create_field *field_def) 01910 { 01911 HA_CREATE_INFO sp_db_info; 01912 LEX_STRING cmt = { 0, 0 }; 01913 uint unused1= 0; 01914 int unused2= 0; 01915 01916 load_db_opt_by_name(thd, m_db.str, &sp_db_info); 01917 01918 if (field_def->init(thd, (char*) "", field_type, lex->length, lex->dec, 01919 lex->type, (Item*) 0, (Item*) 0, &cmt, 0, 01920 &lex->interval_list, 01921 (lex->charset ? lex->charset : 01922 sp_db_info.default_table_charset), 01923 lex->uint_geom_type)) 01924 return TRUE; 01925 01926 if (field_def->interval_list.elements) 01927 field_def->interval= create_typelib(mem_root, field_def, 01928 &field_def->interval_list); 01929 01930 sp_prepare_create_field(thd, field_def); 01931 01932 if (prepare_create_field(field_def, &unused1, &unused2, &unused2, 01933 HA_CAN_GEOMETRY)) 01934 { 01935 return TRUE; 01936 } 01937 01938 return FALSE; 01939 } 01940 01941 01942 void 01943 sp_head::new_cont_backpatch(sp_instr_opt_meta *i) 01944 { 01945 m_cont_level+= 1; 01946 if (i) 01947 { 01948 /* Use the cont. destination slot to store the level */ 01949 i->m_cont_dest= m_cont_level; 01950 (void)m_cont_backpatch.push_front(i); 01951 } 01952 } 01953 01954 void 01955 sp_head::add_cont_backpatch(sp_instr_opt_meta *i) 01956 { 01957 i->m_cont_dest= m_cont_level; 01958 (void)m_cont_backpatch.push_front(i); 01959 } 01960 01961 void 01962 sp_head::do_cont_backpatch() 01963 { 01964 uint dest= instructions(); 01965 uint lev= m_cont_level--; 01966 sp_instr_opt_meta *i; 01967 01968 while ((i= m_cont_backpatch.head()) && i->m_cont_dest == lev) 01969 { 01970 i->m_cont_dest= dest; 01971 (void)m_cont_backpatch.pop(); 01972 } 01973 } 01974 01975 void 01976 sp_head::set_info(longlong created, longlong modified, 01977 st_sp_chistics *chistics, ulong sql_mode) 01978 { 01979 m_created= created; 01980 m_modified= modified; 01981 m_chistics= (st_sp_chistics *) memdup_root(mem_root, (char*) chistics, 01982 sizeof(*chistics)); 01983 if (m_chistics->comment.length == 0) 01984 m_chistics->comment.str= 0; 01985 else 01986 m_chistics->comment.str= strmake_root(mem_root, 01987 m_chistics->comment.str, 01988 m_chistics->comment.length); 01989 m_sql_mode= sql_mode; 01990 } 01991 01992 01993 void 01994 sp_head::set_definer(const char *definer, uint definerlen) 01995 { 01996 char user_name_holder[USERNAME_LENGTH + 1]; 01997 LEX_STRING user_name= { user_name_holder, USERNAME_LENGTH }; 01998 01999 char host_name_holder[HOSTNAME_LENGTH + 1]; 02000 LEX_STRING host_name= { host_name_holder, HOSTNAME_LENGTH }; 02001 02002 parse_user(definer, definerlen, user_name.str, &user_name.length, 02003 host_name.str, &host_name.length); 02004 02005 set_definer(&user_name, &host_name); 02006 } 02007 02008 02009 void 02010 sp_head::set_definer(const LEX_STRING *user_name, const LEX_STRING *host_name) 02011 { 02012 m_definer_user.str= strmake_root(mem_root, user_name->str, user_name->length); 02013 m_definer_user.length= user_name->length; 02014 02015 m_definer_host.str= strmake_root(mem_root, host_name->str, host_name->length); 02016 m_definer_host.length= host_name->length; 02017 } 02018 02019 02020 void 02021 sp_head::reset_thd_mem_root(THD *thd) 02022 { 02023 DBUG_ENTER("sp_head::reset_thd_mem_root"); 02024 m_thd_root= thd->mem_root; 02025 thd->mem_root= &main_mem_root; 02026 DBUG_PRINT("info", ("mem_root 0x%lx moved to thd mem root 0x%lx", 02027 (ulong) &mem_root, (ulong) &thd->mem_root)); 02028 free_list= thd->free_list; // Keep the old list 02029 thd->free_list= NULL; // Start a new one 02030 m_thd= thd; 02031 DBUG_VOID_RETURN; 02032 } 02033 02034 void 02035 sp_head::restore_thd_mem_root(THD *thd) 02036 { 02037 DBUG_ENTER("sp_head::restore_thd_mem_root"); 02038 Item *flist= free_list; // The old list 02039 set_query_arena(thd); // Get new free_list and mem_root 02040 state= INITIALIZED_FOR_SP; 02041 02042 DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx", 02043 (ulong) &mem_root, (ulong) &thd->mem_root)); 02044 thd->free_list= flist; // Restore the old one 02045 thd->mem_root= m_thd_root; 02046 m_thd= NULL; 02047 DBUG_VOID_RETURN; 02048 } 02049 02050 02051 /* 02052 Check if a user has access right to a routine 02053 02054 SYNOPSIS 02055 check_show_routine_access() 02056 thd Thread handler 02057 sp SP 02058 full_access Set to 1 if the user has SELECT right to the 02059 'mysql.proc' able or is the owner of the routine 02060 RETURN 02061 0 ok 02062 1 error 02063 */ 02064 02065 bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access) 02066 { 02067 TABLE_LIST tables; 02068 bzero((char*) &tables,sizeof(tables)); 02069 tables.db= (char*) "mysql"; 02070 tables.table_name= tables.alias= (char*) "proc"; 02071 *full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1) || 02072 (!strcmp(sp->m_definer_user.str, 02073 thd->security_ctx->priv_user) && 02074 !strcmp(sp->m_definer_host.str, 02075 thd->security_ctx->priv_host))); 02076 if (!*full_access) 02077 return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str, 02078 sp->m_type == TYPE_ENUM_PROCEDURE); 02079 return 0; 02080 } 02081 02082 02083 int 02084 sp_head::show_create_procedure(THD *thd) 02085 { 02086 Protocol *protocol= thd->protocol; 02087 char buff[2048]; 02088 String buffer(buff, sizeof(buff), system_charset_info); 02089 int res; 02090 List<Item> field_list; 02091 byte *sql_mode_str; 02092 ulong sql_mode_len; 02093 bool full_access; 02094 DBUG_ENTER("sp_head::show_create_procedure"); 02095 DBUG_PRINT("info", ("procedure %s", m_name.str)); 02096 02097 LINT_INIT(sql_mode_str); 02098 LINT_INIT(sql_mode_len); 02099 02100 if (check_show_routine_access(thd, this, &full_access)) 02101 DBUG_RETURN(1); 02102 02103 sql_mode_str= 02104 sys_var_thd_sql_mode::symbolic_mode_representation(thd, 02105 m_sql_mode, 02106 &sql_mode_len); 02107 field_list.push_back(new Item_empty_string("Procedure", NAME_LEN)); 02108 field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len)); 02109 // 1024 is for not to confuse old clients 02110 Item_empty_string *definition= 02111 new Item_empty_string("Create Procedure", max(buffer.length(),1024)); 02112 definition->maybe_null= TRUE; 02113 field_list.push_back(definition); 02114 02115 if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | 02116 Protocol::SEND_EOF)) 02117 DBUG_RETURN(1); 02118 protocol->prepare_for_resend(); 02119 protocol->store(m_name.str, m_name.length, system_charset_info); 02120 protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info); 02121 if (full_access) 02122 protocol->store(m_defstr.str, m_defstr.length, system_charset_info); 02123 else 02124 protocol->store_null(); 02125 res= protocol->write(); 02126 send_eof(thd); 02127 02128 DBUG_RETURN(res); 02129 } 02130 02131 02132 /* 02133 Add instruction to SP 02134 02135 SYNOPSIS 02136 sp_head::add_instr() 02137 instr Instruction 02138 */ 02139 02140 void sp_head::add_instr(sp_instr *instr) 02141 { 02142 instr->free_list= m_thd->free_list; 02143 m_thd->free_list= 0; 02144 /* 02145 Memory root of every instruction is designated for permanent 02146 transformations (optimizations) made on the parsed tree during 02147 the first execution. It points to the memory root of the 02148 entire stored procedure, as their life span is equal. 02149 */ 02150 instr->mem_root= &main_mem_root; 02151 insert_dynamic(&m_instr, (gptr)&instr); 02152 } 02153 02154 02155 int 02156 sp_head::show_create_function(THD *thd) 02157 { 02158 Protocol *protocol= thd->protocol; 02159 char buff[2048]; 02160 String buffer(buff, sizeof(buff), system_charset_info); 02161 int res; 02162 List<Item> field_list; 02163 byte *sql_mode_str; 02164 ulong sql_mode_len; 02165 bool full_access; 02166 DBUG_ENTER("sp_head::show_create_function"); 02167 DBUG_PRINT("info", ("procedure %s", m_name.str)); 02168 LINT_INIT(sql_mode_str); 02169 LINT_INIT(sql_mode_len); 02170 02171 if (check_show_routine_access(thd, this, &full_access)) 02172 DBUG_RETURN(1); 02173 02174 sql_mode_str= 02175 sys_var_thd_sql_mode::symbolic_mode_representation(thd, 02176 m_sql_mode, 02177 &sql_mode_len); 02178 field_list.push_back(new Item_empty_string("Function",NAME_LEN)); 02179 field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len)); 02180 Item_empty_string *definition= 02181 new Item_empty_string("Create Function", max(buffer.length(),1024)); 02182 definition->maybe_null= TRUE; 02183 field_list.push_back(definition); 02184 02185 if (protocol->send_fields(&field_list, 02186 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) 02187 DBUG_RETURN(1); 02188 protocol->prepare_for_resend(); 02189 protocol->store(m_name.str, m_name.length, system_charset_info); 02190 protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info); 02191 if (full_access) 02192 protocol->store(m_defstr.str, m_defstr.length, system_charset_info); 02193 else 02194 protocol->store_null(); 02195 res= protocol->write(); 02196 send_eof(thd); 02197 02198 DBUG_RETURN(res); 02199 } 02200 02201 02202 /* 02203 Do some minimal optimization of the code: 02204 1) Mark used instructions 02205 1.1) While doing this, shortcut jumps to jump instructions 02206 2) Compact the code, removing unused instructions 02207 02208 This is the main mark and move loop; it relies on the following methods 02209 in sp_instr and its subclasses: 02210 02211 opt_mark() Mark instruction as reachable (will recurse for jumps) 02212 opt_shortcut_jump() Shortcut jumps to the final destination; 02213 used by opt_mark(). 02214 opt_move() Update moved instruction 02215 set_destination() Set the new destination (jump instructions only) 02216 */ 02217 02218 void sp_head::optimize() 02219 { 02220 List<sp_instr> bp; 02221 sp_instr *i; 02222 uint src, dst; 02223 02224 opt_mark(0); 02225 02226 bp.empty(); 02227 src= dst= 0; 02228 while ((i= get_instr(src))) 02229 { 02230 if (! i->marked) 02231 { 02232 delete i; 02233 src+= 1; 02234 } 02235 else 02236 { 02237 if (src != dst) 02238 { // Move the instruction and update prev. jumps 02239 sp_instr *ibp; 02240 List_iterator_fast<sp_instr> li(bp); 02241 02242 set_dynamic(&m_instr, (gptr)&i, dst); 02243 while ((ibp= li++)) 02244 { 02245 sp_instr_opt_meta *im= static_cast<sp_instr_opt_meta *>(ibp); 02246 im->set_destination(src, dst); 02247 } 02248 } 02249 i->opt_move(dst, &bp); 02250 src+= 1; 02251 dst+= 1; 02252 } 02253 } 02254 m_instr.elements= dst; 02255 bp.empty(); 02256 } 02257 02258 void 02259 sp_head::opt_mark(uint ip) 02260 { 02261 sp_instr *i; 02262 02263 while ((i= get_instr(ip)) && !i->marked) 02264 ip= i->opt_mark(this); 02265 } 02266 02267 02268 #ifndef DBUG_OFF 02269 /* 02270 Return the routine instructions as a result set. 02271 Returns 0 if ok, !=0 on error. 02272 */ 02273 int 02274 sp_head::show_routine_code(THD *thd) 02275 { 02276 Protocol *protocol= thd->protocol; 02277 char buff[2048]; 02278 String buffer(buff, sizeof(buff), system_charset_info); 02279 List<Item> field_list; 02280 sp_instr *i; 02281 bool full_access; 02282 int res= 0; 02283 uint ip; 02284 DBUG_ENTER("sp_head::show_routine_code"); 02285 DBUG_PRINT("info", ("procedure: %s", m_name.str)); 02286 02287 if (check_show_routine_access(thd, this, &full_access) || !full_access) 02288 DBUG_RETURN(1); 02289 02290 field_list.push_back(new Item_uint("Pos", 9)); 02291 // 1024 is for not to confuse old clients 02292 field_list.push_back(new Item_empty_string("Instruction", 02293 max(buffer.length(), 1024))); 02294 if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | 02295 Protocol::SEND_EOF)) 02296 DBUG_RETURN(1); 02297 02298 for (ip= 0; (i = get_instr(ip)) ; ip++) 02299 { 02300 /* 02301 Consistency check. If these are different something went wrong 02302 during optimization. 02303 */ 02304 if (ip != i->m_ip) 02305 { 02306 const char *format= "Instruction at position %u has m_ip=%u"; 02307 char tmp[sizeof(format) + 2*SP_INSTR_UINT_MAXLEN + 1]; 02308 02309 sprintf(tmp, format, ip, i->m_ip); 02310 /* 02311 Since this is for debugging purposes only, we don't bother to 02312 introduce a special error code for it. 02313 */ 02314 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, tmp); 02315 } 02316 protocol->prepare_for_resend(); 02317 protocol->store((longlong)ip); 02318 02319 buffer.set("", 0, system_charset_info); 02320 i->print(&buffer); 02321 protocol->store(buffer.ptr(), buffer.length(), system_charset_info); 02322 if ((res= protocol->write())) 02323 break; 02324 } 02325 send_eof(thd); 02326 02327 DBUG_RETURN(res); 02328 } 02329 #endif // ifndef DBUG_OFF 02330 02331 02332 /* 02333 Prepare LEX and thread for execution of instruction, if requested open 02334 and lock LEX's tables, execute instruction's core function, perform 02335 cleanup afterwards. 02336 02337 SYNOPSIS 02338 reset_lex_and_exec_core() 02339 thd - thread context 02340 nextp - out - next instruction 02341 open_tables - if TRUE then check read access to tables in LEX's table 02342 list and open and lock them (used in instructions which 02343 need to calculate some expression and don't execute 02344 complete statement). 02345 sp_instr - instruction for which we prepare context, and which core 02346 function execute by calling its exec_core() method. 02347 02348 NOTE 02349 We are not saving/restoring some parts of THD which may need this because 02350 we do this once for whole routine execution in sp_head::execute(). 02351 02352 RETURN VALUE 02353 0/non-0 - Success/Failure 02354 */ 02355 02356 int 02357 sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, 02358 bool open_tables, sp_instr* instr) 02359 { 02360 int res= 0; 02361 02362 DBUG_ASSERT(!thd->derived_tables); 02363 DBUG_ASSERT(thd->change_list.is_empty()); 02364 /* 02365 Use our own lex. 02366 We should not save old value since it is saved/restored in 02367 sp_head::execute() when we are entering/leaving routine. 02368 */ 02369 thd->lex= m_lex; 02370 02371 VOID(pthread_mutex_lock(&LOCK_thread_count)); 02372 thd->query_id= next_query_id(); 02373 VOID(pthread_mutex_unlock(&LOCK_thread_count)); 02374 02375 if (thd->prelocked_mode == NON_PRELOCKED) 02376 { 02377 /* 02378 This statement will enter/leave prelocked mode on its own. 02379 Entering prelocked mode changes table list and related members 02380 of LEX, so we'll need to restore them. 02381 */ 02382 if (lex_query_tables_own_last) 02383 { 02384 /* 02385 We've already entered/left prelocked mode with this statement. 02386 Attach the list of tables that need to be prelocked and mark m_lex 02387 as having such list attached. 02388 */ 02389 *lex_query_tables_own_last= prelocking_tables; 02390 m_lex->mark_as_requiring_prelocking(lex_query_tables_own_last); 02391 } 02392 } 02393 02394 reinit_stmt_before_use(thd, m_lex); 02395 /* 02396 If requested check whenever we have access to tables in LEX's table list 02397 and open and lock them before executing instructtions core function. 02398 */ 02399 if (open_tables && 02400 (check_table_access(thd, SELECT_ACL, m_lex->query_tables, 0) || 02401 open_and_lock_tables(thd, m_lex->query_tables))) 02402 res= -1; 02403 02404 if (!res) 02405 res= instr->exec_core(thd, nextp); 02406 02407 m_lex->unit.cleanup(); 02408 02409 thd->proc_info="closing tables"; 02410 close_thread_tables(thd); 02411 thd->proc_info= 0; 02412 02413 if (m_lex->query_tables_own_last) 02414 { 02415 /* 02416 We've entered and left prelocking mode when executing statement 02417 stored in m_lex. 02418 m_lex->query_tables(->next_global)* list now has a 'tail' - a list 02419 of tables that are added for prelocking. (If this is the first 02420 execution, the 'tail' was added by open_tables(), otherwise we've 02421 attached it above in this function). 02422 Now we'll save the 'tail', and detach it. 02423 */ 02424 lex_query_tables_own_last= m_lex->query_tables_own_last; 02425 prelocking_tables= *lex_query_tables_own_last; 02426 *lex_query_tables_own_last= NULL; 02427 m_lex->mark_as_requiring_prelocking(NULL); 02428 } 02429 thd->rollback_item_tree_changes(); 02430 /* Update the state of the active arena. */ 02431 thd->stmt_arena->state= Query_arena::EXECUTED; 02432 02433 02434 /* 02435 Unlike for PS we should not call Item's destructors for newly created 02436 items after execution of each instruction in stored routine. This is 02437 because SP often create Item (like Item_int, Item_string etc...) when 02438 they want to store some value in local variable, pass return value and 02439 etc... So their life time should be longer than one instruction. 02440 02441 cleanup_items() is called in sp_head::execute() 02442 */ 02443 return res || thd->net.report_error; 02444 } 02445 02446 02447 /* 02448 sp_instr class functions 02449 */ 02450 02451 int sp_instr::exec_core(THD *thd, uint *nextp) 02452 { 02453 DBUG_ASSERT(0); 02454 return 0; 02455 } 02456 02457 /* 02458 sp_instr_stmt class functions 02459 */ 02460 02461 int 02462 sp_instr_stmt::execute(THD *thd, uint *nextp) 02463 { 02464 char *query; 02465 uint32 query_length; 02466 int res; 02467 DBUG_ENTER("sp_instr_stmt::execute"); 02468 DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command())); 02469 02470 query= thd->query; 02471 query_length= thd->query_length; 02472 if (!(res= alloc_query(thd, m_query.str, m_query.length+1)) && 02473 !(res=subst_spvars(thd, this, &m_query))) 02474 { 02475 /* 02476 (the order of query cache and subst_spvars calls is irrelevant because 02477 queries with SP vars can't be cached) 02478 */ 02479 if (unlikely((thd->options & OPTION_LOG_OFF)==0)) 02480 general_log_print(thd, COM_QUERY, "%s", thd->query); 02481 02482 if (query_cache_send_result_to_client(thd, 02483 thd->query, thd->query_length) <= 0) 02484 { 02485 res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this); 02486 if (!res && unlikely(thd->enable_slow_log)) 02487 log_slow_statement(thd); 02488 query_cache_end_of_result(thd); 02489 } 02490 else 02491 *nextp= m_ip+1; 02492 thd->query= query; 02493 thd->query_length= query_length; 02494 } 02495 DBUG_RETURN(res); 02496 } 02497 02498 02499 void 02500 sp_instr_stmt::print(String *str) 02501 { 02502 uint i, len; 02503 02504 /* stmt CMD "..." */ 02505 if (str->reserve(SP_STMT_PRINT_MAXLEN+SP_INSTR_UINT_MAXLEN+8)) 02506 return; 02507 str->qs_append(STRING_WITH_LEN("stmt ")); 02508 str->qs_append((uint)m_lex_keeper.sql_command()); 02509 str->qs_append(STRING_WITH_LEN(" \"")); 02510 len= m_query.length; 02511 /* 02512 Print the query string (but not too much of it), just to indicate which 02513 statement it is. 02514 */ 02515 if (len > SP_STMT_PRINT_MAXLEN) 02516 len= SP_STMT_PRINT_MAXLEN-3; 02517 /* Copy the query string and replace '\n' with ' ' in the process */ 02518 for (i= 0 ; i < len ; i++) 02519 { 02520 char c= m_query.str[i]; 02521 if (c == '\n') 02522 c= ' '; 02523 str->qs_append(c); 02524 } 02525 if (m_query.length > SP_STMT_PRINT_MAXLEN) 02526 str->qs_append(STRING_WITH_LEN("...")); /* Indicate truncated string */ 02527 str->qs_append('"'); 02528 } 02529 02530 02531 int 02532 sp_instr_stmt::exec_core(THD *thd, uint *nextp) 02533 { 02534 int res= mysql_execute_command(thd); 02535 *nextp= m_ip+1; 02536 return res; 02537 } 02538 02539 02540 /* 02541 sp_instr_set class functions 02542 */ 02543 02544 int 02545 sp_instr_set::execute(THD *thd, uint *nextp) 02546 { 02547 DBUG_ENTER("sp_instr_set::execute"); 02548 DBUG_PRINT("info", ("offset: %u", m_offset)); 02549 02550 DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); 02551 } 02552 02553 02554 int 02555 sp_instr_set::exec_core(THD *thd, uint *nextp) 02556 { 02557 int res= thd->spcont->set_variable(thd, m_offset, &m_value); 02558 02559 if (res && thd->spcont->found_handler_here()) 02560 { 02561 /* 02562 Failed to evaluate the value, and a handler has been found. Reset the 02563 variable to NULL. 02564 */ 02565 02566 if (thd->spcont->set_variable(thd, m_offset, 0)) 02567 { 02568 /* If this also failed, let's abort. */ 02569 02570 sp_rcontext *spcont= thd->spcont; 02571 02572 thd->spcont= 0; /* Avoid handlers */ 02573 my_error(ER_OUT_OF_RESOURCES, MYF(0)); 02574 spcont->clear_handler(); 02575 thd->spcont= spcont; 02576 } 02577 } 02578 02579 *nextp = m_ip+1; 02580 return res; 02581 } 02582 02583 void 02584 sp_instr_set::print(String *str) 02585 { 02586 /* set name@offset ... */ 02587 int rsrv = SP_INSTR_UINT_MAXLEN+6; 02588 sp_variable_t *var = m_ctx->find_variable(m_offset); 02589 02590 /* 'var' should always be non-null, but just in case... */ 02591 if (var) 02592 rsrv+= var->name.length; 02593 if (str->reserve(rsrv)) 02594 return; 02595 str->qs_append(STRING_WITH_LEN("set ")); 02596 if (var) 02597 { 02598 str->qs_append(var->name.str, var->name.length); 02599 str->qs_append('@'); 02600 } 02601 str->qs_append(m_offset); 02602 str->qs_append(' '); 02603 m_value->print(str); 02604 } 02605 02606 02607 /* 02608 sp_instr_set_trigger_field class functions 02609 */ 02610 02611 int 02612 sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) 02613 { 02614 DBUG_ENTER("sp_instr_set_trigger_field::execute"); 02615 DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); 02616 } 02617 02618 02619 int 02620 sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp) 02621 { 02622 const int res= (trigger_field->set_value(thd, &value) ? -1 : 0); 02623 *nextp = m_ip+1; 02624 return res; 02625 } 02626 02627 void 02628 sp_instr_set_trigger_field::print(String *str) 02629 { 02630 str->append(STRING_WITH_LEN("set_trigger_field ")); 02631 trigger_field->print(str); 02632 str->append(STRING_WITH_LEN(":=")); 02633 value->print(str); 02634 } 02635 02636 02637 /* 02638 sp_instr_jump class functions 02639 */ 02640 02641 int 02642 sp_instr_jump::execute(THD *thd, uint *nextp) 02643 { 02644 DBUG_ENTER("sp_instr_jump::execute"); 02645 DBUG_PRINT("info", ("destination: %u", m_dest)); 02646 02647 *nextp= m_dest; 02648 DBUG_RETURN(0); 02649 } 02650 02651 void 02652 sp_instr_jump::print(String *str) 02653 { 02654 /* jump dest */ 02655 if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) 02656 return; 02657 str->qs_append(STRING_WITH_LEN("jump ")); 02658 str->qs_append(m_dest); 02659 } 02660 02661 uint 02662 sp_instr_jump::opt_mark(sp_head *sp) 02663 { 02664 m_dest= opt_shortcut_jump(sp, this); 02665 if (m_dest != m_ip+1) /* Jumping to following instruction? */ 02666 marked= 1; 02667 m_optdest= sp->get_instr(m_dest); 02668 return m_dest; 02669 } 02670 02671 uint 02672 sp_instr_jump::opt_shortcut_jump(sp_head *sp, sp_instr *start) 02673 { 02674 uint dest= m_dest; 02675 sp_instr *i; 02676 02677 while ((i= sp->get_instr(dest))) 02678 { 02679 uint ndest; 02680 02681 if (start == i || this == i) 02682 break; 02683 ndest= i->opt_shortcut_jump(sp, start); 02684 if (ndest == dest) 02685 break; 02686 dest= ndest; 02687 } 02688 return dest; 02689 } 02690 02691 void 02692 sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp) 02693 { 02694 if (m_dest > m_ip) 02695 bp->push_back(this); // Forward 02696 else if (m_optdest) 02697 m_dest= m_optdest->m_ip; // Backward 02698 m_ip= dst; 02699 } 02700 02701 02702 /* 02703 sp_instr_jump_if_not class functions 02704 */ 02705 02706 int 02707 sp_instr_jump_if_not::execute(THD *thd, uint *nextp) 02708 { 02709 DBUG_ENTER("sp_instr_jump_if_not::execute"); 02710 DBUG_PRINT("info", ("destination: %u", m_dest)); 02711 DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); 02712 } 02713 02714 02715 int 02716 sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) 02717 { 02718 Item *it; 02719 int res; 02720 02721 it= sp_prepare_func_item(thd, &m_expr); 02722 if (! it) 02723 { 02724 res= -1; 02725 *nextp = m_cont_dest; 02726 } 02727 else 02728 { 02729 res= 0; 02730 if (! it->val_bool()) 02731 *nextp = m_dest; 02732 else 02733 *nextp = m_ip+1; 02734 } 02735 02736 return res; 02737 } 02738 02739 02740 void 02741 sp_instr_jump_if_not::print(String *str) 02742 { 02743 /* jump_if_not dest(cont) ... */ 02744 if (str->reserve(2*SP_INSTR_UINT_MAXLEN+14+32)) // Add some for the expr. too 02745 return; 02746 str->qs_append(STRING_WITH_LEN("jump_if_not ")); 02747 str->qs_append(m_dest); 02748 str->qs_append('('); 02749 str->qs_append(m_cont_dest); 02750 str->qs_append(STRING_WITH_LEN(") ")); 02751 m_expr->print(str); 02752 } 02753 02754 02755 uint 02756 sp_instr_jump_if_not::opt_mark(sp_head *sp) 02757 { 02758 sp_instr *i; 02759 02760 marked= 1; 02761 if ((i= sp->get_instr(m_dest))) 02762 { 02763 m_dest= i->opt_shortcut_jump(sp, this); 02764 m_optdest= sp->get_instr(m_dest); 02765 } 02766 sp->opt_mark(m_dest); 02767 if ((i= sp->get_instr(m_cont_dest))) 02768 { 02769 m_cont_dest= i->opt_shortcut_jump(sp, this); 02770 m_cont_optdest= sp->get_instr(m_cont_dest); 02771 } 02772 sp->opt_mark(m_cont_dest); 02773 return m_ip+1; 02774 } 02775 02776 void 02777 sp_instr_jump_if_not::opt_move(uint dst, List<sp_instr> *bp) 02778 { 02779 /* 02780 cont. destinations may point backwards after shortcutting jumps 02781 during the mark phase. If it's still pointing forwards, only 02782 push this for backpatching if sp_instr_jump::opt_move() will not 02783 do it (i.e. if the m_dest points backwards). 02784 */ 02785 if (m_cont_dest > m_ip) 02786 { // Forward 02787 if (m_dest < m_ip) 02788 bp->push_back(this); 02789 } 02790 else if (m_cont_optdest) 02791 m_cont_dest= m_cont_optdest->m_ip; // Backward 02792 /* This will take care of m_dest and m_ip */ 02793 sp_instr_jump::opt_move(dst, bp); 02794 } 02795 02796 02797 /* 02798 sp_instr_freturn class functions 02799 */ 02800 02801 int 02802 sp_instr_freturn::execute(THD *thd, uint *nextp) 02803 { 02804 DBUG_ENTER("sp_instr_freturn::execute"); 02805 DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); 02806 } 02807 02808 02809 int 02810 sp_instr_freturn::exec_core(THD *thd, uint *nextp) 02811 { 02812 /* 02813 Change <next instruction pointer>, so that this will be the last 02814 instruction in the stored function. 02815 */ 02816 02817 *nextp= UINT_MAX; 02818 02819 /* 02820 Evaluate the value of return expression and store it in current runtime 02821 context. 02822 02823 NOTE: It's necessary to evaluate result item right here, because we must 02824 do it in scope of execution the current context/block. 02825 */ 02826 02827 return thd->spcont->set_return_value(thd, &m_value); 02828 } 02829 02830 void 02831 sp_instr_freturn::print(String *str) 02832 { 02833 /* freturn type expr... */ 02834 if (str->reserve(UINT_MAX+8+32)) // Add some for the expr. too 02835 return; 02836 str->qs_append(STRING_WITH_LEN("freturn ")); 02837 str->qs_append((uint)m_type); 02838 str->qs_append(' '); 02839 m_value->print(str); 02840 } 02841 02842 /* 02843 sp_instr_hpush_jump class functions 02844 */ 02845 02846 int 02847 sp_instr_hpush_jump::execute(THD *thd, uint *nextp) 02848 { 02849 DBUG_ENTER("sp_instr_hpush_jump::execute"); 02850 List_iterator_fast<sp_cond_type_t> li(m_cond); 02851 sp_cond_type_t *p; 02852 02853 while ((p= li++)) 02854 thd->spcont->push_handler(p, m_ip+1, m_type, m_frame); 02855 02856 *nextp= m_dest; 02857 DBUG_RETURN(0); 02858 } 02859 02860 02861 void 02862 sp_instr_hpush_jump::print(String *str) 02863 { 02864 /* hpush_jump dest fsize type */ 02865 if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 21)) 02866 return; 02867 str->qs_append(STRING_WITH_LEN("hpush_jump ")); 02868 str->qs_append(m_dest); 02869 str->qs_append(' '); 02870 str->qs_append(m_frame); 02871 switch (m_type) { 02872 case SP_HANDLER_NONE: 02873 str->qs_append(STRING_WITH_LEN(" NONE")); // This would be a bug 02874 break; 02875 case SP_HANDLER_EXIT: 02876 str->qs_append(STRING_WITH_LEN(" EXIT")); 02877 break; 02878 case SP_HANDLER_CONTINUE: 02879 str->qs_append(STRING_WITH_LEN(" CONTINUE")); 02880 break; 02881 case SP_HANDLER_UNDO: 02882 str->qs_append(STRING_WITH_LEN(" UNDO")); 02883 break; 02884 default: 02885 // This would be a bug as well 02886 str->qs_append(STRING_WITH_LEN(" UNKNOWN:")); 02887 str->qs_append(m_type); 02888 } 02889 } 02890 02891 02892 uint 02893 sp_instr_hpush_jump::opt_mark(sp_head *sp) 02894 { 02895 sp_instr *i; 02896 02897 marked= 1; 02898 if ((i= sp->get_instr(m_dest))) 02899 { 02900 m_dest= i->opt_shortcut_jump(sp, this); 02901 m_optdest= sp->get_instr(m_dest); 02902 } 02903 sp->opt_mark(m_dest); 02904 return m_ip+1; 02905 } 02906 02907 02908 /* 02909 sp_instr_hpop class functions 02910 */ 02911 02912 int 02913 sp_instr_hpop::execute(THD *thd, uint *nextp) 02914 { 02915 DBUG_ENTER("sp_instr_hpop::execute"); 02916 thd->spcont->pop_handlers(m_count); 02917 *nextp= m_ip+1; 02918 DBUG_RETURN(0); 02919 } 02920 02921 void 02922 sp_instr_hpop::print(String *str) 02923 { 02924 /* hpop count */ 02925 if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) 02926 return; 02927 str->qs_append(STRING_WITH_LEN("hpop ")); 02928 str->qs_append(m_count); 02929 } 02930 02931 02932 /* 02933 sp_instr_hreturn class functions 02934 */ 02935 02936 int 02937 sp_instr_hreturn::execute(THD *thd, uint *nextp) 02938 { 02939 DBUG_ENTER("sp_instr_hreturn::execute"); 02940 if (m_dest) 02941 *nextp= m_dest; 02942 else 02943 { 02944 *nextp= thd->spcont->pop_hstack(); 02945 } 02946 thd->spcont->exit_handler(); 02947 DBUG_RETURN(0); 02948 } 02949 02950 02951 void 02952 sp_instr_hreturn::print(String *str) 02953 { 02954 /* hreturn framesize dest */ 02955 if (str->reserve(SP_INSTR_UINT_MAXLEN*2 + 9)) 02956 return; 02957 str->qs_append(STRING_WITH_LEN("hreturn ")); 02958 str->qs_append(m_frame); 02959 if (m_dest) 02960 { 02961 str->qs_append(' '); 02962 str->qs_append(m_dest); 02963 } 02964 } 02965 02966 02967 uint 02968 sp_instr_hreturn::opt_mark(sp_head *sp) 02969 { 02970 if (m_dest) 02971 return sp_instr_jump::opt_mark(sp); 02972 else 02973 { 02974 marked= 1; 02975 return UINT_MAX; 02976 } 02977 } 02978 02979 02980 /* 02981 sp_instr_cpush class functions 02982 */ 02983 02984 int 02985 sp_instr_cpush::execute(THD *thd, uint *nextp) 02986 { 02987 Query_arena backup_arena; 02988 DBUG_ENTER("sp_instr_cpush::execute"); 02989 02990 /* 02991 We should create cursors in the callers arena, as 02992 it could be (and usually is) used in several instructions. 02993 */ 02994 thd->set_n_backup_active_arena(thd->spcont->callers_arena, &backup_arena); 02995 02996 thd->spcont->push_cursor(&m_lex_keeper, this); 02997 02998 thd->restore_active_arena(thd->spcont->callers_arena, &backup_arena); 02999 03000 *nextp= m_ip+1; 03001 03002 DBUG_RETURN(0); 03003 } 03004 03005 03006 void 03007 sp_instr_cpush::print(String *str) 03008 { 03009 LEX_STRING n; 03010 my_bool found= m_ctx->find_cursor(m_cursor, &n); 03011 /* cpush name@offset */ 03012 uint rsrv= SP_INSTR_UINT_MAXLEN+7; 03013 03014 if (found) 03015 rsrv+= n.length; 03016 if (str->reserve(rsrv)) 03017 return; 03018 str->qs_append(STRING_WITH_LEN("cpush ")); 03019 if (found) 03020 { 03021 str->qs_append(n.str, n.length); 03022 str->qs_append('@'); 03023 } 03024 str->qs_append(m_cursor); 03025 } 03026 03027 03028 /* 03029 sp_instr_cpop class functions 03030 */ 03031 03032 int 03033 sp_instr_cpop::execute(THD *thd, uint *nextp) 03034 { 03035 DBUG_ENTER("sp_instr_cpop::execute"); 03036 thd->spcont->pop_cursors(m_count); 03037 *nextp= m_ip+1; 03038 DBUG_RETURN(0); 03039 } 03040 03041 03042 void 03043 sp_instr_cpop::print(String *str) 03044 { 03045 /* cpop count */ 03046 if (str->reserve(SP_INSTR_UINT_MAXLEN+5)) 03047 return; 03048 str->qs_append(STRING_WITH_LEN("cpop ")); 03049 str->qs_append(m_count); 03050 } 03051 03052 03053 /* 03054 sp_instr_copen class functions 03055 */ 03056 03057 int 03058 sp_instr_copen::execute(THD *thd, uint *nextp) 03059 { 03060 /* 03061 We don't store a pointer to the cursor in the instruction to be 03062 able to reuse the same instruction among different threads in future. 03063 */ 03064 sp_cursor *c= thd->spcont->get_cursor(m_cursor); 03065 int res; 03066 DBUG_ENTER("sp_instr_copen::execute"); 03067 03068 if (! c) 03069 res= -1; 03070 else 03071 { 03072 sp_lex_keeper *lex_keeper= c->get_lex_keeper(); 03073 Query_arena *old_arena= thd->stmt_arena; 03074 03075 /* 03076 Get the Query_arena from the cpush instruction, which contains 03077 the free_list of the query, so new items (if any) are stored in 03078 the right free_list, and we can cleanup after each open. 03079 */ 03080 thd->stmt_arena= c->get_instr(); 03081 res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this); 03082 /* Cleanup the query's items */ 03083 if (thd->stmt_arena->free_list) 03084 cleanup_items(thd->stmt_arena->free_list); 03085 thd->stmt_arena= old_arena; 03086 /* 03087 Work around the fact that errors in selects are not returned properly 03088 (but instead converted into a warning), so if a condition handler 03089 caught, we have lost the result code. 03090 */ 03091 if (!res) 03092 { 03093 uint dummy1, dummy2; 03094 03095 if (thd->spcont->found_handler(&dummy1, &dummy2)) 03096 res= -1; 03097 } 03098 /* TODO: Assert here that we either have an error or a cursor */ 03099 } 03100 DBUG_RETURN(res); 03101 } 03102 03103 03104 int 03105 sp_instr_copen::exec_core(THD *thd, uint *nextp) 03106 { 03107 sp_cursor *c= thd->spcont->get_cursor(m_cursor); 03108 int res= c->open(thd); 03109 *nextp= m_ip+1; 03110 return res; 03111 } 03112 03113 void 03114 sp_instr_copen::print(String *str) 03115 { 03116 LEX_STRING n; 03117 my_bool found= m_ctx->find_cursor(m_cursor, &n); 03118 /* copen name@offset */ 03119 uint rsrv= SP_INSTR_UINT_MAXLEN+7; 03120 03121 if (found) 03122 rsrv+= n.length; 03123 if (str->reserve(rsrv)) 03124 return; 03125 str->qs_append(STRING_WITH_LEN("copen ")); 03126 if (found) 03127 { 03128 str->qs_append(n.str, n.length); 03129 str->qs_append('@'); 03130 } 03131 str->qs_append(m_cursor); 03132 } 03133 03134 03135 /* 03136 sp_instr_cclose class functions 03137 */ 03138 03139 int 03140 sp_instr_cclose::execute(THD *thd, uint *nextp) 03141 { 03142 sp_cursor *c= thd->spcont->get_cursor(m_cursor); 03143 int res; 03144 DBUG_ENTER("sp_instr_cclose::execute"); 03145 03146 if (! c) 03147 res= -1; 03148 else 03149 res= c->close(thd); 03150 *nextp= m_ip+1; 03151 DBUG_RETURN(res); 03152 } 03153 03154 03155 void 03156 sp_instr_cclose::print(String *str) 03157 { 03158 LEX_STRING n; 03159 my_bool found= m_ctx->find_cursor(m_cursor, &n); 03160 /* cclose name@offset */ 03161 uint rsrv= SP_INSTR_UINT_MAXLEN+8; 03162 03163 if (found) 03164 rsrv+= n.length; 03165 if (str->reserve(rsrv)) 03166 return; 03167 str->qs_append(STRING_WITH_LEN("cclose ")); 03168 if (found) 03169 { 03170 str->qs_append(n.str, n.length); 03171 str->qs_append('@'); 03172 } 03173 str->qs_append(m_cursor); 03174 } 03175 03176 03177 /* 03178 sp_instr_cfetch class functions 03179 */ 03180 03181 int 03182 sp_instr_cfetch::execute(THD *thd, uint *nextp) 03183 { 03184 sp_cursor *c= thd->spcont->get_cursor(m_cursor); 03185 int res; 03186 Query_arena backup_arena; 03187 DBUG_ENTER("sp_instr_cfetch::execute"); 03188 03189 res= c ? c->fetch(thd, &m_varlist) : -1; 03190 03191 *nextp= m_ip+1; 03192 DBUG_RETURN(res); 03193 } 03194 03195 03196 void 03197 sp_instr_cfetch::print(String *str) 03198 { 03199 List_iterator_fast<struct sp_variable> li(m_varlist); 03200 sp_variable_t *pv; 03201 LEX_STRING n; 03202 my_bool found= m_ctx->find_cursor(m_cursor, &n); 03203 /* cfetch name@offset vars... */ 03204 uint rsrv= SP_INSTR_UINT_MAXLEN+8; 03205 03206 if (found) 03207 rsrv+= n.length; 03208 if (str->reserve(rsrv)) 03209 return; 03210 str->qs_append(STRING_WITH_LEN("cfetch ")); 03211 if (found) 03212 { 03213 str->qs_append(n.str, n.length); 03214 str->qs_append('@'); 03215 } 03216 str->qs_append(m_cursor); 03217 while ((pv= li++)) 03218 { 03219 if (str->reserve(pv->name.length+SP_INSTR_UINT_MAXLEN+2)) 03220 return; 03221 str->qs_append(' '); 03222 str->qs_append(pv->name.str, pv->name.length); 03223 str->qs_append('@'); 03224 str->qs_append(pv->offset); 03225 } 03226 } 03227 03228 03229 /* 03230 sp_instr_error class functions 03231 */ 03232 03233 int 03234 sp_instr_error::execute(THD *thd, uint *nextp) 03235 { 03236 DBUG_ENTER("sp_instr_error::execute"); 03237 03238 my_message(m_errcode, ER(m_errcode), MYF(0)); 03239 *nextp= m_ip+1; 03240 DBUG_RETURN(-1); 03241 } 03242 03243 03244 void 03245 sp_instr_error::print(String *str) 03246 { 03247 /* error code */ 03248 if (str->reserve(SP_INSTR_UINT_MAXLEN+6)) 03249 return; 03250 str->qs_append(STRING_WITH_LEN("error ")); 03251 str->qs_append(m_errcode); 03252 } 03253 03254 03255 /************************************************************************** 03256 sp_instr_set_case_expr class implementation 03257 **************************************************************************/ 03258 03259 int 03260 sp_instr_set_case_expr::execute(THD *thd, uint *nextp) 03261 { 03262 DBUG_ENTER("sp_instr_set_case_expr::execute"); 03263 03264 DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); 03265 } 03266 03267 03268 int 03269 sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp) 03270 { 03271 int res= thd->spcont->set_case_expr(thd, m_case_expr_id, &m_case_expr); 03272 03273 if (res && 03274 !thd->spcont->get_case_expr(m_case_expr_id) && 03275 thd->spcont->found_handler_here()) 03276 { 03277 /* 03278 Failed to evaluate the value, the case expression is still not 03279 initialized, and a handler has been found. Set to NULL so we can continue. 03280 */ 03281 03282 Item *null_item= new Item_null(); 03283 03284 if (!null_item || 03285 thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item)) 03286 { 03287 /* If this also failed, we have to abort. */ 03288 03289 sp_rcontext *spcont= thd->spcont; 03290 03291 thd->spcont= 0; /* Avoid handlers */ 03292 my_error(ER_OUT_OF_RESOURCES, MYF(0)); 03293 spcont->clear_handler(); 03294 thd->spcont= spcont; 03295 } 03296 *nextp= m_cont_dest; /* For continue handler */ 03297 } 03298 else 03299 *nextp= m_ip+1; 03300 03301 return res; 03302 } 03303 03304 03305 void 03306 sp_instr_set_case_expr::print(String *str) 03307 { 03308 /* set_case_expr (cont) id ... */ 03309 str->reserve(2*SP_INSTR_UINT_MAXLEN+18+32); // Add some extra for expr too 03310 str->qs_append(STRING_WITH_LEN("set_case_expr (")); 03311 str->qs_append(m_cont_dest); 03312 str->qs_append(STRING_WITH_LEN(") ")); 03313 str->qs_append(m_case_expr_id); 03314 str->qs_append(' '); 03315 m_case_expr->print(str); 03316 } 03317 03318 uint 03319 sp_instr_set_case_expr::opt_mark(sp_head *sp) 03320 { 03321 sp_instr *i; 03322 03323 marked= 1; 03324 if ((i= sp->get_instr(m_cont_dest))) 03325 { 03326 m_cont_dest= i->opt_shortcut_jump(sp, this); 03327 m_cont_optdest= sp->get_instr(m_cont_dest); 03328 } 03329 sp->opt_mark(m_cont_dest); 03330 return m_ip+1; 03331 } 03332 03333 void 03334 sp_instr_set_case_expr::opt_move(uint dst, List<sp_instr> *bp) 03335 { 03336 if (m_cont_dest > m_ip) 03337 bp->push_back(this); // Forward 03338 else if (m_cont_optdest) 03339 m_cont_dest= m_cont_optdest->m_ip; // Backward 03340 m_ip= dst; 03341 } 03342 03343 03344 /* ------------------------------------------------------------------ */ 03345 03346 /* 03347 Security context swapping 03348 */ 03349 03350 #ifndef NO_EMBEDDED_ACCESS_CHECKS 03351 bool 03352 sp_change_security_context(THD *thd, sp_head *sp, Security_context **backup) 03353 { 03354 *backup= 0; 03355 if (sp->m_chistics->suid != SP_IS_NOT_SUID && 03356 (strcmp(sp->m_definer_user.str, 03357 thd->security_ctx->priv_user) || 03358 my_strcasecmp(system_charset_info, sp->m_definer_host.str, 03359 thd->security_ctx->priv_host))) 03360 { 03361 if (acl_getroot_no_password(&sp->m_security_ctx, sp->m_definer_user.str, 03362 sp->m_definer_host.str, 03363 sp->m_definer_host.str, 03364 sp->m_db.str)) 03365 { 03366 my_error(ER_NO_SUCH_USER, MYF(0), sp->m_definer_user.str, 03367 sp->m_definer_host.str); 03368 return TRUE; 03369 } 03370 *backup= thd->security_ctx; 03371 thd->security_ctx= &sp->m_security_ctx; 03372 } 03373 return FALSE; 03374 } 03375 03376 void 03377 sp_restore_security_context(THD *thd, Security_context *backup) 03378 { 03379 if (backup) 03380 thd->security_ctx= backup; 03381 } 03382 03383 #endif /* NO_EMBEDDED_ACCESS_CHECKS */ 03384 03385 /* 03386 Structure that represent all instances of one table 03387 in optimized multi-set of tables used by routine. 03388 */ 03389 03390 typedef struct st_sp_table 03391 { 03392 /* 03393 Multi-set key: 03394 db_name\0table_name\0alias\0 - for normal tables 03395 db_name\0table_name\0 - for temporary tables 03396 Note that in both cases we don't take last '\0' into account when 03397 we count length of key. 03398 */ 03399 LEX_STRING qname; 03400 uint db_length, table_name_length; 03401 bool temp; /* true if corresponds to a temporary table */ 03402 thr_lock_type lock_type; /* lock type used for prelocking */ 03403 uint lock_count; 03404 uint query_lock_count; 03405 } SP_TABLE; 03406 03407 byte * 03408 sp_table_key(const byte *ptr, uint *plen, my_bool first) 03409 { 03410 SP_TABLE *tab= (SP_TABLE *)ptr; 03411 *plen= tab->qname.length; 03412 return (byte *)tab->qname.str; 03413 } 03414 03415 03416 /* 03417 Merge the list of tables used by some query into the multi-set of 03418 tables used by routine. 03419 03420 SYNOPSIS 03421 merge_table_list() 03422 thd - thread context 03423 table - table list 03424 lex_for_tmp_check - LEX of the query for which we are merging 03425 table list. 03426 03427 NOTE 03428 This method will use LEX provided to check whenever we are creating 03429 temporary table and mark it as such in target multi-set. 03430 03431 RETURN VALUE 03432 TRUE - Success 03433 FALSE - Error 03434 */ 03435 03436 bool 03437 sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) 03438 { 03439 SP_TABLE *tab; 03440 03441 if (lex_for_tmp_check->sql_command == SQLCOM_DROP_TABLE && 03442 lex_for_tmp_check->drop_temporary) 03443 return TRUE; 03444 03445 for (uint i= 0 ; i < m_sptabs.records ; i++) 03446 { 03447 tab= (SP_TABLE *)hash_element(&m_sptabs, i); 03448 tab->query_lock_count= 0; 03449 } 03450 03451 for (; table ; table= table->next_global) 03452 if (!table->derived && !table->schema_table) 03453 { 03454 char tname[(NAME_LEN + 1) * 3]; // db\0table\0alias\0 03455 uint tlen, alen; 03456 03457 tlen= table->db_length; 03458 memcpy(tname, table->db, tlen); 03459 tname[tlen++]= '\0'; 03460 memcpy(tname+tlen, table->table_name, table->table_name_length); 03461 tlen+= table->table_name_length; 03462 tname[tlen++]= '\0'; 03463 alen= strlen(table->alias); 03464 memcpy(tname+tlen, table->alias, alen); 03465 tlen+= alen; 03466 tname[tlen]= '\0'; 03467 03468 /* 03469 We ignore alias when we check if table was already marked as temporary 03470 (and therefore should not be prelocked). Otherwise we will erroneously 03471 treat table with same name but with different alias as non-temporary. 03472 */ 03473 if ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, tlen)) || 03474 ((tab= (SP_TABLE *)hash_search(&m_sptabs, (byte *)tname, 03475 tlen - alen - 1)) && 03476 tab->temp)) 03477 { 03478 if (tab->lock_type < table->lock_type) 03479 tab->lock_type= table->lock_type; // Use the table with the highest lock type 03480 tab->query_lock_count++; 03481 if (tab->query_lock_count > tab->lock_count) 03482 tab->lock_count++; 03483 } 03484 else 03485 { 03486 if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE)))) 03487 return FALSE; 03488 if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE && 03489 lex_for_tmp_check->query_tables == table && 03490 lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE) 03491 { 03492 tab->temp= TRUE; 03493 tab->qname.length= tlen - alen - 1; 03494 } 03495 else 03496 tab->qname.length= tlen; 03497 tab->qname.str= (char*) thd->memdup(tname, tab->qname.length + 1); 03498 if (!tab->qname.str) 03499 return FALSE; 03500 tab->table_name_length= table->table_name_length; 03501 tab->db_length= table->db_length; 03502 tab->lock_type= table->lock_type; 03503 tab->lock_count= tab->query_lock_count= 1; 03504 my_hash_insert(&m_sptabs, (byte *)tab); 03505 } 03506 } 03507 return TRUE; 03508 } 03509 03510 03511 /* 03512 Add tables used by routine to the table list. 03513 03514 SYNOPSIS 03515 add_used_tables_to_table_list() 03516 thd [in] Thread context 03517 query_tables_last_ptr [in/out] Pointer to the next_global member of 03518 last element of the list where tables 03519 will be added (or to its root). 03520 belong_to_view [in] Uppermost view which uses this routine, 03521 0 if none. 03522 03523 DESCRIPTION 03524 Converts multi-set of tables used by this routine to table list and adds 03525 this list to the end of table list specified by 'query_tables_last_ptr'. 03526 03527 Elements of list will be allocated in PS memroot, so this list will be 03528 persistent between PS executions. 03529 03530 RETURN VALUE 03531 TRUE - if some elements were added, FALSE - otherwise. 03532 */ 03533 03534 bool 03535 sp_head::add_used_tables_to_table_list(THD *thd, 03536 TABLE_LIST ***query_tables_last_ptr, 03537 TABLE_LIST *belong_to_view) 03538 { 03539 uint i; 03540 Query_arena *arena, backup; 03541 bool result= FALSE; 03542 DBUG_ENTER("sp_head::add_used_tables_to_table_list"); 03543 03544 /* 03545 Use persistent arena for table list allocation to be PS/SP friendly. 03546 Note that we also have to copy database/table names and alias to PS/SP 03547 memory since current instance of sp_head object can pass away before 03548 next execution of PS/SP for which tables are added to prelocking list. 03549 This will be fixed by introducing of proper invalidation mechanism 03550 once new TDC is ready. 03551 */ 03552 arena= thd->activate_stmt_arena_if_needed(&backup); 03553 03554 for (i=0 ; i < m_sptabs.records ; i++) 03555 { 03556 char *tab_buff, *key_buff; 03557 TABLE_LIST *table; 03558 SP_TABLE *stab= (SP_TABLE *)hash_element(&m_sptabs, i); 03559 if (stab->temp) 03560 continue; 03561 03562 if (!(tab_buff= (char *)thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST)) * 03563 stab->lock_count)) || 03564 !(key_buff= (char*)thd->memdup(stab->qname.str, 03565 stab->qname.length + 1))) 03566 DBUG_RETURN(FALSE); 03567 03568 for (uint j= 0; j < stab->lock_count; j++) 03569 { 03570 table= (TABLE_LIST *)tab_buff; 03571 03572 table->db= key_buff; 03573 table->db_length= stab->db_length; 03574 table->table_name= table->db + table->db_length + 1; 03575 table->table_name_length= stab->table_name_length; 03576 table->alias= table->table_name + table->table_name_length + 1; 03577 table->lock_type= stab->lock_type; 03578 table->cacheable_table= 1; 03579 table->prelocking_placeholder= 1; 03580 table->belong_to_view= belong_to_view; 03581 03582 /* Everyting else should be zeroed */ 03583 03584 **query_tables_last_ptr= table; 03585 table->prev_global= *query_tables_last_ptr; 03586 *query_tables_last_ptr= &table->next_global; 03587 03588 tab_buff+= ALIGN_SIZE(sizeof(TABLE_LIST)); 03589 result= TRUE; 03590 } 03591 } 03592 03593 if (arena) 03594 thd->restore_active_arena(arena, &backup); 03595 03596 DBUG_RETURN(result); 03597 } 03598 03599 03600 /* 03601 Simple function for adding an explicetly named (systems) table to 03602 the global table list, e.g. "mysql", "proc". 03603 */ 03604 03605 TABLE_LIST * 03606 sp_add_to_query_tables(THD *thd, LEX *lex, 03607 const char *db, const char *name, 03608 thr_lock_type locktype) 03609 { 03610 TABLE_LIST *table; 03611 03612 if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST)))) 03613 { 03614 my_error(ER_OUTOFMEMORY, MYF(0), sizeof(TABLE_LIST)); 03615 return NULL; 03616 } 03617 table->db_length= strlen(db); 03618 table->db= thd->strmake(db, table->db_length); 03619 table->table_name_length= strlen(name); 03620 table->table_name= thd->strmake(name, table->table_name_length); 03621 table->alias= thd->strdup(name); 03622 table->lock_type= locktype; 03623 table->select_lex= lex->current_select; 03624 table->cacheable_table= 1; 03625 03626 lex->add_to_query_tables(table); 03627 return table; 03628 } 03629
1.4.7

