diff options
Diffstat (limited to 'storage/innobase/row/row0sel.cc')
-rw-r--r-- | storage/innobase/row/row0sel.cc | 412 |
1 files changed, 24 insertions, 388 deletions
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index d23a0d8c432..4cd7a443d79 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -221,7 +221,6 @@ row_sel_sec_rec_is_for_clust_rec( /* For virtual column, its value will need to be reconstructed from base column in cluster index */ if (is_virtual) { -#ifdef MYSQL_VIRTUAL_COLUMNS const dict_v_col_t* v_col; const dtuple_t* row; dfield_t* vfield; @@ -243,7 +242,6 @@ row_sel_sec_rec_is_for_clust_rec( clust_len = vfield->len; clust_field = static_cast<byte*>(vfield->data); -#endif /* MYSQL_VIRTUAL_COLUMNS */ } else { clust_pos = dict_col_get_clust_pos(col, clust_index); @@ -3617,10 +3615,7 @@ row_sel_get_clust_rec_for_mysql( func_exit: *out_rec = clust_rec; - /* Store the current position if select_lock_type is not - LOCK_NONE or if we are scanning using InnoDB APIs */ - if (prebuilt->select_lock_type != LOCK_NONE - || prebuilt->innodb_api) { + if (prebuilt->select_lock_type != LOCK_NONE) { /* We may use the cursor in update or in unlock_row(): store its position */ @@ -4091,320 +4086,6 @@ row_search_idx_cond_check( return(result); } -/** Traverse to next/previous record. -@param[in] moves_up if true, move to next record else previous -@param[in] match_mode 0 or ROW_SEL_EXACT or ROW_SEL_EXACT_PREFIX -@param[in,out] pcur cursor to record -@param[in] mtr mini transaction - -@return DB_SUCCESS or error code */ -static -dberr_t -row_search_traverse( - bool moves_up, - ulint match_mode, - btr_pcur_t* pcur, - mtr_t* mtr) -{ - dberr_t err = DB_SUCCESS; - - if (moves_up) { - if (!btr_pcur_move_to_next(pcur, mtr)) { - err = (match_mode != 0) - ? DB_RECORD_NOT_FOUND : DB_END_OF_INDEX; - return(err); - } - } else { - if (!btr_pcur_move_to_prev(pcur, mtr)) { - err = (match_mode != 0) - ? DB_RECORD_NOT_FOUND : DB_END_OF_INDEX; - return(err); - } - } - - return(err); -} - -/** Searches for rows in the database using cursor. -Function is for temporary tables that are not shared accross connections -and so lot of complexity is reduced especially locking and transaction related. -The cursor is an iterator over the table/index. - -@param[out] buf buffer for the fetched row in MySQL format -@param[in] mode search mode PAGE_CUR_L -@param[in,out] prebuilt prebuilt struct for the table handler; - this contains the info to search_tuple, - index; if search tuple contains 0 field then - we position the cursor at start or the end of - index, depending on 'mode' -@param[in] match_mode 0 or ROW_SEL_EXACT or ROW_SEL_EXACT_PREFIX -@param[in] direction 0 or ROW_SEL_NEXT or ROW_SEL_PREV; - Note: if this is != 0, then prebuilt must has a - pcur with stored position! In opening of a - cursor 'direction' should be 0. -@return DB_SUCCESS or error code */ -dberr_t -row_search_no_mvcc( - byte* buf, - page_cur_mode_t mode, - row_prebuilt_t* prebuilt, - ulint match_mode, - ulint direction) -{ - dict_index_t* index = prebuilt->index; - const dtuple_t* search_tuple = prebuilt->search_tuple; - btr_pcur_t* pcur = prebuilt->pcur; - - const rec_t* result_rec = NULL; - const rec_t* clust_rec = NULL; - - dberr_t err = DB_SUCCESS; - - mem_heap_t* heap = NULL; - ulint offsets_[REC_OFFS_NORMAL_SIZE]; - ulint* offsets = offsets_; - rec_offs_init(offsets_); - ut_ad(index && pcur && search_tuple); - - /* Step-0: Re-use the cached mtr. */ - mtr_t* mtr = &index->last_sel_cur->mtr; - dict_index_t* clust_index = dict_table_get_first_index(index->table); - - /* Step-1: Build the select graph. */ - if (direction == 0 && prebuilt->sel_graph == NULL) { - row_prebuild_sel_graph(prebuilt); - } - - que_thr_t* thr = que_fork_get_first_thr(prebuilt->sel_graph); - - bool moves_up; - - if (direction == 0) { - - if (mode == PAGE_CUR_GE || mode == PAGE_CUR_G) { - moves_up = true; - } else { - moves_up = false; - } - - } else if (direction == ROW_SEL_NEXT) { - moves_up = true; - } else { - moves_up = false; - } - - /* Step-2: Open or Restore the cursor. - If search key is specified, cursor is open using the key else - cursor is open to return all the records. */ - if (direction != 0) { - if (index->last_sel_cur->invalid) { - - /* Index tree has changed and so active cached cursor - is no more valid. Re-set it based on the last selected - position. */ - index->last_sel_cur->release(); - - mtr_start(mtr); - dict_disable_redo_if_temporary(index->table, mtr); - - mem_heap_t* heap = mem_heap_create(256); - dtuple_t* tuple; - - tuple = dict_index_build_data_tuple( - index, pcur->old_rec, - pcur->old_n_fields, heap); - - btr_pcur_open_with_no_init( - index, tuple, pcur->search_mode, - BTR_SEARCH_LEAF, pcur, 0, mtr); - - mem_heap_free(heap); - } else { - /* Restore the cursor for reading next record from cache - information. */ - ut_ad(index->last_sel_cur->rec != NULL); - - pcur->btr_cur.page_cur.rec = index->last_sel_cur->rec; - pcur->btr_cur.page_cur.block = - index->last_sel_cur->block; - - err = row_search_traverse( - moves_up, match_mode, pcur, mtr); - if (err != DB_SUCCESS) { - return(err); - } - } - } else { - /* There could be previous uncommitted transaction if SELECT - is operation as part of SELECT (IF NOT FOUND) INSERT - (IF DUPLICATE) UPDATE plan. */ - index->last_sel_cur->release(); - - /* Capture table snapshot in form of trx-id. */ - index->trx_id = dict_table_get_curr_table_sess_trx_id( - index->table); - - /* Fresh search commences. */ - mtr_start(mtr); - dict_disable_redo_if_temporary(index->table, mtr); - - if (dtuple_get_n_fields(search_tuple) > 0) { - - btr_pcur_open_with_no_init( - index, search_tuple, mode, BTR_SEARCH_LEAF, - pcur, 0, mtr); - - } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_L) { - - btr_pcur_open_at_index_side( - mode == PAGE_CUR_G, index, BTR_SEARCH_LEAF, - pcur, false, 0, mtr); - - } - } - - /* Step-3: Traverse the records filtering non-qualifiying records. */ - for (/* No op */; - err == DB_SUCCESS; - err = row_search_traverse(moves_up, match_mode, pcur, mtr)) { - - const rec_t* rec = btr_pcur_get_rec(pcur); - - if (page_rec_is_infimum(rec) - || page_rec_is_supremum(rec) - || rec_get_deleted_flag( - rec, dict_table_is_comp(index->table))) { - - /* The infimum record on a page cannot be in the - result set, and neither can a record lock be placed on - it: we skip such a record. */ - continue; - } - - offsets = rec_get_offsets( - rec, index, offsets, ULINT_UNDEFINED, &heap); - - /* Note that we cannot trust the up_match value in the cursor - at this place because we can arrive here after moving the - cursor! Thus we have to recompare rec and search_tuple to - determine if they match enough. */ - if (match_mode == ROW_SEL_EXACT) { - /* Test if the index record matches completely to - search_tuple in prebuilt: if not, then we return with - DB_RECORD_NOT_FOUND */ - if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) { - err = DB_RECORD_NOT_FOUND; - break; - } - } else if (match_mode == ROW_SEL_EXACT_PREFIX) { - if (!cmp_dtuple_is_prefix_of_rec( - search_tuple, rec, offsets)) { - err = DB_RECORD_NOT_FOUND; - break; - } - } - - /* Get the clustered index. We always need clustered index - record for snapshort verification. */ - if (index != clust_index) { - - err = row_sel_get_clust_rec_for_mysql( - prebuilt, index, rec, thr, &clust_rec, - &offsets, &heap, NULL, mtr); - - if (err != DB_SUCCESS) { - break; - } - - if (rec_get_deleted_flag( - clust_rec, dict_table_is_comp(index->table))) { - - /* The record is delete marked in clustered - index. We can skip this record. */ - continue; - } - - result_rec = clust_rec; - } else { - result_rec = rec; - } - - /* Step-4: Check if row is part of the consistent view that was - captured while SELECT statement started execution. */ - { - trx_id_t trx_id; - - ulint len; - ulint trx_id_off = rec_get_nth_field_offs( - offsets, clust_index->n_uniq, &len); - - ut_ad(len == DATA_TRX_ID_LEN); - - trx_id = trx_read_trx_id(result_rec + trx_id_off); - - if (trx_id > index->trx_id) { - /* This row was recently added skip it from - SELECT view. */ - continue; - } - } - - /* Step-5: Cache the row-id of selected row to prebuilt cache.*/ - if (prebuilt->clust_index_was_generated) { - row_sel_store_row_id_to_prebuilt( - prebuilt, result_rec, clust_index, offsets); - } - - /* Step-6: Convert selected record to MySQL format and - store it. */ - if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) { - - const rec_t* ret_rec = - (index != clust_index - && prebuilt->need_to_access_clustered) - ? result_rec : rec; - - offsets = rec_get_offsets(ret_rec, index, offsets, - ULINT_UNDEFINED, &heap); - - memcpy(buf + 4, ret_rec - rec_offs_extra_size(offsets), - rec_offs_size(offsets)); - - mach_write_to_4(buf, rec_offs_extra_size(offsets) + 4); - - } else if (!row_sel_store_mysql_rec( - buf, prebuilt, result_rec, NULL, TRUE, - clust_index, offsets)) { - err = DB_ERROR; - break; - } - - /* Step-7: Store cursor position to fetch next record. - MySQL calls this function iteratively get_next(), get_next() - fashion. */ - ut_ad(err == DB_SUCCESS); - index->last_sel_cur->rec = btr_pcur_get_rec(pcur); - index->last_sel_cur->block = btr_pcur_get_block(pcur); - - /* This is needed in order to restore the cursor if index - structure changes while SELECT is still active. */ - pcur->old_rec = dict_index_copy_rec_order_prefix( - index, rec, &pcur->old_n_fields, - &pcur->old_rec_buf, &pcur->buf_size); - - break; - } - - if (err != DB_SUCCESS) { - index->last_sel_cur->release(); - } - - if (heap != NULL) { - mem_heap_free(heap); - } - return(err); -} - /** Extract virtual column data from a virtual index record and fill a dtuple @param[in] rec the virtual (secondary) index record @param[in] index the virtual index @@ -4459,7 +4140,7 @@ row_sel_fill_vrow( } /** Searches for rows in the database using cursor. -Function is mainly used for tables that are shared accorss connection and +Function is mainly used for tables that are shared across connections and so it employs technique that can help re-construct the rows that transaction is suppose to see. It also has optimization such as pre-caching the rows, using AHI, etc. @@ -4713,13 +4394,11 @@ row_search_mvcc( && dict_index_is_clust(index) && !prebuilt->templ_contains_blob && !prebuilt->used_in_HANDLER - && (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8) - && !prebuilt->innodb_api) { + && (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8)) { mode = PAGE_CUR_GE; if (trx->mysql_n_tables_locked == 0 - && !prebuilt->ins_sel_stmt && prebuilt->select_lock_type == LOCK_NONE && trx->isolation_level > TRX_ISO_READ_UNCOMMITTED && MVCC::is_view_active(trx->read_view)) { @@ -5590,7 +5269,7 @@ locks_ok: This optimization can avoid many IOs for certain schemas. */ ibool row_contains_all_values = TRUE; - int i; + uint i; for (i = 0; i < prebuilt->n_template; i++) { /* Condition (1) from above: is the field in the index (prefix or not)? */ @@ -5758,7 +5437,6 @@ requires_clust_rec: && !prebuilt->templ_contains_fixed_point && !prebuilt->clust_index_was_generated && !prebuilt->used_in_HANDLER - && !prebuilt->innodb_api && prebuilt->template_type != ROW_MYSQL_DUMMY_TEMPLATE && !prebuilt->in_fts_query) { @@ -5848,7 +5526,7 @@ requires_clust_rec: rec_offs_size(offsets)); mach_write_to_4(buf, rec_offs_extra_size(offsets) + 4); - } else if (!prebuilt->idx_cond && !prebuilt->innodb_api) { + } else if (!prebuilt->idx_cond) { /* The record was not yet converted to MySQL format. */ if (!row_sel_store_mysql_rec( buf, prebuilt, result_rec, vrow, @@ -5891,18 +5569,13 @@ idx_cond_failed: || !dict_index_is_clust(index) || direction != 0 || prebuilt->select_lock_type != LOCK_NONE - || prebuilt->used_in_HANDLER - || prebuilt->innodb_api) { + || prebuilt->used_in_HANDLER) { /* Inside an update always store the cursor position */ if (!spatial_search) { btr_pcur_store_position(pcur, &mtr); } - - if (prebuilt->innodb_api) { - prebuilt->innodb_api_rec = result_rec; - } } goto normal_return; @@ -6362,29 +6035,7 @@ row_search_autoinc_read_column( data = rec_get_nth_field(rec, offsets, col_no, &len); - switch (mtype) { - case DATA_INT: - ut_a(len <= sizeof value); - value = mach_read_int_type(data, len, unsigned_type); - break; - - case DATA_FLOAT: - ut_a(len == sizeof(float)); - value = (ib_uint64_t) mach_float_read(data); - break; - - case DATA_DOUBLE: - ut_a(len == sizeof(double)); - value = (ib_uint64_t) mach_double_read(data); - break; - - default: - ut_error; - } - - if (!unsigned_type && static_cast<int64_t>(value) < 0) { - value = 0; - } + value = row_parse_int(data, len, mtype, unsigned_type); func_exit: if (UNIV_LIKELY_NULL(heap)) { @@ -6430,42 +6081,27 @@ row_search_get_max_rec( return(rec); } -/*******************************************************************//** -Read the max AUTOINC value from an index. -@return DB_SUCCESS if all OK else error code, DB_RECORD_NOT_FOUND if -column name can't be found in index */ -dberr_t -row_search_max_autoinc( -/*===================*/ - dict_index_t* index, /*!< in: index to search */ - const char* col_name, /*!< in: name of autoinc column */ - ib_uint64_t* value) /*!< out: AUTOINC value read */ +/** Read the max AUTOINC value from an index. +@param[in] index index starting with an AUTO_INCREMENT column +@return the largest AUTO_INCREMENT value +@retval 0 if no records were found */ +ib_uint64_t +row_search_max_autoinc(dict_index_t* index) { - dict_field_t* dfield = dict_index_get_nth_field(index, 0); - dberr_t error = DB_SUCCESS; - *value = 0; - - if (strcmp(col_name, dfield->name) != 0) { - error = DB_RECORD_NOT_FOUND; - } else { - mtr_t mtr; - const rec_t* rec; - - mtr_start(&mtr); + const dict_field_t* dfield = dict_index_get_nth_field(index, 0); - rec = row_search_get_max_rec(index, &mtr); + ib_uint64_t value = 0; - if (rec != NULL) { - ibool unsigned_type = ( - dfield->col->prtype & DATA_UNSIGNED); - - *value = row_search_autoinc_read_column( - index, rec, 0, - dfield->col->mtype, unsigned_type); - } + mtr_t mtr; + mtr.start(); - mtr_commit(&mtr); + if (const rec_t* rec = row_search_get_max_rec(index, &mtr)) { + value = row_search_autoinc_read_column( + index, rec, 0, + dfield->col->mtype, + dfield->col->prtype & DATA_UNSIGNED); } - return(error); + mtr.commit(); + return(value); } |