/****************************************************** Select (c) 1997 Innobase Oy 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 "row0types.h" #include "que0types.h" #include "pars0sym.h" #include "btr0pcur.h" #include "read0read.h" #include "row0mysql.h" /************************************************************************* Creates a select node struct. */ sel_node_t* sel_node_create( /*============*/ /* out, own: select node struct */ 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. */ UNIV_INLINE plan_t* sel_node_get_nth_plan( /*==================*/ sel_node_t* node, ulint i); /************************************************************************** Performs a select step. This is a high-level function used in SQL execution graphs. */ que_thr_t* row_sel_step( /*=========*/ /* out: query thread to run next or NULL */ que_thr_t* thr); /* in: query thread */ /************************************************************************** Performs an execution step of an open or close cursor statement node. */ UNIV_INLINE que_thr_t* open_step( /*======*/ /* out: query thread to run next or NULL */ que_thr_t* thr); /* in: query thread */ /************************************************************************** Performs a fetch for a cursor. */ que_thr_t* fetch_step( /*=======*/ /* out: query thread to run next or NULL */ que_thr_t* thr); /* in: query thread */ /*************************************************************** Prints a row in a select result. */ que_thr_t* row_printf_step( /*============*/ /* out: query thread to run next or NULL */ que_thr_t* thr); /* in: query thread */ /******************************************************************** 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: 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 */ ulint buf_len, /* in: buffer length */ dict_index_t* index, /* in: index of the key value */ byte* key_ptr, /* in: MySQL key value */ ulint key_len); /* in: MySQL key value length */ /************************************************************************ 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! */ ulint row_search_for_mysql( /*=================*/ /* out: DB_SUCCESS, DB_RECORD_NOT_FOUND, DB_END_OF_INDEX, DB_DEADLOCK, or DB_TOO_BIG_RECORD */ byte* buf, /* in/out: buffer for the fetched row in the MySQL format */ ulint mode, /* in: search mode PAGE_CUR_L, ... */ 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 match_mode, /* in: 0 or ROW_SEL_EXACT or ROW_SEL_EXACT_PREFIX */ ulint direction); /* in: 0 or ROW_SEL_NEXT or ROW_SEL_PREV; NOTE: if this is != 0, then prebuilt must have a pcur with stored position! In opening of a cursor 'direction' should be 0. */ /*********************************************************************** Checks if MySQL at the moment is allowed for this table to retrieve a consistent read result, or store it to the query cache. */ ibool row_search_check_if_query_cache_permitted( /*======================================*/ /* out: TRUE if storing or retrieving from the query cache is permitted */ trx_t* trx, /* in: transaction object */ char* norm_name); /* in: concatenation of database name, '/' char, table name */ /* A structure for caching column values for prefetched rows */ struct sel_buf_struct{ 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 */ }; struct plan_struct{ 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 */ ulint 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 */ ibool mixed_index; /* TRUE if index is a clustered index in a mixed cluster */ 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 */ }; struct sel_node_struct{ que_common_t common; /* node type: QUE_NODE_SELECT */ ulint 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 */ ibool select_will_do_update; /* TRUE if the select is for a searched update which can be performed in-place: in this case the select will take care of the update */ ulint latch_mode; /* BTR_SEARCH_LEAF, or BTR_MODIFY_LEAF if select_will_do_update is TRUE */ 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 */ read_view_t* 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 */ }; /* Select node states */ #define SEL_NODE_CLOSED 0 /* it is a declared cursor which is not currently open */ #define SEL_NODE_OPEN 1 /* intention locks not yet set on tables */ #define SEL_NODE_FETCH 2 /* intention locks have been set */ #define SEL_NODE_NO_MORE_ROWS 3 /* cursor has reached the result set end */ /* Fetch statement node */ struct fetch_node_struct{ que_common_t common; /* type: QUE_NODE_FETCH */ sel_node_t* cursor_def; /* cursor definition */ sym_node_t* into_list; /* variables to set */ }; /* Open or close cursor statement node */ struct open_node_struct{ que_common_t common; /* type: QUE_NODE_OPEN */ ulint op_type; /* ROW_SEL_OPEN_CURSOR or ROW_SEL_CLOSE_CURSOR */ sel_node_t* cursor_def; /* cursor definition */ }; /* Row printf statement node */ struct row_printf_node_struct{ que_common_t common; /* type: QUE_NODE_ROW_PRINTF */ sel_node_t* sel_node; /* select */ }; #define ROW_SEL_OPEN_CURSOR 0 #define ROW_SEL_CLOSE_CURSOR 1 /* Flags for the MySQL interface */ #define ROW_SEL_NEXT 1 #define ROW_SEL_PREV 2 #define ROW_SEL_EXACT 1 /* search using a complete key value */ #define ROW_SEL_EXACT_PREFIX 2 /* search using a key prefix which must match to rows: the prefix may contain an incomplete field (the last field in prefix may be just a prefix of a fixed length column) */ #ifndef UNIV_NONINL #include "row0sel.ic" #endif #endif