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 00022 #if defined(WIN32) || defined(__WIN__) 00023 #undef SAFEMALLOC /* Problems with threads */ 00024 #endif 00025 00026 #include "mysql.h" 00027 #include "sp_head.h" 00028 #include "sql_cursor.h" 00029 #include "sp_rcontext.h" 00030 #include "sp_pcontext.h" 00031 00032 00033 sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx, 00034 Field *return_value_fld, 00035 sp_rcontext *prev_runtime_ctx) 00036 :m_root_parsing_ctx(root_parsing_ctx), 00037 m_var_table(0), 00038 m_var_items(0), 00039 m_return_value_fld(return_value_fld), 00040 m_return_value_set(FALSE), 00041 m_hcount(0), 00042 m_hsp(0), 00043 m_ihsp(0), 00044 m_hfound(-1), 00045 m_ccount(0), 00046 m_case_expr_holders(0), 00047 m_prev_runtime_ctx(prev_runtime_ctx) 00048 { 00049 } 00050 00051 00052 sp_rcontext::~sp_rcontext() 00053 { 00054 if (m_var_table) 00055 free_blobs(m_var_table); 00056 } 00057 00058 00059 /* 00060 Initialize sp_rcontext instance. 00061 00062 SYNOPSIS 00063 thd Thread handle 00064 RETURN 00065 FALSE on success 00066 TRUE on error 00067 */ 00068 00069 bool sp_rcontext::init(THD *thd) 00070 { 00071 if (init_var_table(thd) || init_var_items()) 00072 return TRUE; 00073 00074 return 00075 !(m_handler= 00076 (sp_handler_t*)thd->alloc(m_root_parsing_ctx->max_handler_index() * 00077 sizeof(sp_handler_t))) || 00078 !(m_hstack= 00079 (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() * 00080 sizeof(uint))) || 00081 !(m_in_handler= 00082 (uint*)thd->alloc(m_root_parsing_ctx->max_handler_index() * 00083 sizeof(uint))) || 00084 !(m_cstack= 00085 (sp_cursor**)thd->alloc(m_root_parsing_ctx->max_cursor_index() * 00086 sizeof(sp_cursor*))) || 00087 !(m_case_expr_holders= 00088 (Item_cache**)thd->calloc(m_root_parsing_ctx->get_num_case_exprs() * 00089 sizeof (Item_cache*))); 00090 } 00091 00092 00093 /* 00094 Create and initialize a table to store SP-vars. 00095 00096 SYNOPSIS 00097 thd Thread handler. 00098 RETURN 00099 FALSE on success 00100 TRUE on error 00101 */ 00102 00103 bool 00104 sp_rcontext::init_var_table(THD *thd) 00105 { 00106 List<create_field> field_def_lst; 00107 00108 if (!m_root_parsing_ctx->max_var_index()) 00109 return FALSE; 00110 00111 m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst); 00112 00113 DBUG_ASSERT(field_def_lst.elements == m_root_parsing_ctx->max_var_index()); 00114 00115 if (!(m_var_table= create_virtual_tmp_table(thd, field_def_lst))) 00116 return TRUE; 00117 00118 m_var_table->copy_blobs= TRUE; 00119 m_var_table->alias= ""; 00120 00121 return FALSE; 00122 } 00123 00124 00125 /* 00126 Create and initialize an Item-adapter (Item_field) for each SP-var field. 00127 00128 RETURN 00129 FALSE on success 00130 TRUE on error 00131 */ 00132 00133 bool 00134 sp_rcontext::init_var_items() 00135 { 00136 uint idx; 00137 uint num_vars= m_root_parsing_ctx->max_var_index(); 00138 00139 if (!(m_var_items= (Item**) sql_alloc(num_vars * sizeof (Item *)))) 00140 return TRUE; 00141 00142 for (idx = 0; idx < num_vars; ++idx) 00143 { 00144 if (!(m_var_items[idx]= new Item_field(m_var_table->field[idx]))) 00145 return TRUE; 00146 } 00147 00148 return FALSE; 00149 } 00150 00151 00152 bool 00153 sp_rcontext::set_return_value(THD *thd, Item **return_value_item) 00154 { 00155 DBUG_ASSERT(m_return_value_fld); 00156 00157 m_return_value_set = TRUE; 00158 00159 return sp_eval_expr(thd, m_return_value_fld, return_value_item); 00160 } 00161 00162 00163 #define IS_WARNING_CONDITION(S) ((S)[0] == '0' && (S)[1] == '1') 00164 #define IS_NOT_FOUND_CONDITION(S) ((S)[0] == '0' && (S)[1] == '2') 00165 #define IS_EXCEPTION_CONDITION(S) ((S)[0] != '0' || (S)[1] > '2') 00166 00167 /* 00168 Find a handler for the given errno. 00169 This is called from all error message functions (e.g. push_warning, 00170 net_send_error, et al) when a sp_rcontext is in effect. If a handler 00171 is found, no error is sent, and the the SP execution loop will instead 00172 invoke the found handler. 00173 This might be called several times before we get back to the execution 00174 loop, so m_hfound can be >= 0 if a handler has already been found. 00175 (In which case we don't search again - the first found handler will 00176 be used.) 00177 Handlers are pushed on the stack m_handler, with the latest/innermost 00178 one on the top; we then search for matching handlers from the top and 00179 down. 00180 We search through all the handlers, looking for the most specific one 00181 (sql_errno more specific than sqlstate more specific than the rest). 00182 Note that mysql error code handlers is a MySQL extension, not part of 00183 the standard. 00184 00185 SYNOPSIS 00186 sql_errno The error code 00187 level Warning level 00188 00189 RETURN 00190 1 if a handler was found, m_hfound is set to its index (>= 0) 00191 0 if not found, m_hfound is -1 00192 */ 00193 00194 bool 00195 sp_rcontext::find_handler(uint sql_errno, 00196 MYSQL_ERROR::enum_warning_level level) 00197 { 00198 if (m_hfound >= 0) 00199 return 1; // Already got one 00200 00201 const char *sqlstate= mysql_errno_to_sqlstate(sql_errno); 00202 int i= m_hcount, found= -1; 00203 00204 /* Search handlers from the latest (innermost) to the oldest (outermost) */ 00205 while (i--) 00206 { 00207 sp_cond_type_t *cond= m_handler[i].cond; 00208 int j= m_ihsp; 00209 00210 /* Check active handlers, to avoid invoking one recursively */ 00211 while (j--) 00212 if (m_in_handler[j] == m_handler[i].handler) 00213 break; 00214 if (j >= 0) 00215 continue; // Already executing this handler 00216 00217 switch (cond->type) 00218 { 00219 case sp_cond_type_t::number: 00220 if (sql_errno == cond->mysqlerr && 00221 (found < 0 || m_handler[found].cond->type > sp_cond_type_t::number)) 00222 found= i; // Always the most specific 00223 break; 00224 case sp_cond_type_t::state: 00225 if (strcmp(sqlstate, cond->sqlstate) == 0 && 00226 (found < 0 || m_handler[found].cond->type > sp_cond_type_t::state)) 00227 found= i; 00228 break; 00229 case sp_cond_type_t::warning: 00230 if ((IS_WARNING_CONDITION(sqlstate) || 00231 level == MYSQL_ERROR::WARN_LEVEL_WARN) && 00232 found < 0) 00233 found= i; 00234 break; 00235 case sp_cond_type_t::notfound: 00236 if (IS_NOT_FOUND_CONDITION(sqlstate) && found < 0) 00237 found= i; 00238 break; 00239 case sp_cond_type_t::exception: 00240 if (IS_EXCEPTION_CONDITION(sqlstate) && 00241 level == MYSQL_ERROR::WARN_LEVEL_ERROR && 00242 found < 0) 00243 found= i; 00244 break; 00245 } 00246 } 00247 if (found < 0) 00248 { 00249 /* 00250 Only "exception conditions" are propagated to handlers in calling 00251 contexts. If no handler is found locally for a "completion condition" 00252 (warning or "not found") we will simply resume execution. 00253 */ 00254 if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) && 00255 level == MYSQL_ERROR::WARN_LEVEL_ERROR) 00256 return m_prev_runtime_ctx->find_handler(sql_errno, level); 00257 return FALSE; 00258 } 00259 m_hfound= found; 00260 return TRUE; 00261 } 00262 00263 00264 void 00265 sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i) 00266 { 00267 m_cstack[m_ccount++]= new sp_cursor(lex_keeper, i); 00268 } 00269 00270 00271 void 00272 sp_rcontext::pop_cursors(uint count) 00273 { 00274 while (count--) 00275 { 00276 delete m_cstack[--m_ccount]; 00277 } 00278 } 00279 00280 00281 int 00282 sp_rcontext::set_variable(THD *thd, uint var_idx, Item **value) 00283 { 00284 return set_variable(thd, m_var_table->field[var_idx], value); 00285 } 00286 00287 00288 int 00289 sp_rcontext::set_variable(THD *thd, Field *field, Item **value) 00290 { 00291 if (!value) 00292 { 00293 field->set_null(); 00294 return 0; 00295 } 00296 00297 return sp_eval_expr(thd, field, value); 00298 } 00299 00300 00301 Item * 00302 sp_rcontext::get_item(uint var_idx) 00303 { 00304 return m_var_items[var_idx]; 00305 } 00306 00307 00308 Item ** 00309 sp_rcontext::get_item_addr(uint var_idx) 00310 { 00311 return m_var_items + var_idx; 00312 } 00313 00314 00315 /* 00316 * 00317 * sp_cursor 00318 * 00319 */ 00320 00321 sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i) 00322 :m_lex_keeper(lex_keeper), 00323 server_side_cursor(NULL), 00324 m_i(i) 00325 { 00326 /* 00327 currsor can't be stored in QC, so we should prevent opening QC for 00328 try to write results which are absent. 00329 */ 00330 lex_keeper->disable_query_cache(); 00331 } 00332 00333 00334 /* 00335 Open an SP cursor 00336 00337 SYNOPSIS 00338 open() 00339 THD Thread handler 00340 00341 00342 RETURN 00343 0 in case of success, -1 otherwise 00344 */ 00345 00346 int 00347 sp_cursor::open(THD *thd) 00348 { 00349 if (server_side_cursor) 00350 { 00351 my_message(ER_SP_CURSOR_ALREADY_OPEN, ER(ER_SP_CURSOR_ALREADY_OPEN), 00352 MYF(0)); 00353 return -1; 00354 } 00355 if (mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR, &result, 00356 &server_side_cursor)) 00357 return -1; 00358 return 0; 00359 } 00360 00361 00362 int 00363 sp_cursor::close(THD *thd) 00364 { 00365 if (! server_side_cursor) 00366 { 00367 my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0)); 00368 return -1; 00369 } 00370 destroy(); 00371 return 0; 00372 } 00373 00374 00375 void 00376 sp_cursor::destroy() 00377 { 00378 delete server_side_cursor; 00379 server_side_cursor= 0; 00380 } 00381 00382 00383 int 00384 sp_cursor::fetch(THD *thd, List<struct sp_variable> *vars) 00385 { 00386 if (! server_side_cursor) 00387 { 00388 my_message(ER_SP_CURSOR_NOT_OPEN, ER(ER_SP_CURSOR_NOT_OPEN), MYF(0)); 00389 return -1; 00390 } 00391 if (vars->elements != result.get_field_count()) 00392 { 00393 my_message(ER_SP_WRONG_NO_OF_FETCH_ARGS, 00394 ER(ER_SP_WRONG_NO_OF_FETCH_ARGS), MYF(0)); 00395 return -1; 00396 } 00397 00398 result.set_spvar_list(vars); 00399 00400 /* Attempt to fetch one row */ 00401 if (server_side_cursor->is_open()) 00402 server_side_cursor->fetch(1); 00403 00404 /* 00405 If the cursor was pointing after the last row, the fetch will 00406 close it instead of sending any rows. 00407 */ 00408 if (! server_side_cursor->is_open()) 00409 { 00410 my_message(ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA), MYF(0)); 00411 return -1; 00412 } 00413 00414 return 0; 00415 } 00416 00417 00418 /* 00419 Create an instance of appropriate Item_cache class depending on the 00420 specified type in the callers arena. 00421 00422 SYNOPSIS 00423 thd thread handler 00424 result_type type of the expression 00425 00426 RETURN 00427 Pointer to valid object on success 00428 NULL on error 00429 00430 NOTE 00431 We should create cache items in the callers arena, as they are used 00432 between in several instructions. 00433 */ 00434 00435 Item_cache * 00436 sp_rcontext::create_case_expr_holder(THD *thd, Item_result result_type) 00437 { 00438 Item_cache *holder; 00439 Query_arena current_arena; 00440 00441 thd->set_n_backup_active_arena(thd->spcont->callers_arena, ¤t_arena); 00442 00443 holder= Item_cache::get_cache(result_type); 00444 00445 thd->restore_active_arena(thd->spcont->callers_arena, ¤t_arena); 00446 00447 return holder; 00448 } 00449 00450 00451 /* 00452 Set CASE expression to the specified value. 00453 00454 SYNOPSIS 00455 thd thread handler 00456 case_expr_id identifier of the CASE expression 00457 case_expr_item a value of the CASE expression 00458 00459 RETURN 00460 FALSE on success 00461 TRUE on error 00462 00463 NOTE 00464 The idea is to reuse Item_cache for the expression of the one CASE 00465 statement. This optimization takes place when there is CASE statement 00466 inside of a loop. So, in other words, we will use the same object on each 00467 iteration instead of creating a new one for each iteration. 00468 00469 TODO 00470 Hypothetically, a type of CASE expression can be different for each 00471 iteration. For instance, this can happen if the expression contains a 00472 session variable (something like @@VAR) and its type is changed from one 00473 iteration to another. 00474 00475 In order to cope with this problem, we check type each time, when we use 00476 already created object. If the type does not match, we re-create Item. 00477 This also can (should?) be optimized. 00478 */ 00479 00480 int 00481 sp_rcontext::set_case_expr(THD *thd, int case_expr_id, Item **case_expr_item_ptr) 00482 { 00483 Item *case_expr_item= sp_prepare_func_item(thd, case_expr_item_ptr); 00484 if (!case_expr_item) 00485 return TRUE; 00486 00487 if (!m_case_expr_holders[case_expr_id] || 00488 m_case_expr_holders[case_expr_id]->result_type() != 00489 case_expr_item->result_type()) 00490 { 00491 m_case_expr_holders[case_expr_id]= 00492 create_case_expr_holder(thd, case_expr_item->result_type()); 00493 } 00494 00495 m_case_expr_holders[case_expr_id]->store(case_expr_item); 00496 00497 return FALSE; 00498 } 00499 00500 00501 Item * 00502 sp_rcontext::get_case_expr(int case_expr_id) 00503 { 00504 return m_case_expr_holders[case_expr_id]; 00505 } 00506 00507 00508 Item ** 00509 sp_rcontext::get_case_expr_addr(int case_expr_id) 00510 { 00511 return (Item**) m_case_expr_holders + case_expr_id; 00512 } 00513 00514 00515 /*************************************************************************** 00516 Select_fetch_into_spvars 00517 ****************************************************************************/ 00518 00519 int Select_fetch_into_spvars::prepare(List<Item> &fields, SELECT_LEX_UNIT *u) 00520 { 00521 /* 00522 Cache the number of columns in the result set in order to easily 00523 return an error if column count does not match value count. 00524 */ 00525 field_count= fields.elements; 00526 return select_result_interceptor::prepare(fields, u); 00527 } 00528 00529 00530 bool Select_fetch_into_spvars::send_data(List<Item> &items) 00531 { 00532 List_iterator_fast<struct sp_variable> spvar_iter(*spvar_list); 00533 List_iterator_fast<Item> item_iter(items); 00534 sp_variable_t *spvar; 00535 Item *item; 00536 00537 /* Must be ensured by the caller */ 00538 DBUG_ASSERT(spvar_list->elements == items.elements); 00539 00540 /* 00541 Assign the row fetched from a server side cursor to stored 00542 procedure variables. 00543 */ 00544 for (; spvar= spvar_iter++, item= item_iter++; ) 00545 { 00546 if (thd->spcont->set_variable(thd, spvar->offset, &item)) 00547 return TRUE; 00548 } 00549 return FALSE; 00550 }
1.4.7

