#include "univ.i"#include "data0data.h"#include "que0types.h"#include "dict0types.h"#include "trx0types.h"#include "row0types.h"#include "pars0sym.h"#include "btr0pcur.h"#include "read0read.h"#include "row0mysql.h"Include dependency graph for row0sel.h:

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.
| #define ROW_SEL_EXACT 1 |
| #define ROW_SEL_EXACT_PREFIX 2 |
| #define ROW_SEL_NEXT 1 |
Definition at line 366 of file row0sel.h.
Referenced by row_scan_and_check_index(), and row_search_for_mysql().
| #define SEL_NODE_CLOSED 0 |
Definition at line 319 of file row0sel.h.
Referenced by fetch_step(), and pars_cursor_declaration().
| #define SEL_NODE_FETCH 2 |
Definition at line 323 of file row0sel.h.
Referenced by row_ins_step(), row_printf_step(), row_sel_step(), and row_upd_step().
| #define SEL_NODE_NO_MORE_ROWS 3 |
Definition at line 324 of file row0sel.h.
Referenced by eval_notfound(), fetch_step(), row_ins_step(), row_printf_step(), row_sel(), and row_upd_step().
| #define SEL_NODE_OPEN 1 |
Definition at line 321 of file row0sel.h.
Referenced by pars_select_statement(), row_ins_step(), row_printf_step(), row_sel_step(), row_upd_step(), and sel_node_create().
Definition at line 1986 of file row0sel.c.
References pars_user_func_struct::arg, sel_node_struct::common, fetch_node_struct::cursor_def, DB_ERROR, trx_struct::error_state, fetch_node_struct::func, pars_user_func_struct::func, fetch_node_struct::into_list, NULL, que_common_struct::parent, que_thr_struct::prev_node, QUE_NODE_FETCH, que_node_get_parent(), que_node_get_type(), que_thr_struct::run_node, sel_assign_into_var_values(), SEL_NODE_CLOSED, SEL_NODE_NO_MORE_ROWS, sel_node_struct::state, thr_get_trx(), and ut_ad.
Referenced by que_thr_step().
01988 : query thread to run next or NULL */ 01989 que_thr_t* thr) /* in: query thread */ 01990 { 01991 sel_node_t* sel_node; 01992 fetch_node_t* node; 01993 01994 ut_ad(thr); 01995 01996 node = thr->run_node; 01997 sel_node = node->cursor_def; 01998 01999 ut_ad(que_node_get_type(node) == QUE_NODE_FETCH); 02000 02001 if (thr->prev_node != que_node_get_parent(node)) { 02002 02003 if (sel_node->state != SEL_NODE_NO_MORE_ROWS) { 02004 02005 if (node->into_list) { 02006 sel_assign_into_var_values(node->into_list, 02007 sel_node); 02008 } else { 02009 void* ret = (*node->func->func)(sel_node, 02010 node->func->arg); 02011 02012 if (!ret) { 02013 sel_node->state = 02014 SEL_NODE_NO_MORE_ROWS; 02015 } 02016 } 02017 } 02018 02019 thr->run_node = que_node_get_parent(node); 02020 02021 return(thr); 02022 } 02023 02024 /* Make the fetch node the parent of the cursor definition for 02025 the time of the fetch, so that execution knows to return to this 02026 fetch node after a row has been selected or we know that there is 02027 no row left */ 02028 02029 sel_node->common.parent = node; 02030 02031 if (sel_node->state == SEL_NODE_CLOSED) { 02032 fprintf(stderr, 02033 "InnoDB: Error: fetch called on a closed cursor\n"); 02034 02035 thr_get_trx(thr)->error_state = DB_ERROR; 02036 02037 return(NULL); 02038 } 02039 02040 thr->run_node = sel_node; 02041 02042 return(thr); 02043 }
Here is the call graph for this function:

Here is the caller graph for this function:

| void* row_fetch_print | ( | void * | row, | |
| void * | user_arg | |||
| ) |
Definition at line 2049 of file row0sel.c.
References dfield_get_data(), dfield_get_len(), dfield_get_type(), dtype_print(), que_node_get_next(), que_node_get_val(), sel_node_struct::select_list, UT_NOT_USED, and ut_print_buf().
02051 : always returns non-NULL */ 02052 void* row, /* in: sel_node_t* */ 02053 void* user_arg) /* in: not used */ 02054 { 02055 sel_node_t* node = row; 02056 que_node_t* exp; 02057 ulint i = 0; 02058 02059 UT_NOT_USED(user_arg); 02060 02061 fprintf(stderr, "row_fetch_print: row %p\n", row); 02062 02063 exp = node->select_list; 02064 02065 while (exp) { 02066 dfield_t* dfield = que_node_get_val(exp); 02067 dtype_t* type = dfield_get_type(dfield); 02068 02069 fprintf(stderr, " column %lu:\n", (ulong)i); 02070 02071 dtype_print(type); 02072 fprintf(stderr, "\n"); 02073 02074 if (dfield_get_len(dfield) != UNIV_SQL_NULL) { 02075 ut_print_buf(stderr, dfield_get_data(dfield), 02076 dfield_get_len(dfield)); 02077 } else { 02078 fprintf(stderr, " <NULL>;"); 02079 } 02080 02081 fprintf(stderr, "\n"); 02082 02083 exp = que_node_get_next(exp); 02084 i++; 02085 } 02086 02087 return((void*)42); 02088 }
Here is the call graph for this function:

| void* row_fetch_store_uint4 | ( | void * | row, | |
| void * | user_arg | |||
| ) |
Definition at line 2096 of file row0sel.c.
References DATA_INT, DATA_UNSIGNED, dfield_get_data(), dfield_get_len(), dfield_get_type(), dtype_get_mtype(), dtype_get_prtype(), mach_read_from_4(), NULL, que_node_get_val(), sel_node_struct::select_list, and ut_a.
02098 : always returns NULL */ 02099 void* row, /* in: sel_node_t* */ 02100 void* user_arg) /* in: data pointer */ 02101 { 02102 sel_node_t* node = row; 02103 ib_uint32_t* val = user_arg; 02104 ulint tmp; 02105 02106 dfield_t* dfield = que_node_get_val(node->select_list); 02107 dtype_t* type = dfield_get_type(dfield); 02108 ulint len = dfield_get_len(dfield); 02109 02110 ut_a(dtype_get_mtype(type) == DATA_INT); 02111 ut_a(dtype_get_prtype(type) & DATA_UNSIGNED); 02112 ut_a(len == 4); 02113 02114 tmp = mach_read_from_4(dfield_get_data(dfield)); 02115 *val = tmp; 02116 02117 return(NULL); 02118 }
Here is the call graph for this function:

Definition at line 2124 of file row0sel.c.
References dfield_print_also_hex(), que_thr_struct::prev_node, que_node_get_next(), que_node_get_parent(), que_node_get_type(), que_node_get_val(), QUE_NODE_ROW_PRINTF, que_thr_struct::run_node, row_printf_node_struct::sel_node, SEL_NODE_FETCH, SEL_NODE_NO_MORE_ROWS, SEL_NODE_OPEN, sel_node_struct::select_list, sel_node_struct::state, and ut_ad.
Referenced by que_thr_step().
02126 : query thread to run next or NULL */ 02127 que_thr_t* thr) /* in: query thread */ 02128 { 02129 row_printf_node_t* node; 02130 sel_node_t* sel_node; 02131 que_node_t* arg; 02132 02133 ut_ad(thr); 02134 02135 node = thr->run_node; 02136 02137 sel_node = node->sel_node; 02138 02139 ut_ad(que_node_get_type(node) == QUE_NODE_ROW_PRINTF); 02140 02141 if (thr->prev_node == que_node_get_parent(node)) { 02142 02143 /* Reset the cursor */ 02144 sel_node->state = SEL_NODE_OPEN; 02145 02146 /* Fetch next row to print */ 02147 02148 thr->run_node = sel_node; 02149 02150 return(thr); 02151 } 02152 02153 if (sel_node->state != SEL_NODE_FETCH) { 02154 02155 ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS); 02156 02157 /* No more rows to print */ 02158 02159 thr->run_node = que_node_get_parent(node); 02160 02161 return(thr); 02162 } 02163 02164 arg = sel_node->select_list; 02165 02166 while (arg) { 02167 dfield_print_also_hex(que_node_get_val(arg)); 02168 02169 fputs(" ::: ", stderr); 02170 02171 arg = que_node_get_next(arg); 02172 } 02173 02174 putc('\n', stderr); 02175 02176 /* Fetch next row to print */ 02177 02178 thr->run_node = sel_node; 02179 02180 return(thr); 02181 }
Here is the call graph for this function:

Here is the caller graph for this function:

| ibool row_search_check_if_query_cache_permitted | ( | trx_t * | trx, | |
| const char * | norm_name | |||
| ) |
Definition at line 4405 of file row0sel.c.
References dict_table_get(), FALSE, trx_struct::global_read_view, trx_struct::global_read_view_heap, trx_struct::id, trx_struct::isolation_level, kernel_mutex, dict_table_struct::locks, mutex_enter, mutex_exit(), NULL, dict_table_struct::query_cache_inv_trx_id, trx_struct::read_view, read_view_open_now(), TRUE, TRX_ISO_REPEATABLE_READ, trx_start_if_not_started_low(), ut_dulint_cmp(), and UT_LIST_GET_LEN.
04407 : TRUE if storing or retrieving 04408 from the query cache is permitted */ 04409 trx_t* trx, /* in: transaction object */ 04410 const char* norm_name) /* in: concatenation of database name, 04411 '/' char, table name */ 04412 { 04413 dict_table_t* table; 04414 ibool ret = FALSE; 04415 04416 table = dict_table_get(norm_name); 04417 04418 if (table == NULL) { 04419 04420 return(FALSE); 04421 } 04422 04423 mutex_enter(&kernel_mutex); 04424 04425 /* Start the transaction if it is not started yet */ 04426 04427 trx_start_if_not_started_low(trx); 04428 04429 /* If there are locks on the table or some trx has invalidated the 04430 cache up to our trx id, then ret = FALSE. 04431 We do not check what type locks there are on the table, though only 04432 IX type locks actually would require ret = FALSE. */ 04433 04434 if (UT_LIST_GET_LEN(table->locks) == 0 04435 && ut_dulint_cmp(trx->id, 04436 table->query_cache_inv_trx_id) >= 0) { 04437 04438 ret = TRUE; 04439 04440 /* If the isolation level is high, assign a read view for the 04441 transaction if it does not yet have one */ 04442 04443 if (trx->isolation_level >= TRX_ISO_REPEATABLE_READ 04444 && !trx->read_view) { 04445 04446 trx->read_view = read_view_open_now(trx->id, 04447 trx->global_read_view_heap); 04448 trx->global_read_view = trx->read_view; 04449 } 04450 } 04451 04452 mutex_exit(&kernel_mutex); 04453 04454 return(ret); 04455 }
Here is the call graph for this function:

| ulint row_search_for_mysql | ( | byte * | buf, | |
| ulint | mode, | |||
| row_prebuilt_t * | prebuilt, | |||
| ulint | match_mode, | |||
| ulint | direction | |||
| ) |
Definition at line 3175 of file row0sel.c.
References btr_index_rec_validate(), btr_pcur_get_rec(), btr_pcur_move_to_last_on_page(), btr_pcur_move_to_next(), btr_pcur_move_to_prev(), btr_pcur_open_at_index_side(), btr_pcur_open_with_no_init(), btr_pcur_store_position(), BTR_SEA_TIMEOUT, btr_search_latch, BTR_SEARCH_LEAF, buf_block_align(), buf_frame_align(), buf_frame_get_page_no(), buf_page_print(), buf_pool, row_prebuilt_struct::clust_index_was_generated, cmp_dtuple_is_prefix_of_rec(), cmp_dtuple_rec(), DB_CORRUPTION, DB_END_OF_INDEX, DB_ERROR, DB_LOCK_WAIT, DB_RECORD_NOT_FOUND, DB_SUCCESS, DB_TOO_BIG_RECORD, DICT_CLUSTERED, dict_index_get_n_unique(), dict_index_name_print(), dict_str_starts_with_keyword(), dict_table_get_first_index(), dict_table_is_comp(), DICT_UNIQUE, dtuple_contains_null(), dtuple_get_n_fields(), dtuple_get_n_fields_cmp(), err, trx_struct::error_state, FALSE, row_prebuilt_struct::fetch_cache_first, row_prebuilt_struct::fetch_direction, buf_pool_struct::frame_zero, trx_struct::has_search_latch, buf_pool_struct::high_end, dict_table_struct::ibd_file_missing, index(), row_prebuilt_struct::index, trx_struct::isolation_level, kernel_mutex, lock_cancel_waiting_and_release(), lock_clust_rec_cons_read_sees(), LOCK_GAP, LOCK_IS, LOCK_IX, LOCK_NONE, LOCK_ORDINARY, LOCK_REC_NOT_GAP, LOCK_S, lock_sec_rec_cons_read_sees(), que_thr_struct::lock_state, lock_table(), mach_write_to_4(), row_prebuilt_struct::magic_n, mem_analyze_corruption(), mem_heap_free, memcpy, mtr_commit(), mtr_start(), mutex_enter, mutex_exit(), MYSQL_FETCH_CACHE_SIZE, MYSQL_FETCH_CACHE_THRESHOLD, trx_struct::mysql_n_tables_locked, trx_struct::mysql_query_str, row_prebuilt_struct::mysql_row_len, trx_struct::mysql_thd, trx_struct::mysql_thread_id, row_prebuilt_struct::n_fetch_cached, trx_struct::n_mysql_tables_in_use, row_prebuilt_struct::n_rows_fetched, dict_table_struct::name, row_prebuilt_struct::need_to_access_clustered, NULL, trx_struct::op_info, os_thread_get_curr_id(), PAGE_CUR_G, PAGE_CUR_GE, PAGE_CUR_L, PAGE_DIR, PAGE_NEW_SUPREMUM, PAGE_OLD_SUPREMUM, page_rec_is_comp(), page_rec_is_infimum(), page_rec_is_supremum(), row_prebuilt_struct::pcur, que_fork_get_first_thr(), QUE_THR_LOCK_NOLOCK, QUE_THR_LOCK_ROW, que_thr_move_to_run_state_for_mysql(), que_thr_stop_for_mysql(), que_thr_stop_for_mysql_no_error(), trx_struct::read_view, rec_get_deleted_flag(), rec_get_next_offs(), rec_get_offsets, rec_offs_extra_size(), REC_OFFS_NORMAL_SIZE, rec_offs_size(), rec_offs_validate(), rec_validate(), ROW_MYSQL_DUMMY_TEMPLATE, row_mysql_handle_errors(), row_prebuild_sel_graph(), ROW_PREBUILT_ALLOCATED, ROW_READ_DID_SEMI_CONSISTENT, ROW_READ_TRY_SEMI_CONSISTENT, row_prebuilt_struct::row_read_type, ROW_READ_WITH_LOCKS, row_sel_build_committed_vers_for_mysql(), row_sel_build_prev_vers_for_mysql(), ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX, row_sel_get_clust_rec_for_mysql(), ROW_SEL_NEXT, row_sel_pop_cached_row_for_mysql(), row_sel_push_cache_row_for_mysql(), row_sel_store_mysql_rec(), row_sel_store_row_id_to_prebuilt(), row_sel_try_search_shortcut_for_mysql(), row_unlock_for_mysql(), RW_LOCK_NOT_LOCKED, rw_lock_s_lock, rw_lock_s_unlock, trx_struct::search_latch_timeout, btr_pcur_struct::search_mode, row_prebuilt_struct::search_tuple, SEL_EXHAUSTED, SEL_FOUND, row_prebuilt_struct::sel_graph, sel_restore_position_for_mysql(), sel_set_rec_lock(), row_prebuilt_struct::select_lock_type, row_prebuilt_struct::sql_stat_start, srv_force_recovery, srv_locks_unsafe_for_binlog, srv_n_rows_read, row_prebuilt_struct::table, row_prebuilt_struct::templ_contains_blob, row_prebuilt_struct::template_type, TRUE, row_prebuilt_struct::trx, trx_assign_read_view(), btr_pcur_struct::trx_if_known, TRX_ISO_READ_COMMITTED, TRX_ISO_READ_UNCOMMITTED, trx_print(), trx_reset_new_rec_lock_info(), trx_start_if_not_started(), UNIV_PAGE_SIZE, row_prebuilt_struct::used_in_HANDLER, ut_a, ut_ad, ut_align_offset(), ut_error, ut_print_name(), ut_print_timestamp(), trx_struct::wait_lock, and trx_struct::was_chosen_as_deadlock_victim.
Referenced by row_scan_and_check_index().
03177 : DB_SUCCESS, 03178 DB_RECORD_NOT_FOUND, 03179 DB_END_OF_INDEX, DB_DEADLOCK, 03180 DB_LOCK_TABLE_FULL, DB_CORRUPTION, 03181 or DB_TOO_BIG_RECORD */ 03182 byte* buf, /* in/out: buffer for the fetched 03183 row in the MySQL format */ 03184 ulint mode, /* in: search mode PAGE_CUR_L, ... */ 03185 row_prebuilt_t* prebuilt, /* in: prebuilt struct for the 03186 table handle; this contains the info 03187 of search_tuple, index; if search 03188 tuple contains 0 fields then we 03189 position the cursor at the start or 03190 the end of the index, depending on 03191 'mode' */ 03192 ulint match_mode, /* in: 0 or ROW_SEL_EXACT or 03193 ROW_SEL_EXACT_PREFIX */ 03194 ulint direction) /* in: 0 or ROW_SEL_NEXT or 03195 ROW_SEL_PREV; NOTE: if this is != 0, 03196 then prebuilt must have a pcur 03197 with stored position! In opening of a 03198 cursor 'direction' should be 0. */ 03199 { 03200 dict_index_t* index = prebuilt->index; 03201 ibool comp = dict_table_is_comp(index->table); 03202 dtuple_t* search_tuple = prebuilt->search_tuple; 03203 btr_pcur_t* pcur = prebuilt->pcur; 03204 trx_t* trx = prebuilt->trx; 03205 dict_index_t* clust_index; 03206 que_thr_t* thr; 03207 rec_t* rec; 03208 rec_t* result_rec; 03209 rec_t* clust_rec; 03210 ulint err = DB_SUCCESS; 03211 ibool unique_search = FALSE; 03212 ibool unique_search_from_clust_index = FALSE; 03213 ibool mtr_has_extra_clust_latch = FALSE; 03214 ibool moves_up = FALSE; 03215 ibool set_also_gap_locks = TRUE; 03216 /* if the query is a plain 03217 locking SELECT, and the isolation 03218 level is <= TRX_ISO_READ_COMMITTED, 03219 then this is set to FALSE */ 03220 ibool did_semi_consistent_read = FALSE; 03221 /* if the returned record was locked 03222 and we did a semi-consistent read 03223 (fetch the newest committed version), 03224 then this is set to TRUE */ 03225 #ifdef UNIV_SEARCH_DEBUG 03226 ulint cnt = 0; 03227 #endif /* UNIV_SEARCH_DEBUG */ 03228 ulint next_offs; 03229 ibool same_user_rec; 03230 mtr_t mtr; 03231 mem_heap_t* heap = NULL; 03232 ulint offsets_[REC_OFFS_NORMAL_SIZE]; 03233 ulint* offsets = offsets_; 03234 03235 *offsets_ = (sizeof offsets_) / sizeof *offsets_; 03236 03237 ut_ad(index && pcur && search_tuple); 03238 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); 03239 03240 if (UNIV_UNLIKELY(prebuilt->table->ibd_file_missing)) { 03241 ut_print_timestamp(stderr); 03242 fprintf(stderr, " InnoDB: Error:\n" 03243 "InnoDB: MySQL is trying to use a table handle but the .ibd file for\n" 03244 "InnoDB: table %s does not exist.\n" 03245 "InnoDB: Have you deleted the .ibd file from the database directory under\n" 03246 "InnoDB: the MySQL datadir, or have you used DISCARD TABLESPACE?\n" 03247 "InnoDB: Look from\n" 03248 "http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n" 03249 "InnoDB: how you can resolve the problem.\n", 03250 prebuilt->table->name); 03251 03252 return(DB_ERROR); 03253 } 03254 03255 if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) { 03256 fprintf(stderr, 03257 "InnoDB: Error: trying to free a corrupt\n" 03258 "InnoDB: table handle. Magic n %lu, table name ", 03259 (ulong) prebuilt->magic_n); 03260 ut_print_name(stderr, trx, TRUE, prebuilt->table->name); 03261 putc('\n', stderr); 03262 03263 mem_analyze_corruption(prebuilt); 03264 03265 ut_error; 03266 } 03267 03268 if (trx->n_mysql_tables_in_use == 0 03269 && UNIV_UNLIKELY(prebuilt->select_lock_type == LOCK_NONE)) { 03270 /* Note that if MySQL uses an InnoDB temp table that it 03271 created inside LOCK TABLES, then n_mysql_tables_in_use can 03272 be zero; in that case select_lock_type is set to LOCK_X in 03273 ::start_stmt. */ 03274 03275 /* August 19, 2005 by Heikki: temporarily disable this error print until the 03276 cursor lock count is done correctly. See bugs #12263 and #12456! 03277 03278 fputs( 03279 "InnoDB: Error: MySQL is trying to perform a SELECT\n" 03280 "InnoDB: but it has not locked any tables in ::external_lock()!\n", 03281 stderr); 03282 trx_print(stderr, trx, 600); 03283 fputc('\n', stderr); 03284 */ 03285 03286 } 03287 03288 /* fprintf(stderr, "Match mode %lu\n search tuple ", (ulong) match_mode); 03289 dtuple_print(search_tuple); 03290 03291 fprintf(stderr, "N tables locked %lu\n", trx->mysql_n_tables_locked); 03292 */ 03293 /*-------------------------------------------------------------*/ 03294 /* PHASE 0: Release a possible s-latch we are holding on the 03295 adaptive hash index latch if there is someone waiting behind */ 03296 03297 if (UNIV_UNLIKELY(btr_search_latch.writer != RW_LOCK_NOT_LOCKED) 03298 && trx->has_search_latch) { 03299 03300 /* There is an x-latch request on the adaptive hash index: 03301 release the s-latch to reduce starvation and wait for 03302 BTR_SEA_TIMEOUT rounds before trying to keep it again over 03303 calls from MySQL */ 03304 03305 rw_lock_s_unlock(&btr_search_latch); 03306 trx->has_search_latch = FALSE; 03307 03308 trx->search_latch_timeout = BTR_SEA_TIMEOUT; 03309 } 03310 03311 /* Reset the new record lock info if srv_locks_unsafe_for_binlog 03312 is set or session is using a READ COMMITED isolation level. Then 03313 we are able to remove the record locks set here on an individual 03314 row. */ 03315 03316 if ((srv_locks_unsafe_for_binlog 03317 || trx->isolation_level == TRX_ISO_READ_COMMITTED) 03318 && prebuilt->select_lock_type != LOCK_NONE) { 03319 03320 trx_reset_new_rec_lock_info(trx); 03321 } 03322 03323 /*-------------------------------------------------------------*/ 03324 /* PHASE 1: Try to pop the row from the prefetch cache */ 03325 03326 if (UNIV_UNLIKELY(direction == 0)) { 03327 trx->op_info = "starting index read"; 03328 03329 prebuilt->n_rows_fetched = 0; 03330 prebuilt->n_fetch_cached = 0; 03331 prebuilt->fetch_cache_first = 0; 03332 03333 if (prebuilt->sel_graph == NULL) { 03334 /* Build a dummy select query graph */ 03335 row_prebuild_sel_graph(prebuilt); 03336 } 03337 } else { 03338 trx->op_info = "fetching rows"; 03339 03340 if (prebuilt->n_rows_fetched == 0) { 03341 prebuilt->fetch_direction = direction; 03342 } 03343 03344 if (UNIV_UNLIKELY(direction != prebuilt->fetch_direction)) { 03345 if (UNIV_UNLIKELY(prebuilt->n_fetch_cached > 0)) { 03346 ut_error; 03347 /* TODO: scrollable cursor: restore cursor to 03348 the place of the latest returned row, 03349 or better: prevent caching for a scroll 03350 cursor! */ 03351 } 03352 03353 prebuilt->n_rows_fetched = 0; 03354 prebuilt->n_fetch_cached = 0; 03355 prebuilt->fetch_cache_first = 0; 03356 03357 } else if (UNIV_LIKELY(prebuilt->n_fetch_cached > 0)) { 03358 row_sel_pop_cached_row_for_mysql(buf, prebuilt); 03359 03360 prebuilt->n_rows_fetched++; 03361 03362 srv_n_rows_read++; 03363 err = DB_SUCCESS; 03364 goto func_exit; 03365 } 03366 03367 if (prebuilt->fetch_cache_first > 0 03368 && prebuilt->fetch_cache_first < MYSQL_FETCH_CACHE_SIZE) { 03369 03370 /* The previous returned row was popped from the fetch 03371 cache, but the cache was not full at the time of the 03372 popping: no more rows can exist in the result set */ 03373 03374 err = DB_RECORD_NOT_FOUND; 03375 goto func_exit; 03376 } 03377 03378 prebuilt->n_rows_fetched++; 03379 03380 if (prebuilt->n_rows_fetched > 1000000000) { 03381 /* Prevent wrap-over */ 03382 prebuilt->n_rows_fetched = 500000000; 03383 } 03384 03385 mode = pcur->search_mode; 03386 } 03387 03388 /* In a search where at most one record in the index may match, we 03389 can use a LOCK_REC_NOT_GAP type record lock when locking a non-delete- 03390 marked matching record. 03391 03392 Note that in a unique secondary index there may be different delete- 03393 marked versions of a record where only the primary key values differ: 03394 thus in a secondary index we must use next-key locks when locking 03395 delete-marked records. */ 03396 03397 if (match_mode == ROW_SEL_EXACT 03398 && index->type & DICT_UNIQUE 03399 && dtuple_get_n_fields(search_tuple) 03400 == dict_index_get_n_unique(index) 03401 && (index->type & DICT_CLUSTERED 03402 || !dtuple_contains_null(search_tuple))) { 03403 03404 /* Note above that a UNIQUE secondary index can contain many 03405 rows with the same key value if one of the columns is the SQL 03406 null. A clustered index under MySQL can never contain null 03407 columns because we demand that all the columns in primary key 03408 are non-null. */ 03409 03410 unique_search = TRUE; 03411 03412 /* Even if the condition is unique, MySQL seems to try to 03413 retrieve also a second row if a primary key contains more than 03414 1 column. Return immediately if this is not a HANDLER 03415 command. */ 03416 03417 if (UNIV_UNLIKELY(direction != 0 && 03418 !prebuilt->used_in_HANDLER)) { 03419 03420 err = DB_RECORD_NOT_FOUND; 03421 goto func_exit; 03422 } 03423 } 03424 03425 mtr_start(&mtr); 03426 03427 /*-------------------------------------------------------------*/ 03428 /* PHASE 2: Try fast adaptive hash index search if possible */ 03429 03430 /* Next test if this is the special case where we can use the fast 03431 adaptive hash index to try the search. Since we must release the 03432 search system latch when we retrieve an externally stored field, we 03433 cannot use the adaptive hash index in a search in the case the row 03434 may be long and there may be externally stored fields */ 03435 03436 if (UNIV_UNLIKELY(direction == 0) 03437 && unique_search 03438 && index->type & DICT_CLUSTERED 03439 && !prebuilt->templ_contains_blob 03440 && !prebuilt->used_in_HANDLER 03441 && (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8)) { 03442 03443 mode = PAGE_CUR_GE; 03444 03445 unique_search_from_clust_index = TRUE; 03446 03447 if (trx->mysql_n_tables_locked == 0 03448 && prebuilt->select_lock_type == LOCK_NONE 03449 && trx->isolation_level > TRX_ISO_READ_UNCOMMITTED 03450 && trx->read_view) { 03451 03452 /* This is a SELECT query done as a consistent read, 03453 and the read view has already been allocated: 03454 let us try a search shortcut through the hash 03455 index. 03456 NOTE that we must also test that 03457 mysql_n_tables_locked == 0, because this might 03458 also be INSERT INTO ... SELECT ... or 03459 CREATE TABLE ... SELECT ... . Our algorithm is 03460 NOT prepared to inserts interleaved with the SELECT, 03461 and if we try that, we can deadlock on the adaptive 03462 hash index semaphore! */ 03463 03464 #ifndef UNIV_SEARCH_DEBUG 03465 if (!trx->has_search_latch) { 03466 rw_lock_s_lock(&btr_search_latch); 03467 trx->has_search_latch = TRUE; 03468 } 03469 #endif 03470 switch (row_sel_try_search_shortcut_for_mysql(&rec, 03471 prebuilt, &offsets, &heap, &mtr)) { 03472 case SEL_FOUND: 03473 #ifdef UNIV_SEARCH_DEBUG 03474 ut_a(0 == cmp_dtuple_rec(search_tuple, 03475 rec, offsets)); 03476 #endif 03477 if (!row_sel_store_mysql_rec(buf, prebuilt, 03478 rec, offsets)) { 03479 err = DB_TOO_BIG_RECORD; 03480 03481 /* We let the main loop to do the 03482 error handling */ 03483 goto shortcut_fails_too_big_rec; 03484 } 03485 03486 mtr_commit(&mtr); 03487 03488 /* ut_print_name(stderr, index->name); 03489 fputs(" shortcut\n", stderr); */ 03490 03491 srv_n_rows_read++; 03492 03493 if (trx->search_latch_timeout > 0 03494 && trx->has_search_latch) { 03495 03496 trx->search_latch_timeout--; 03497 03498 rw_lock_s_unlock(&btr_search_latch); 03499 trx->has_search_latch = FALSE; 03500 } 03501 03502 /* NOTE that we do NOT store the cursor 03503 position */ 03504 err = DB_SUCCESS; 03505 goto func_exit; 03506 03507 case SEL_EXHAUSTED: 03508 mtr_commit(&mtr); 03509 03510 /* ut_print_name(stderr, index->name); 03511 fputs(" record not found 2\n", stderr); */ 03512 03513 if (trx->search_latch_timeout > 0 03514 && trx->has_search_latch) { 03515 03516 trx->search_latch_timeout--; 03517 03518 rw_lock_s_unlock(&btr_search_latch); 03519 trx->has_search_latch = FALSE; 03520 } 03521 03522 /* NOTE that we do NOT store the cursor 03523 position */ 03524 03525 err = DB_RECORD_NOT_FOUND; 03526 goto func_exit; 03527 } 03528 shortcut_fails_too_big_rec: 03529 mtr_commit(&mtr); 03530 mtr_start(&mtr); 03531 } 03532 } 03533 03534 /*-------------------------------------------------------------*/ 03535 /* PHASE 3: Open or restore index cursor position */ 03536 03537 if (trx->has_search_latch) { 03538 rw_lock_s_unlock(&btr_search_latch); 03539 trx->has_search_latch = FALSE; 03540 } 03541 03542 trx_start_if_not_started(trx); 03543 03544 if (trx->isolation_level <= TRX_ISO_READ_COMMITTED 03545 && prebuilt->select_lock_type != LOCK_NONE 03546 && trx->mysql_query_str && trx->mysql_thd) { 03547 03548 /* Scan the MySQL query string; check if SELECT is the first 03549 word there */ 03550 03551 if (dict_str_starts_with_keyword(trx->mysql_thd, 03552 *trx->mysql_query_str, "SELECT")) { 03553 /* It is a plain locking SELECT and the isolation 03554 level is low: do not lock gaps */ 03555 03556 set_also_gap_locks = FALSE; 03557 } 03558 } 03559 03560 /* Note that if the search mode was GE or G, then the cursor 03561 naturally moves upward (in fetch next) in alphabetical order, 03562 otherwise downward */ 03563 03564 if (UNIV_UNLIKELY(direction == 0)) { 03565 if (mode == PAGE_CUR_GE || mode == PAGE_CUR_G) { 03566 moves_up = TRUE; 03567 } 03568 } else if (direction == ROW_SEL_NEXT) { 03569 moves_up = TRUE; 03570 } 03571 03572 thr = que_fork_get_first_thr(prebuilt->sel_graph); 03573 03574 que_thr_move_to_run_state_for_mysql(thr, trx); 03575 03576 clust_index = dict_table_get_first_index(index->table); 03577 03578 if (UNIV_LIKELY(direction != 0)) { 03579 ibool need_to_process = sel_restore_position_for_mysql( 03580 &same_user_rec, BTR_SEARCH_LEAF, 03581 pcur, moves_up, &mtr); 03582 03583 if (UNIV_UNLIKELY(need_to_process)) { 03584 if (UNIV_UNLIKELY(prebuilt->row_read_type 03585 == ROW_READ_DID_SEMI_CONSISTENT)) { 03586 /* We did a semi-consistent read, 03587 but the record was removed in 03588 the meantime. */ 03589 prebuilt->row_read_type 03590 = ROW_READ_TRY_SEMI_CONSISTENT; 03591 } 03592 } else if (UNIV_LIKELY(prebuilt->row_read_type 03593 != ROW_READ_DID_SEMI_CONSISTENT)) { 03594 03595 /* The cursor was positioned on the record 03596 that we returned previously. If we need 03597 to repeat a semi-consistent read as a 03598 pessimistic locking read, the record 03599 cannot be skipped. */ 03600 03601 goto next_rec; 03602 } 03603 03604 } else if (dtuple_get_n_fields(search_tuple) > 0) { 03605 03606 btr_pcur_open_with_no_init(index, search_tuple, mode, 03607 BTR_SEARCH_LEAF, 03608 pcur, 0, &mtr); 03609 03610 pcur->trx_if_known = trx; 03611 } else { 03612 if (mode == PAGE_CUR_G) { 03613 btr_pcur_open_at_index_side(TRUE, index, 03614 BTR_SEARCH_LEAF, pcur, FALSE, &mtr); 03615 } else if (mode == PAGE_CUR_L) { 03616 btr_pcur_open_at_index_side(FALSE, index, 03617 BTR_SEARCH_LEAF, pcur, FALSE, &mtr); 03618 } 03619 } 03620 03621 if (!prebuilt->sql_stat_start) { 03622 /* No need to set an intention lock or assign a read view */ 03623 03624 if (trx->read_view == NULL 03625 && prebuilt->select_lock_type == LOCK_NONE) { 03626 03627 fputs( 03628 "InnoDB: Error: MySQL is trying to perform a consistent read\n" 03629 "InnoDB: but the read view is not assigned!\n", stderr); 03630 trx_print(stderr, trx, 600); 03631 fputc('\n', stderr); 03632 ut_a(0); 03633 } 03634 } else if (prebuilt->select_lock_type == LOCK_NONE) { 03635 /* This is a consistent read */ 03636 /* Assign a read view for the query */ 03637 03638 trx_assign_read_view(trx); 03639 prebuilt->sql_stat_start = FALSE; 03640 } else { 03641 ulint lock_mode; 03642 if (prebuilt->select_lock_type == LOCK_S) { 03643 lock_mode = LOCK_IS; 03644 } else { 03645 lock_mode = LOCK_IX; 03646 } 03647 err = lock_table(0, index->table, lock_mode, thr); 03648 03649 if (err != DB_SUCCESS) { 03650 03651 goto lock_wait_or_error; 03652 } 03653 prebuilt->sql_stat_start = FALSE; 03654 } 03655 03656 rec_loop: 03657 /*-------------------------------------------------------------*/ 03658 /* PHASE 4: Look for matching records in a loop */ 03659 03660 rec = btr_pcur_get_rec(pcur); 03661 ut_ad(!!page_rec_is_comp(rec) == comp); 03662 #ifdef UNIV_SEARCH_DEBUG 03663 /* 03664 fputs("Using ", stderr); 03665 dict_index_name_print(stderr, index); 03666 fprintf(stderr, " cnt %lu ; Page no %lu\n", cnt, 03667 buf_frame_get_page_no(buf_frame_align(rec))); 03668 rec_print(rec); 03669 */ 03670 #endif /* UNIV_SEARCH_DEBUG */ 03671 03672 if (page_rec_is_infimum(rec)) { 03673 03674 /* The infimum record on a page cannot be in the result set, 03675 and neither can a record lock be placed on it: we skip such 03676 a record. */ 03677 03678 goto next_rec; 03679 } 03680 03681 if (page_rec_is_supremum(rec)) { 03682 03683 if (set_also_gap_locks 03684 && !(srv_locks_unsafe_for_binlog 03685 || trx->isolation_level == TRX_ISO_READ_COMMITTED) 03686 && prebuilt->select_lock_type != LOCK_NONE) { 03687 03688 /* Try to place a lock on the index record */ 03689 03690 /* If innodb_locks_unsafe_for_binlog option is used 03691 or this session is using a READ COMMITTED isolation 03692 level we do not lock gaps. Supremum record is really 03693 a gap and therefore we do not set locks there. */ 03694 03695 offsets = rec_get_offsets(rec, index, offsets, 03696 ULINT_UNDEFINED, &heap); 03697 err = sel_set_rec_lock(rec, index, offsets, 03698 prebuilt->select_lock_type, 03699 LOCK_ORDINARY, thr); 03700 03701 if (err != DB_SUCCESS) { 03702 03703 goto lock_wait_or_error; 03704 } 03705 } 03706 /* A page supremum record cannot be in the result set: skip 03707 it now that we have placed a possible lock on it */ 03708 03709 goto next_rec; 03710 } 03711 03712 /*-------------------------------------------------------------*/ 03713 /* Do sanity checks in case our cursor has bumped into page 03714 corruption */ 03715 03716 if (comp) { 03717 next_offs = rec_get_next_offs(rec, TRUE); 03718 if (UNIV_UNLIKELY(next_offs < PAGE_NEW_SUPREMUM)) { 03719 03720 goto wrong_offs; 03721 } 03722 } else { 03723 next_offs = rec_get_next_offs(rec, FALSE); 03724 if (UNIV_UNLIKELY(next_offs < PAGE_OLD_SUPREMUM)) { 03725 03726 goto wrong_offs; 03727 } 03728 } 03729 03730 if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) { 03731 03732 wrong_offs: 03733 if (srv_force_recovery == 0 || moves_up == FALSE) { 03734 ut_print_timestamp(stderr); 03735 buf_page_print(buf_frame_align(rec)); 03736 fprintf(stderr, 03737 "\nInnoDB: rec address %p, first buffer frame %p\n" 03738 "InnoDB: buffer pool high end %p, buf block fix count %lu\n", 03739 rec, buf_pool->frame_zero, 03740 buf_pool->high_end, 03741 (ulong)buf_block_align(rec)->buf_fix_count); 03742 fprintf(stderr, 03743 "InnoDB: Index corruption: rec offs %lu next offs %lu, page no %lu,\n" 03744 "InnoDB: ", 03745 (ulong) ut_align_offset(rec, UNIV_PAGE_SIZE), 03746 (ulong) next_offs, 03747 (ulong) buf_frame_get_page_no(rec)); 03748 dict_index_name_print(stderr, trx, index); 03749 fputs(". Run CHECK TABLE. You may need to\n" 03750 "InnoDB: restore from a backup, or dump + drop + reimport the table.\n", 03751 stderr); 03752 03753 err = DB_CORRUPTION; 03754 03755 goto lock_wait_or_error; 03756 } else { 03757 /* The user may be dumping a corrupt table. Jump 03758 over the corruption to recover as much as possible. */ 03759 03760 fprintf(stderr, 03761 "InnoDB: Index corruption: rec offs %lu next offs %lu, page no %lu,\n" 03762 "InnoDB: ", 03763 (ulong) ut_align_offset(rec, UNIV_PAGE_SIZE), 03764 (ulong) next_offs, 03765 (ulong) buf_frame_get_page_no(rec)); 03766 dict_index_name_print(stderr, trx, index); 03767 fputs(". We try to skip the rest of the page.\n", 03768 stderr); 03769 03770 btr_pcur_move_to_last_on_page(pcur, &mtr); 03771 03772 goto next_rec; 03773 } 03774 } 03775 /*-------------------------------------------------------------*/ 03776 03777 /* Calculate the 'offsets' associated with 'rec' */ 03778 03779 offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap); 03780 03781 if (UNIV_UNLIKELY(srv_force_recovery > 0)) { 03782 if (!rec_validate(rec, offsets) 03783 || !btr_index_rec_validate(rec, index, FALSE)) { 03784 fprintf(stderr, 03785 "InnoDB: Index corruption: rec offs %lu next offs %lu, page no %lu,\n" 03786 "InnoDB: ", 03787 (ulong) ut_align_offset(rec, UNIV_PAGE_SIZE), 03788 (ulong) next_offs, 03789 (ulong) buf_frame_get_page_no(rec)); 03790 dict_index_name_print(stderr, trx, index); 03791 fputs(". We try to skip the record.\n", 03792 stderr); 03793 03794 goto next_rec; 03795 } 03796 } 03797 03798 /* Note that we cannot trust the up_match value in the cursor at this 03799 place because we can arrive here after moving the cursor! Thus 03800 we have to recompare rec and search_tuple to determine if they 03801 match enough. */ 03802 03803 if (match_mode == ROW_SEL_EXACT) { 03804 /* Test if the index record matches completely to search_tuple 03805 in prebuilt: if not, then we return with DB_RECORD_NOT_FOUND */ 03806 03807 /* fputs("Comparing rec and search tuple\n", stderr); */ 03808 03809 if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) { 03810 03811 if (set_also_gap_locks 03812 && !(srv_locks_unsafe_for_binlog 03813 || trx->isolation_level == TRX_ISO_READ_COMMITTED) 03814 && prebuilt->select_lock_type != LOCK_NONE) { 03815 03816 /* Try to place a gap lock on the index 03817 record only if innodb_locks_unsafe_for_binlog 03818 option is not set or this session is not 03819 using a READ COMMITTED isolation level. */ 03820 03821 err = sel_set_rec_lock(rec, index, offsets, 03822 prebuilt->select_lock_type, 03823 LOCK_GAP, thr); 03824 03825 if (err != DB_SUCCESS) { 03826 03827 goto lock_wait_or_error; 03828 } 03829 } 03830 03831 btr_pcur_store_position(pcur, &mtr); 03832 03833 err = DB_RECORD_NOT_FOUND; 03834 /* ut_print_name(stderr, index->name); 03835 fputs(" record not found 3\n", stderr); */ 03836 03837 goto normal_return; 03838 } 03839 03840 } else if (match_mode == ROW_SEL_EXACT_PREFIX) { 03841 03842 if (!cmp_dtuple_is_prefix_of_rec(search_tuple, rec, offsets)) { 03843 03844 if (set_also_gap_locks 03845 && !(srv_locks_unsafe_for_binlog 03846 || trx->isolation_level == TRX_ISO_READ_COMMITTED) 03847 && prebuilt->select_lock_type != LOCK_NONE) { 03848 03849 /* Try to place a gap lock on the index 03850 record only if innodb_locks_unsafe_for_binlog 03851 option is not set or this session is not 03852 using a READ COMMITTED isolation level. */ 03853 03854 err = sel_set_rec_lock(rec, index, offsets, 03855 prebuilt->select_lock_type, 03856 LOCK_GAP, thr); 03857 03858 if (err != DB_SUCCESS) { 03859 03860 goto lock_wait_or_error; 03861 } 03862 } 03863 03864 btr_pcur_store_position(pcur, &mtr); 03865 03866 err = DB_RECORD_NOT_FOUND; 03867 /* ut_print_name(stderr, index->name); 03868 fputs(" record not found 4\n", stderr); */ 03869 03870 goto normal_return; 03871 } 03872 } 03873 03874 /* We are ready to look at a possible new index entry in the result 03875 set: the cursor is now placed on a user record */ 03876 03877 if (prebuilt->select_lock_type != LOCK_NONE) { 03878 /* Try to place a lock on the index record; note that delete 03879 marked records are a special case in a unique search. If there 03880 is a non-delete marked record, then it is enough to lock its 03881 existence with LOCK_REC_NOT_GAP. */ 03882 03883 /* If innodb_locks_unsafe_for_binlog option is used 03884 or this session is using a READ COMMITED isolation 03885 level we lock only the record, i.e., next-key locking is 03886 not used. */ 03887 03888 ulint lock_type; 03889 03890 if (!set_also_gap_locks 03891 || srv_locks_unsafe_for_binlog 03892 || trx->isolation_level == TRX_ISO_READ_COMMITTED 03893 || (unique_search 03894 && !UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp)))) { 03895 03896 goto no_gap_lock; 03897 } else { 03898 lock_type = LOCK_ORDINARY; 03899 } 03900 03901 /* If we are doing a 'greater or equal than a primary key 03902 value' search from a clustered index, and we find a record 03903 that has that exact primary key value, then there is no need 03904 to lock the gap before the record, because no insert in the 03905 gap can be in our search range. That is, no phantom row can 03906 appear that way. 03907 03908 An example: if col1 is the primary key, the search is WHERE 03909 col1 >= 100, and we find a record where col1 = 100, then no 03910 need to lock the gap before that record. */ 03911 03912 if (index == clust_index 03913 && mode == PAGE_CUR_GE 03914 && direction == 0 03915 && dtuple_get_n_fields_cmp(search_tuple) 03916 == dict_index_get_n_unique(index) 03917 && 0 == cmp_dtuple_rec(search_tuple, rec, offsets)) { 03918 no_gap_lock: 03919 lock_type = LOCK_REC_NOT_GAP; 03920 } 03921 03922 err = sel_set_rec_lock(rec, index, offsets, 03923 prebuilt->select_lock_type, 03924 lock_type, thr); 03925 03926 switch (err) { 03927 rec_t* old_vers; 03928 case DB_SUCCESS: 03929 break; 03930 case DB_LOCK_WAIT: 03931 if (UNIV_LIKELY(prebuilt->row_read_type 03932 != ROW_READ_TRY_SEMI_CONSISTENT) 03933 || index != clust_index) { 03934 03935 goto lock_wait_or_error; 03936 } 03937 03938 /* The following call returns 'offsets' 03939 associated with 'old_vers' */ 03940 err = row_sel_build_committed_vers_for_mysql( 03941 clust_index, prebuilt, rec, 03942 &offsets, &heap, 03943 &old_vers, &mtr); 03944 03945 if (err != DB_SUCCESS) { 03946 03947 goto lock_wait_or_error; 03948 } 03949 03950 mutex_enter(&kernel_mutex); 03951 if (trx->was_chosen_as_deadlock_victim) { 03952 mutex_exit(&kernel_mutex); 03953 03954 goto lock_wait_or_error; 03955 } 03956 if (UNIV_LIKELY(trx->wait_lock != NULL)) { 03957 lock_cancel_waiting_and_release( 03958 trx->wait_lock); 03959 trx_reset_new_rec_lock_info(trx); 03960 } else { 03961 mutex_exit(&kernel_mutex); 03962 03963 /* The lock was granted while we were 03964 searching for the last committed version. 03965 Do a normal locking read. */ 03966 03967 offsets = rec_get_offsets(rec, index, offsets, 03968 ULINT_UNDEFINED, &heap); 03969 err = DB_SUCCESS; 03970 break; 03971 } 03972 mutex_exit(&kernel_mutex); 03973 03974 if (old_vers == NULL) { 03975 /* The row was not yet committed */ 03976 03977 goto next_rec; 03978 } 03979 03980 did_semi_consistent_read = TRUE; 03981 rec = old_vers; 03982 break; 03983 default: 03984 03985 goto lock_wait_or_error; 03986 } 03987 } else { 03988 /* This is a non-locking consistent read: if necessary, fetch 03989 a previous version of the record */ 03990 03991 if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED) { 03992 03993 /* Do nothing: we let a non-locking SELECT read the 03994 latest version of the record */ 03995 03996 } else if (index == clust_index) { 03997 03998 /* Fetch a previous version of the row if the current 03999 one is not visible in the snapshot; if we have a very 04000 high force recovery level set, we try to avoid crashes 04001 by skipping this lookup */ 04002 04003 if (UNIV_LIKELY(srv_force_recovery < 5) 04004 && !lock_clust_rec_cons_read_sees(rec, index, 04005 offsets, trx->read_view)) { 04006 04007 rec_t* old_vers; 04008 /* The following call returns 'offsets' 04009 associated with 'old_vers' */ 04010 err = row_sel_build_prev_vers_for_mysql( 04011 trx->read_view, clust_index, 04012 prebuilt, rec, 04013 &offsets, &heap, 04014 &old_vers, &mtr); 04015 04016 if (err != DB_SUCCESS) { 04017 04018 goto lock_wait_or_error; 04019 } 04020 04021 if (old_vers == NULL) { 04022 /* The row did not exist yet in 04023 the read view */ 04024 04025 goto next_rec; 04026 } 04027 04028 rec = old_vers; 04029 } 04030 } else if (!lock_sec_rec_cons_read_sees(rec, index, 04031 trx->read_view)) { 04032 /* We are looking into a non-clustered index, 04033 and to get the right version of the record we 04034 have to look also into the clustered index: this 04035 is necessary, because we can only get the undo 04036 information via the clustered index record. */ 04037 04038 ut_ad(index != clust_index); 04039 04040 goto requires_clust_rec; 04041 } 04042 } 04043 04044 /* NOTE that at this point rec can be an old version of a clustered 04045 index record built for a consistent read. We cannot assume after this 04046 point that rec is on a buffer pool page. Functions like 04047 page_rec_is_comp() cannot be used! */ 04048 04049 if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp))) { 04050 04051 /* The record is delete-marked: we can skip it */ 04052 04053 if ((srv_locks_unsafe_for_binlog 04054 || trx->isolation_level == TRX_ISO_READ_COMMITTED) 04055 && prebuilt->select_lock_type != LOCK_NONE 04056 && !did_semi_consistent_read) { 04057 04058 /* No need to keep a lock on a delete-marked record 04059 if we do not want to use next-key locking. */ 04060 04061 row_unlock_for_mysql(prebuilt, TRUE); 04062 } 04063 04064 goto next_rec; 04065 } 04066 04067 /* Get the clustered index record if needed, if we did not do the 04068 search using the clustered index. */ 04069 04070 if (index != clust_index && prebuilt->need_to_access_clustered) { 04071 04072 requires_clust_rec: 04073 /* We use a 'goto' to the preceding label if a consistent 04074 read of a secondary index record requires us to look up old 04075 versions of the associated clustered index record. */ 04076 04077 ut_ad(rec_offs_validate(rec, index, offsets)); 04078 04079 /* It was a non-clustered index and we must fetch also the 04080 clustered index record */ 04081 04082 mtr_has_extra_clust_latch = TRUE; 04083 04084 /* The following call returns 'offsets' associated with 04085 'clust_rec'. Note that 'clust_rec' can be an old version 04086 built for a consistent read. */ 04087 04088 err = row_sel_get_clust_rec_for_mysql(prebuilt, index, rec, 04089 thr, &clust_rec, 04090 &offsets, &heap, &mtr); 04091 if (err != DB_SUCCESS) { 04092 04093 goto lock_wait_or_error; 04094 } 04095 04096 if (clust_rec == NULL) { 04097 /* The record did not exist in the read view */ 04098 ut_ad(prebuilt->select_lock_type == LOCK_NONE); 04099 04100 goto next_rec; 04101 } 04102 04103 if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec, comp))) { 04104 04105 /* The record is delete marked: we can skip it */ 04106 04107 if ((srv_locks_unsafe_for_binlog 04108 || trx->isolation_level == TRX_ISO_READ_COMMITTED) 04109 && prebuilt->select_lock_type != LOCK_NONE) { 04110 04111 /* No need to keep a lock on a delete-marked 04112 record if we do not want to use next-key 04113 locking. */ 04114 04115 row_unlock_for_mysql(prebuilt, TRUE); 04116 } 04117 04118 goto next_rec; 04119 } 04120 04121 if (prebuilt->need_to_access_clustered) { 04122 04123 result_rec = clust_rec; 04124 04125 ut_ad(rec_offs_validate(result_rec, clust_index, 04126 offsets)); 04127 } else { 04128 /* We used 'offsets' for the clust rec, recalculate 04129 them for 'rec' */ 04130 offsets = rec_get_offsets(rec, index, offsets, 04131 ULINT_UNDEFINED, &heap); 04132 result_rec = rec; 04133 } 04134 } else { 04135 result_rec = rec; 04136 } 04137 04138 /* We found a qualifying record 'result_rec'. At this point, 04139 'offsets' are associated with 'result_rec'. */ 04140 04141 ut_ad(rec_offs_validate(result_rec, 04142 result_rec != rec ? clust_index : index, 04143 offsets)); 04144 04145 if ((match_mode == ROW_SEL_EXACT 04146 || prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD) 04147 && prebuilt->select_lock_type == LOCK_NONE 04148 && !prebuilt->templ_contains_blob 04149 && !prebuilt->clust_index_was_generated 04150 && !prebuilt->used_in_HANDLER 04151 && prebuilt->template_type 04152 != ROW_MYSQL_DUMMY_TEMPLATE) { 04153 04154 /* Inside an update, for example, we do not cache rows, 04155 since we may use the cursor position to do the actual 04156 update, that is why we require ...lock_type == LOCK_NONE. 04157 Since we keep space in prebuilt only for the BLOBs of 04158 a single row, we cannot cache rows in the case there 04159 are BLOBs in the fields to be fetched. In HANDLER we do 04160 not cache rows because there the cursor is a scrollable 04161 cursor. */ 04162 04163 row_sel_push_cache_row_for_mysql(prebuilt, result_rec, 04164 offsets); 04165 if (prebuilt->n_fetch_cached == MYSQL_FETCH_CACHE_SIZE) { 04166 04167 goto got_row; 04168 } 04169 04170 goto next_rec; 04171 } else { 04172 if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) { 04173 memcpy(buf + 4, result_rec 04174 - rec_offs_extra_size(offsets), 04175 rec_offs_size(offsets)); 04176 mach_write_to_4(buf, 04177 rec_offs_extra_size(offsets) + 4); 04178 } else { 04179 if (!row_sel_store_mysql_rec(buf, prebuilt, 04180 result_rec, offsets)) { 04181 err = DB_TOO_BIG_RECORD; 04182 04183 goto lock_wait_or_error; 04184 } 04185 } 04186 04187 if (prebuilt->clust_index_was_generated) { 04188 if (result_rec != rec) { 04189 offsets = rec_get_offsets( 04190 rec, index, offsets, 04191 ULINT_UNDEFINED, &heap); 04192 } 04193 row_sel_store_row_id_to_prebuilt(prebuilt, rec, 04194 index, offsets); 04195 } 04196 } 04197 04198 /* From this point on, 'offsets' are invalid. */ 04199 04200 got_row: 04201 /* We have an optimization to save CPU time: if this is a consistent 04202 read on a unique condition on the clustered index, then we do not 04203 store the pcur position, because any fetch next or prev will anyway 04204 return 'end of file'. Exceptions are locking reads and the MySQL 04205 HANDLER command where the user can move the cursor with PREV or NEXT 04206 even after a unique search. */ 04207 04208 if (!unique_search_from_clust_index 04209 || prebuilt->select_lock_type != LOCK_NONE 04210 || prebuilt->used_in_HANDLER) { 04211 04212 /* Inside an update always store the cursor position */ 04213 04214 btr_pcur_store_position(pcur, &mtr); 04215 } 04216 04217 err = DB_SUCCESS; 04218 04219 goto normal_return; 04220 04221 next_rec: 04222 /* Reset the old and new "did semi-consistent read" flags. */ 04223 if (UNIV_UNLIKELY(prebuilt->row_read_type 04224 == ROW_READ_DID_SEMI_CONSISTENT)) { 04225 prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT; 04226 } 04227 did_semi_consistent_read = FALSE; 04228 04229 if (UNIV_UNLIKELY(srv_locks_unsafe_for_binlog 04230 || trx->isolation_level == TRX_ISO_READ_COMMITTED) 04231 && prebuilt->select_lock_type != LOCK_NONE) { 04232 04233 trx_reset_new_rec_lock_info(trx); 04234 } 04235 04236 /*-------------------------------------------------------------*/ 04237 /* PHASE 5: Move the cursor to the next index record */ 04238 04239 if (UNIV_UNLIKELY(mtr_has_extra_clust_latch)) { 04240 /* We must commit mtr if we are moving to the next 04241 non-clustered index record, because we could break the 04242 latching order if we would access a different clustered 04243 index page right away without releasing the previous. */ 04244 04245 btr_pcur_store_position(pcur, &mtr); 04246 04247 mtr_commit(&mtr); 04248 mtr_has_extra_clust_latch = FALSE; 04249 04250 mtr_start(&mtr); 04251 if (sel_restore_position_for_mysql(&same_user_rec, 04252 BTR_SEARCH_LEAF, 04253 pcur, moves_up, &mtr)) { 04254 #ifdef UNIV_SEARCH_DEBUG 04255 cnt++; 04256 #endif /* UNIV_SEARCH_DEBUG */ 04257 04258 goto rec_loop; 04259 } 04260 } 04261 04262 if (moves_up) { 04263 if (UNIV_UNLIKELY(!btr_pcur_move_to_next(pcur, &mtr))) { 04264 not_moved: 04265 btr_pcur_store_position(pcur, &mtr); 04266 04267 if (match_mode != 0) { 04268 err = DB_RECORD_NOT_FOUND; 04269 } else { 04270 err = DB_END_OF_INDEX; 04271 } 04272 04273 goto normal_return; 04274 } 04275 } else { 04276 if (UNIV_UNLIKELY(!btr_pcur_move_to_prev(pcur, &mtr))) { 04277 goto not_moved; 04278 } 04279 } 04280 04281 #ifdef UNIV_SEARCH_DEBUG 04282 cnt++; 04283 #endif /* UNIV_SEARCH_DEBUG */ 04284 04285 goto rec_loop; 04286 04287 lock_wait_or_error: 04288 /* Reset the old and new "did semi-consistent read" flags. */ 04289 if (UNIV_UNLIKELY(prebuilt->row_read_type 04290 == ROW_READ_DID_SEMI_CONSISTENT)) { 04291 prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT; 04292 } 04293 did_semi_consistent_read = FALSE; 04294 04295 /*-------------------------------------------------------------*/ 04296 04297 btr_pcur_store_position(pcur, &mtr); 04298 04299 mtr_commit(&mtr); 04300 mtr_has_extra_clust_latch = FALSE; 04301 04302 trx->error_state = err; 04303 04304 /* The following is a patch for MySQL */ 04305 04306 que_thr_stop_for_mysql(thr); 04307 04308 thr->lock_state = QUE_THR_LOCK_ROW; 04309 04310 if (row_mysql_handle_errors(&err, trx, thr, NULL)) { 04311 /* It was a lock wait, and it ended */ 04312 04313 thr->lock_state = QUE_THR_LOCK_NOLOCK; 04314 mtr_start(&mtr); 04315 04316 sel_restore_position_for_mysql(&same_user_rec, 04317 BTR_SEARCH_LEAF, pcur, 04318 moves_up, &mtr); 04319 04320 if ((srv_locks_unsafe_for_binlog 04321 || trx->isolation_level == TRX_ISO_READ_COMMITTED) 04322 && !same_user_rec) { 04323 04324 /* Since we were not able to restore the cursor 04325 on the same user record, we cannot use 04326 row_unlock_for_mysql() to unlock any records, and 04327 we must thus reset the new rec lock info. Since 04328 in lock0lock.c we have blocked the inheriting of gap 04329 X-locks, we actually do not have any new record locks 04330 set in this case. 04331 04332 Note that if we were able to restore on the 'same' 04333 user record, it is still possible that we were actually 04334 waiting on a delete-marked record, and meanwhile 04335 it was removed by purge and inserted again by some 04336 other user. But that is no problem, because in 04337 rec_loop we will again try to set a lock, and 04338 new_rec_lock_info in trx will be right at the end. */ 04339 04340 trx_reset_new_rec_lock_info(trx); 04341 } 04342 04343 mode = pcur->search_mode; 04344 04345 goto rec_loop; 04346 } 04347 04348 thr->lock_state = QUE_THR_LOCK_NOLOCK; 04349 04350 #ifdef UNIV_SEARCH_DEBUG 04351 /* fputs("Using ", stderr); 04352 dict_index_name_print(stderr, index); 04353 fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */ 04354 #endif /* UNIV_SEARCH_DEBUG */ 04355 goto func_exit; 04356 04357 normal_return: 04358 /*-------------------------------------------------------------*/ 04359 que_thr_stop_for_mysql_no_error(thr, trx); 04360 04361 mtr_commit(&mtr); 04362 04363 if (prebuilt->n_fetch_cached > 0) { 04364 row_sel_pop_cached_row_for_mysql(buf, prebuilt); 04365 04366 err = DB_SUCCESS; 04367 } 04368 04369 #ifdef UNIV_SEARCH_DEBUG 04370 /* fputs("Using ", stderr); 04371 dict_index_name_print(stderr, index); 04372 fprintf(stderr, " cnt %lu ret value %lu err\n", cnt, err); */ 04373 #endif /* UNIV_SEARCH_DEBUG */ 04374 if (err == DB_SUCCESS) { 04375 srv_n_rows_read++; 04376 } 04377 04378 func_exit: 04379 trx->op_info = ""; 04380 if (UNIV_LIKELY_NULL(heap)) { 04381 mem_heap_free(heap); 04382 } 04383 04384 /* Set or reset the "did semi-consistent read" flag on return. 04385 The flag did_semi_consistent_read is set if and only if 04386 the record being returned was fetched with a semi-consistent read. */ 04387 ut_ad(prebuilt->row_read_type != ROW_READ_WITH_LOCKS 04388 || !did_semi_consistent_read); 04389 04390 if (UNIV_UNLIKELY(prebuilt->row_read_type != ROW_READ_WITH_LOCKS)) { 04391 if (UNIV_UNLIKELY(did_semi_consistent_read)) { 04392 prebuilt->row_read_type = ROW_READ_DID_SEMI_CONSISTENT; 04393 } else { 04394 prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT; 04395 } 04396 } 04397 return(err); 04398 }
Here is the call graph for this function:

Here is the caller graph for this function:

| void row_sel_convert_mysql_key_to_innobase | ( | dtuple_t * | tuple, | |
| byte * | buf, | |||
| ulint | buf_len, | |||
| dict_index_t * | index, | |||
| byte * | key_ptr, | |||
| ulint | key_len, | |||
| trx_t * | trx | |||
| ) |
Definition at line 2192 of file row0sel.c.
References dict_field_struct::col, DATA_BLOB, DATA_INT, DATA_MYSQL_TRUE_VARCHAR, DATA_NOT_NULL, DATA_ROW_ID_LEN, DATA_SYS, dfield_get_type(), dfield_set_data(), dict_col_get_type(), dict_index_get_nth_field(), dict_index_name_print(), dict_table_is_comp(), dtuple_get_nth_field(), dtuple_set_n_fields(), dtype_get_mysql_type(), FALSE, index(), key_end(), dtype_struct::len, dfield_struct::len, dtype_struct::mtype, NULL, dict_field_struct::prefix_len, row_mysql_store_col_in_innobase_format(), TRUE, ut_a, ut_print_buf(), and ut_print_timestamp().
02194 : tuple where to build; 02195 NOTE: we assume that the type info 02196 in the tuple is already according 02197 to index! */ 02198 byte* buf, /* in: buffer to use in field 02199 conversions */ 02200 ulint buf_len, /* in: buffer length */ 02201 dict_index_t* index, /* in: index of the key value */ 02202 byte* key_ptr, /* in: MySQL key value */ 02203 ulint key_len, /* in: MySQL key value length */ 02204 trx_t* trx) /* in: transaction */ 02205 { 02206 byte* original_buf = buf; 02207 byte* original_key_ptr = key_ptr; 02208 dict_field_t* field; 02209 dfield_t* dfield; 02210 ulint data_offset; 02211 ulint data_len; 02212 ulint data_field_len; 02213 ibool is_null; 02214 byte* key_end; 02215 ulint n_fields = 0; 02216 ulint type; 02217 02218 /* For documentation of the key value storage format in MySQL, see 02219 ha_innobase::store_key_val_for_row() in ha_innodb.cc. */ 02220 02221 key_end = key_ptr + key_len; 02222 02223 /* Permit us to access any field in the tuple (ULINT_MAX): */ 02224 02225 dtuple_set_n_fields(tuple, ULINT_MAX); 02226 02227 dfield = dtuple_get_nth_field(tuple, 0); 02228 field = dict_index_get_nth_field(index, 0); 02229 02230 if (dfield_get_type(dfield)->mtype == DATA_SYS) { 02231 /* A special case: we are looking for a position in the 02232 generated clustered index which InnoDB automatically added 02233 to a table with no primary key: the first and the only 02234 ordering column is ROW_ID which InnoDB stored to the key_ptr 02235 buffer. */ 02236 02237 ut_a(key_len == DATA_ROW_ID_LEN); 02238 02239 dfield_set_data(dfield, key_ptr, DATA_ROW_ID_LEN); 02240 02241 dtuple_set_n_fields(tuple, 1); 02242 02243 return; 02244 } 02245 02246 while (key_ptr < key_end) { 02247 02248 ut_a(dict_col_get_type(field->col)->mtype 02249 == dfield_get_type(dfield)->mtype); 02250 02251 data_offset = 0; 02252 is_null = FALSE; 02253 02254 if (!(dfield_get_type(dfield)->prtype & DATA_NOT_NULL)) { 02255 /* The first byte in the field tells if this is 02256 an SQL NULL value */ 02257 02258 data_offset = 1; 02259 02260 if (*key_ptr != 0) { 02261 dfield_set_data(dfield, NULL, UNIV_SQL_NULL); 02262 02263 is_null = TRUE; 02264 } 02265 } 02266 02267 type = dfield_get_type(dfield)->mtype; 02268 02269 /* Calculate data length and data field total length */ 02270 02271 if (type == DATA_BLOB) { 02272 /* The key field is a column prefix of a BLOB or 02273 TEXT */ 02274 02275 ut_a(field->prefix_len > 0); 02276 02277 /* MySQL stores the actual data length to the first 2 02278 bytes after the optional SQL NULL marker byte. The 02279 storage format is little-endian, that is, the most 02280 significant byte at a higher address. In UTF-8, MySQL 02281 seems to reserve field->prefix_len bytes for 02282 storing this field in the key value buffer, even 02283 though the actual value only takes data_len bytes 02284 from the start. */ 02285 02286 data_len = key_ptr[data_offset] 02287 + 256 * key_ptr[data_offset + 1]; 02288 data_field_len = data_offset + 2 + field->prefix_len; 02289 02290 data_offset += 2; 02291 02292 /* Now that we know the length, we store the column 02293 value like it would be a fixed char field */ 02294 02295 } else if (field->prefix_len > 0) { 02296 /* Looks like MySQL pads unused end bytes in the 02297 prefix with space. Therefore, also in UTF-8, it is ok 02298 to compare with a prefix containing full prefix_len 02299 bytes, and no need to take at most prefix_len / 3 02300 UTF-8 characters from the start. 02301 If the prefix is used as the upper end of a LIKE 02302 'abc%' query, then MySQL pads the end with chars 02303 0xff. TODO: in that case does it any harm to compare 02304 with the full prefix_len bytes. How do characters 02305 0xff in UTF-8 behave? */ 02306 02307 data_len = field->prefix_len; 02308 data_field_len = data_offset + data_len; 02309 } else { 02310 data_len = dfield_get_type(dfield)->len; 02311 data_field_len = data_offset + data_len; 02312 } 02313 02314 if (dtype_get_mysql_type(dfield_get_type(dfield)) 02315 == DATA_MYSQL_TRUE_VARCHAR 02316 && dfield_get_type(dfield)->mtype != DATA_INT) { 02317 /* In a MySQL key value format, a true VARCHAR is 02318 always preceded by 2 bytes of a length field. 02319 dfield_get_type(dfield)->len returns the maximum 02320 'payload' len in bytes. That does not include the 02321 2 bytes that tell the actual data length. 02322 02323 We added the check != DATA_INT to make sure we do 02324 not treat MySQL ENUM or SET as a true VARCHAR! */ 02325 02326 data_len += 2; 02327 data_field_len += 2; 02328 } 02329 02330 /* Storing may use at most data_len bytes of buf */ 02331 02332 if (!is_null) { 02333 row_mysql_store_col_in_innobase_format( 02334 dfield, 02335 buf, 02336 FALSE, /* MySQL key value format col */ 02337 key_ptr + data_offset, 02338 data_len, 02339 dict_table_is_comp(index->table)); 02340 buf += data_len; 02341 } 02342 02343 key_ptr += data_field_len; 02344 02345 if (key_ptr > key_end) { 02346 /* The last field in key was not a complete key field 02347 but a prefix of it. 02348 02349 Print a warning about this! HA_READ_PREFIX_LAST does 02350 not currently work in InnoDB with partial-field key 02351 value prefixes. Since MySQL currently uses a padding 02352 trick to calculate LIKE 'abc%' type queries there 02353 should never be partial-field prefixes in searches. */ 02354 02355 ut_print_timestamp(stderr); 02356 02357 fputs( 02358 " InnoDB: Warning: using a partial-field key prefix in search.\n" 02359 "InnoDB: ", stderr); 02360 dict_index_name_print(stderr, trx, index); 02361 fprintf(stderr, ". Last data field length %lu bytes,\n" 02362 "InnoDB: key ptr now exceeds key end by %lu bytes.\n" 02363 "InnoDB: Key value in the MySQL format:\n", 02364 (ulong) data_field_len, 02365 (ulong) (key_ptr - key_end)); 02366 fflush(stderr); 02367 ut_print_buf(stderr, original_key_ptr, key_len); 02368 fprintf(stderr, "\n"); 02369 02370 if (!is_null) { 02371 dfield->len -= (ulint)(key_ptr - key_end); 02372 } 02373 } 02374 02375 n_fields++; 02376 field++; 02377 dfield++; 02378 } 02379 02380 ut_a(buf <= original_buf + buf_len); 02381 02382 /* We set the length of tuple to n_fields: we assume that the memory 02383 area allocated for it is big enough (usually bigger than n_fields). */ 02384 02385 dtuple_set_n_fields(tuple, n_fields); 02386 }
Here is the call graph for this function:

Definition at line 1885 of file row0sel.c.
References sel_node_struct::consistent_read, sel_node_struct::copy_variables, DB_SUCCESS, err, trx_struct::error_state, sel_node_struct::explicit_cursor, sel_node_struct::fetch_table, que_thr_struct::graph, sel_node_struct::into_list, sel_node_struct::is_aggregate, que_fork_struct::last_sel_node, LOCK_IS, LOCK_IX, lock_table(), NULL, plan_reset_cursor(), que_thr_struct::prev_node, que_node_get_next(), que_node_get_parent(), que_node_get_type(), QUE_NODE_SELECT, sel_node_struct::read_view, row_sel(), row_sel_copy_input_variable_vals(), que_thr_struct::run_node, SEL_NODE_FETCH, sel_node_get_nth_plan(), SEL_NODE_OPEN, sel_reset_aggregate_vals(), sel_node_struct::set_x_locks, sel_node_struct::state, sym_node_struct::table, sel_node_struct::table_list, thr_get_trx(), trx_assign_read_view(), trx_start_if_not_started(), ut_ad, and UT_LIST_GET_FIRST.
Referenced by que_thr_step().
01887 : query thread to run next or NULL */ 01888 que_thr_t* thr) /* in: query thread */ 01889 { 01890 ulint i_lock_mode; 01891 sym_node_t* table_node; 01892 sel_node_t* node; 01893 ulint err; 01894 01895 ut_ad(thr); 01896 01897 node = thr->run_node; 01898 01899 ut_ad(que_node_get_type(node) == QUE_NODE_SELECT); 01900 01901 /* If this is a new time this node is executed (or when execution 01902 resumes after wait for a table intention lock), set intention locks 01903 on the tables, or assign a read view */ 01904 01905 if (node->into_list && (thr->prev_node == que_node_get_parent(node))) { 01906 01907 node->state = SEL_NODE_OPEN; 01908 } 01909 01910 if (node->state == SEL_NODE_OPEN) { 01911 01912 /* It may be that the current session has not yet started 01913 its transaction, or it has been committed: */ 01914 01915 trx_start_if_not_started(thr_get_trx(thr)); 01916 01917 plan_reset_cursor(sel_node_get_nth_plan(node, 0)); 01918 01919 if (node->consistent_read) { 01920 /* Assign a read view for the query */ 01921 node->read_view = trx_assign_read_view( 01922 thr_get_trx(thr)); 01923 } else { 01924 if (node->set_x_locks) { 01925 i_lock_mode = LOCK_IX; 01926 } else { 01927 i_lock_mode = LOCK_IS; 01928 } 01929 01930 table_node = node->table_list; 01931 01932 while (table_node) { 01933 err = lock_table(0, table_node->table, 01934 i_lock_mode, thr); 01935 if (err != DB_SUCCESS) { 01936 thr_get_trx(thr)->error_state = err; 01937 01938 return(NULL); 01939 } 01940 01941 table_node = que_node_get_next(table_node); 01942 } 01943 } 01944 01945 /* If this is an explicit cursor, copy stored procedure 01946 variable values, so that the values cannot change between 01947 fetches (currently, we copy them also for non-explicit 01948 cursors) */ 01949 01950 if (node->explicit_cursor && 01951 UT_LIST_GET_FIRST(node->copy_variables)) { 01952 01953 row_sel_copy_input_variable_vals(node); 01954 } 01955 01956 node->state = SEL_NODE_FETCH; 01957 node->fetch_table = 0; 01958 01959 if (node->is_aggregate) { 01960 /* Reset the aggregate total values */ 01961 sel_reset_aggregate_vals(node); 01962 } 01963 } 01964 01965 err = row_sel(node, thr); 01966 01967 /* NOTE! if queries are parallelized, the following assignment may 01968 have problems; the assignment should be made only if thr is the 01969 only top-level thr in the graph: */ 01970 01971 thr->graph->last_sel_node = node; 01972 01973 if (err != DB_SUCCESS) { 01974 thr_get_trx(thr)->error_state = err; 01975 01976 return(NULL); 01977 } 01978 01979 return(thr); 01980 }
Here is the call graph for this function:

Here is the caller graph for this function:

| void sel_col_prefetch_buf_free | ( | sel_buf_t * | prefetch_buf | ) |
Definition at line 382 of file row0sel.c.
References sel_buf_struct::data, mem_free, SEL_MAX_N_PREFETCH, and sel_buf_struct::val_buf_size.
Referenced by sym_tab_free_private().
00384 : prefetch buffer */ 00385 { 00386 sel_buf_t* sel_buf; 00387 ulint i; 00388 00389 for (i = 0; i < SEL_MAX_N_PREFETCH; i++) { 00390 sel_buf = prefetch_buf + i; 00391 00392 if (sel_buf->val_buf_size > 0) { 00393 00394 mem_free(sel_buf->data); 00395 } 00396 } 00397 }
Here is the caller graph for this function:

| sel_node_t* sel_node_create | ( | mem_heap_t * | heap | ) |
Definition at line 141 of file row0sel.c.
References BTR_SEARCH_LEAF, sel_node_struct::common, FALSE, sel_node_struct::latch_mode, mem_heap_alloc(), NULL, sel_node_struct::plans, QUE_NODE_SELECT, SEL_NODE_OPEN, sel_node_struct::select_will_do_update, sel_node_struct::state, and que_common_struct::type.
Referenced by pars_select_list(), and row_prebuild_sel_graph().
00143 : select node struct */ 00144 mem_heap_t* heap) /* in: memory heap where created */ 00145 { 00146 sel_node_t* node; 00147 00148 node = mem_heap_alloc(heap, sizeof(sel_node_t)); 00149 node->common.type = QUE_NODE_SELECT; 00150 node->state = SEL_NODE_OPEN; 00151 00152 node->select_will_do_update = FALSE; 00153 node->latch_mode = BTR_SEARCH_LEAF; 00154 00155 node->plans = NULL; 00156 00157 return(node); 00158 }
Here is the call graph for this function:

Here is the caller graph for this function:

| void sel_node_free_private | ( | sel_node_t * | node | ) |
Definition at line 165 of file row0sel.c.
References btr_pcur_close(), mem_heap_free, sel_node_struct::n_tables, NULL, plan(), sel_node_struct::plans, and sel_node_get_nth_plan().
Referenced by que_graph_free_recursive().
00167 : select node struct */ 00168 { 00169 ulint i; 00170 plan_t* plan; 00171 00172 if (node->plans != NULL) { 00173 for (i = 0; i < node->n_tables; i++) { 00174 plan = sel_node_get_nth_plan(node, i); 00175 00176 btr_pcur_close(&(plan->pcur)); 00177 btr_pcur_close(&(plan->clust_pcur)); 00178 00179 if (plan->old_vers_heap) { 00180 mem_heap_free(plan->old_vers_heap); 00181 } 00182 } 00183 } 00184 }
Here is the call graph for this function:

Here is the caller graph for this function:

| UNIV_INLINE plan_t* sel_node_get_nth_plan | ( | sel_node_t * | node, | |
| ulint | i | |||
| ) |
Referenced by opt_check_exp_determined_before(), opt_check_order_by(), opt_classify_cols(), opt_classify_comparison(), opt_clust_access(), opt_determine_and_normalize_test_conds(), opt_find_copy_cols(), opt_find_test_conds(), opt_look_for_col_in_comparison_before(), opt_print_query_plan(), opt_search_plan_for_table(), pars_update_statement(), row_sel(), row_sel_step(), and sel_node_free_private().
Here is the caller graph for this function:

1.4.7

