diff options
Diffstat (limited to 'storage/xtradb/api/api0api.cc')
-rw-r--r-- | storage/xtradb/api/api0api.cc | 3886 |
1 files changed, 0 insertions, 3886 deletions
diff --git a/storage/xtradb/api/api0api.cc b/storage/xtradb/api/api0api.cc deleted file mode 100644 index 2a46dd4b4c1..00000000000 --- a/storage/xtradb/api/api0api.cc +++ /dev/null @@ -1,3886 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2008, 2015, Oracle and/or its affiliates. All Rights Reserved. - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file api/api0api.cc -InnoDB Native API - -2008-08-01 Created Sunny Bains -3/20/2011 Jimmy Yang extracted from Embedded InnoDB -*******************************************************/ - -#include "univ.i" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "api0api.h" -#include "api0misc.h" -#include "srv0start.h" -#include "dict0dict.h" -#include "btr0pcur.h" -#include "row0ins.h" -#include "row0upd.h" -#include "row0vers.h" -#include "trx0roll.h" -#include "dict0crea.h" -#include "row0merge.h" -#include "pars0pars.h" -#include "lock0types.h" -#include "row0sel.h" -#include "lock0lock.h" -#include "rem0cmp.h" -#include "ut0dbg.h" -#include "dict0priv.h" -#include "ut0ut.h" -#include "ha_prototypes.h" -#include "trx0roll.h" - -/** configure variable for binlog option with InnoDB APIs */ -my_bool ib_binlog_enabled = FALSE; - -/** configure variable for MDL option with InnoDB APIs */ -my_bool ib_mdl_enabled = FALSE; - -/** configure variable for disable rowlock with InnoDB APIs */ -my_bool ib_disable_row_lock = FALSE; - -/** configure variable for Transaction isolation levels */ -ulong ib_trx_level_setting = IB_TRX_READ_UNCOMMITTED; - -/** configure variable for background commit interval in seconds */ -ulong ib_bk_commit_interval = 0; - -/** InnoDB tuple types. */ -enum ib_tuple_type_t{ - TPL_TYPE_ROW, /*!< Data row tuple */ - TPL_TYPE_KEY /*!< Index key tuple */ -}; - -/** Query types supported. */ -enum ib_qry_type_t{ - QRY_NON, /*!< None/Sentinel */ - QRY_INS, /*!< Insert operation */ - QRY_UPD, /*!< Update operation */ - QRY_SEL /*!< Select operation */ -}; - -/** Query graph types. */ -struct ib_qry_grph_t { - que_fork_t* ins; /*!< Innobase SQL query graph used - in inserts */ - que_fork_t* upd; /*!< Innobase SQL query graph used - in updates or deletes */ - que_fork_t* sel; /*!< dummy query graph used in - selects */ -}; - -/** Query node types. */ -struct ib_qry_node_t { - ins_node_t* ins; /*!< Innobase SQL insert node - used to perform inserts to the table */ - upd_node_t* upd; /*!< Innobase SQL update node - used to perform updates and deletes */ - sel_node_t* sel; /*!< Innobase SQL select node - used to perform selects on the table */ -}; - -/** Query processing fields. */ -struct ib_qry_proc_t { - - ib_qry_node_t node; /*!< Query node*/ - - ib_qry_grph_t grph; /*!< Query graph */ -}; - -/** Cursor instance for traversing tables/indexes. This will eventually -become row_prebuilt_t. */ -struct ib_cursor_t { - mem_heap_t* heap; /*!< Instance heap */ - - mem_heap_t* query_heap; /*!< Heap to use for query graphs */ - - ib_qry_proc_t q_proc; /*!< Query processing info */ - - ib_match_mode_t match_mode; /*!< ib_cursor_moveto match mode */ - - row_prebuilt_t* prebuilt; /*!< For reading rows */ - - bool valid_trx; /*!< Valid transaction attached */ -}; - -/** InnoDB table columns used during table and index schema creation. */ -struct ib_col_t { - const char* name; /*!< Name of column */ - - ib_col_type_t ib_col_type; /*!< Main type of the column */ - - ulint len; /*!< Length of the column */ - - ib_col_attr_t ib_col_attr; /*!< Column attributes */ - -}; - -/** InnoDB index columns used during index and index schema creation. */ -struct ib_key_col_t { - const char* name; /*!< Name of column */ - - ulint prefix_len; /*!< Column index prefix len or 0 */ -}; - -struct ib_table_def_t; - -/** InnoDB index schema used during index creation */ -struct ib_index_def_t { - mem_heap_t* heap; /*!< Heap used to build this and all - its columns in the list */ - - const char* name; /*!< Index name */ - - dict_table_t* table; /*!< Parent InnoDB table */ - - ib_table_def_t* schema; /*!< Parent table schema that owns - this instance */ - - ibool clustered; /*!< True if clustered index */ - - ibool unique; /*!< True if unique index */ - - ib_vector_t* cols; /*!< Vector of columns */ - - trx_t* usr_trx; /*!< User transacton covering the - DDL operations */ -}; - -/** InnoDB table schema used during table creation */ -struct ib_table_def_t { - mem_heap_t* heap; /*!< Heap used to build this and all - its columns in the list */ - const char* name; /*!< Table name */ - - ib_tbl_fmt_t ib_tbl_fmt; /*!< Row format */ - - ulint page_size; /*!< Page size */ - - ib_vector_t* cols; /*!< Vector of columns */ - - ib_vector_t* indexes; /*!< Vector of indexes */ - - dict_table_t* table; /* Table read from or NULL */ -}; - -/** InnoDB tuple used for key operations. */ -struct ib_tuple_t { - mem_heap_t* heap; /*!< Heap used to build - this and for copying - the column values. */ - - ib_tuple_type_t type; /*!< Tuple discriminitor. */ - - const dict_index_t* index; /*!< Index for tuple can be either - secondary or cluster index. */ - - dtuple_t* ptr; /*!< The internal tuple - instance */ -}; - -/** The following counter is used to convey information to InnoDB -about server activity: in case of normal DML ops it is not -sensible to call srv_active_wake_master_thread after each -operation, we only do it every INNOBASE_WAKE_INTERVAL'th step. */ - -#define INNOBASE_WAKE_INTERVAL 32 - -/*****************************************************************//** -Check whether the Innodb persistent cursor is positioned. -@return IB_TRUE if positioned */ -UNIV_INLINE -ib_bool_t -ib_btr_cursor_is_positioned( -/*========================*/ - btr_pcur_t* pcur) /*!< in: InnoDB persistent cursor */ -{ - return(pcur->old_stored == BTR_PCUR_OLD_STORED - && (pcur->pos_state == BTR_PCUR_IS_POSITIONED - || pcur->pos_state == BTR_PCUR_WAS_POSITIONED)); -} - - -/********************************************************************//** -Open a table using the table id, if found then increment table ref count. -@return table instance if found */ -static -dict_table_t* -ib_open_table_by_id( -/*================*/ - ib_id_u64_t tid, /*!< in: table id to lookup */ - ib_bool_t locked) /*!< in: TRUE if own dict mutex */ -{ - dict_table_t* table; - table_id_t table_id; - - table_id = tid; - - if (!locked) { - dict_mutex_enter_for_mysql(); - } - - table = dict_table_open_on_id(table_id, TRUE, DICT_TABLE_OP_NORMAL); - - if (table != NULL && table->file_unreadable) { - table = NULL; - } - - if (!locked) { - dict_mutex_exit_for_mysql(); - } - - return(table); -} - -/********************************************************************//** -Open a table using the table name, if found then increment table ref count. -@return table instance if found */ -UNIV_INTERN -void* -ib_open_table_by_name( -/*==================*/ - const char* name) /*!< in: table name to lookup */ -{ - dict_table_t* table; - - table = dict_table_open_on_name(name, FALSE, FALSE, - DICT_ERR_IGNORE_NONE); - - if (table != NULL && table->file_unreadable) { - table = NULL; - } - - return(table); -} - -/********************************************************************//** -Find table using table name. -@return table instance if found */ -static -dict_table_t* -ib_lookup_table_by_name( -/*====================*/ - const char* name) /*!< in: table name to lookup */ -{ - dict_table_t* table; - - table = dict_table_get_low(name); - - if (table != NULL && table->file_unreadable) { - table = NULL; - } - - return(table); -} - -/********************************************************************//** -Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth -time calls srv_active_wake_master_thread. This function should be used -when a single database operation may introduce a small need for -server utility activity, like checkpointing. */ -UNIV_INLINE -void -ib_wake_master_thread(void) -/*=======================*/ -{ - static ulint ib_signal_counter = 0; - - ++ib_signal_counter; - - if ((ib_signal_counter % INNOBASE_WAKE_INTERVAL) == 0) { - srv_active_wake_master_thread(); - } -} - -/*****************************************************************//** -Read the columns from a rec into a tuple. */ -static -void -ib_read_tuple( -/*==========*/ - const rec_t* rec, /*!< in: Record to read */ - ib_bool_t page_format, /*!< in: IB_TRUE if compressed format */ - ib_tuple_t* tuple, /*!< in: tuple to read into */ - void** rec_buf, /*!< in/out: row buffer */ - ulint* len) /*!< in/out: buffer len */ -{ - ulint i; - void* ptr; - rec_t* copy; - ulint rec_meta_data; - ulint n_index_fields; - ulint offsets_[REC_OFFS_NORMAL_SIZE]; - ulint* offsets = offsets_; - dtuple_t* dtuple = tuple->ptr; - const dict_index_t* index = tuple->index; - ulint offset_size; - - rec_offs_init(offsets_); - - offsets = rec_get_offsets( - rec, index, offsets, ULINT_UNDEFINED, &tuple->heap); - - rec_meta_data = rec_get_info_bits(rec, page_format); - dtuple_set_info_bits(dtuple, rec_meta_data); - - offset_size = rec_offs_size(offsets); - - if (rec_buf && *rec_buf) { - if (*len < offset_size) { - free(*rec_buf); - *rec_buf = malloc(offset_size); - *len = offset_size; - } - ptr = *rec_buf; - } else { - /* Make a copy of the rec. */ - ptr = mem_heap_alloc(tuple->heap, offset_size); - } - - copy = rec_copy(ptr, rec, offsets); - - n_index_fields = ut_min( - rec_offs_n_fields(offsets), dtuple_get_n_fields(dtuple)); - - for (i = 0; i < n_index_fields; ++i) { - ulint len; - const byte* data; - dfield_t* dfield; - - if (tuple->type == TPL_TYPE_ROW) { - const dict_col_t* col; - ulint col_no; - const dict_field_t* index_field; - - index_field = dict_index_get_nth_field(index, i); - col = dict_field_get_col(index_field); - col_no = dict_col_get_no(col); - - dfield = dtuple_get_nth_field(dtuple, col_no); - } else { - dfield = dtuple_get_nth_field(dtuple, i); - } - - data = rec_get_nth_field(copy, offsets, i, &len); - - /* Fetch and copy any externally stored column. */ - if (rec_offs_nth_extern(offsets, i)) { - - ulint zip_size; - - zip_size = dict_table_zip_size(index->table); - - data = btr_rec_copy_externally_stored_field( - copy, offsets, zip_size, i, &len, - tuple->heap, NULL); - - ut_a(len != UNIV_SQL_NULL); - } - - dfield_set_data(dfield, data, len); - } -} - -/*****************************************************************//** -Create an InnoDB key tuple. -@return tuple instance created, or NULL */ -static -ib_tpl_t -ib_key_tuple_new_low( -/*=================*/ - const dict_index_t* index, /*!< in: index for which tuple - required */ - ulint n_cols, /*!< in: no. of user defined cols */ - mem_heap_t* heap) /*!< in: memory heap */ -{ - ib_tuple_t* tuple; - ulint i; - ulint n_cmp_cols; - - tuple = static_cast<ib_tuple_t*>( - mem_heap_alloc(heap, sizeof(*tuple))); - - if (tuple == NULL) { - mem_heap_free(heap); - return(NULL); - } - - tuple->heap = heap; - tuple->index = index; - tuple->type = TPL_TYPE_KEY; - - /* Is it a generated clustered index ? */ - if (n_cols == 0) { - ++n_cols; - } - - tuple->ptr = dtuple_create(heap, n_cols); - - /* Copy types and set to SQL_NULL. */ - dict_index_copy_types(tuple->ptr, index, n_cols); - - for (i = 0; i < n_cols; i++) { - - dfield_t* dfield; - - dfield = dtuple_get_nth_field(tuple->ptr, i); - dfield_set_null(dfield); - } - - n_cmp_cols = dict_index_get_n_ordering_defined_by_user(index); - - dtuple_set_n_fields_cmp(tuple->ptr, n_cmp_cols); - - return((ib_tpl_t) tuple); -} - -/*****************************************************************//** -Create an InnoDB key tuple. -@return tuple instance created, or NULL */ -static -ib_tpl_t -ib_key_tuple_new( -/*=============*/ - const dict_index_t* index, /*!< in: index of tuple */ - ulint n_cols) /*!< in: no. of user defined cols */ -{ - mem_heap_t* heap; - - heap = mem_heap_create(64); - - if (heap == NULL) { - return(NULL); - } - - return(ib_key_tuple_new_low(index, n_cols, heap)); -} - -/*****************************************************************//** -Create an InnoDB row tuple. -@return tuple instance, or NULL */ -static -ib_tpl_t -ib_row_tuple_new_low( -/*=================*/ - const dict_index_t* index, /*!< in: index of tuple */ - ulint n_cols, /*!< in: no. of cols in tuple */ - mem_heap_t* heap) /*!< in: memory heap */ -{ - ib_tuple_t* tuple; - - tuple = static_cast<ib_tuple_t*>(mem_heap_alloc(heap, sizeof(*tuple))); - - if (tuple == NULL) { - mem_heap_free(heap); - return(NULL); - } - - tuple->heap = heap; - tuple->index = index; - tuple->type = TPL_TYPE_ROW; - - tuple->ptr = dtuple_create(heap, n_cols); - - /* Copy types and set to SQL_NULL. */ - dict_table_copy_types(tuple->ptr, index->table); - - return((ib_tpl_t) tuple); -} - -/*****************************************************************//** -Create an InnoDB row tuple. -@return tuple instance, or NULL */ -static -ib_tpl_t -ib_row_tuple_new( -/*=============*/ - const dict_index_t* index, /*!< in: index of tuple */ - ulint n_cols) /*!< in: no. of cols in tuple */ -{ - mem_heap_t* heap; - - heap = mem_heap_create(64); - - if (heap == NULL) { - return(NULL); - } - - return(ib_row_tuple_new_low(index, n_cols, heap)); -} - -/*****************************************************************//** -Begin a transaction. -@return innobase txn handle */ -UNIV_INTERN -ib_err_t -ib_trx_start( -/*=========*/ - ib_trx_t ib_trx, /*!< in: transaction to restart */ - ib_trx_level_t ib_trx_level, /*!< in: trx isolation level */ - ib_bool_t read_write, /*!< in: true if read write - transaction */ - ib_bool_t auto_commit, /*!< in: auto commit after each - single DML */ - void* thd) /*!< in: THD */ -{ - ib_err_t err = DB_SUCCESS; - trx_t* trx = (trx_t*) ib_trx; - - ut_a(ib_trx_level <= IB_TRX_SERIALIZABLE); - - trx->api_trx = true; - trx->api_auto_commit = auto_commit; - trx->read_write = read_write; - - trx_start_if_not_started(trx); - - trx->isolation_level = ib_trx_level; - - /* FIXME: This is a place holder, we should add an arg that comes - from the client. */ - trx->mysql_thd = static_cast<THD*>(thd); - - return(err); -} - -/*****************************************************************//** -Begin a transaction. This will allocate a new transaction handle. -put the transaction in the active state. -@return innobase txn handle */ -UNIV_INTERN -ib_trx_t -ib_trx_begin( -/*=========*/ - ib_trx_level_t ib_trx_level, /*!< in: trx isolation level */ - ib_bool_t read_write, /*!< in: true if read write - transaction */ - ib_bool_t auto_commit) /*!< in: auto commit after each - single DML */ -{ - trx_t* trx; - ib_bool_t started; - - trx = trx_allocate_for_mysql(); - - started = ib_trx_start(static_cast<ib_trx_t>(trx), ib_trx_level, - read_write, auto_commit, NULL); - ut_a(started); - - return(static_cast<ib_trx_t>(trx)); -} - - -/*****************************************************************//** -Check if transaction is read_only -@return transaction read_only status */ -UNIV_INTERN -ib_u32_t -ib_trx_read_only( -/*=============*/ - ib_trx_t ib_trx) /*!< in: trx handle */ -{ - trx_t* trx = (trx_t*) ib_trx; - - return(trx->read_only); -} - -/*****************************************************************//** -Get the transaction's state. -@return transaction state */ -UNIV_INTERN -ib_trx_state_t -ib_trx_state( -/*=========*/ - ib_trx_t ib_trx) /*!< in: trx handle */ -{ - trx_t* trx = (trx_t*) ib_trx; - - return((ib_trx_state_t) trx->state); -} - -/*****************************************************************//** -Get a trx start time. -@return trx start_time */ -UNIV_INTERN -ib_u64_t -ib_trx_get_start_time( -/*==================*/ - ib_trx_t ib_trx) /*!< in: transaction */ -{ - trx_t* trx = (trx_t*) ib_trx; - return(static_cast<ib_u64_t>(trx->start_time)); -} -/*****************************************************************//** -Release the resources of the transaction. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_trx_release( -/*===========*/ - ib_trx_t ib_trx) /*!< in: trx handle */ -{ - trx_t* trx = (trx_t*) ib_trx; - - ut_ad(trx != NULL); - trx_free_for_mysql(trx); - - return(DB_SUCCESS); -} - -/*****************************************************************//** -Commit a transaction. This function will also release the schema -latches too. -@return DB_SUCCESS or err code */ - -ib_err_t -ib_trx_commit( -/*==========*/ - ib_trx_t ib_trx) /*!< in: trx handle */ -{ - ib_err_t err = DB_SUCCESS; - trx_t* trx = (trx_t*) ib_trx; - - if (trx->state == TRX_STATE_NOT_STARTED) { - return(err); - } - - trx_commit(trx); - - return(DB_SUCCESS); -} - -/*****************************************************************//** -Rollback a transaction. This function will also release the schema -latches too. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_trx_rollback( -/*============*/ - ib_trx_t ib_trx) /*!< in: trx handle */ -{ - ib_err_t err; - trx_t* trx = (trx_t*) ib_trx; - - err = static_cast<ib_err_t>(trx_rollback_for_mysql(trx)); - - /* It should always succeed */ - ut_a(err == DB_SUCCESS); - - return(err); -} - -#ifdef __WIN__ -/*****************************************************************//** -Convert a string to lower case. */ -static -void -ib_to_lower_case( -/*=============*/ - char* ptr) /*!< string to convert to lower case */ -{ - while (*ptr) { - *ptr = tolower(*ptr); - ++ptr; - } -} -#endif /* __WIN__ */ - -/*****************************************************************//** -Normalizes a table name string. A normalized name consists of the -database name catenated to '/' and table name. An example: -test/mytable. On Windows normalization puts both the database name and the -table name always to lower case. This function can be called for system -tables and they don't have a database component. For tables that don't have -a database component, we don't normalize them to lower case on Windows. -The assumption is that they are system tables that reside in the system -table space. */ -static -void -ib_normalize_table_name( -/*====================*/ - char* norm_name, /*!< out: normalized name as a - null-terminated string */ - const char* name) /*!< in: table name string */ -{ - const char* ptr = name; - - /* Scan name from the end */ - - ptr += ut_strlen(name) - 1; - - /* Find the start of the table name. */ - while (ptr >= name && *ptr != '\\' && *ptr != '/' && ptr > name) { - --ptr; - } - - - /* For system tables there is no '/' or dbname. */ - ut_a(ptr >= name); - - if (ptr > name) { - const char* db_name; - const char* table_name; - - table_name = ptr + 1; - - --ptr; - - while (ptr >= name && *ptr != '\\' && *ptr != '/') { - ptr--; - } - - db_name = ptr + 1; - - memcpy(norm_name, db_name, - ut_strlen(name) + 1 - (db_name - name)); - - norm_name[table_name - db_name - 1] = '/'; -#ifdef __WIN__ - ib_to_lower_case(norm_name); -#endif - } else { - ut_strcpy(norm_name, name); - } -} - -/*****************************************************************//** -Check whether the table name conforms to our requirements. Currently -we only do a simple check for the presence of a '/'. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_table_name_check( -/*================*/ - const char* name) /*!< in: table name to check */ -{ - const char* slash = NULL; - ulint len = ut_strlen(name); - - if (len < 2 - || *name == '/' - || name[len - 1] == '/' - || (name[0] == '.' && name[1] == '/') - || (name[0] == '.' && name[1] == '.' && name[2] == '/')) { - - return(DB_DATA_MISMATCH); - } - - for ( ; *name; ++name) { -#ifdef __WIN__ - /* Check for reserved characters in DOS filenames. */ - switch (*name) { - case ':': - case '|': - case '"': - case '*': - case '<': - case '>': - return(DB_DATA_MISMATCH); - } -#endif /* __WIN__ */ - if (*name == '/') { - if (slash) { - return(DB_DATA_MISMATCH); - } - slash = name; - } - } - - return(slash ? DB_SUCCESS : DB_DATA_MISMATCH); -} - - - -/*****************************************************************//** -Get a table id. The caller must have acquired the dictionary mutex. -@return DB_SUCCESS if found */ -static -ib_err_t -ib_table_get_id_low( -/*================*/ - const char* table_name, /*!< in: table to find */ - ib_id_u64_t* table_id) /*!< out: table id if found */ -{ - dict_table_t* table; - ib_err_t err = DB_TABLE_NOT_FOUND; - - *table_id = 0; - - table = ib_lookup_table_by_name(table_name); - - if (table != NULL) { - *table_id = (table->id); - - err = DB_SUCCESS; - } - - return(err); -} - -/*****************************************************************//** -Create an internal cursor instance. -@return DB_SUCCESS or err code */ -static -ib_err_t -ib_create_cursor( -/*=============*/ - ib_crsr_t* ib_crsr, /*!< out: InnoDB cursor */ - dict_table_t* table, /*!< in: table instance */ - dict_index_t* index, /*!< in: index to use */ - trx_t* trx) /*!< in: transaction */ -{ - mem_heap_t* heap; - ib_cursor_t* cursor; - ib_err_t err = DB_SUCCESS; - - heap = mem_heap_create(sizeof(*cursor) * 2); - - if (heap != NULL) { - row_prebuilt_t* prebuilt; - - cursor = static_cast<ib_cursor_t*>( - mem_heap_zalloc(heap, sizeof(*cursor))); - - cursor->heap = heap; - - cursor->query_heap = mem_heap_create(64); - - if (cursor->query_heap == NULL) { - mem_heap_free(heap); - - return(DB_OUT_OF_MEMORY); - } - - cursor->prebuilt = row_create_prebuilt(table, 0); - - prebuilt = cursor->prebuilt; - - prebuilt->trx = trx; - - cursor->valid_trx = TRUE; - - prebuilt->table = table; - prebuilt->select_lock_type = LOCK_NONE; - prebuilt->innodb_api = TRUE; - - prebuilt->index = index; - - ut_a(prebuilt->index != NULL); - - if (prebuilt->trx != NULL) { - ++prebuilt->trx->n_mysql_tables_in_use; - - prebuilt->index_usable = - row_merge_is_index_usable( - prebuilt->trx, prebuilt->index); - - /* Assign a read view if the transaction does - not have it yet */ - - trx_assign_read_view(prebuilt->trx); - } - - *ib_crsr = (ib_crsr_t) cursor; - } else { - err = DB_OUT_OF_MEMORY; - } - - return(err); -} - -/*****************************************************************//** -Create an internal cursor instance, and set prebuilt->index to index -with supplied index_id. -@return DB_SUCCESS or err code */ -static -ib_err_t -ib_create_cursor_with_index_id( -/*===========================*/ - ib_crsr_t* ib_crsr, /*!< out: InnoDB cursor */ - dict_table_t* table, /*!< in: table instance */ - ib_id_u64_t index_id, /*!< in: index id or 0 */ - trx_t* trx) /*!< in: transaction */ -{ - dict_index_t* index; - - if (index_id != 0) { - mutex_enter(&dict_sys->mutex); - index = dict_index_find_on_id_low(index_id); - mutex_exit(&dict_sys->mutex); - } else { - index = dict_table_get_first_index(table); - } - - return(ib_create_cursor(ib_crsr, table, index, trx)); -} - -/*****************************************************************//** -Open an InnoDB table and return a cursor handle to it. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_open_table_using_id( -/*==========================*/ - ib_id_u64_t table_id, /*!< in: table id of table to open */ - ib_trx_t ib_trx, /*!< in: Current transaction handle - can be NULL */ - ib_crsr_t* ib_crsr) /*!< out,own: InnoDB cursor */ -{ - ib_err_t err; - dict_table_t* table; - - if (ib_trx == NULL || !ib_schema_lock_is_exclusive(ib_trx)) { - table = ib_open_table_by_id(table_id, FALSE); - } else { - table = ib_open_table_by_id(table_id, TRUE); - } - - if (table == NULL) { - - return(DB_TABLE_NOT_FOUND); - } - - err = ib_create_cursor_with_index_id(ib_crsr, table, 0, - (trx_t*) ib_trx); - - return(err); -} - -/*****************************************************************//** -Open an InnoDB index and return a cursor handle to it. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_open_index_using_id( -/*==========================*/ - ib_id_u64_t index_id, /*!< in: index id of index to open */ - ib_trx_t ib_trx, /*!< in: Current transaction handle - can be NULL */ - ib_crsr_t* ib_crsr) /*!< out: InnoDB cursor */ -{ - ib_err_t err; - dict_table_t* table; - ulint table_id = (ulint)( index_id >> 32); - - if (ib_trx == NULL || !ib_schema_lock_is_exclusive(ib_trx)) { - table = ib_open_table_by_id(table_id, FALSE); - } else { - table = ib_open_table_by_id(table_id, TRUE); - } - - if (table == NULL) { - - return(DB_TABLE_NOT_FOUND); - } - - /* We only return the lower 32 bits of the dulint. */ - err = ib_create_cursor_with_index_id( - ib_crsr, table, index_id, (trx_t*) ib_trx); - - if (ib_crsr != NULL) { - const ib_cursor_t* cursor; - - cursor = *(ib_cursor_t**) ib_crsr; - - if (cursor->prebuilt->index == NULL) { - ib_err_t crsr_err; - - crsr_err = ib_cursor_close(*ib_crsr); - ut_a(crsr_err == DB_SUCCESS); - - *ib_crsr = NULL; - } - } - - return(err); -} - -/*****************************************************************//** -Open an InnoDB secondary index cursor and return a cursor handle to it. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_open_index_using_name( -/*============================*/ - ib_crsr_t ib_open_crsr, /*!< in: open/active cursor */ - const char* index_name, /*!< in: secondary index name */ - ib_crsr_t* ib_crsr, /*!< out,own: InnoDB index cursor */ - int* idx_type, /*!< out: index is cluster index */ - ib_id_u64_t* idx_id) /*!< out: index id */ -{ - dict_table_t* table; - dict_index_t* index; - index_id_t index_id = 0; - ib_err_t err = DB_TABLE_NOT_FOUND; - ib_cursor_t* cursor = (ib_cursor_t*) ib_open_crsr; - - *idx_type = 0; - *idx_id = 0; - *ib_crsr = NULL; - - /* We want to increment the ref count, so we do a redundant search. */ - table = dict_table_open_on_id(cursor->prebuilt->table->id, - FALSE, DICT_TABLE_OP_NORMAL); - ut_a(table != NULL); - - /* The first index is always the cluster index. */ - index = dict_table_get_first_index(table); - - /* Traverse the user defined indexes. */ - while (index != NULL) { - if (innobase_strcasecmp(index->name, index_name) == 0) { - index_id = index->id; - *idx_type = index->type; - *idx_id = index_id; - break; - } - index = UT_LIST_GET_NEXT(indexes, index); - } - - if (!index_id) { - dict_table_close(table, FALSE, FALSE); - return(DB_ERROR); - } - - if (index_id > 0) { - ut_ad(index->id == index_id); - err = ib_create_cursor( - ib_crsr, table, index, cursor->prebuilt->trx); - } - - if (*ib_crsr != NULL) { - const ib_cursor_t* cursor; - - cursor = *(ib_cursor_t**) ib_crsr; - - if (cursor->prebuilt->index == NULL) { - err = ib_cursor_close(*ib_crsr); - ut_a(err == DB_SUCCESS); - *ib_crsr = NULL; - } - } - - return(err); -} - -/*****************************************************************//** -Open an InnoDB table and return a cursor handle to it. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_open_table( -/*=================*/ - const char* name, /*!< in: table name */ - ib_trx_t ib_trx, /*!< in: Current transaction handle - can be NULL */ - ib_crsr_t* ib_crsr) /*!< out,own: InnoDB cursor */ -{ - ib_err_t err; - dict_table_t* table; - char* normalized_name; - - normalized_name = static_cast<char*>(mem_alloc(ut_strlen(name) + 1)); - ib_normalize_table_name(normalized_name, name); - - if (ib_trx != NULL) { - if (!ib_schema_lock_is_exclusive(ib_trx)) { - table = (dict_table_t*)ib_open_table_by_name( - normalized_name); - } else { - /* NOTE: We do not acquire MySQL metadata lock */ - table = ib_lookup_table_by_name(normalized_name); - } - } else { - table = (dict_table_t*)ib_open_table_by_name(normalized_name); - } - - mem_free(normalized_name); - normalized_name = NULL; - - /* It can happen that another thread has created the table but - not the cluster index or it's a broken table definition. Refuse to - open if that's the case. */ - if (table != NULL && dict_table_get_first_index(table) == NULL) { - table = NULL; - } - - if (table != NULL) { - err = ib_create_cursor_with_index_id(ib_crsr, table, 0, - (trx_t*) ib_trx); - } else { - err = DB_TABLE_NOT_FOUND; - } - - return(err); -} - -/********************************************************************//** -Free a context struct for a table handle. */ -static -void -ib_qry_proc_free( -/*=============*/ - ib_qry_proc_t* q_proc) /*!< in, own: qproc struct */ -{ - que_graph_free_recursive(q_proc->grph.ins); - que_graph_free_recursive(q_proc->grph.upd); - que_graph_free_recursive(q_proc->grph.sel); - - memset(q_proc, 0x0, sizeof(*q_proc)); -} - -/*****************************************************************//** -set a cursor trx to NULL */ -UNIV_INTERN -void -ib_cursor_clear_trx( -/*================*/ - ib_crsr_t ib_crsr) /*!< in/out: InnoDB cursor */ -{ - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - - cursor->prebuilt->trx = NULL; -} - -/*****************************************************************//** -Reset the cursor. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_reset( -/*============*/ - ib_crsr_t ib_crsr) /*!< in/out: InnoDB cursor */ -{ - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - - if (cursor->valid_trx && prebuilt->trx != NULL - && prebuilt->trx->n_mysql_tables_in_use > 0) { - - --prebuilt->trx->n_mysql_tables_in_use; - } - - /* The fields in this data structure are allocated from - the query heap and so need to be reset too. */ - ib_qry_proc_free(&cursor->q_proc); - - mem_heap_empty(cursor->query_heap); - - return(DB_SUCCESS); -} - -/*****************************************************************//** -update the cursor with new transactions and also reset the cursor -@return DB_SUCCESS or err code */ -ib_err_t -ib_cursor_new_trx( -/*==============*/ - ib_crsr_t ib_crsr, /*!< in/out: InnoDB cursor */ - ib_trx_t ib_trx) /*!< in: transaction */ -{ - ib_err_t err = DB_SUCCESS; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - trx_t* trx = (trx_t*) ib_trx; - - row_prebuilt_t* prebuilt = cursor->prebuilt; - - row_update_prebuilt_trx(prebuilt, trx); - - cursor->valid_trx = TRUE; - - trx_assign_read_view(prebuilt->trx); - - ib_qry_proc_free(&cursor->q_proc); - - mem_heap_empty(cursor->query_heap); - - return(err); -} - -/*****************************************************************//** -Commit the transaction in a cursor -@return DB_SUCCESS or err code */ -ib_err_t -ib_cursor_commit_trx( -/*=================*/ - ib_crsr_t ib_crsr, /*!< in/out: InnoDB cursor */ - ib_trx_t ib_trx) /*!< in: transaction */ -{ - ib_err_t err = DB_SUCCESS; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; -#ifdef UNIV_DEBUG - row_prebuilt_t* prebuilt = cursor->prebuilt; - - ut_ad(prebuilt->trx == (trx_t*) ib_trx); -#endif /* UNIV_DEBUG */ - ib_trx_commit(ib_trx); - cursor->valid_trx = FALSE; - return(err); -} - -/*****************************************************************//** -Close an InnoDB table and free the cursor. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_close( -/*============*/ - ib_crsr_t ib_crsr) /*!< in,own: InnoDB cursor */ -{ - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt; - trx_t* trx; - - if (!cursor) { - return(DB_SUCCESS); - } - - prebuilt = cursor->prebuilt; - trx = prebuilt->trx; - - ib_qry_proc_free(&cursor->q_proc); - - /* The transaction could have been detached from the cursor. */ - if (cursor->valid_trx && trx != NULL - && trx->n_mysql_tables_in_use > 0) { - --trx->n_mysql_tables_in_use; - } - - row_prebuilt_free(prebuilt, FALSE); - cursor->prebuilt = NULL; - - mem_heap_free(cursor->query_heap); - mem_heap_free(cursor->heap); - cursor = NULL; - - return(DB_SUCCESS); -} - -/*****************************************************************//** -Close the table, decrement n_ref_count count. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_close_table( -/*==================*/ - ib_crsr_t ib_crsr) /*!< in,own: InnoDB cursor */ -{ - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - - if (prebuilt && prebuilt->table) { - dict_table_close(prebuilt->table, FALSE, FALSE); - } - - return(DB_SUCCESS); -} -/**********************************************************************//** -Run the insert query and do error handling. -@return DB_SUCCESS or error code */ -UNIV_INLINE -ib_err_t -ib_insert_row_with_lock_retry( -/*==========================*/ - que_thr_t* thr, /*!< in: insert query graph */ - ins_node_t* node, /*!< in: insert node for the query */ - trx_savept_t* savept) /*!< in: savepoint to rollback to - in case of an error */ -{ - trx_t* trx; - ib_err_t err; - ib_bool_t lock_wait; - - trx = thr_get_trx(thr); - - do { - thr->run_node = node; - thr->prev_node = node; - - row_ins_step(thr); - - err = trx->error_state; - - if (err != DB_SUCCESS) { - que_thr_stop_for_mysql(thr); - - thr->lock_state = QUE_THR_LOCK_ROW; - lock_wait = static_cast<ib_bool_t>( - ib_handle_errors(&err, trx, thr, savept)); - thr->lock_state = QUE_THR_LOCK_NOLOCK; - } else { - lock_wait = FALSE; - } - } while (lock_wait); - - return(err); -} - -/*****************************************************************//** -Write a row. -@return DB_SUCCESS or err code */ -static -ib_err_t -ib_execute_insert_query_graph( -/*==========================*/ - dict_table_t* table, /*!< in: table where to insert */ - que_fork_t* ins_graph, /*!< in: query graph */ - ins_node_t* node) /*!< in: insert node */ -{ - trx_t* trx; - que_thr_t* thr; - trx_savept_t savept; - ib_err_t err = DB_SUCCESS; - - trx = ins_graph->trx; - - savept = trx_savept_take(trx); - - thr = que_fork_get_first_thr(ins_graph); - - que_thr_move_to_run_state_for_mysql(thr, trx); - - err = ib_insert_row_with_lock_retry(thr, node, &savept); - - if (err == DB_SUCCESS) { - que_thr_stop_for_mysql_no_error(thr, trx); - - dict_table_n_rows_inc(table); - - if (table->is_system_db) { - srv_stats.n_system_rows_inserted.inc(); - } else { - srv_stats.n_rows_inserted.inc(); - } - } - - trx->op_info = ""; - - return(err); -} - -/*****************************************************************//** -Create an insert query graph node. */ -static -void -ib_insert_query_graph_create( -/*==========================*/ - ib_cursor_t* cursor) /*!< in: Cursor instance */ -{ - ib_qry_proc_t* q_proc = &cursor->q_proc; - ib_qry_node_t* node = &q_proc->node; - trx_t* trx = cursor->prebuilt->trx; - - ut_a(trx->state != TRX_STATE_NOT_STARTED); - - if (node->ins == NULL) { - dtuple_t* row; - ib_qry_grph_t* grph = &q_proc->grph; - mem_heap_t* heap = cursor->query_heap; - dict_table_t* table = cursor->prebuilt->table; - - node->ins = ins_node_create(INS_DIRECT, table, heap); - - node->ins->select = NULL; - node->ins->values_list = NULL; - - row = dtuple_create(heap, dict_table_get_n_cols(table)); - dict_table_copy_types(row, table); - - ins_node_set_new_row(node->ins, row); - - grph->ins = static_cast<que_fork_t*>( - que_node_get_parent( - pars_complete_graph_for_exec(node->ins, trx, - heap))); - - grph->ins->state = QUE_FORK_ACTIVE; - } -} - -/*****************************************************************//** -Insert a row to a table. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_insert_row( -/*=================*/ - ib_crsr_t ib_crsr, /*!< in/out: InnoDB cursor instance */ - const ib_tpl_t ib_tpl) /*!< in: tuple to insert */ -{ - ib_ulint_t i; - ib_qry_node_t* node; - ib_qry_proc_t* q_proc; - ulint n_fields; - dtuple_t* dst_dtuple; - ib_err_t err = DB_SUCCESS; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - const ib_tuple_t* src_tuple = (const ib_tuple_t*) ib_tpl; - - ib_insert_query_graph_create(cursor); - - ut_ad(src_tuple->type == TPL_TYPE_ROW); - - q_proc = &cursor->q_proc; - node = &q_proc->node; - - node->ins->state = INS_NODE_ALLOC_ROW_ID; - dst_dtuple = node->ins->row; - - n_fields = dtuple_get_n_fields(src_tuple->ptr); - ut_ad(n_fields == dtuple_get_n_fields(dst_dtuple)); - - /* Do a shallow copy of the data fields and check for NULL - constraints on columns. */ - for (i = 0; i < n_fields; i++) { - ulint mtype; - dfield_t* src_field; - dfield_t* dst_field; - - src_field = dtuple_get_nth_field(src_tuple->ptr, i); - - mtype = dtype_get_mtype(dfield_get_type(src_field)); - - /* Don't touch the system columns. */ - if (mtype != DATA_SYS) { - ulint prtype; - - prtype = dtype_get_prtype(dfield_get_type(src_field)); - - if ((prtype & DATA_NOT_NULL) - && dfield_is_null(src_field)) { - - err = DB_DATA_MISMATCH; - break; - } - - dst_field = dtuple_get_nth_field(dst_dtuple, i); - ut_ad(mtype - == dtype_get_mtype(dfield_get_type(dst_field))); - - /* Do a shallow copy. */ - dfield_set_data( - dst_field, src_field->data, src_field->len); - - if (dst_field->len != IB_SQL_NULL) { - UNIV_MEM_ASSERT_RW(dst_field->data, - dst_field->len); - } - } - } - - if (err == DB_SUCCESS) { - err = ib_execute_insert_query_graph( - src_tuple->index->table, q_proc->grph.ins, node->ins); - } - - ib_wake_master_thread(); - - return(err); -} - -/*********************************************************************//** -Gets pointer to a prebuilt update vector used in updates. -@return update vector */ -UNIV_INLINE -upd_t* -ib_update_vector_create( -/*====================*/ - ib_cursor_t* cursor) /*!< in: current cursor */ -{ - trx_t* trx = cursor->prebuilt->trx; - mem_heap_t* heap = cursor->query_heap; - dict_table_t* table = cursor->prebuilt->table; - ib_qry_proc_t* q_proc = &cursor->q_proc; - ib_qry_grph_t* grph = &q_proc->grph; - ib_qry_node_t* node = &q_proc->node; - - ut_a(trx->state != TRX_STATE_NOT_STARTED); - - if (node->upd == NULL) { - node->upd = static_cast<upd_node_t*>( - row_create_update_node_for_mysql(table, heap)); - } - - grph->upd = static_cast<que_fork_t*>( - que_node_get_parent( - pars_complete_graph_for_exec(node->upd, trx, heap))); - - grph->upd->state = QUE_FORK_ACTIVE; - - return(node->upd->update); -} - -/**********************************************************************//** -Note that a column has changed. */ -static -void -ib_update_col( -/*==========*/ - - ib_cursor_t* cursor, /*!< in: current cursor */ - upd_field_t* upd_field, /*!< in/out: update field */ - ulint col_no, /*!< in: column number */ - dfield_t* dfield) /*!< in: updated dfield */ -{ - ulint data_len; - dict_table_t* table = cursor->prebuilt->table; - dict_index_t* index = dict_table_get_first_index(table); - - data_len = dfield_get_len(dfield); - - if (data_len == UNIV_SQL_NULL) { - dfield_set_null(&upd_field->new_val); - } else { - dfield_copy_data(&upd_field->new_val, dfield); - } - - upd_field->exp = NULL; - - upd_field->orig_len = 0; - - upd_field->field_no = dict_col_get_clust_pos( - &table->cols[col_no], index); -} - -/**********************************************************************//** -Checks which fields have changed in a row and stores the new data -to an update vector. -@return DB_SUCCESS or err code */ -static -ib_err_t -ib_calc_diff( -/*=========*/ - ib_cursor_t* cursor, /*!< in: current cursor */ - upd_t* upd, /*!< in/out: update vector */ - const ib_tuple_t*old_tuple, /*!< in: Old tuple in table */ - const ib_tuple_t*new_tuple) /*!< in: New tuple to update */ -{ - ulint i; - ulint n_changed = 0; - ib_err_t err = DB_SUCCESS; - ulint n_fields = dtuple_get_n_fields(new_tuple->ptr); - - ut_a(old_tuple->type == TPL_TYPE_ROW); - ut_a(new_tuple->type == TPL_TYPE_ROW); - ut_a(old_tuple->index->table == new_tuple->index->table); - - for (i = 0; i < n_fields; ++i) { - ulint mtype; - ulint prtype; - upd_field_t* upd_field; - dfield_t* new_dfield; - dfield_t* old_dfield; - - new_dfield = dtuple_get_nth_field(new_tuple->ptr, i); - old_dfield = dtuple_get_nth_field(old_tuple->ptr, i); - - mtype = dtype_get_mtype(dfield_get_type(old_dfield)); - prtype = dtype_get_prtype(dfield_get_type(old_dfield)); - - /* Skip the system columns */ - if (mtype == DATA_SYS) { - continue; - - } else if ((prtype & DATA_NOT_NULL) - && dfield_is_null(new_dfield)) { - - err = DB_DATA_MISMATCH; - break; - } - - if (dfield_get_len(new_dfield) != dfield_get_len(old_dfield) - || (!dfield_is_null(old_dfield) - && memcmp(dfield_get_data(new_dfield), - dfield_get_data(old_dfield), - dfield_get_len(old_dfield)) != 0)) { - - upd_field = &upd->fields[n_changed]; - - ib_update_col(cursor, upd_field, i, new_dfield); - - ++n_changed; - } - } - - if (err == DB_SUCCESS) { - upd->info_bits = 0; - upd->n_fields = n_changed; - } - - return(err); -} - -/**********************************************************************//** -Run the update query and do error handling. -@return DB_SUCCESS or error code */ -UNIV_INLINE -ib_err_t -ib_update_row_with_lock_retry( -/*==========================*/ - que_thr_t* thr, /*!< in: Update query graph */ - upd_node_t* node, /*!< in: Update node for the query */ - trx_savept_t* savept) /*!< in: savepoint to rollback to - in case of an error */ - -{ - trx_t* trx; - ib_err_t err; - ib_bool_t lock_wait; - - trx = thr_get_trx(thr); - - do { - thr->run_node = node; - thr->prev_node = node; - - row_upd_step(thr); - - err = trx->error_state; - - if (err != DB_SUCCESS) { - que_thr_stop_for_mysql(thr); - - if (err != DB_RECORD_NOT_FOUND) { - thr->lock_state = QUE_THR_LOCK_ROW; - - lock_wait = static_cast<ib_bool_t>( - ib_handle_errors(&err, trx, thr, savept)); - - thr->lock_state = QUE_THR_LOCK_NOLOCK; - } else { - lock_wait = FALSE; - } - } else { - lock_wait = FALSE; - } - } while (lock_wait); - - return(err); -} - -/*********************************************************************//** -Does an update or delete of a row. -@return DB_SUCCESS or err code */ -UNIV_INLINE -ib_err_t -ib_execute_update_query_graph( -/*==========================*/ - ib_cursor_t* cursor, /*!< in: Cursor instance */ - btr_pcur_t* pcur) /*!< in: Btree persistent cursor */ -{ - ib_err_t err; - que_thr_t* thr; - upd_node_t* node; - trx_savept_t savept; - trx_t* trx = cursor->prebuilt->trx; - dict_table_t* table = cursor->prebuilt->table; - ib_qry_proc_t* q_proc = &cursor->q_proc; - - /* The transaction must be running. */ - ut_a(trx->state != TRX_STATE_NOT_STARTED); - - node = q_proc->node.upd; - - ut_a(dict_index_is_clust(pcur->btr_cur.index)); - btr_pcur_copy_stored_position(node->pcur, pcur); - - ut_a(node->pcur->rel_pos == BTR_PCUR_ON); - - savept = trx_savept_take(trx); - - thr = que_fork_get_first_thr(q_proc->grph.upd); - - node->state = UPD_NODE_UPDATE_CLUSTERED; - - que_thr_move_to_run_state_for_mysql(thr, trx); - - err = ib_update_row_with_lock_retry(thr, node, &savept); - - if (err == DB_SUCCESS) { - - que_thr_stop_for_mysql_no_error(thr, trx); - - if (node->is_delete) { - - dict_table_n_rows_dec(table); - - if (table->is_system_db) { - srv_stats.n_system_rows_deleted.inc(); - } else { - srv_stats.n_rows_deleted.inc(); - } - } else { - if (table->is_system_db) { - srv_stats.n_system_rows_updated.inc(); - } else { - srv_stats.n_rows_updated.inc(); - } - } - - } else if (err == DB_RECORD_NOT_FOUND) { - trx->error_state = DB_SUCCESS; - } - - trx->op_info = ""; - - return(err); -} - -/*****************************************************************//** -Update a row in a table. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_update_row( -/*=================*/ - ib_crsr_t ib_crsr, /*!< in: InnoDB cursor instance */ - const ib_tpl_t ib_old_tpl, /*!< in: Old tuple in table */ - const ib_tpl_t ib_new_tpl) /*!< in: New tuple to update */ -{ - upd_t* upd; - ib_err_t err; - btr_pcur_t* pcur; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - const ib_tuple_t*old_tuple = (const ib_tuple_t*) ib_old_tpl; - const ib_tuple_t*new_tuple = (const ib_tuple_t*) ib_new_tpl; - - if (dict_index_is_clust(prebuilt->index)) { - pcur = &cursor->prebuilt->pcur; - } else if (prebuilt->need_to_access_clustered) { - pcur = &cursor->prebuilt->clust_pcur; - } else { - return(DB_ERROR); - } - - ut_a(old_tuple->type == TPL_TYPE_ROW); - ut_a(new_tuple->type == TPL_TYPE_ROW); - - upd = ib_update_vector_create(cursor); - - err = ib_calc_diff(cursor, upd, old_tuple, new_tuple); - - if (err == DB_SUCCESS) { - /* Note that this is not a delete. */ - cursor->q_proc.node.upd->is_delete = FALSE; - - err = ib_execute_update_query_graph(cursor, pcur); - } - - ib_wake_master_thread(); - - return(err); -} - -/**********************************************************************//** -Build the update query graph to delete a row from an index. -@return DB_SUCCESS or err code */ -static -ib_err_t -ib_delete_row( -/*==========*/ - ib_cursor_t* cursor, /*!< in: current cursor */ - btr_pcur_t* pcur, /*!< in: Btree persistent cursor */ - const rec_t* rec) /*!< in: record to delete */ -{ - ulint i; - upd_t* upd; - ib_err_t err; - ib_tuple_t* tuple; - ib_tpl_t ib_tpl; - ulint n_cols; - upd_field_t* upd_field; - ib_bool_t page_format; - dict_table_t* table = cursor->prebuilt->table; - dict_index_t* index = dict_table_get_first_index(table); - - n_cols = dict_index_get_n_ordering_defined_by_user(index); - ib_tpl = ib_key_tuple_new(index, n_cols); - - if (!ib_tpl) { - return(DB_OUT_OF_MEMORY); - } - - tuple = (ib_tuple_t*) ib_tpl; - - upd = ib_update_vector_create(cursor); - - page_format = static_cast<ib_bool_t>( - dict_table_is_comp(index->table)); - ib_read_tuple(rec, page_format, tuple, NULL, NULL); - - upd->n_fields = ib_tuple_get_n_cols(ib_tpl); - - for (i = 0; i < upd->n_fields; ++i) { - dfield_t* dfield; - - upd_field = &upd->fields[i]; - dfield = dtuple_get_nth_field(tuple->ptr, i); - - dfield_copy_data(&upd_field->new_val, dfield); - - upd_field->exp = NULL; - - upd_field->orig_len = 0; - - upd->info_bits = 0; - - upd_field->field_no = dict_col_get_clust_pos( - &table->cols[i], index); - } - - /* Note that this is a delete. */ - cursor->q_proc.node.upd->is_delete = TRUE; - - err = ib_execute_update_query_graph(cursor, pcur); - - ib_tuple_delete(ib_tpl); - - return(err); -} - -/*****************************************************************//** -Delete a row in a table. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_delete_row( -/*=================*/ - ib_crsr_t ib_crsr) /*!< in: InnoDB cursor instance */ -{ - ib_err_t err; - btr_pcur_t* pcur; - dict_index_t* index; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - - index = dict_table_get_first_index(prebuilt->index->table); - - /* Check whether this is a secondary index cursor */ - if (index != prebuilt->index) { - if (prebuilt->need_to_access_clustered) { - pcur = &prebuilt->clust_pcur; - } else { - return(DB_ERROR); - } - } else { - pcur = &prebuilt->pcur; - } - - if (ib_btr_cursor_is_positioned(pcur)) { - const rec_t* rec; - ib_bool_t page_format; - mtr_t mtr; - rec_t* copy = NULL; - byte ptr[UNIV_PAGE_SIZE_MAX]; - - page_format = static_cast<ib_bool_t>( - dict_table_is_comp(index->table)); - - mtr_start(&mtr); - - if (btr_pcur_restore_position( - BTR_SEARCH_LEAF, pcur, &mtr)) { - mem_heap_t* heap = NULL; - ulint offsets_[REC_OFFS_NORMAL_SIZE]; - ulint* offsets = offsets_; - - rec_offs_init(offsets_); - - rec = btr_pcur_get_rec(pcur); - - /* Since mtr will be commited, the rec - will not be protected. Make a copy of - the rec. */ - offsets = rec_get_offsets( - rec, index, offsets, ULINT_UNDEFINED, &heap); - ut_ad(rec_offs_size(offsets) < UNIV_PAGE_SIZE_MAX); - copy = rec_copy(ptr, rec, offsets); - } - - mtr_commit(&mtr); - - if (copy && !rec_get_deleted_flag(copy, page_format)) { - err = ib_delete_row(cursor, pcur, copy); - } else { - err = DB_RECORD_NOT_FOUND; - } - } else { - err = DB_RECORD_NOT_FOUND; - } - - ib_wake_master_thread(); - - return(err); -} - -/*****************************************************************//** -Read current row. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_read_row( -/*===============*/ - ib_crsr_t ib_crsr, /*!< in: InnoDB cursor instance */ - ib_tpl_t ib_tpl, /*!< out: read cols into this tuple */ - void** row_buf, /*!< in/out: row buffer */ - ib_ulint_t* row_len) /*!< in/out: row buffer len */ -{ - ib_err_t err; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - - ut_a(cursor->prebuilt->trx->state != TRX_STATE_NOT_STARTED); - - /* When searching with IB_EXACT_MATCH set, row_search_for_mysql() - will not position the persistent cursor but will copy the record - found into the row cache. It should be the only entry. */ - if (!ib_cursor_is_positioned(ib_crsr) ) { - err = DB_RECORD_NOT_FOUND; - } else { - mtr_t mtr; - btr_pcur_t* pcur; - row_prebuilt_t* prebuilt = cursor->prebuilt; - - if (prebuilt->need_to_access_clustered - && tuple->type == TPL_TYPE_ROW) { - pcur = &prebuilt->clust_pcur; - } else { - pcur = &prebuilt->pcur; - } - - if (pcur == NULL) { - return(DB_ERROR); - } - - mtr_start(&mtr); - - if (btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr)) { - const rec_t* rec; - ib_bool_t page_format; - - page_format = static_cast<ib_bool_t>( - dict_table_is_comp(tuple->index->table)); - rec = btr_pcur_get_rec(pcur); - - if (prebuilt->innodb_api_rec && - prebuilt->innodb_api_rec != rec) { - rec = prebuilt->innodb_api_rec; - } - - if (!rec_get_deleted_flag(rec, page_format)) { - ib_read_tuple(rec, page_format, tuple, - row_buf, (ulint*) row_len); - err = DB_SUCCESS; - } else{ - err = DB_RECORD_NOT_FOUND; - } - - } else { - err = DB_RECORD_NOT_FOUND; - } - - mtr_commit(&mtr); - } - - return(err); -} - -/*****************************************************************//** -Move cursor to the first record in the table. -@return DB_SUCCESS or err code */ -UNIV_INLINE -ib_err_t -ib_cursor_position( -/*===============*/ - ib_cursor_t* cursor, /*!< in: InnoDB cursor instance */ - ib_srch_mode_t mode) /*!< in: Search mode */ -{ - ib_err_t err; - row_prebuilt_t* prebuilt = cursor->prebuilt; - unsigned char* buf; - - buf = static_cast<unsigned char*>(mem_alloc(UNIV_PAGE_SIZE)); - - /* We want to position at one of the ends, row_search_for_mysql() - uses the search_tuple fields to work out what to do. */ - dtuple_set_n_fields(prebuilt->search_tuple, 0); - - err = static_cast<ib_err_t>(row_search_for_mysql( - buf, mode, prebuilt, 0, 0)); - - mem_free(buf); - - return(err); -} - -/*****************************************************************//** -Move cursor to the first record in the table. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_first( -/*============*/ - ib_crsr_t ib_crsr) /*!< in: InnoDB cursor instance */ -{ - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - - return(ib_cursor_position(cursor, IB_CUR_G)); -} - -/*****************************************************************//** -Move cursor to the last record in the table. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_last( -/*===========*/ - ib_crsr_t ib_crsr) /*!< in: InnoDB cursor instance */ -{ - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - - return(ib_cursor_position(cursor, IB_CUR_L)); -} - -/*****************************************************************//** -Move cursor to the next user record in the table. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_next( -/*===========*/ - ib_crsr_t ib_crsr) /*!< in: InnoDB cursor instance */ -{ - ib_err_t err; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - byte buf[UNIV_PAGE_SIZE_MAX]; - - /* We want to move to the next record */ - dtuple_set_n_fields(prebuilt->search_tuple, 0); - - err = static_cast<ib_err_t>(row_search_for_mysql( - buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT)); - - return(err); -} - -/*****************************************************************//** -Search for key. -@return DB_SUCCESS or err code */ -UNIV_INTERN -ib_err_t -ib_cursor_moveto( -/*=============*/ - ib_crsr_t ib_crsr, /*!< in: InnoDB cursor instance */ - ib_tpl_t ib_tpl, /*!< in: Key to search for */ - ib_srch_mode_t ib_srch_mode) /*!< in: search mode */ -{ - ulint i; - ulint n_fields; - ib_err_t err = DB_SUCCESS; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - dtuple_t* search_tuple = prebuilt->search_tuple; - unsigned char* buf; - - ut_a(tuple->type == TPL_TYPE_KEY); - - n_fields = dict_index_get_n_ordering_defined_by_user(prebuilt->index); - - if (n_fields > dtuple_get_n_fields(tuple->ptr)) { - n_fields = dtuple_get_n_fields(tuple->ptr); - } - - dtuple_set_n_fields(search_tuple, n_fields); - dtuple_set_n_fields_cmp(search_tuple, n_fields); - - /* Do a shallow copy */ - for (i = 0; i < n_fields; ++i) { - dfield_copy(dtuple_get_nth_field(search_tuple, i), - dtuple_get_nth_field(tuple->ptr, i)); - } - - ut_a(prebuilt->select_lock_type <= LOCK_NUM); - - prebuilt->innodb_api_rec = NULL; - - buf = static_cast<unsigned char*>(mem_alloc(UNIV_PAGE_SIZE)); - - err = static_cast<ib_err_t>(row_search_for_mysql( - buf, ib_srch_mode, prebuilt, cursor->match_mode, 0)); - - mem_free(buf); - - return(err); -} - -/*****************************************************************//** -Set the cursor search mode. */ -UNIV_INTERN -void -ib_cursor_set_match_mode( -/*=====================*/ - ib_crsr_t ib_crsr, /*!< in: Cursor instance */ - ib_match_mode_t match_mode) /*!< in: ib_cursor_moveto match mode */ -{ - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - - cursor->match_mode = match_mode; -} - -/*****************************************************************//** -Get the dfield instance for the column in the tuple. -@return dfield instance in tuple */ -UNIV_INLINE -dfield_t* -ib_col_get_dfield( -/*==============*/ - ib_tuple_t* tuple, /*!< in: tuple instance */ - ulint col_no) /*!< in: col no. in tuple */ -{ - dfield_t* dfield; - - dfield = dtuple_get_nth_field(tuple->ptr, col_no); - - return(dfield); -} - -/*****************************************************************//** -Predicate to check whether a column type contains variable length data. -@return DB_SUCCESS or error code */ -UNIV_INLINE -ib_err_t -ib_col_is_capped( -/*==============*/ - const dtype_t* dtype) /*!< in: column type */ -{ - return(static_cast<ib_err_t>( - (dtype_get_mtype(dtype) == DATA_VARCHAR - || dtype_get_mtype(dtype) == DATA_CHAR - || dtype_get_mtype(dtype) == DATA_MYSQL - || dtype_get_mtype(dtype) == DATA_VARMYSQL - || dtype_get_mtype(dtype) == DATA_FIXBINARY - || dtype_get_mtype(dtype) == DATA_BINARY) - && dtype_get_len(dtype) > 0)); -} - -/*****************************************************************//** -Set a column of the tuple. Make a copy using the tuple's heap. -@return DB_SUCCESS or error code */ -UNIV_INTERN -ib_err_t -ib_col_set_value( -/*=============*/ - ib_tpl_t ib_tpl, /*!< in: tuple instance */ - ib_ulint_t col_no, /*!< in: column index in tuple */ - const void* src, /*!< in: data value */ - ib_ulint_t len, /*!< in: data value len */ - ib_bool_t need_cpy) /*!< in: if need memcpy */ -{ - const dtype_t* dtype; - dfield_t* dfield; - void* dst = NULL; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - ulint col_len; - - dfield = ib_col_get_dfield(tuple, col_no); - - /* User wants to set the column to NULL. */ - if (len == IB_SQL_NULL) { - dfield_set_null(dfield); - return(DB_SUCCESS); - } - - dtype = dfield_get_type(dfield); - col_len = dtype_get_len(dtype); - - /* Not allowed to update system columns. */ - if (dtype_get_mtype(dtype) == DATA_SYS) { - return(DB_DATA_MISMATCH); - } - - dst = dfield_get_data(dfield); - - /* Since TEXT/CLOB also map to DATA_VARCHAR we need to make an - exception. Perhaps we need to set the precise type and check - for that. */ - if (ib_col_is_capped(dtype)) { - - len = ut_min(len, static_cast<ib_ulint_t>(col_len)); - - if (dst == NULL || len > dfield_get_len(dfield)) { - dst = mem_heap_alloc(tuple->heap, col_len); - ut_a(dst != NULL); - } - } else if (dst == NULL || len > dfield_get_len(dfield)) { - dst = mem_heap_alloc(tuple->heap, len); - } - - if (dst == NULL) { - return(DB_OUT_OF_MEMORY); - } - - switch (dtype_get_mtype(dtype)) { - case DATA_INT: { - - if (col_len == len) { - ibool usign; - - usign = dtype_get_prtype(dtype) & DATA_UNSIGNED; - mach_write_int_type(static_cast<byte*>(dst), - static_cast<const byte*>(src), - len, usign); - - } else { - return(DB_DATA_MISMATCH); - } - break; - } - - case DATA_FLOAT: - if (len == sizeof(float)) { - mach_float_write(static_cast<byte*>(dst), *(float*)src); - } else { - return(DB_DATA_MISMATCH); - } - break; - - case DATA_DOUBLE: - if (len == sizeof(double)) { - mach_double_write(static_cast<byte*>(dst), - *(double*)src); - } else { - return(DB_DATA_MISMATCH); - } - break; - - case DATA_SYS: - ut_error; - break; - - case DATA_CHAR: { - ulint pad_char = ULINT_UNDEFINED; - - pad_char = dtype_get_pad_char( - dtype_get_mtype(dtype), dtype_get_prtype(dtype)); - - ut_a(pad_char != ULINT_UNDEFINED); - - memset((byte*) dst + len, - static_cast<int>(pad_char), - static_cast<size_t>(col_len - len)); - - memcpy(dst, src, len); - - len = static_cast<ib_ulint_t>(col_len); - break; - } - case DATA_BLOB: - case DATA_BINARY: - case DATA_DECIMAL: - case DATA_VARCHAR: - case DATA_FIXBINARY: - if (need_cpy) { - memcpy(dst, src, len); - } else { - dfield_set_data(dfield, src, len); - dst = dfield_get_data(dfield); - } - break; - - case DATA_MYSQL: - case DATA_VARMYSQL: { - ulint cset; - CHARSET_INFO* cs; - int error = 0; - ulint true_len = len; - - /* For multi byte character sets we need to - calculate the true length of the data. */ - cset = dtype_get_charset_coll( - dtype_get_prtype(dtype)); - cs = all_charsets[cset]; - if (cs) { - uint pos = (uint)(col_len / cs->mbmaxlen); - - if (len > 0 && cs->mbmaxlen > 1) { - true_len = (ulint) - my_well_formed_length( - cs, - (const char*)src, - (const char*)src + len, - pos, - &error); - - if (true_len < len) { - len = static_cast<ib_ulint_t>(true_len); - } - } - } - - /* All invalid bytes in data need be truncated. - If len == 0, means all bytes of the data is invalid. - In this case, the data will be truncated to empty.*/ - memcpy(dst, src, len); - - /* For DATA_MYSQL, need to pad the unused - space with spaces. */ - if (dtype_get_mtype(dtype) == DATA_MYSQL) { - ulint n_chars; - - if (len < col_len) { - ulint pad_len = col_len - len; - - ut_a(cs != NULL); - ut_a(!(pad_len % cs->mbminlen)); - - cs->cset->fill(cs, (char*)dst + len, - pad_len, - 0x20 /* space */); - } - - /* Why we should do below? See function - row_mysql_store_col_in_innobase_format */ - - ut_a(!(dtype_get_len(dtype) - % dtype_get_mbmaxlen(dtype))); - - n_chars = dtype_get_len(dtype) - / dtype_get_mbmaxlen(dtype); - - /* Strip space padding. */ - while (col_len > n_chars - && ((char*)dst)[col_len - 1] == 0x20) { - col_len--; - } - - len = static_cast<ib_ulint_t>(col_len); - } - break; - } - - default: - ut_error; - } - - if (dst != dfield_get_data(dfield)) { - dfield_set_data(dfield, dst, len); - } else { - dfield_set_len(dfield, len); - } - - return(DB_SUCCESS); -} - -/*****************************************************************//** -Get the size of the data available in a column of the tuple. -@return bytes avail or IB_SQL_NULL */ -UNIV_INTERN -ib_ulint_t -ib_col_get_len( -/*===========*/ - ib_tpl_t ib_tpl, /*!< in: tuple instance */ - ib_ulint_t i) /*!< in: column index in tuple */ -{ - const dfield_t* dfield; - ulint data_len; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - - dfield = ib_col_get_dfield(tuple, i); - - data_len = dfield_get_len(dfield); - - return(static_cast<ib_ulint_t>( - data_len == UNIV_SQL_NULL ? IB_SQL_NULL : data_len)); -} - -/*****************************************************************//** -Copy a column value from the tuple. -@return bytes copied or IB_SQL_NULL */ -UNIV_INLINE -ib_ulint_t -ib_col_copy_value_low( -/*==================*/ - ib_tpl_t ib_tpl, /*!< in: tuple instance */ - ib_ulint_t i, /*!< in: column index in tuple */ - void* dst, /*!< out: copied data value */ - ib_ulint_t len) /*!< in: max data value len to copy */ -{ - const void* data; - const dfield_t* dfield; - ulint data_len; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - - dfield = ib_col_get_dfield(tuple, i); - - data = dfield_get_data(dfield); - data_len = dfield_get_len(dfield); - - if (data_len != UNIV_SQL_NULL) { - - const dtype_t* dtype = dfield_get_type(dfield); - - switch (dtype_get_mtype(dfield_get_type(dfield))) { - case DATA_INT: { - ibool usign; - ullint ret; - - ut_a(data_len == len); - - usign = dtype_get_prtype(dtype) & DATA_UNSIGNED; - ret = mach_read_int_type(static_cast<const byte*>(data), - data_len, usign); - - if (usign) { - if (len == 1) { - *(ib_i8_t*)dst = (ib_i8_t)ret; - } else if (len == 2) { - *(ib_i16_t*)dst = (ib_i16_t)ret; - } else if (len == 4) { - *(ib_i32_t*)dst = (ib_i32_t)ret; - } else { - *(ib_i64_t*)dst = (ib_i64_t)ret; - } - } else { - if (len == 1) { - *(ib_u8_t*)dst = (ib_i8_t)ret; - } else if (len == 2) { - *(ib_u16_t*)dst = (ib_i16_t)ret; - } else if (len == 4) { - *(ib_u32_t*)dst = (ib_i32_t)ret; - } else { - *(ib_u64_t*)dst = (ib_i64_t)ret; - } - } - - break; - } - case DATA_FLOAT: - if (len == data_len) { - float f; - - ut_a(data_len == sizeof(f)); - f = mach_float_read(static_cast<const byte*>( - data)); - memcpy(dst, &f, sizeof(f)); - } else { - data_len = 0; - } - break; - case DATA_DOUBLE: - if (len == data_len) { - double d; - - ut_a(data_len == sizeof(d)); - d = mach_double_read(static_cast<const byte*>( - data)); - memcpy(dst, &d, sizeof(d)); - } else { - data_len = 0; - } - break; - default: - data_len = ut_min(data_len, len); - memcpy(dst, data, data_len); - } - } else { - data_len = IB_SQL_NULL; - } - - return(static_cast<ib_ulint_t>(data_len)); -} - -/*****************************************************************//** -Copy a column value from the tuple. -@return bytes copied or IB_SQL_NULL */ -UNIV_INTERN -ib_ulint_t -ib_col_copy_value( -/*==============*/ - ib_tpl_t ib_tpl, /*!< in: tuple instance */ - ib_ulint_t i, /*!< in: column index in tuple */ - void* dst, /*!< out: copied data value */ - ib_ulint_t len) /*!< in: max data value len to copy */ -{ - return(ib_col_copy_value_low(ib_tpl, i, dst, len)); -} - -/*****************************************************************//** -Get the InnoDB column attribute from the internal column precise type. -@return precise type in api format */ -UNIV_INLINE -ib_col_attr_t -ib_col_get_attr( -/*============*/ - ulint prtype) /*!< in: column definition */ -{ - ib_col_attr_t attr = IB_COL_NONE; - - if (prtype & DATA_UNSIGNED) { - attr = static_cast<ib_col_attr_t>(attr | IB_COL_UNSIGNED); - } - - if (prtype & DATA_NOT_NULL) { - attr = static_cast<ib_col_attr_t>(attr | IB_COL_NOT_NULL); - } - - return(attr); -} - -/*****************************************************************//** -Get a column name from the tuple. -@return name of the column */ -UNIV_INTERN -const char* -ib_col_get_name( -/*============*/ - ib_crsr_t ib_crsr, /*!< in: InnoDB cursor instance */ - ib_ulint_t i) /*!< in: column index in tuple */ -{ - const char* name; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - dict_table_t* table = cursor->prebuilt->table; - dict_col_t* col = dict_table_get_nth_col(table, i); - ulint col_no = dict_col_get_no(col); - - name = dict_table_get_col_name(table, col_no); - - return(name); -} - -/*****************************************************************//** -Get an index field name from the cursor. -@return name of the field */ -UNIV_INTERN -const char* -ib_get_idx_field_name( -/*==================*/ - ib_crsr_t ib_crsr, /*!< in: InnoDB cursor instance */ - ib_ulint_t i) /*!< in: column index in tuple */ -{ - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - dict_index_t* index = cursor->prebuilt->index; - dict_field_t* field; - - if (index) { - field = dict_index_get_nth_field(cursor->prebuilt->index, i); - - if (field) { - return(field->name); - } - } - - return(NULL); -} - -/*****************************************************************//** -Get a column type, length and attributes from the tuple. -@return len of column data */ -UNIV_INLINE -ib_ulint_t -ib_col_get_meta_low( -/*================*/ - ib_tpl_t ib_tpl, /*!< in: tuple instance */ - ib_ulint_t i, /*!< in: column index in tuple */ - ib_col_meta_t* ib_col_meta) /*!< out: column meta data */ -{ - ib_u16_t prtype; - const dfield_t* dfield; - ulint data_len; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - - dfield = ib_col_get_dfield(tuple, i); - - data_len = dfield_get_len(dfield); - - /* We assume 1-1 mapping between the ENUM and internal type codes. */ - ib_col_meta->type = static_cast<ib_col_type_t>( - dtype_get_mtype(dfield_get_type(dfield))); - - ib_col_meta->type_len = static_cast<ib_u32_t>( - dtype_get_len(dfield_get_type(dfield))); - - prtype = (ib_u16_t) dtype_get_prtype(dfield_get_type(dfield)); - - ib_col_meta->attr = ib_col_get_attr(prtype); - ib_col_meta->client_type = prtype & DATA_MYSQL_TYPE_MASK; - - return(static_cast<ib_ulint_t>(data_len)); -} - -/*************************************************************//** -Read a signed int 8 bit column from an InnoDB tuple. */ -UNIV_INLINE -ib_err_t -ib_tuple_check_int( -/*===============*/ - ib_tpl_t ib_tpl, /*!< in: InnoDB tuple */ - ib_ulint_t i, /*!< in: column number */ - ib_bool_t usign, /*!< in: true if unsigned */ - ulint size) /*!< in: size of integer */ -{ - ib_col_meta_t ib_col_meta; - - ib_col_get_meta_low(ib_tpl, i, &ib_col_meta); - - if (ib_col_meta.type != IB_INT) { - return(DB_DATA_MISMATCH); - } else if (ib_col_meta.type_len == IB_SQL_NULL) { - return(DB_UNDERFLOW); - } else if (ib_col_meta.type_len != size) { - return(DB_DATA_MISMATCH); - } else if ((ib_col_meta.attr & IB_COL_UNSIGNED) && !usign) { - return(DB_DATA_MISMATCH); - } - - return(DB_SUCCESS); -} - -/*************************************************************//** -Read a signed int 8 bit column from an InnoDB tuple. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_read_i8( -/*=============*/ - ib_tpl_t ib_tpl, /*!< in: InnoDB tuple */ - ib_ulint_t i, /*!< in: column number */ - ib_i8_t* ival) /*!< out: integer value */ -{ - ib_err_t err; - - err = ib_tuple_check_int(ib_tpl, i, IB_FALSE, sizeof(*ival)); - - if (err == DB_SUCCESS) { - ib_col_copy_value_low(ib_tpl, i, ival, sizeof(*ival)); - } - - return(err); -} - -/*************************************************************//** -Read an unsigned int 8 bit column from an InnoDB tuple. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_read_u8( -/*=============*/ - ib_tpl_t ib_tpl, /*!< in: InnoDB tuple */ - ib_ulint_t i, /*!< in: column number */ - ib_u8_t* ival) /*!< out: integer value */ -{ - ib_err_t err; - - err = ib_tuple_check_int(ib_tpl, i, IB_TRUE, sizeof(*ival)); - - if (err == DB_SUCCESS) { - ib_col_copy_value_low(ib_tpl, i, ival, sizeof(*ival)); - } - - return(err); -} - -/*************************************************************//** -Read a signed int 16 bit column from an InnoDB tuple. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_read_i16( -/*==============*/ - ib_tpl_t ib_tpl, /*!< in: InnoDB tuple */ - ib_ulint_t i, /*!< in: column number */ - ib_i16_t* ival) /*!< out: integer value */ -{ - ib_err_t err; - - err = ib_tuple_check_int(ib_tpl, i, FALSE, sizeof(*ival)); - - if (err == DB_SUCCESS) { - ib_col_copy_value_low(ib_tpl, i, ival, sizeof(*ival)); - } - - return(err); -} - -/*************************************************************//** -Read an unsigned int 16 bit column from an InnoDB tuple. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_read_u16( -/*==============*/ - ib_tpl_t ib_tpl, /*!< in: InnoDB tuple */ - ib_ulint_t i, /*!< in: column number */ - ib_u16_t* ival) /*!< out: integer value */ -{ - ib_err_t err; - - err = ib_tuple_check_int(ib_tpl, i, IB_TRUE, sizeof(*ival)); - - if (err == DB_SUCCESS) { - ib_col_copy_value_low(ib_tpl, i, ival, sizeof(*ival)); - } - - return(err); -} - -/*************************************************************//** -Read a signed int 32 bit column from an InnoDB tuple. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_read_i32( -/*==============*/ - ib_tpl_t ib_tpl, /*!< in: InnoDB tuple */ - ib_ulint_t i, /*!< in: column number */ - ib_i32_t* ival) /*!< out: integer value */ -{ - ib_err_t err; - - err = ib_tuple_check_int(ib_tpl, i, FALSE, sizeof(*ival)); - - if (err == DB_SUCCESS) { - ib_col_copy_value_low(ib_tpl, i, ival, sizeof(*ival)); - } - - return(err); -} - -/*************************************************************//** -Read an unsigned int 32 bit column from an InnoDB tuple. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_read_u32( -/*==============*/ - ib_tpl_t ib_tpl, /*!< in: InnoDB tuple */ - ib_ulint_t i, /*!< in: column number */ - ib_u32_t* ival) /*!< out: integer value */ -{ - ib_err_t err; - - err = ib_tuple_check_int(ib_tpl, i, IB_TRUE, sizeof(*ival)); - - if (err == DB_SUCCESS) { - ib_col_copy_value_low(ib_tpl, i, ival, sizeof(*ival)); - } - - return(err); -} - -/*************************************************************//** -Read a signed int 64 bit column from an InnoDB tuple. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_read_i64( -/*==============*/ - ib_tpl_t ib_tpl, /*!< in: InnoDB tuple */ - ib_ulint_t i, /*!< in: column number */ - ib_i64_t* ival) /*!< out: integer value */ -{ - ib_err_t err; - - err = ib_tuple_check_int(ib_tpl, i, FALSE, sizeof(*ival)); - - if (err == DB_SUCCESS) { - ib_col_copy_value_low(ib_tpl, i, ival, sizeof(*ival)); - } - - return(err); -} - -/*************************************************************//** -Read an unsigned int 64 bit column from an InnoDB tuple. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_read_u64( -/*==============*/ - ib_tpl_t ib_tpl, /*!< in: InnoDB tuple */ - ib_ulint_t i, /*!< in: column number */ - ib_u64_t* ival) /*!< out: integer value */ -{ - ib_err_t err; - - err = ib_tuple_check_int(ib_tpl, i, IB_TRUE, sizeof(*ival)); - - if (err == DB_SUCCESS) { - ib_col_copy_value_low(ib_tpl, i, ival, sizeof(*ival)); - } - - return(err); -} - -/*****************************************************************//** -Get a column value pointer from the tuple. -@return NULL or pointer to buffer */ -UNIV_INTERN -const void* -ib_col_get_value( -/*=============*/ - ib_tpl_t ib_tpl, /*!< in: tuple instance */ - ib_ulint_t i) /*!< in: column index in tuple */ -{ - const void* data; - const dfield_t* dfield; - ulint data_len; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - - dfield = ib_col_get_dfield(tuple, i); - - data = dfield_get_data(dfield); - data_len = dfield_get_len(dfield); - - return(data_len != UNIV_SQL_NULL ? data : NULL); -} - -/*****************************************************************//** -Get a column type, length and attributes from the tuple. -@return len of column data */ -UNIV_INTERN -ib_ulint_t -ib_col_get_meta( -/*============*/ - ib_tpl_t ib_tpl, /*!< in: tuple instance */ - ib_ulint_t i, /*!< in: column index in tuple */ - ib_col_meta_t* ib_col_meta) /*!< out: column meta data */ -{ - return(ib_col_get_meta_low(ib_tpl, i, ib_col_meta)); -} - -/*****************************************************************//** -"Clear" or reset an InnoDB tuple. We free the heap and recreate the tuple. -@return new tuple, or NULL */ -UNIV_INTERN -ib_tpl_t -ib_tuple_clear( -/*============*/ - ib_tpl_t ib_tpl) /*!< in,own: tuple (will be freed) */ -{ - const dict_index_t* index; - ulint n_cols; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - ib_tuple_type_t type = tuple->type; - mem_heap_t* heap = tuple->heap; - - index = tuple->index; - n_cols = dtuple_get_n_fields(tuple->ptr); - - mem_heap_empty(heap); - - if (type == TPL_TYPE_ROW) { - return(ib_row_tuple_new_low(index, n_cols, heap)); - } else { - return(ib_key_tuple_new_low(index, n_cols, heap)); - } -} - -/*****************************************************************//** -Create a new cluster key search tuple and copy the contents of the -secondary index key tuple columns that refer to the cluster index record -to the cluster key. It does a deep copy of the column data. -@return DB_SUCCESS or error code */ -UNIV_INTERN -ib_err_t -ib_tuple_get_cluster_key( -/*=====================*/ - ib_crsr_t ib_crsr, /*!< in: secondary index cursor */ - ib_tpl_t* ib_dst_tpl, /*!< out,own: destination tuple */ - const ib_tpl_t ib_src_tpl) /*!< in: source tuple */ -{ - ulint i; - ulint n_fields; - ib_err_t err = DB_SUCCESS; - ib_tuple_t* dst_tuple = NULL; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - ib_tuple_t* src_tuple = (ib_tuple_t*) ib_src_tpl; - dict_index_t* clust_index; - - clust_index = dict_table_get_first_index(cursor->prebuilt->table); - - /* We need to ensure that the src tuple belongs to the same table - as the open cursor and that it's not a tuple for a cluster index. */ - if (src_tuple->type != TPL_TYPE_KEY) { - return(DB_ERROR); - } else if (src_tuple->index->table != cursor->prebuilt->table) { - return(DB_DATA_MISMATCH); - } else if (src_tuple->index == clust_index) { - return(DB_ERROR); - } - - /* Create the cluster index key search tuple. */ - *ib_dst_tpl = ib_clust_search_tuple_create(ib_crsr); - - if (!*ib_dst_tpl) { - return(DB_OUT_OF_MEMORY); - } - - dst_tuple = (ib_tuple_t*) *ib_dst_tpl; - ut_a(dst_tuple->index == clust_index); - - n_fields = dict_index_get_n_unique(dst_tuple->index); - - /* Do a deep copy of the data fields. */ - for (i = 0; i < n_fields; i++) { - ulint pos; - dfield_t* src_field; - dfield_t* dst_field; - - pos = dict_index_get_nth_field_pos( - src_tuple->index, dst_tuple->index, i); - - ut_a(pos != ULINT_UNDEFINED); - - src_field = dtuple_get_nth_field(src_tuple->ptr, pos); - dst_field = dtuple_get_nth_field(dst_tuple->ptr, i); - - if (!dfield_is_null(src_field)) { - UNIV_MEM_ASSERT_RW(src_field->data, src_field->len); - - dst_field->data = mem_heap_dup( - dst_tuple->heap, - src_field->data, - src_field->len); - - dst_field->len = src_field->len; - } else { - dfield_set_null(dst_field); - } - } - - return(err); -} - -/*****************************************************************//** -Copy the contents of source tuple to destination tuple. The tuples -must be of the same type and belong to the same table/index. -@return DB_SUCCESS or error code */ -UNIV_INTERN -ib_err_t -ib_tuple_copy( -/*==========*/ - ib_tpl_t ib_dst_tpl, /*!< in: destination tuple */ - const ib_tpl_t ib_src_tpl) /*!< in: source tuple */ -{ - ulint i; - ulint n_fields; - ib_err_t err = DB_SUCCESS; - const ib_tuple_t*src_tuple = (const ib_tuple_t*) ib_src_tpl; - ib_tuple_t* dst_tuple = (ib_tuple_t*) ib_dst_tpl; - - /* Make sure src and dst are not the same. */ - ut_a(src_tuple != dst_tuple); - - /* Make sure they are the same type and refer to the same index. */ - if (src_tuple->type != dst_tuple->type - || src_tuple->index != dst_tuple->index) { - - return(DB_DATA_MISMATCH); - } - - n_fields = dtuple_get_n_fields(src_tuple->ptr); - ut_ad(n_fields == dtuple_get_n_fields(dst_tuple->ptr)); - - /* Do a deep copy of the data fields. */ - for (i = 0; i < n_fields; ++i) { - dfield_t* src_field; - dfield_t* dst_field; - - src_field = dtuple_get_nth_field(src_tuple->ptr, i); - dst_field = dtuple_get_nth_field(dst_tuple->ptr, i); - - if (!dfield_is_null(src_field)) { - UNIV_MEM_ASSERT_RW(src_field->data, src_field->len); - - dst_field->data = mem_heap_dup( - dst_tuple->heap, - src_field->data, - src_field->len); - - dst_field->len = src_field->len; - } else { - dfield_set_null(dst_field); - } - } - - return(err); -} - -/*****************************************************************//** -Create an InnoDB tuple used for index/table search. -@return own: Tuple for current index */ -UNIV_INTERN -ib_tpl_t -ib_sec_search_tuple_create( -/*=======================*/ - ib_crsr_t ib_crsr) /*!< in: Cursor instance */ -{ - ulint n_cols; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - dict_index_t* index = cursor->prebuilt->index; - - n_cols = dict_index_get_n_unique_in_tree(index); - return(ib_key_tuple_new(index, n_cols)); -} - -/*****************************************************************//** -Create an InnoDB tuple used for index/table search. -@return own: Tuple for current index */ -UNIV_INTERN -ib_tpl_t -ib_sec_read_tuple_create( -/*=====================*/ - ib_crsr_t ib_crsr) /*!< in: Cursor instance */ -{ - ulint n_cols; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - dict_index_t* index = cursor->prebuilt->index; - - n_cols = dict_index_get_n_fields(index); - return(ib_row_tuple_new(index, n_cols)); -} - -/*****************************************************************//** -Create an InnoDB tuple used for table key operations. -@return own: Tuple for current table */ -UNIV_INTERN -ib_tpl_t -ib_clust_search_tuple_create( -/*=========================*/ - ib_crsr_t ib_crsr) /*!< in: Cursor instance */ -{ - ulint n_cols; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - dict_index_t* index; - - index = dict_table_get_first_index(cursor->prebuilt->table); - - n_cols = dict_index_get_n_ordering_defined_by_user(index); - return(ib_key_tuple_new(index, n_cols)); -} - -/*****************************************************************//** -Create an InnoDB tuple for table row operations. -@return own: Tuple for current table */ -UNIV_INTERN -ib_tpl_t -ib_clust_read_tuple_create( -/*=======================*/ - ib_crsr_t ib_crsr) /*!< in: Cursor instance */ -{ - ulint n_cols; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - dict_index_t* index; - - index = dict_table_get_first_index(cursor->prebuilt->table); - - n_cols = dict_table_get_n_cols(cursor->prebuilt->table); - return(ib_row_tuple_new(index, n_cols)); -} - -/*****************************************************************//** -Return the number of user columns in the tuple definition. -@return number of user columns */ -UNIV_INTERN -ib_ulint_t -ib_tuple_get_n_user_cols( -/*=====================*/ - const ib_tpl_t ib_tpl) /*!< in: Tuple for current table */ -{ - const ib_tuple_t* tuple = (const ib_tuple_t*) ib_tpl; - - if (tuple->type == TPL_TYPE_ROW) { - return(static_cast<ib_ulint_t>( - dict_table_get_n_user_cols(tuple->index->table))); - } - - return(static_cast<ib_ulint_t>( - dict_index_get_n_ordering_defined_by_user(tuple->index))); -} - -/*****************************************************************//** -Return the number of columns in the tuple definition. -@return number of columns */ -UNIV_INTERN -ib_ulint_t -ib_tuple_get_n_cols( -/*================*/ - const ib_tpl_t ib_tpl) /*!< in: Tuple for table/index */ -{ - const ib_tuple_t* tuple = (const ib_tuple_t*) ib_tpl; - - return(static_cast<ib_ulint_t>(dtuple_get_n_fields(tuple->ptr))); -} - -/*****************************************************************//** -Destroy an InnoDB tuple. */ -UNIV_INTERN -void -ib_tuple_delete( -/*============*/ - ib_tpl_t ib_tpl) /*!< in,own: Tuple instance to delete */ -{ - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - - if (!ib_tpl) { - return; - } - - mem_heap_free(tuple->heap); -} - -/*****************************************************************//** -Get a table id. This function will acquire the dictionary mutex. -@return DB_SUCCESS if found */ -UNIV_INTERN -ib_err_t -ib_table_get_id( -/*============*/ - const char* table_name, /*!< in: table to find */ - ib_id_u64_t* table_id) /*!< out: table id if found */ -{ - ib_err_t err; - - dict_mutex_enter_for_mysql(); - - err = ib_table_get_id_low(table_name, table_id); - - dict_mutex_exit_for_mysql(); - - return(err); -} - -/*****************************************************************//** -Get an index id. -@return DB_SUCCESS if found */ -UNIV_INTERN -ib_err_t -ib_index_get_id( -/*============*/ - const char* table_name, /*!< in: find index for this table */ - const char* index_name, /*!< in: index to find */ - ib_id_u64_t* index_id) /*!< out: index id if found */ -{ - dict_table_t* table; - char* normalized_name; - ib_err_t err = DB_TABLE_NOT_FOUND; - - *index_id = 0; - - normalized_name = static_cast<char*>( - mem_alloc(ut_strlen(table_name) + 1)); - ib_normalize_table_name(normalized_name, table_name); - - table = ib_lookup_table_by_name(normalized_name); - - mem_free(normalized_name); - normalized_name = NULL; - - if (table != NULL) { - dict_index_t* index; - - index = dict_table_get_index_on_name(table, index_name); - - if (index != NULL) { - /* We only support 32 bit table and index ids. Because - we need to pack the table id into the index id. */ - - *index_id = (table->id); - *index_id <<= 32; - *index_id |= (index->id); - - err = DB_SUCCESS; - } - } - - return(err); -} - -#ifdef __WIN__ -#define SRV_PATH_SEPARATOR '\\' -#else -#define SRV_PATH_SEPARATOR '/' -#endif - - -/*****************************************************************//** -Check if cursor is positioned. -@return IB_TRUE if positioned */ -UNIV_INTERN -ib_bool_t -ib_cursor_is_positioned( -/*====================*/ - const ib_crsr_t ib_crsr) /*!< in: InnoDB cursor instance */ -{ - const ib_cursor_t* cursor = (const ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - - return(ib_btr_cursor_is_positioned(&prebuilt->pcur)); -} - - -/*****************************************************************//** -Checks if the data dictionary is latched in exclusive mode. -@return TRUE if exclusive latch */ -UNIV_INTERN -ib_bool_t -ib_schema_lock_is_exclusive( -/*========================*/ - const ib_trx_t ib_trx) /*!< in: transaction */ -{ - const trx_t* trx = (const trx_t*) ib_trx; - - return(trx->dict_operation_lock_mode == RW_X_LATCH); -} - -/*****************************************************************//** -Checks if the data dictionary is latched in shared mode. -@return TRUE if shared latch */ -UNIV_INTERN -ib_bool_t -ib_schema_lock_is_shared( -/*=====================*/ - const ib_trx_t ib_trx) /*!< in: transaction */ -{ - const trx_t* trx = (const trx_t*) ib_trx; - - return(trx->dict_operation_lock_mode == RW_S_LATCH); -} - -/*****************************************************************//** -Set the Lock an InnoDB cursor/table. -@return DB_SUCCESS or error code */ -UNIV_INTERN -ib_err_t -ib_cursor_lock( -/*===========*/ - ib_crsr_t ib_crsr, /*!< in/out: InnoDB cursor */ - ib_lck_mode_t ib_lck_mode) /*!< in: InnoDB lock mode */ -{ - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - trx_t* trx = prebuilt->trx; - dict_table_t* table = prebuilt->table; - - return(ib_trx_lock_table_with_retry( - trx, table, (enum lock_mode) ib_lck_mode)); -} - -/*****************************************************************//** -Set the Lock an InnoDB table using the table id. -@return DB_SUCCESS or error code */ -UNIV_INTERN -ib_err_t -ib_table_lock( -/*==========*/ - ib_trx_t ib_trx, /*!< in/out: transaction */ - ib_id_u64_t table_id, /*!< in: table id */ - ib_lck_mode_t ib_lck_mode) /*!< in: InnoDB lock mode */ -{ - ib_err_t err; - que_thr_t* thr; - mem_heap_t* heap; - dict_table_t* table; - ib_qry_proc_t q_proc; - trx_t* trx = (trx_t*) ib_trx; - - ut_a(trx->state != TRX_STATE_NOT_STARTED); - - table = ib_open_table_by_id(table_id, FALSE); - - if (table == NULL) { - return(DB_TABLE_NOT_FOUND); - } - - ut_a(ib_lck_mode <= static_cast<ib_lck_mode_t>(LOCK_NUM)); - - heap = mem_heap_create(128); - - q_proc.node.sel = sel_node_create(heap); - - thr = pars_complete_graph_for_exec(q_proc.node.sel, trx, heap); - - q_proc.grph.sel = static_cast<que_fork_t*>(que_node_get_parent(thr)); - q_proc.grph.sel->state = QUE_FORK_ACTIVE; - - trx->op_info = "setting table lock"; - - ut_a(ib_lck_mode == IB_LOCK_IS || ib_lck_mode == IB_LOCK_IX); - err = static_cast<ib_err_t>( - lock_table(0, table, (enum lock_mode) ib_lck_mode, thr)); - - trx->error_state = err; - - mem_heap_free(heap); - - return(err); -} - -/*****************************************************************//** -Unlock an InnoDB table. -@return DB_SUCCESS or error code */ -UNIV_INTERN -ib_err_t -ib_cursor_unlock( -/*=============*/ - ib_crsr_t ib_crsr) /*!< in/out: InnoDB cursor */ -{ - ib_err_t err = DB_SUCCESS; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - - if (prebuilt->trx->mysql_n_tables_locked > 0) { - --prebuilt->trx->mysql_n_tables_locked; - } else { - err = DB_ERROR; - } - - return(err); -} - -/*****************************************************************//** -Set the Lock mode of the cursor. -@return DB_SUCCESS or error code */ -UNIV_INTERN -ib_err_t -ib_cursor_set_lock_mode( -/*====================*/ - ib_crsr_t ib_crsr, /*!< in/out: InnoDB cursor */ - ib_lck_mode_t ib_lck_mode) /*!< in: InnoDB lock mode */ -{ - ib_err_t err = DB_SUCCESS; - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - - ut_a(ib_lck_mode <= static_cast<ib_lck_mode_t>(LOCK_NUM)); - - if (ib_lck_mode == IB_LOCK_X) { - err = ib_cursor_lock(ib_crsr, IB_LOCK_IX); - } else if (ib_lck_mode == IB_LOCK_S) { - err = ib_cursor_lock(ib_crsr, IB_LOCK_IS); - } - - if (err == DB_SUCCESS) { - prebuilt->select_lock_type = (enum lock_mode) ib_lck_mode; - ut_a(prebuilt->trx->state != TRX_STATE_NOT_STARTED); - } - - return(err); -} - -/*****************************************************************//** -Set need to access clustered index record. */ -UNIV_INTERN -void -ib_cursor_set_cluster_access( -/*=========================*/ - ib_crsr_t ib_crsr) /*!< in/out: InnoDB cursor */ -{ - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - - prebuilt->need_to_access_clustered = TRUE; -} - -/*****************************************************************//** -Write an integer value to a column. Integers are stored in big-endian -format and will need to be converted from the host format. -@return DB_SUCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_write_i8( -/*==============*/ - ib_tpl_t ib_tpl, /*!< in/out: tuple to write to */ - int col_no, /*!< in: column number */ - ib_i8_t val) /*!< in: value to write */ -{ - return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true)); -} - -/*****************************************************************//** -Write an integer value to a column. Integers are stored in big-endian -format and will need to be converted from the host format. -@return DB_SUCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_write_i16( -/*===============*/ - ib_tpl_t ib_tpl, /*!< in/out: tuple to write to */ - int col_no, /*!< in: column number */ - ib_i16_t val) /*!< in: value to write */ -{ - return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true)); -} - -/*****************************************************************//** -Write an integer value to a column. Integers are stored in big-endian -format and will need to be converted from the host format. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_write_i32( -/*===============*/ - ib_tpl_t ib_tpl, /*!< in/out: tuple to write to */ - int col_no, /*!< in: column number */ - ib_i32_t val) /*!< in: value to write */ -{ - return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true)); -} - -/*****************************************************************//** -Write an integer value to a column. Integers are stored in big-endian -format and will need to be converted from the host format. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_write_i64( -/*===============*/ - ib_tpl_t ib_tpl, /*!< in/out: tuple to write to */ - int col_no, /*!< in: column number */ - ib_i64_t val) /*!< in: value to write */ -{ - return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true)); -} - -/*****************************************************************//** -Write an integer value to a column. Integers are stored in big-endian -format and will need to be converted from the host format. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_write_u8( -/*==============*/ - ib_tpl_t ib_tpl, /*!< in/out: tuple to write to */ - int col_no, /*!< in: column number */ - ib_u8_t val) /*!< in: value to write */ -{ - return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true)); -} - -/*****************************************************************//** -Write an integer value to a column. Integers are stored in big-endian -format and will need to be converted from the host format. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_write_u16( -/*===============*/ - ib_tpl_t ib_tpl, /*!< in/out: tupe to write to */ - int col_no, /*!< in: column number */ - ib_u16_t val) /*!< in: value to write */ -{ - return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true)); -} - -/*****************************************************************//** -Write an integer value to a column. Integers are stored in big-endian -format and will need to be converted from the host format. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_write_u32( -/*===============*/ - ib_tpl_t ib_tpl, /*!< in/out: tuple to write to */ - int col_no, /*!< in: column number */ - ib_u32_t val) /*!< in: value to write */ -{ - return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true)); -} - -/*****************************************************************//** -Write an integer value to a column. Integers are stored in big-endian -format and will need to be converted from the host format. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_write_u64( -/*===============*/ - ib_tpl_t ib_tpl, /*!< in/out: tuple to write to */ - int col_no, /*!< in: column number */ - ib_u64_t val) /*!< in: value to write */ -{ - return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true)); -} - -/*****************************************************************//** -Inform the cursor that it's the start of an SQL statement. */ -UNIV_INTERN -void -ib_cursor_stmt_begin( -/*=================*/ - ib_crsr_t ib_crsr) /*!< in: cursor */ -{ - ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr; - - cursor->prebuilt->sql_stat_start = TRUE; -} - -/*****************************************************************//** -Write a double value to a column. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_write_double( -/*==================*/ - ib_tpl_t ib_tpl, /*!< in/out: tuple to write to */ - int col_no, /*!< in: column number */ - double val) /*!< in: value to write */ -{ - const dfield_t* dfield; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - - dfield = ib_col_get_dfield(tuple, col_no); - - if (dtype_get_mtype(dfield_get_type(dfield)) == DATA_DOUBLE) { - return(ib_col_set_value(ib_tpl, col_no, - &val, sizeof(val), true)); - } else { - return(DB_DATA_MISMATCH); - } -} - -/*************************************************************//** -Read a double column value from an InnoDB tuple. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_read_double( -/*=================*/ - ib_tpl_t ib_tpl, /*!< in: InnoDB tuple */ - ib_ulint_t col_no, /*!< in: column number */ - double* dval) /*!< out: double value */ -{ - ib_err_t err; - const dfield_t* dfield; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - - dfield = ib_col_get_dfield(tuple, col_no); - - if (dtype_get_mtype(dfield_get_type(dfield)) == DATA_DOUBLE) { - ib_col_copy_value_low(ib_tpl, col_no, dval, sizeof(*dval)); - err = DB_SUCCESS; - } else { - err = DB_DATA_MISMATCH; - } - - return(err); -} - -/*****************************************************************//** -Write a float value to a column. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_write_float( -/*=================*/ - ib_tpl_t ib_tpl, /*!< in/out: tuple to write to */ - int col_no, /*!< in: column number */ - float val) /*!< in: value to write */ -{ - const dfield_t* dfield; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - - dfield = ib_col_get_dfield(tuple, col_no); - - if (dtype_get_mtype(dfield_get_type(dfield)) == DATA_FLOAT) { - return(ib_col_set_value(ib_tpl, col_no, - &val, sizeof(val), true)); - } else { - return(DB_DATA_MISMATCH); - } -} - -/*************************************************************//** -Read a float value from an InnoDB tuple. -@return DB_SUCCESS or error */ -UNIV_INTERN -ib_err_t -ib_tuple_read_float( -/*================*/ - ib_tpl_t ib_tpl, /*!< in: InnoDB tuple */ - ib_ulint_t col_no, /*!< in: column number */ - float* fval) /*!< out: float value */ -{ - ib_err_t err; - const dfield_t* dfield; - ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl; - - dfield = ib_col_get_dfield(tuple, col_no); - - if (dtype_get_mtype(dfield_get_type(dfield)) == DATA_FLOAT) { - ib_col_copy_value_low(ib_tpl, col_no, fval, sizeof(*fval)); - err = DB_SUCCESS; - } else { - err = DB_DATA_MISMATCH; - } - - return(err); -} - -/*****************************************************************//** -Truncate a table. The cursor handle will be closed and set to NULL -on success. -@return DB_SUCCESS or error code */ -UNIV_INTERN -ib_err_t -ib_cursor_truncate( -/*===============*/ - ib_crsr_t* ib_crsr, /*!< in/out: cursor for table - to truncate */ - ib_id_u64_t* table_id) /*!< out: new table id */ -{ - ib_err_t err; - ib_cursor_t* cursor = *(ib_cursor_t**) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - - *table_id = 0; - - err = ib_cursor_lock(*ib_crsr, IB_LOCK_X); - - if (err == DB_SUCCESS) { - trx_t* trx; - dict_table_t* table = prebuilt->table; - - /* We are going to free the cursor and the prebuilt. Store - the transaction handle locally. */ - trx = prebuilt->trx; - err = ib_cursor_close(*ib_crsr); - ut_a(err == DB_SUCCESS); - - *ib_crsr = NULL; - - /* A temp go around for assertion in trx_start_for_ddl_low - we already start the trx */ - if (trx->state == TRX_STATE_ACTIVE) { -#ifdef UNIV_DEBUG - trx->start_file = 0; -#endif /* UNIV_DEBUG */ - trx->dict_operation = TRX_DICT_OP_TABLE; - } - - /* This function currently commits the transaction - on success. */ - err = static_cast<ib_err_t>( - row_truncate_table_for_mysql(table, trx)); - - if (err == DB_SUCCESS) { - *table_id = (table->id); - } - } - - return(err); -} - -/*****************************************************************//** -Truncate a table. -@return DB_SUCCESS or error code */ -UNIV_INTERN -ib_err_t -ib_table_truncate( -/*==============*/ - const char* table_name, /*!< in: table name */ - ib_id_u64_t* table_id) /*!< out: new table id */ -{ - ib_err_t err; - dict_table_t* table; - ib_err_t trunc_err; - ib_trx_t ib_trx = NULL; - ib_crsr_t ib_crsr = NULL; - ib_ulint_t memcached_sync = 0; - - ib_trx = ib_trx_begin(IB_TRX_SERIALIZABLE, true, false); - - dict_mutex_enter_for_mysql(); - - table = dict_table_open_on_name(table_name, TRUE, FALSE, - DICT_ERR_IGNORE_NONE); - - if (table != NULL && dict_table_get_first_index(table)) { - err = ib_create_cursor_with_index_id(&ib_crsr, table, 0, - (trx_t*) ib_trx); - } else { - err = DB_TABLE_NOT_FOUND; - } - - /* Remember the memcached_sync_count and set it to 0, so the - truncate can be executed. */ - if (table != NULL && err == DB_SUCCESS) { - memcached_sync = static_cast<ib_ulint_t>( - table->memcached_sync_count); - table->memcached_sync_count = 0; - } - - dict_mutex_exit_for_mysql(); - - if (err == DB_SUCCESS) { - trunc_err = ib_cursor_truncate(&ib_crsr, table_id); - ut_a(err == DB_SUCCESS); - } else { - trunc_err = err; - } - - if (ib_crsr != NULL) { - err = ib_cursor_close(ib_crsr); - ut_a(err == DB_SUCCESS); - } - - if (trunc_err == DB_SUCCESS) { - ut_a(ib_trx_state(ib_trx) == static_cast<ib_trx_state_t>( - TRX_STATE_NOT_STARTED)); - } else { - err = ib_trx_rollback(ib_trx); - ut_a(err == DB_SUCCESS); - } - - err = ib_trx_release(ib_trx); - ut_a(err == DB_SUCCESS); - - /* Set the memcached_sync_count back. */ - if (table != NULL && memcached_sync != 0) { - dict_mutex_enter_for_mysql(); - - table->memcached_sync_count = memcached_sync; - - dict_mutex_exit_for_mysql(); - } - - return(trunc_err); -} - -/*****************************************************************//** -Frees a possible InnoDB trx object associated with the current THD. -@return 0 or error number */ -UNIV_INTERN -ib_err_t -ib_close_thd( -/*=========*/ - void* thd) /*!< in: handle to the MySQL thread of the user - whose resources should be free'd */ -{ - innobase_close_thd(static_cast<THD*>(thd)); - - return(DB_SUCCESS); -} - -/*****************************************************************//** -Return isolation configuration set by "innodb_api_trx_level" -@return trx isolation level*/ -UNIV_INTERN -ib_trx_state_t -ib_cfg_trx_level() -/*==============*/ -{ - return(static_cast<ib_trx_state_t>(ib_trx_level_setting)); -} - -/*****************************************************************//** -Return configure value for background commit interval (in seconds) -@return background commit interval (in seconds) */ -UNIV_INTERN -ib_ulint_t -ib_cfg_bk_commit_interval() -/*=======================*/ -{ - return(static_cast<ib_ulint_t>(ib_bk_commit_interval)); -} - -/*****************************************************************//** -Get generic configure status -@return configure status*/ -UNIV_INTERN -int -ib_cfg_get_cfg() -/*============*/ -{ - int cfg_status; - - cfg_status = (ib_binlog_enabled) ? IB_CFG_BINLOG_ENABLED : 0; - - if (ib_mdl_enabled) { - cfg_status |= IB_CFG_MDL_ENABLED; - } - - if (ib_disable_row_lock) { - cfg_status |= IB_CFG_DISABLE_ROWLOCK; - } - - return(cfg_status); -} - -/*****************************************************************//** -Increase/decrease the memcached sync count of table to sync memcached -DML with SQL DDLs. -@return DB_SUCCESS or error number */ -UNIV_INTERN -ib_err_t -ib_cursor_set_memcached_sync( -/*=========================*/ - ib_crsr_t ib_crsr, /*!< in: cursor */ - ib_bool_t flag) /*!< in: true for increase */ -{ - const ib_cursor_t* cursor = (const ib_cursor_t*) ib_crsr; - row_prebuilt_t* prebuilt = cursor->prebuilt; - dict_table_t* table = prebuilt->table; - ib_err_t err = DB_SUCCESS; - - if (table != NULL) { - /* If memcached_sync_count is -1, means table is - doing DDL, we just return error. */ - if (table->memcached_sync_count == DICT_TABLE_IN_DDL) { - return(DB_ERROR); - } - - if (flag) { -#ifdef HAVE_ATOMIC_BUILTINS - os_atomic_increment_lint(&table->memcached_sync_count, 1); -#else - dict_mutex_enter_for_mysql(); - ++table->memcached_sync_count; - dict_mutex_exit_for_mysql(); -#endif - } else { -#ifdef HAVE_ATOMIC_BUILTINS - os_atomic_decrement_lint(&table->memcached_sync_count, 1); -#else - dict_mutex_enter_for_mysql(); - --table->memcached_sync_count; - dict_mutex_exit_for_mysql(); -#endif - ut_a(table->memcached_sync_count >= 0); - } - } else { - err = DB_TABLE_NOT_FOUND; - } - - return(err); -} |