/***************************************************************************** Copyright (c) 1997, 2017, Oracle and/or its affiliates. Copyright (c) 2017, 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, Suite 500, Boston, MA 02110-1335 USA *****************************************************************************/ /**************************************************//** @file include/row0sel.h Select Created 12/19/1997 Heikki Tuuri *******************************************************/ #ifndef row0sel_h #define row0sel_h #include "univ.i" #include "data0data.h" #include "que0types.h" #include "dict0types.h" #include "trx0types.h" #include "read0types.h" #include "row0types.h" #include "que0types.h" #include "pars0sym.h" #include "btr0pcur.h" #include "row0mysql.h" /*********************************************************************//** Creates a select node struct. @return own: select node struct */ sel_node_t* sel_node_create( /*============*/ mem_heap_t* heap); /*!< in: memory heap where created */ /*********************************************************************//** Frees the memory private to a select node when a query graph is freed, does not free the heap where the node was originally created. */ void sel_node_free_private( /*==================*/ sel_node_t* node); /*!< in: select node struct */ /*********************************************************************//** Frees a prefetch buffer for a column, including the dynamically allocated memory for data stored there. */ void sel_col_prefetch_buf_free( /*======================*/ sel_buf_t* prefetch_buf); /*!< in, own: prefetch buffer */ /*********************************************************************//** Gets the plan node for the nth table in a join. @return plan node */ UNIV_INLINE plan_t* sel_node_get_nth_plan( /*==================*/ sel_node_t* node, /*!< in: select node */ ulint i); /*!< in: get ith plan node */ /**********************************************************************//** Performs a select step. This is a high-level function used in SQL execution graphs. @return query thread to run next or NULL */ que_thr_t* row_sel_step( /*=========*/ que_thr_t* thr); /*!< in: query thread */ /**********************************************************************//** Performs an execution step of an open or close cursor statement node. @return query thread to run next or NULL */ UNIV_INLINE que_thr_t* open_step( /*======*/ que_thr_t* thr); /*!< in: query thread */ /**********************************************************************//** Performs a fetch for a cursor. @return query thread to run next or NULL */ que_thr_t* fetch_step( /*=======*/ que_thr_t* thr); /*!< in: query thread */ /***********************************************************//** Prints a row in a select result. @return query thread to run next or NULL */ que_thr_t* row_printf_step( /*============*/ que_thr_t* thr); /*!< in: query thread */ /** Copy used fields from cached row. Copy cache record field by field, don't touch fields that are not covered by current key. @param[out] buf Where to copy the MySQL row. @param[in] cached_rec What to copy (in MySQL row format). @param[in] prebuilt prebuilt struct. */ void row_sel_copy_cached_fields_for_mysql( byte* buf, const byte* cached_rec, row_prebuilt_t* prebuilt); /****************************************************************//** Converts a key value stored in MySQL format to an Innobase dtuple. The last field of the key value may be just a prefix of a fixed length field: hence the parameter key_len. But currently we do not allow search keys where the last field is only a prefix of the full key field len and print a warning if such appears. */ void row_sel_convert_mysql_key_to_innobase( /*==================================*/ dtuple_t* tuple, /*!< in/out: tuple where to build; NOTE: we assume that the type info in the tuple is already according to index! */ byte* buf, /*!< in: buffer to use in field conversions; NOTE that dtuple->data may end up pointing inside buf so do not discard that buffer while the tuple is being used. See row_mysql_store_col_in_innobase_format() in the case of DATA_INT */ ulint buf_len, /*!< in: buffer length */ dict_index_t* index, /*!< in: index of the key value */ const byte* key_ptr, /*!< in: MySQL key value */ ulint key_len, /*!< in: MySQL key value length */ trx_t* trx); /*!< in: transaction */ /** Searches for rows in the database. This is used in the interface to MySQL. This function opens a cursor, and also implements fetch next and fetch prev. NOTE that if we do a search with a full key value from a unique index (ROW_SEL_EXACT), then we will not store the cursor position and fetch next or fetch prev must not be tried to the cursor! @param[out] buf buffer for the fetched row in MySQL format @param[in] mode search mode PAGE_CUR_L @param[in,out] prebuilt prebuilt struct for the table handler; this contains the info to search_tuple, index; if search tuple contains 0 field then we position the cursor at start or the end of index, depending on 'mode' @param[in] match_mode 0 or ROW_SEL_EXACT or ROW_SEL_EXACT_PREFIX @param[in] direction 0 or ROW_SEL_NEXT or ROW_SEL_PREV; Note: if this is != 0, then prebuilt must has a pcur with stored position! In opening of a cursor 'direction' should be 0. @return DB_SUCCESS, DB_RECORD_NOT_FOUND, DB_END_OF_INDEX, DB_DEADLOCK, DB_LOCK_TABLE_FULL, DB_CORRUPTION, or DB_TOO_BIG_RECORD */ UNIV_INLINE dberr_t row_search_for_mysql( byte* buf, page_cur_mode_t mode, row_prebuilt_t* prebuilt, ulint match_mode, ulint direction) MY_ATTRIBUTE((warn_unused_result)); /** Searches for rows in the database using cursor. Function is mainly used for tables that are shared across connections and so it employs technique that can help re-construct the rows that transaction is suppose to see. It also has optimization such as pre-caching the rows, using AHI, etc. @param[out] buf buffer for the fetched row in MySQL format @param[in] mode search mode PAGE_CUR_L @param[in,out] prebuilt prebuilt struct for the table handler; this contains the info to search_tuple, index; if search tuple contains 0 field then we position the cursor at start or the end of index, depending on 'mode' @param[in] match_mode 0 or ROW_SEL_EXACT or ROW_SEL_EXACT_PREFIX @param[in] direction 0 or ROW_SEL_NEXT or ROW_SEL_PREV; Note: if this is != 0, then prebuilt must has a pcur with stored position! In opening of a cursor 'direction' should be 0. @return DB_SUCCESS or error code */ dberr_t row_search_mvcc( byte* buf, page_cur_mode_t mode, row_prebuilt_t* prebuilt, ulint match_mode, ulint direction) MY_ATTRIBUTE((warn_unused_result)); /********************************************************************//** Count rows in a R-Tree leaf level. @return DB_SUCCESS if successful */ dberr_t row_count_rtree_recs( /*=================*/ row_prebuilt_t* prebuilt, /*!< in: prebuilt struct for the table handle; this contains the info of search_tuple, index; if search tuple contains 0 fields then we position the cursor at the start or the end of the index, depending on 'mode' */ ulint* n_rows); /*!< out: number of entries seen in the consistent read */ /*******************************************************************//** Checks if MySQL at the moment is allowed for this table to retrieve a consistent read result, or store it to the query cache. @return whether storing or retrieving from the query cache is permitted */ bool row_search_check_if_query_cache_permitted( /*======================================*/ trx_t* trx, /*!< in: transaction object */ const char* norm_name); /*!< in: concatenation of database name, '/' char, table name */ /** Read the max AUTOINC value from an index. @param[in] index index starting with an AUTO_INCREMENT column @return the largest AUTO_INCREMENT value @retval 0 if no records were found */ ib_uint64_t row_search_max_autoinc(dict_index_t* index) MY_ATTRIBUTE((nonnull, warn_unused_result)); /** A structure for caching column values for prefetched rows */ struct sel_buf_t{ byte* data; /*!< data, or NULL; if not NULL, this field has allocated memory which must be explicitly freed; can be != NULL even when len is UNIV_SQL_NULL */ ulint len; /*!< data length or UNIV_SQL_NULL */ ulint val_buf_size; /*!< size of memory buffer allocated for data: this can be more than len; this is defined when data != NULL */ }; /** Copy used fields from cached row. Copy cache record field by field, don't touch fields that are not covered by current key. @param[out] buf Where to copy the MySQL row. @param[in] cached_rec What to copy (in MySQL row format). @param[in] prebuilt prebuilt struct. */ void row_sel_copy_cached_fields_for_mysql( byte* buf, const byte* cached_rec, row_prebuilt_t* prebuilt); /** Query plan */ struct plan_t{ dict_table_t* table; /*!< table struct in the dictionary cache */ dict_index_t* index; /*!< table index used in the search */ btr_pcur_t pcur; /*!< persistent cursor used to search the index */ ibool asc; /*!< TRUE if cursor traveling upwards */ ibool pcur_is_open; /*!< TRUE if pcur has been positioned and we can try to fetch new rows */ ibool cursor_at_end; /*!< TRUE if the cursor is open but we know that there are no more qualifying rows left to retrieve from the index tree; NOTE though, that there may still be unprocessed rows in the prefetch stack; always FALSE when pcur_is_open is FALSE */ ibool stored_cursor_rec_processed; /*!< TRUE if the pcur position has been stored and the record it is positioned on has already been processed */ que_node_t** tuple_exps; /*!< array of expressions which are used to calculate the field values in the search tuple: there is one expression for each field in the search tuple */ dtuple_t* tuple; /*!< search tuple */ page_cur_mode_t mode; /*!< search mode: PAGE_CUR_G, ... */ ulint n_exact_match; /*!< number of first fields in the search tuple which must be exactly matched */ ibool unique_search; /*!< TRUE if we are searching an index record with a unique key */ ulint n_rows_fetched; /*!< number of rows fetched using pcur after it was opened */ ulint n_rows_prefetched;/*!< number of prefetched rows cached for fetch: fetching several rows in the same mtr saves CPU time */ ulint first_prefetched;/*!< index of the first cached row in select buffer arrays for each column */ ibool no_prefetch; /*!< no prefetch for this table */ sym_node_list_t columns; /*!< symbol table nodes for the columns to retrieve from the table */ UT_LIST_BASE_NODE_T(func_node_t) end_conds; /*!< conditions which determine the fetch limit of the index segment we have to look at: when one of these fails, the result set has been exhausted for the cursor in this index; these conditions are normalized so that in a comparison the column for this table is the first argument */ UT_LIST_BASE_NODE_T(func_node_t) other_conds; /*!< the rest of search conditions we can test at this table in a join */ ibool must_get_clust; /*!< TRUE if index is a non-clustered index and we must also fetch the clustered index record; this is the case if the non-clustered record does not contain all the needed columns, or if this is a single-table explicit cursor, or a searched update or delete */ ulint* clust_map; /*!< map telling how clust_ref is built from the fields of a non-clustered record */ dtuple_t* clust_ref; /*!< the reference to the clustered index entry is built here if index is a non-clustered index */ btr_pcur_t clust_pcur; /*!< if index is non-clustered, we use this pcur to search the clustered index */ mem_heap_t* old_vers_heap; /*!< memory heap used in building an old version of a row, or NULL */ }; /** Select node states */ enum sel_node_state { SEL_NODE_CLOSED, /*!< it is a declared cursor which is not currently open */ SEL_NODE_OPEN, /*!< intention locks not yet set on tables */ SEL_NODE_FETCH, /*!< intention locks have been set */ SEL_NODE_NO_MORE_ROWS /*!< cursor has reached the result set end */ }; /** Select statement node */ struct sel_node_t{ que_common_t common; /*!< node type: QUE_NODE_SELECT */ enum sel_node_state state; /*!< node state */ que_node_t* select_list; /*!< select list */ sym_node_t* into_list; /*!< variables list or NULL */ sym_node_t* table_list; /*!< table list */ ibool asc; /*!< TRUE if the rows should be fetched in an ascending order */ ibool set_x_locks; /*!< TRUE if the cursor is for update or delete, which means that a row x-lock should be placed on the cursor row */ ulint row_lock_mode; /*!< LOCK_X or LOCK_S */ ulint n_tables; /*!< number of tables */ ulint fetch_table; /*!< number of the next table to access in the join */ plan_t* plans; /*!< array of n_tables many plan nodes containing the search plan and the search data structures */ que_node_t* search_cond; /*!< search condition */ ReadView* read_view; /*!< if the query is a non-locking consistent read, its read view is placed here, otherwise NULL */ ibool consistent_read;/*!< TRUE if the select is a consistent, non-locking read */ order_node_t* order_by; /*!< order by column definition, or NULL */ ibool is_aggregate; /*!< TRUE if the select list consists of aggregate functions */ ibool aggregate_already_fetched; /*!< TRUE if the aggregate row has already been fetched for the current cursor */ ibool can_get_updated;/*!< this is TRUE if the select is in a single-table explicit cursor which can get updated within the stored procedure, or in a searched update or delete; NOTE that to determine of an explicit cursor if it can get updated, the parser checks from a stored procedure if it contains positioned update or delete statements */ sym_node_t* explicit_cursor;/*!< not NULL if an explicit cursor */ UT_LIST_BASE_NODE_T(sym_node_t) copy_variables; /*!< variables whose values we have to copy when an explicit cursor is opened, so that they do not change between fetches */ }; /** Fetch statement node */ struct fetch_node_t{ que_common_t common; /*!< type: QUE_NODE_FETCH */ sel_node_t* cursor_def; /*!< cursor definition */ sym_node_t* into_list; /*!< variables to set */ pars_user_func_t* func; /*!< User callback function or NULL. The first argument to the function is a sel_node_t*, containing the results of the SELECT operation for one row. If the function returns NULL, it is not interested in further rows and the cursor is modified so (cursor % NOTFOUND) is true. If it returns not-NULL, continue normally. */ }; /** Open or close cursor operation type */ enum open_node_op { ROW_SEL_OPEN_CURSOR, /*!< open cursor */ ROW_SEL_CLOSE_CURSOR /*!< close cursor */ }; /** Open or close cursor statement node */ struct open_node_t{ que_common_t common; /*!< type: QUE_NODE_OPEN */ enum open_node_op op_type; /*!< operation type: open or close cursor */ sel_node_t* cursor_def; /*!< cursor definition */ }; /** Row printf statement node */ struct row_printf_node_t{ que_common_t common; /*!< type: QUE_NODE_ROW_PRINTF */ sel_node_t* sel_node; /*!< select */ }; /** Search direction for the MySQL interface */ enum row_sel_direction { ROW_SEL_NEXT = 1, /*!< ascending direction */ ROW_SEL_PREV = 2 /*!< descending direction */ }; /** Match mode for the MySQL interface */ enum row_sel_match_mode { ROW_SEL_EXACT = 1, /*!< search using a complete key value */ ROW_SEL_EXACT_PREFIX /*!< search using a key prefix which must match rows: the prefix may contain an incomplete field (the last field in prefix may be just a prefix of a fixed length column) */ }; #ifdef UNIV_DEBUG /** Convert a non-SQL-NULL field from Innobase format to MySQL format. */ # define row_sel_field_store_in_mysql_format(dest,templ,idx,field,src,len) \ row_sel_field_store_in_mysql_format_func(dest,templ,idx,field,src,len) #else /* UNIV_DEBUG */ /** Convert a non-SQL-NULL field from Innobase format to MySQL format. */ # define row_sel_field_store_in_mysql_format(dest,templ,idx,field,src,len) \ row_sel_field_store_in_mysql_format_func(dest,templ,src,len) #endif /* UNIV_DEBUG */ /**************************************************************//** Stores a non-SQL-NULL field in the MySQL format. The counterpart of this function is row_mysql_store_col_in_innobase_format() in row0mysql.cc. */ void row_sel_field_store_in_mysql_format_func( /*=====================================*/ byte* dest, /*!< in/out: buffer where to store; NOTE that BLOBs are not in themselves stored here: the caller must allocate and copy the BLOB into buffer before, and pass the pointer to the BLOB in 'data' */ const mysql_row_templ_t* templ, /*!< in: MySQL column template. Its following fields are referenced: type, is_unsigned, mysql_col_len, mbminlen, mbmaxlen */ #ifdef UNIV_DEBUG const dict_index_t* index, /*!< in: InnoDB index */ ulint field_no, /*!< in: templ->rec_field_no or templ->clust_rec_field_no or templ->icp_rec_field_no */ #endif /* UNIV_DEBUG */ const byte* data, /*!< in: data to store */ ulint len); /*!< in: length of the data */ #include "row0sel.ic" #endif