/***************************************************************************** Copyright (c) 2000, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2017, 2022, MariaDB Corporation. 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, Fifth Floor, Boston, MA 02110-1335 USA *****************************************************************************/ /**************************************************//** @file include/row0mysql.h Interface between Innobase row operations and MySQL. Contains also create table and other data dictionary operations. Created 9/17/2000 Heikki Tuuri *******************************************************/ #ifndef row0mysql_h #define row0mysql_h #include "que0types.h" #include "trx0types.h" #include "row0types.h" #include "btr0types.h" #include "lock0types.h" #include "fil0fil.h" #include "fts0fts.h" #include "gis0type.h" struct row_prebuilt_t; class ha_innobase; class ha_handler_stats; /*******************************************************************//** Frees the blob heap in prebuilt when no longer needed. */ void row_mysql_prebuilt_free_blob_heap( /*==============================*/ row_prebuilt_t* prebuilt); /*!< in: prebuilt struct of a ha_innobase:: table handle */ /*******************************************************************//** Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row format. @return pointer to the data, we skip the 1 or 2 bytes at the start that are used to store the len */ byte* row_mysql_store_true_var_len( /*=========================*/ byte* dest, /*!< in: where to store */ ulint len, /*!< in: length, must fit in two bytes */ ulint lenlen);/*!< in: storage length of len: either 1 or 2 bytes */ /*******************************************************************//** Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and returns a pointer to the data. @return pointer to the data, we skip the 1 or 2 bytes at the start that are used to store the len */ const byte* row_mysql_read_true_varchar( /*========================*/ ulint* len, /*!< out: variable-length field length */ const byte* field, /*!< in: field in the MySQL format */ ulint lenlen);/*!< in: storage length of len: either 1 or 2 bytes */ /*******************************************************************//** Stores a reference to a BLOB in the MySQL format. */ void row_mysql_store_blob_ref( /*=====================*/ byte* dest, /*!< in: where to store */ ulint col_len,/*!< in: dest buffer size: determines into how many bytes the BLOB length is stored, the space for the length may vary from 1 to 4 bytes */ const void* data, /*!< in: BLOB data; if the value to store is SQL NULL this should be NULL pointer */ ulint len); /*!< in: BLOB length; if the value to store is SQL NULL this should be 0; remember also to set the NULL bit in the MySQL record header! */ /*******************************************************************//** Reads a reference to a BLOB in the MySQL format. @return pointer to BLOB data */ const byte* row_mysql_read_blob_ref( /*====================*/ ulint* len, /*!< out: BLOB length */ const byte* ref, /*!< in: BLOB reference in the MySQL format */ ulint col_len); /*!< in: BLOB reference length (not BLOB length) */ /*******************************************************************//** Converts InnoDB geometry data format to MySQL data format. */ void row_mysql_store_geometry( /*=====================*/ byte* dest, /*!< in/out: where to store */ ulint dest_len, /*!< in: dest buffer size: determines into how many bytes the geometry length is stored, the space for the length may vary from 1 to 4 bytes */ const byte* src, /*!< in: geometry data; if the value to store is SQL NULL this should be NULL pointer */ ulint src_len); /*!< in: geometry length; if the value to store is SQL NULL this should be 0; remember also to set the NULL bit in the MySQL record header! */ /**************************************************************//** Pad a column with spaces. */ void row_mysql_pad_col( /*==============*/ ulint mbminlen, /*!< in: minimum size of a character, in bytes */ byte* pad, /*!< out: padded buffer */ ulint len); /*!< in: number of bytes to pad */ /**************************************************************//** Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format. The counterpart of this function is row_sel_field_store_in_mysql_format() in row0sel.cc. @return up to which byte we used buf in the conversion */ byte* row_mysql_store_col_in_innobase_format( /*===================================*/ dfield_t* dfield, /*!< in/out: dfield where dtype information must be already set when this function is called! */ byte* buf, /*!< in/out: buffer for a converted integer value; this must be at least col_len long then! NOTE that dfield may also get a pointer to 'buf', therefore do not discard this as long as dfield is used! */ ibool row_format_col, /*!< TRUE if the mysql_data is from a MySQL row, FALSE if from a MySQL key value; in MySQL, a true VARCHAR storage format differs in a row and in a key value: in a key value the length is always stored in 2 bytes! */ const byte* mysql_data, /*!< in: MySQL column value, not SQL NULL; NOTE that dfield may also get a pointer to mysql_data, therefore do not discard this as long as dfield is used! */ ulint col_len, /*!< in: MySQL column length; NOTE that this is the storage length of the column in the MySQL format row, not necessarily the length of the actual payload data; if the column is a true VARCHAR then this is irrelevant */ ulint comp); /*!< in: nonzero=compact format */ /****************************************************************//** Handles user errors and lock waits detected by the database engine. @return true if it was a lock wait and we should continue running the query thread */ bool row_mysql_handle_errors( /*====================*/ dberr_t* new_err,/*!< out: possible new error encountered in rollback, or the old error which was during the function entry */ trx_t* trx, /*!< in: transaction */ que_thr_t* thr, /*!< in: query thread, or NULL */ trx_savept_t* savept) /*!< in: savepoint, or NULL */ MY_ATTRIBUTE((nonnull(1,2))); /********************************************************************//** Create a prebuilt struct for a MySQL table handle. @return own: a prebuilt struct */ row_prebuilt_t* row_create_prebuilt( /*================*/ dict_table_t* table, /*!< in: Innobase table handle */ ulint mysql_row_len); /*!< in: length in bytes of a row in the MySQL format */ /** Free a prebuilt struct for a TABLE handle. */ void row_prebuilt_free(row_prebuilt_t *prebuilt); /*********************************************************************//** Updates the transaction pointers in query graphs stored in the prebuilt struct. */ void row_update_prebuilt_trx( /*====================*/ row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct in MySQL handle */ trx_t* trx); /*!< in: transaction handle */ /*********************************************************************//** Sets an AUTO_INC type lock on the table mentioned in prebuilt. The AUTO_INC lock gives exclusive access to the auto-inc counter of the table. The lock is reserved only for the duration of an SQL statement. It is not compatible with another AUTO_INC or exclusive lock on the table. @return error code or DB_SUCCESS */ dberr_t row_lock_table_autoinc_for_mysql( /*=============================*/ row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in the MySQL table handle */ MY_ATTRIBUTE((nonnull, warn_unused_result)); /** Lock a table. @param[in,out] prebuilt table handle @return error code or DB_SUCCESS */ dberr_t row_lock_table(row_prebuilt_t* prebuilt); /** System Versioning: row_insert_for_mysql() modes */ enum ins_mode_t { /* plain row (without versioning) */ ROW_INS_NORMAL = 0, /* row_start = TRX_ID, row_end = MAX */ ROW_INS_VERSIONED, /* row_end = TRX_ID */ ROW_INS_HISTORICAL }; /** Does an insert for MySQL. @param[in] mysql_rec row in the MySQL format @param[in,out] prebuilt prebuilt struct in MySQL handle @param[in] ins_mode what row type we're inserting @return error code or DB_SUCCESS*/ dberr_t row_insert_for_mysql( const byte* mysql_rec, row_prebuilt_t* prebuilt, ins_mode_t ins_mode) MY_ATTRIBUTE((warn_unused_result)); /*********************************************************************//** Builds a dummy query graph used in selects. */ void row_prebuild_sel_graph( /*===================*/ row_prebuilt_t* prebuilt); /*!< in: prebuilt struct in MySQL handle */ /*********************************************************************//** Gets pointer to a prebuilt update vector used in updates. If the update graph has not yet been built in the prebuilt struct, then this function first builds it. @return prebuilt update vector */ upd_t* row_get_prebuilt_update_vector( /*===========================*/ row_prebuilt_t* prebuilt); /*!< in: prebuilt struct in MySQL handle */ /** Does an update or delete of a row for MySQL. @param[in,out] prebuilt prebuilt struct in MySQL handle @return error code or DB_SUCCESS */ dberr_t row_update_for_mysql( row_prebuilt_t* prebuilt) MY_ATTRIBUTE((warn_unused_result)); /** This can only be used when the current transaction is at READ COMMITTED or READ UNCOMMITTED isolation level. Before calling this function row_search_mvcc() must have initialized prebuilt->new_rec_locks to store the information which new record locks really were set. This function removes a newly set clustered index record lock under prebuilt->pcur or prebuilt->clust_pcur. Thus, this implements a 'mini-rollback' that releases the latest clustered index record lock we set. @param[in,out] prebuilt prebuilt struct in MySQL handle @param[in] has_latches_on_recs TRUE if called so that we have the latches on the records under pcur and clust_pcur, and we do not need to reposition the cursors. */ void row_unlock_for_mysql( row_prebuilt_t* prebuilt, ibool has_latches_on_recs); /*********************************************************************//** Creates an query graph node of 'update' type to be used in the MySQL interface. @return own: update node */ upd_node_t* row_create_update_node_for_mysql( /*=============================*/ dict_table_t* table, /*!< in: table to update */ mem_heap_t* heap); /*!< in: mem heap from which allocated */ /**********************************************************************//** Does a cascaded delete or set null in a foreign key operation. @return error code or DB_SUCCESS */ dberr_t row_update_cascade_for_mysql( /*=========================*/ que_thr_t* thr, /*!< in: query thread */ upd_node_t* node, /*!< in: update node used in the cascade or set null operation */ dict_table_t* table) /*!< in: table where we do the operation */ MY_ATTRIBUTE((nonnull, warn_unused_result)); /** Lock the data dictionary cache exclusively. */ #define row_mysql_lock_data_dictionary(trx) \ do { \ ut_ad(!trx->dict_operation_lock_mode); \ dict_sys.lock(SRW_LOCK_CALL); \ trx->dict_operation_lock_mode = true; \ } while (0) /** Unlock the data dictionary. */ #define row_mysql_unlock_data_dictionary(trx) \ do { \ ut_ad(!lock_trx_has_sys_table_locks(trx)); \ ut_ad(trx->dict_operation_lock_mode); \ trx->dict_operation_lock_mode = false; \ dict_sys.unlock(); \ } while (0) /*********************************************************************//** Creates a table for MySQL. On failure the transaction will be rolled back and the 'table' object will be freed. @return error code or DB_SUCCESS */ dberr_t row_create_table_for_mysql( /*=======================*/ dict_table_t* table, /*!< in, own: table definition (will be freed, or on DB_SUCCESS added to the data dictionary cache) */ trx_t* trx) /*!< in/out: transaction */ MY_ATTRIBUTE((warn_unused_result)); /*********************************************************************//** Create an index when creating a table. On failure, the caller must drop the table! @return error number or DB_SUCCESS */ dberr_t row_create_index_for_mysql( /*=======================*/ dict_index_t* index, /*!< in, own: index definition (will be freed) */ trx_t* trx, /*!< in: transaction handle */ const ulint* field_lengths, /*!< in: if not NULL, must contain dict_index_get_n_fields(index) actual field lengths for the index columns, which are then checked for not being too large. */ fil_encryption_t mode, /*!< in: encryption mode */ uint32_t key_id) /*!< in: encryption key_id */ MY_ATTRIBUTE((warn_unused_result)); /*********************************************************************//** Discards the tablespace of a table which stored in an .ibd file. Discarding means that this function deletes the .ibd file and assigns a new table id for the table. Also the file_unreadable flag is set. @return error code or DB_SUCCESS */ dberr_t row_discard_tablespace_for_mysql(dict_table_t *table, trx_t *trx) MY_ATTRIBUTE((nonnull, warn_unused_result)); /*****************************************************************//** Imports a tablespace. The space id in the .ibd file must match the space id of the table in the data dictionary. @return error code or DB_SUCCESS */ dberr_t row_import_tablespace_for_mysql( /*============================*/ dict_table_t* table, /*!< in/out: table */ row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL */ MY_ATTRIBUTE((nonnull, warn_unused_result)); /*********************************************************************//** Renames a table for MySQL. @return error code or DB_SUCCESS */ dberr_t row_rename_table_for_mysql( /*=======================*/ const char* old_name, /*!< in: old table name */ const char* new_name, /*!< in: new table name */ trx_t* trx, /*!< in/out: transaction */ bool use_fk) /*!< in: whether to parse and enforce FOREIGN KEY constraints */ MY_ATTRIBUTE((nonnull, warn_unused_result)); /* A struct describing a place for an individual column in the MySQL row format which is presented to the table handler in ha_innobase. This template struct is used to speed up row transformations between Innobase and MySQL. */ struct mysql_row_templ_t { ulint col_no; /*!< column number of the column */ ulint rec_field_no; /*!< field number of the column in an Innobase record in the current index; not defined if template_type is ROW_MYSQL_WHOLE_ROW */ ibool rec_field_is_prefix; /* is this field in a prefix index? */ ulint rec_prefix_field_no; /* record field, even if just a prefix; same as rec_field_no when not a prefix, otherwise rec_field_no is ULINT_UNDEFINED but this is the true field number*/ ulint clust_rec_field_no; /*!< field number of the column in an Innobase record in the clustered index; not defined if template_type is ROW_MYSQL_WHOLE_ROW */ ulint icp_rec_field_no; /*!< field number of the column in an Innobase record in the current index; not defined unless index condition pushdown is used */ ulint mysql_col_offset; /*!< offset of the column in the MySQL row format */ ulint mysql_col_len; /*!< length of the column in the MySQL row format */ ulint mysql_null_byte_offset; /*!< MySQL NULL bit byte offset in a MySQL record */ ulint mysql_null_bit_mask; /*!< bit mask to get the NULL bit, zero if column cannot be NULL */ ulint type; /*!< column type in Innobase mtype numbers DATA_CHAR... */ ulint mysql_type; /*!< MySQL type code; this is always < 256 */ ulint mysql_length_bytes; /*!< if mysql_type == DATA_MYSQL_TRUE_VARCHAR, this tells whether we should use 1 or 2 bytes to store the MySQL true VARCHAR data length at the start of row in the MySQL format (NOTE that the MySQL key value format always uses 2 bytes for the data len) */ ulint charset; /*!< MySQL charset-collation code of the column, or zero */ ulint mbminlen; /*!< minimum length of a char, in bytes, or zero if not a char type */ ulint mbmaxlen; /*!< maximum length of a char, in bytes, or zero if not a char type */ ulint is_unsigned; /*!< if a column type is an integer type and this field is != 0, then it is an unsigned integer type */ ulint is_virtual; /*!< if a column is a virtual column */ }; #define MYSQL_FETCH_CACHE_SIZE 8 /* After fetching this many rows, we start caching them in fetch_cache */ #define MYSQL_FETCH_CACHE_THRESHOLD 4 #define ROW_PREBUILT_ALLOCATED 78540783 #define ROW_PREBUILT_FREED 26423527 /** A struct for (sometimes lazily) prebuilt structures in an Innobase table handle used within MySQL; these are used to save CPU time. */ struct row_prebuilt_t { ulint magic_n; /*!< this magic number is set to ROW_PREBUILT_ALLOCATED when created, or ROW_PREBUILT_FREED when the struct has been freed */ dict_table_t* table; /*!< Innobase table handle */ dict_index_t* index; /*!< current index for a search, if any */ trx_t* trx; /*!< current transaction handle */ unsigned sql_stat_start:1;/*!< TRUE when we start processing of an SQL statement: we may have to set an intention lock on the table, create a consistent read view etc. */ unsigned clust_index_was_generated:1; /*!< if the user did not define a primary key in MySQL, then Innobase automatically generated a clustered index where the ordering column is the row id: in this case this flag is set to TRUE */ unsigned index_usable:1; /*!< caches the value of row_merge_is_index_usable(trx,index) */ unsigned read_just_key:1;/*!< set to 1 when MySQL calls ha_innobase::extra with the argument HA_EXTRA_KEYREAD; it is enough to read just columns defined in the index (i.e., no read of the clustered index record necessary) */ unsigned used_in_HANDLER:1;/*!< TRUE if we have been using this handle in a MySQL HANDLER low level index cursor command: then we must store the pcur position even in a unique search from a clustered index, because HANDLER allows NEXT and PREV in such a situation */ unsigned template_type:2;/*!< ROW_MYSQL_WHOLE_ROW, ROW_MYSQL_REC_FIELDS, ROW_MYSQL_DUMMY_TEMPLATE, or ROW_MYSQL_NO_TEMPLATE */ unsigned n_template:10; /*!< number of elements in the template */ unsigned null_bitmap_len:10;/*!< number of bytes in the SQL NULL bitmap at the start of a row in the MySQL format */ unsigned need_to_access_clustered:1; /*!< if we are fetching columns through a secondary index and at least one column is not in the secondary index, then this is set to TRUE; note that sometimes this is set but we later optimize out the clustered index lookup */ unsigned templ_contains_blob:1;/*!< TRUE if the template contains a column with DATA_LARGE_MTYPE( get_innobase_type_from_mysql_type()) is TRUE; not to be confused with InnoDB externally stored columns (VARCHAR can be off-page too) */ unsigned versioned_write:1;/*!< whether this is a versioned write */ mysql_row_templ_t* mysql_template;/*!< template used to transform rows fast between MySQL and Innobase formats; memory for this template is not allocated from 'heap' */ mem_heap_t* heap; /*!< memory heap from which these auxiliary structures are allocated when needed */ ins_node_t* ins_node; /*!< Innobase SQL insert node used to perform inserts to the table */ byte* ins_upd_rec_buff;/*!< buffer for storing data converted to the Innobase format from the MySQL format */ const byte* default_rec; /*!< the default values of all columns (a "default row") in MySQL format */ ulint hint_need_to_fetch_extra_cols; /*!< normally this is set to 0; if this is set to ROW_RETRIEVE_PRIMARY_KEY, then we should at least retrieve all columns in the primary key; if this is set to ROW_RETRIEVE_ALL_COLS, then we must retrieve all columns in the key (if read_just_key == 1), or all columns in the table */ upd_node_t* upd_node; /*!< Innobase SQL update node used to perform updates and deletes */ trx_id_t trx_id; /*!< The table->def_trx_id when ins_graph was built */ que_fork_t* ins_graph; /*!< Innobase SQL query graph used in inserts. Will be rebuilt on trx_id or n_indexes mismatch. */ que_fork_t* upd_graph; /*!< Innobase SQL query graph used in updates or deletes */ btr_pcur_t* pcur; /*!< persistent cursor used in selects and updates */ btr_pcur_t* clust_pcur; /*!< persistent cursor used in some selects and updates */ que_fork_t* sel_graph; /*!< dummy query graph used in selects */ dtuple_t* search_tuple; /*!< prebuilt dtuple used in selects */ byte row_id[DATA_ROW_ID_LEN]; /*!< if the clustered index was generated, the row id of the last row fetched is stored here */ doc_id_t fts_doc_id; /* if the table has an FTS index on it then we fetch the doc_id. FTS-FIXME: Currently we fetch it always but in the future we must only fetch it when FTS columns are being updated */ dtuple_t* clust_ref; /*!< prebuilt dtuple used in sel/upd/del */ lock_mode select_lock_type;/*!< LOCK_NONE, LOCK_S, or LOCK_X */ bool skip_locked; /*!< TL_{READ,WRITE}_SKIP_LOCKED */ lock_mode stored_select_lock_type;/*!< this field is used to remember the original select_lock_type that was decided in ha_innodb.cc, ::store_lock(), ::external_lock(), etc. */ ulint row_read_type; /*!< ROW_READ_WITH_LOCKS if row locks should be the obtained for records under an UPDATE or DELETE cursor. At READ UNCOMMITTED or READ COMMITTED isolation level, this can be set to ROW_READ_TRY_SEMI_CONSISTENT, so that if the row under an UPDATE or DELETE cursor was locked by another transaction, InnoDB will resort to reading the last committed value ('semi-consistent read'). Then, this field will be set to ROW_READ_DID_SEMI_CONSISTENT to indicate that. If the row does not match the WHERE condition, MySQL will invoke handler::unlock_row() to clear the flag back to ROW_READ_TRY_SEMI_CONSISTENT and to simply skip the row. If the row matches, the next call to row_search_mvcc() will lock the row. This eliminates lock waits in some cases; note that this breaks serializability. */ ulint new_rec_locks; /*!< normally 0; if the session is using READ COMMITTED or READ UNCOMMITTED isolation level, set in row_search_mvcc() if we set a new record lock on the secondary or clustered index; this is used in row_unlock_for_mysql() when releasing the lock under the cursor if we determine after retrieving the row that it does not need to be locked ('mini-rollback') */ ulint mysql_prefix_len;/*!< byte offset of the end of the last requested column */ ulint mysql_row_len; /*!< length in bytes of a row in the MySQL format */ ulint n_rows_fetched; /*!< number of rows fetched after positioning the current cursor */ ulint fetch_direction;/*!< ROW_SEL_NEXT or ROW_SEL_PREV */ byte* fetch_cache[MYSQL_FETCH_CACHE_SIZE]; /*!< a cache for fetched rows if we fetch many rows from the same cursor: it saves CPU time to fetch them in a batch; we reserve mysql_row_len bytes for each such row; these pointers point 4 bytes past the allocated mem buf start, because there is a 4 byte magic number at the start and at the end */ bool keep_other_fields_on_keyread; /*!< when using fetch cache with HA_EXTRA_KEYREAD, don't overwrite other fields in mysql row row buffer.*/ ulint fetch_cache_first;/*!< position of the first not yet fetched row in fetch_cache */ ulint n_fetch_cached; /*!< number of not yet fetched rows in fetch_cache */ mem_heap_t* blob_heap; /*!< in SELECTS BLOB fields are copied to this heap */ mem_heap_t* old_vers_heap; /*!< memory heap where a previous version is built in consistent read */ bool in_fts_query; /*!< Whether we are in a FTS query */ bool fts_doc_id_in_read_set; /*!< true if table has externally defined FTS_DOC_ID coulmn. */ /*----------------------*/ ulonglong autoinc_last_value; /*!< last value of AUTO-INC interval */ ulonglong autoinc_increment;/*!< The increment step of the auto increment column. Value must be greater than or equal to 1. Required to calculate the next value */ ulonglong autoinc_offset; /*!< The offset passed to get_auto_increment() by MySQL. Required to calculate the next value */ dberr_t autoinc_error; /*!< The actual error code encountered while trying to init or read the autoinc value from the table. We store it here so that we can return it to MySQL */ /*----------------------*/ /** Argument of handler_rowid_filter_check(), or NULL if no PRIMARY KEY filter is pushed */ ha_innobase* pk_filter; /** Argument to handler_index_cond_check(), or NULL if no index condition pushdown (ICP) is used. */ ha_innobase* idx_cond; ulint idx_cond_n_cols;/*!< Number of fields in idx_cond_cols. 0 if and only if idx_cond == NULL. */ /*----------------------*/ /*----------------------*/ rtr_info_t* rtr_info; /*!< R-tree Search Info */ /*----------------------*/ ulint magic_n2; /*!< this should be the same as magic_n */ byte* srch_key_val1; /*!< buffer used in converting search key values from MySQL format to InnoDB format.*/ byte* srch_key_val2; /*!< buffer used in converting search key values from MySQL format to InnoDB format.*/ uint srch_key_val_len; /*!< Size of search key */ /** The MySQL table object */ TABLE* m_mysql_table; /** Get template by dict_table_t::cols[] number */ const mysql_row_templ_t* get_template_by_col(ulint col) const { ut_ad(col < n_template); ut_ad(mysql_template); for (ulint i = col; i < n_template; ++i) { const mysql_row_templ_t* templ = &mysql_template[i]; if (!templ->is_virtual && templ->col_no == col) { return templ; } } return NULL; } }; /** Callback for row_mysql_sys_index_iterate() */ struct SysIndexCallback { virtual ~SysIndexCallback() = default; /** Callback method @param mtr current mini transaction @param pcur persistent cursor. */ virtual void operator()(mtr_t* mtr, btr_pcur_t* pcur) throw() = 0; }; /** Storage for calculating virtual columns */ class String; struct VCOL_STORAGE { TABLE *maria_table; byte *innobase_record; byte *maria_record; String *blob_value_storage; VCOL_STORAGE(): maria_table(NULL), innobase_record(NULL), maria_record(NULL), blob_value_storage(NULL) {} }; /** Allocate a heap and record for calculating virtual fields Used mainly for virtual fields in indexes @param[in] thd MariaDB THD @param[in] index Index in use @param[out] heap Heap that holds temporary row @param[in,out] mysql_table MariaDB table @param[out] rec Pointer to allocated MariaDB record @param[out] storage Internal storage for blobs etc @return FALSE ok @return TRUE malloc failure */ bool innobase_allocate_row_for_vcol(THD *thd, const dict_index_t* index, mem_heap_t** heap, TABLE** table, VCOL_STORAGE* storage); /** Free memory allocated by innobase_allocate_row_for_vcol() */ void innobase_free_row_for_vcol(VCOL_STORAGE *storage); class ib_vcol_row { VCOL_STORAGE storage; public: mem_heap_t *heap; ib_vcol_row(mem_heap_t *heap) : heap(heap) {} byte *record(THD *thd, const dict_index_t *index, TABLE **table) { if (!storage.innobase_record && !innobase_allocate_row_for_vcol(thd, index, &heap, table, &storage)) return nullptr; return storage.innobase_record; } ~ib_vcol_row() { if (heap) { if (storage.innobase_record) innobase_free_row_for_vcol(&storage); mem_heap_free(heap); } } }; /** Report virtual value computation failure in ib::error @param[in] row the data row */ ATTRIBUTE_COLD void innobase_report_computed_value_failed(dtuple_t *row); /** Get the computed value by supplying the base column values. @param[in,out] row the data row @param[in] col virtual column @param[in] index index on the virtual column @param[in,out] local_heap heap memory for processing large data etc. @param[in,out] heap memory heap that copies the actual index row @param[in] ifield index field @param[in] thd connection handle @param[in,out] mysql_table MariaDB table handle @param[in,out] mysql_rec MariaDB record buffer @param[in] old_table during ALTER TABLE, this is the old table or NULL. @param[in] update update vector for the parent row @param[in] ignore_warnings ignore warnings during calculation. Usually means that a calculation is internal and should have no side effects. @return the field filled with computed value */ dfield_t* innobase_get_computed_value( dtuple_t* row, const dict_v_col_t* col, const dict_index_t* index, mem_heap_t** local_heap, mem_heap_t* heap, const dict_field_t* ifield, THD* thd, TABLE* mysql_table, byte* mysql_rec, const dict_table_t* old_table=NULL, const upd_t* update=NULL, bool ignore_warnings=false); /** Change dbname and table name in table->vc_templ. @param[in,out] table the table whose virtual column template dbname and tbname to be renamed. */ void innobase_rename_vc_templ( dict_table_t* table); #define ROW_PREBUILT_FETCH_MAGIC_N 465765687 #define ROW_MYSQL_WHOLE_ROW 0 #define ROW_MYSQL_REC_FIELDS 1 #define ROW_MYSQL_NO_TEMPLATE 2 #define ROW_MYSQL_DUMMY_TEMPLATE 3 /* dummy template used in row_check_index() */ /* Values for hint_need_to_fetch_extra_cols */ #define ROW_RETRIEVE_PRIMARY_KEY 1 #define ROW_RETRIEVE_ALL_COLS 2 /* Values for row_read_type */ #define ROW_READ_WITH_LOCKS 0 #define ROW_READ_TRY_SEMI_CONSISTENT 1 #define ROW_READ_DID_SEMI_CONSISTENT 2 #endif /* row0mysql.h */