mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 15:50:51 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			2376 lines
		
	
	
		
			76 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
			
		
		
	
	
			2376 lines
		
	
	
		
			76 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
| /* Copyright (C) 2000-2006 MySQL AB
 | |
| 
 | |
|    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | |
| 
 | |
| 
 | |
| /* Classes in mysql */
 | |
| 
 | |
| #ifdef USE_PRAGMA_INTERFACE
 | |
| #pragma interface			/* gcc class implementation */
 | |
| #endif
 | |
| 
 | |
| #include "log.h"
 | |
| #include "rpl_tblmap.h"
 | |
| 
 | |
| struct st_relay_log_info;
 | |
| typedef st_relay_log_info RELAY_LOG_INFO;
 | |
| 
 | |
| class Query_log_event;
 | |
| class Load_log_event;
 | |
| class Slave_log_event;
 | |
| class sp_rcontext;
 | |
| class sp_cache;
 | |
| class Lex_input_stream;
 | |
| class Rows_log_event;
 | |
| 
 | |
| enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
 | |
| enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME };
 | |
| enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_UPDATE };
 | |
| enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON,
 | |
| 			    DELAY_KEY_WRITE_ALL };
 | |
| enum enum_check_fields
 | |
| { CHECK_FIELD_IGNORE, CHECK_FIELD_WARN, CHECK_FIELD_ERROR_FOR_NULL };
 | |
| enum enum_mark_columns
 | |
| { MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE};
 | |
| 
 | |
| extern char internal_table_name[2];
 | |
| extern char empty_c_string[1];
 | |
| extern const char **errmesg;
 | |
| 
 | |
| #define TC_LOG_PAGE_SIZE   8192
 | |
| #define TC_LOG_MIN_SIZE    (3*TC_LOG_PAGE_SIZE)
 | |
| 
 | |
| #define TC_HEURISTIC_RECOVER_COMMIT   1
 | |
| #define TC_HEURISTIC_RECOVER_ROLLBACK 2
 | |
| extern uint tc_heuristic_recover;
 | |
| 
 | |
| typedef struct st_user_var_events
 | |
| {
 | |
|   user_var_entry *user_var_event;
 | |
|   char *value;
 | |
|   ulong length;
 | |
|   Item_result type;
 | |
|   uint charset_number;
 | |
| } BINLOG_USER_VAR_EVENT;
 | |
| 
 | |
| #define RP_LOCK_LOG_IS_ALREADY_LOCKED 1
 | |
| #define RP_FORCE_ROTATE               2
 | |
| 
 | |
| typedef struct st_copy_info {
 | |
|   ha_rows records;
 | |
|   ha_rows deleted;
 | |
|   ha_rows updated;
 | |
|   ha_rows copied;
 | |
|   ha_rows error_count;
 | |
|   enum enum_duplicates handle_duplicates;
 | |
|   int escape_char, last_errno;
 | |
|   bool ignore;
 | |
|   /* for INSERT ... UPDATE */
 | |
|   List<Item> *update_fields;
 | |
|   List<Item> *update_values;
 | |
|   /* for VIEW ... WITH CHECK OPTION */
 | |
|   TABLE_LIST *view;
 | |
| } COPY_INFO;
 | |
| 
 | |
| 
 | |
| class key_part_spec :public Sql_alloc {
 | |
| public:
 | |
|   const char *field_name;
 | |
|   uint length;
 | |
|   key_part_spec(const char *name,uint len=0) :field_name(name), length(len) {}
 | |
|   bool operator==(const key_part_spec& other) const;
 | |
|   /**
 | |
|     Construct a copy of this key_part_spec. field_name is copied
 | |
|     by-pointer as it is known to never change. At the same time
 | |
|     'length' may be reset in mysql_prepare_create_table, and this
 | |
|     is why we supply it with a copy.
 | |
| 
 | |
|     @return If out of memory, 0 is returned and an error is set in
 | |
|     THD.
 | |
|   */
 | |
|   key_part_spec *clone(MEM_ROOT *mem_root) const
 | |
|   { return new (mem_root) key_part_spec(*this); }
 | |
| };
 | |
| 
 | |
| 
 | |
| class Alter_drop :public Sql_alloc {
 | |
| public:
 | |
|   enum drop_type {KEY, COLUMN };
 | |
|   const char *name;
 | |
|   enum drop_type type;
 | |
|   Alter_drop(enum drop_type par_type,const char *par_name)
 | |
|     :name(par_name), type(par_type) {}
 | |
|   /**
 | |
|     Used to make a clone of this object for ALTER/CREATE TABLE
 | |
|     @sa comment for key_part_spec::clone
 | |
|   */
 | |
|   Alter_drop *clone(MEM_ROOT *mem_root) const
 | |
|     { return new (mem_root) Alter_drop(*this); }
 | |
| };
 | |
| 
 | |
| 
 | |
| class Alter_column :public Sql_alloc {
 | |
| public:
 | |
|   const char *name;
 | |
|   Item *def;
 | |
|   Alter_column(const char *par_name,Item *literal)
 | |
|     :name(par_name), def(literal) {}
 | |
|   /**
 | |
|     Used to make a clone of this object for ALTER/CREATE TABLE
 | |
|     @sa comment for key_part_spec::clone
 | |
|   */
 | |
|   Alter_column *clone(MEM_ROOT *mem_root) const
 | |
|     { return new (mem_root) Alter_column(*this); }
 | |
| };
 | |
| 
 | |
| 
 | |
| class Key :public Sql_alloc {
 | |
| public:
 | |
|   enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL, FOREIGN_KEY};
 | |
|   enum Keytype type;
 | |
|   KEY_CREATE_INFO key_create_info;
 | |
|   List<key_part_spec> columns;
 | |
|   const char *name;
 | |
|   bool generated;
 | |
| 
 | |
|   Key(enum Keytype type_par, const char *name_arg,
 | |
|       KEY_CREATE_INFO *key_info_arg,
 | |
|       bool generated_arg, List<key_part_spec> &cols)
 | |
|     :type(type_par), key_create_info(*key_info_arg), columns(cols),
 | |
|     name(name_arg), generated(generated_arg)
 | |
|   {}
 | |
|   Key(const Key &rhs, MEM_ROOT *mem_root);
 | |
|   virtual ~Key() {}
 | |
|   /* Equality comparison of keys (ignoring name) */
 | |
|   friend bool foreign_key_prefix(Key *a, Key *b);
 | |
|   /**
 | |
|     Used to make a clone of this object for ALTER/CREATE TABLE
 | |
|     @sa comment for key_part_spec::clone
 | |
|   */
 | |
|   virtual Key *clone(MEM_ROOT *mem_root) const
 | |
|     { return new (mem_root) Key(*this, mem_root); }
 | |
| };
 | |
| 
 | |
| class Table_ident;
 | |
| 
 | |
| class foreign_key: public Key {
 | |
| public:
 | |
|   enum fk_match_opt { FK_MATCH_UNDEF, FK_MATCH_FULL,
 | |
| 		      FK_MATCH_PARTIAL, FK_MATCH_SIMPLE};
 | |
|   enum fk_option { FK_OPTION_UNDEF, FK_OPTION_RESTRICT, FK_OPTION_CASCADE,
 | |
| 		   FK_OPTION_SET_NULL, FK_OPTION_NO_ACTION, FK_OPTION_DEFAULT};
 | |
| 
 | |
|   Table_ident *ref_table;
 | |
|   List<key_part_spec> ref_columns;
 | |
|   uint delete_opt, update_opt, match_opt;
 | |
|   foreign_key(const char *name_arg, List<key_part_spec> &cols,
 | |
| 	      Table_ident *table,   List<key_part_spec> &ref_cols,
 | |
| 	      uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg)
 | |
|     :Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols),
 | |
|     ref_table(table), ref_columns(cols),
 | |
|     delete_opt(delete_opt_arg), update_opt(update_opt_arg),
 | |
|     match_opt(match_opt_arg)
 | |
|   {}
 | |
|   foreign_key(const foreign_key &rhs, MEM_ROOT *mem_root);
 | |
|   /**
 | |
|     Used to make a clone of this object for ALTER/CREATE TABLE
 | |
|     @sa comment for key_part_spec::clone
 | |
|   */
 | |
|   virtual Key *clone(MEM_ROOT *mem_root) const
 | |
|   { return new (mem_root) foreign_key(*this, mem_root); }
 | |
| };
 | |
| 
 | |
| typedef struct st_mysql_lock
 | |
| {
 | |
|   TABLE **table;
 | |
|   uint table_count,lock_count;
 | |
|   THR_LOCK_DATA **locks;
 | |
| } MYSQL_LOCK;
 | |
| 
 | |
| 
 | |
| class LEX_COLUMN : public Sql_alloc
 | |
| {
 | |
| public:
 | |
|   String column;
 | |
|   uint rights;
 | |
|   LEX_COLUMN (const String& x,const  uint& y ): column (x),rights (y) {}
 | |
| };
 | |
| 
 | |
| #include "sql_lex.h"				/* Must be here */
 | |
| 
 | |
| class Delayed_insert;
 | |
| class select_result;
 | |
| class Time_zone;
 | |
| 
 | |
| #define THD_SENTRY_MAGIC 0xfeedd1ff
 | |
| #define THD_SENTRY_GONE  0xdeadbeef
 | |
| 
 | |
| #define THD_CHECK_SENTRY(thd) DBUG_ASSERT(thd->dbug_sentry == THD_SENTRY_MAGIC)
 | |
| 
 | |
| struct system_variables
 | |
| {
 | |
|   /*
 | |
|     How dynamically allocated system variables are handled:
 | |
|     
 | |
|     The global_system_variables and max_system_variables are "authoritative"
 | |
|     They both should have the same 'version' and 'size'.
 | |
|     When attempting to access a dynamic variable, if the session version
 | |
|     is out of date, then the session version is updated and realloced if
 | |
|     neccessary and bytes copied from global to make up for missing data.
 | |
|   */ 
 | |
|   ulong dynamic_variables_version;
 | |
|   char* dynamic_variables_ptr;
 | |
|   uint dynamic_variables_head;  /* largest valid variable offset */
 | |
|   uint dynamic_variables_size;  /* how many bytes are in use */
 | |
|   
 | |
|   ulonglong myisam_max_extra_sort_file_size;
 | |
|   ulonglong myisam_max_sort_file_size;
 | |
|   ulonglong max_heap_table_size;
 | |
|   ulonglong tmp_table_size;
 | |
|   ha_rows select_limit;
 | |
|   ha_rows max_join_size;
 | |
|   ulong auto_increment_increment, auto_increment_offset;
 | |
|   ulong bulk_insert_buff_size;
 | |
|   ulong join_buff_size;
 | |
|   ulong long_query_time;
 | |
|   ulong max_allowed_packet;
 | |
|   ulong max_error_count;
 | |
|   ulong max_length_for_sort_data;
 | |
|   ulong max_sort_length;
 | |
|   ulong max_tmp_tables;
 | |
|   ulong max_insert_delayed_threads;
 | |
|   ulong multi_range_count;
 | |
|   ulong myisam_repair_threads;
 | |
|   ulong myisam_sort_buff_size;
 | |
|   ulong myisam_stats_method;
 | |
|   ulong net_buffer_length;
 | |
|   ulong net_interactive_timeout;
 | |
|   ulong net_read_timeout;
 | |
|   ulong net_retry_count;
 | |
|   ulong net_wait_timeout;
 | |
|   ulong net_write_timeout;
 | |
|   ulong optimizer_prune_level;
 | |
|   ulong optimizer_search_depth;
 | |
|   ulong preload_buff_size;
 | |
|   ulong query_cache_type;
 | |
|   ulong read_buff_size;
 | |
|   ulong read_rnd_buff_size;
 | |
|   ulong div_precincrement;
 | |
|   ulong sortbuff_size;
 | |
|   ulong thread_handling;
 | |
|   ulong tx_isolation;
 | |
|   ulong completion_type;
 | |
|   /* Determines which non-standard SQL behaviour should be enabled */
 | |
|   ulong sql_mode;
 | |
|   ulong max_sp_recursion_depth;
 | |
|   /* check of key presence in updatable view */
 | |
|   ulong updatable_views_with_limit;
 | |
|   ulong default_week_format;
 | |
|   ulong max_seeks_for_key;
 | |
|   ulong range_alloc_block_size;
 | |
|   ulong query_alloc_block_size;
 | |
|   ulong query_prealloc_size;
 | |
|   ulong trans_alloc_block_size;
 | |
|   ulong trans_prealloc_size;
 | |
|   ulong log_warnings;
 | |
|   ulong group_concat_max_len;
 | |
|   ulong ndb_autoincrement_prefetch_sz;
 | |
|   ulong ndb_index_stat_cache_entries;
 | |
|   ulong ndb_index_stat_update_freq;
 | |
|   ulong binlog_format; // binlog format for this thd (see enum_binlog_format)
 | |
|   /*
 | |
|     In slave thread we need to know in behalf of which
 | |
|     thread the query is being run to replicate temp tables properly
 | |
|   */
 | |
|   my_thread_id pseudo_thread_id;
 | |
| 
 | |
|   my_bool low_priority_updates;
 | |
|   my_bool new_mode;
 | |
|   /* 
 | |
|     compatibility option:
 | |
|       - index usage hints (USE INDEX without a FOR clause) behave as in 5.0 
 | |
|   */
 | |
|   my_bool old_mode;
 | |
|   my_bool query_cache_wlock_invalidate;
 | |
|   my_bool engine_condition_pushdown;
 | |
|   my_bool ndb_force_send;
 | |
|   my_bool ndb_use_copying_alter_table;
 | |
|   my_bool ndb_use_exact_count;
 | |
|   my_bool ndb_use_transactions;
 | |
|   my_bool ndb_index_stat_enable;
 | |
| 
 | |
|   my_bool old_alter_table;
 | |
|   my_bool old_passwords;
 | |
| 
 | |
|   plugin_ref table_plugin;
 | |
| 
 | |
|   /* Only charset part of these variables is sensible */
 | |
|   CHARSET_INFO  *character_set_filesystem;
 | |
|   CHARSET_INFO  *character_set_client;
 | |
|   CHARSET_INFO  *character_set_results;
 | |
| 
 | |
|   /* Both charset and collation parts of these variables are important */
 | |
|   CHARSET_INFO	*collation_server;
 | |
|   CHARSET_INFO	*collation_database;
 | |
|   CHARSET_INFO  *collation_connection;
 | |
| 
 | |
|   /* Locale Support */
 | |
|   MY_LOCALE *lc_time_names;
 | |
| 
 | |
|   Time_zone *time_zone;
 | |
| 
 | |
|   /* DATE, DATETIME and MYSQL_TIME formats */
 | |
|   DATE_TIME_FORMAT *date_format;
 | |
|   DATE_TIME_FORMAT *datetime_format;
 | |
|   DATE_TIME_FORMAT *time_format;
 | |
|   my_bool sysdate_is_now;
 | |
| 
 | |
| };
 | |
| 
 | |
| 
 | |
| /* per thread status variables */
 | |
| 
 | |
| typedef struct system_status_var
 | |
| {
 | |
|   ulong bytes_received;
 | |
|   ulong bytes_sent;
 | |
|   ulong com_other;
 | |
|   ulong com_stat[(uint) SQLCOM_END];
 | |
|   ulong created_tmp_disk_tables;
 | |
|   ulong created_tmp_tables;
 | |
|   ulong ha_commit_count;
 | |
|   ulong ha_delete_count;
 | |
|   ulong ha_read_first_count;
 | |
|   ulong ha_read_last_count;
 | |
|   ulong ha_read_key_count;
 | |
|   ulong ha_read_next_count;
 | |
|   ulong ha_read_prev_count;
 | |
|   ulong ha_read_rnd_count;
 | |
|   ulong ha_read_rnd_next_count;
 | |
|   ulong ha_rollback_count;
 | |
|   ulong ha_update_count;
 | |
|   ulong ha_write_count;
 | |
|   ulong ha_prepare_count;
 | |
|   ulong ha_discover_count;
 | |
|   ulong ha_savepoint_count;
 | |
|   ulong ha_savepoint_rollback_count;
 | |
| 
 | |
|   /* KEY_CACHE parts. These are copies of the original */
 | |
|   ulong key_blocks_changed;
 | |
|   ulong key_blocks_used;
 | |
|   ulong key_cache_r_requests;
 | |
|   ulong key_cache_read;
 | |
|   ulong key_cache_w_requests;
 | |
|   ulong key_cache_write;
 | |
|   /* END OF KEY_CACHE parts */
 | |
| 
 | |
|   ulong net_big_packet_count;
 | |
|   ulong opened_tables;
 | |
|   ulong opened_shares;
 | |
|   ulong select_full_join_count;
 | |
|   ulong select_full_range_join_count;
 | |
|   ulong select_range_count;
 | |
|   ulong select_range_check_count;
 | |
|   ulong select_scan_count;
 | |
|   ulong long_query_count;
 | |
|   ulong filesort_merge_passes;
 | |
|   ulong filesort_range_count;
 | |
|   ulong filesort_rows;
 | |
|   ulong filesort_scan_count;
 | |
|   /* Prepared statements and binary protocol */
 | |
|   ulong com_stmt_prepare;
 | |
|   ulong com_stmt_execute;
 | |
|   ulong com_stmt_send_long_data;
 | |
|   ulong com_stmt_fetch;
 | |
|   ulong com_stmt_reset;
 | |
|   ulong com_stmt_close;
 | |
| 
 | |
|   /*
 | |
|     Status variables which it does not make sense to add to
 | |
|     global status variable counter
 | |
|   */
 | |
|   double last_query_cost;
 | |
| } STATUS_VAR;
 | |
| 
 | |
| /*
 | |
|   This is used for 'SHOW STATUS'. It must be updated to the last ulong
 | |
|   variable in system_status_var which is makes sens to add to the global
 | |
|   counter
 | |
| */
 | |
| 
 | |
| #define last_system_status_var com_stmt_close
 | |
| 
 | |
| #ifdef MYSQL_SERVER
 | |
| 
 | |
| void free_tmp_table(THD *thd, TABLE *entry);
 | |
| 
 | |
| 
 | |
| /* The following macro is to make init of Query_arena simpler */
 | |
| #ifndef DBUG_OFF
 | |
| #define INIT_ARENA_DBUG_INFO is_backup_arena= 0
 | |
| #else
 | |
| #define INIT_ARENA_DBUG_INFO
 | |
| #endif
 | |
| 
 | |
| class Query_arena
 | |
| {
 | |
| public:
 | |
|   /*
 | |
|     List of items created in the parser for this query. Every item puts
 | |
|     itself to the list on creation (see Item::Item() for details))
 | |
|   */
 | |
|   Item *free_list;
 | |
|   MEM_ROOT *mem_root;                   // Pointer to current memroot
 | |
| #ifndef DBUG_OFF
 | |
|   bool is_backup_arena; /* True if this arena is used for backup. */
 | |
| #endif
 | |
|   enum enum_state
 | |
|   {
 | |
|     INITIALIZED= 0, INITIALIZED_FOR_SP= 1, PREPARED= 2,
 | |
|     CONVENTIONAL_EXECUTION= 3, EXECUTED= 4, ERROR= -1
 | |
|   };
 | |
| 
 | |
|   enum_state state;
 | |
| 
 | |
|   /* We build without RTTI, so dynamic_cast can't be used. */
 | |
|   enum Type
 | |
|   {
 | |
|     STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE
 | |
|   };
 | |
| 
 | |
|   Query_arena(MEM_ROOT *mem_root_arg, enum enum_state state_arg) :
 | |
|     free_list(0), mem_root(mem_root_arg), state(state_arg)
 | |
|   { INIT_ARENA_DBUG_INFO; }
 | |
|   /*
 | |
|     This constructor is used only when Query_arena is created as
 | |
|     backup storage for another instance of Query_arena.
 | |
|   */
 | |
|   Query_arena() { INIT_ARENA_DBUG_INFO; }
 | |
| 
 | |
|   virtual Type type() const;
 | |
|   virtual ~Query_arena() {};
 | |
| 
 | |
|   inline bool is_stmt_prepare() const { return state == INITIALIZED; }
 | |
|   inline bool is_first_sp_execute() const
 | |
|   { return state == INITIALIZED_FOR_SP; }
 | |
|   inline bool is_stmt_prepare_or_first_sp_execute() const
 | |
|   { return (int)state < (int)PREPARED; }
 | |
|   inline bool is_first_stmt_execute() const { return state == PREPARED; }
 | |
|   inline bool is_stmt_execute() const
 | |
|   { return state == PREPARED || state == EXECUTED; }
 | |
|   inline bool is_conventional() const
 | |
|   { return state == CONVENTIONAL_EXECUTION; }
 | |
| 
 | |
|   inline void* alloc(size_t size) { return alloc_root(mem_root,size); }
 | |
|   inline void* calloc(size_t size)
 | |
|   {
 | |
|     void *ptr;
 | |
|     if ((ptr=alloc_root(mem_root,size)))
 | |
|       bzero(ptr, size);
 | |
|     return ptr;
 | |
|   }
 | |
|   inline char *strdup(const char *str)
 | |
|   { return strdup_root(mem_root,str); }
 | |
|   inline char *strmake(const char *str, size_t size)
 | |
|   { return strmake_root(mem_root,str,size); }
 | |
|   inline bool LEX_STRING_make(LEX_STRING *lex_str, const char *str,
 | |
|                               size_t size)
 | |
|   {
 | |
|     return ((lex_str->str= 
 | |
|              strmake_root(mem_root, str, (lex_str->length= size)))) == 0;
 | |
|   }
 | |
| 
 | |
|   inline void *memdup(const void *str, size_t size)
 | |
|   { return memdup_root(mem_root,str,size); }
 | |
|   inline void *memdup_w_gap(const void *str, size_t size, uint gap)
 | |
|   {
 | |
|     void *ptr;
 | |
|     if ((ptr= alloc_root(mem_root,size+gap)))
 | |
|       memcpy(ptr,str,size);
 | |
|     return ptr;
 | |
|   }
 | |
| 
 | |
|   void set_query_arena(Query_arena *set);
 | |
| 
 | |
|   void free_items();
 | |
|   /* Close the active state associated with execution of this statement */
 | |
|   virtual void cleanup_stmt();
 | |
| };
 | |
| 
 | |
| 
 | |
| class Server_side_cursor;
 | |
| 
 | |
| /**
 | |
|   @class Statement
 | |
|   @brief State of a single command executed against this connection.
 | |
| 
 | |
|   One connection can contain a lot of simultaneously running statements,
 | |
|   some of which could be:
 | |
|    - prepared, that is, contain placeholders,
 | |
|    - opened as cursors. We maintain 1 to 1 relationship between
 | |
|      statement and cursor - if user wants to create another cursor for his
 | |
|      query, we create another statement for it. 
 | |
|   To perform some action with statement we reset THD part to the state  of
 | |
|   that statement, do the action, and then save back modified state from THD
 | |
|   to the statement. It will be changed in near future, and Statement will
 | |
|   be used explicitly.
 | |
| */
 | |
| 
 | |
| class Statement: public ilink, public Query_arena
 | |
| {
 | |
|   Statement(const Statement &rhs);              /* not implemented: */
 | |
|   Statement &operator=(const Statement &rhs);   /* non-copyable */
 | |
| public:
 | |
|   /*
 | |
|     Uniquely identifies each statement object in thread scope; change during
 | |
|     statement lifetime. FIXME: must be const
 | |
|   */
 | |
|    ulong id;
 | |
| 
 | |
|   /*
 | |
|     MARK_COLUMNS_NONE:  Means mark_used_colums is not set and no indicator to
 | |
|                         handler of fields used is set
 | |
|     MARK_COLUMNS_READ:  Means a bit in read set is set to inform handler
 | |
| 	                that the field is to be read. If field list contains
 | |
|                         duplicates, then thd->dup_field is set to point
 | |
|                         to the last found duplicate.
 | |
|     MARK_COLUMNS_WRITE: Means a bit is set in write set to inform handler
 | |
| 			that it needs to update this field in write_row
 | |
|                         and update_row.
 | |
|   */
 | |
|   enum enum_mark_columns mark_used_columns;
 | |
| 
 | |
|   LEX_STRING name; /* name for named prepared statements */
 | |
|   LEX *lex;                                     // parse tree descriptor
 | |
|   /*
 | |
|     Points to the query associated with this statement. It's const, but
 | |
|     we need to declare it char * because all table handlers are written
 | |
|     in C and need to point to it.
 | |
| 
 | |
|     Note that (A) if we set query = NULL, we must at the same time set
 | |
|     query_length = 0, and protect the whole operation with the
 | |
|     LOCK_thread_count mutex. And (B) we are ONLY allowed to set query to a
 | |
|     non-NULL value if its previous value is NULL. We do not need to protect
 | |
|     operation (B) with any mutex. To avoid crashes in races, if we do not
 | |
|     know that thd->query cannot change at the moment, one should print
 | |
|     thd->query like this:
 | |
|       (1) reserve the LOCK_thread_count mutex;
 | |
|       (2) check if thd->query is NULL;
 | |
|       (3) if not NULL, then print at most thd->query_length characters from
 | |
|       it. We will see the query_length field as either 0, or the right value
 | |
|       for it.
 | |
|     Assuming that the write and read of an n-bit memory field in an n-bit
 | |
|     computer is atomic, we can avoid races in the above way. 
 | |
|     This printing is needed at least in SHOW PROCESSLIST and SHOW INNODB
 | |
|     STATUS.
 | |
|   */
 | |
|   char *query;
 | |
|   uint32 query_length;                          // current query length
 | |
|   Server_side_cursor *cursor;
 | |
| 
 | |
| public:
 | |
| 
 | |
|   /* This constructor is called for backup statements */
 | |
|   Statement() {}
 | |
| 
 | |
|   Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg,
 | |
|             enum enum_state state_arg, ulong id_arg);
 | |
|   virtual ~Statement();
 | |
| 
 | |
|   /* Assign execution context (note: not all members) of given stmt to self */
 | |
|   void set_statement(Statement *stmt);
 | |
|   void set_n_backup_statement(Statement *stmt, Statement *backup);
 | |
|   void restore_backup_statement(Statement *stmt, Statement *backup);
 | |
|   /* return class type */
 | |
|   virtual Type type() const;
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Container for all statements created/used in a connection.
 | |
|   Statements in Statement_map have unique Statement::id (guaranteed by id
 | |
|   assignment in Statement::Statement)
 | |
|   Non-empty statement names are unique too: attempt to insert a new statement
 | |
|   with duplicate name causes older statement to be deleted
 | |
| 
 | |
|   Statements are auto-deleted when they are removed from the map and when the
 | |
|   map is deleted.
 | |
| */
 | |
| 
 | |
| class Statement_map
 | |
| {
 | |
| public:
 | |
|   Statement_map();
 | |
| 
 | |
|   int insert(THD *thd, Statement *statement);
 | |
| 
 | |
|   Statement *find_by_name(LEX_STRING *name)
 | |
|   {
 | |
|     Statement *stmt;
 | |
|     stmt= (Statement*)hash_search(&names_hash, (uchar*)name->str,
 | |
|                                   name->length);
 | |
|     return stmt;
 | |
|   }
 | |
| 
 | |
|   Statement *find(ulong id)
 | |
|   {
 | |
|     if (last_found_statement == 0 || id != last_found_statement->id)
 | |
|     {
 | |
|       Statement *stmt;
 | |
|       stmt= (Statement *) hash_search(&st_hash, (uchar *) &id, sizeof(id));
 | |
|       if (stmt && stmt->name.str)
 | |
|         return NULL;
 | |
|       last_found_statement= stmt;
 | |
|     }
 | |
|     return last_found_statement;
 | |
|   }
 | |
|   /*
 | |
|     Close all cursors of this connection that use tables of a storage
 | |
|     engine that has transaction-specific state and therefore can not
 | |
|     survive COMMIT or ROLLBACK. Currently all but MyISAM cursors are closed.
 | |
|   */
 | |
|   void close_transient_cursors();
 | |
|   void erase(Statement *statement);
 | |
|   /* Erase all statements (calls Statement destructor) */
 | |
|   void reset();
 | |
|   ~Statement_map();
 | |
| private:
 | |
|   HASH st_hash;
 | |
|   HASH names_hash;
 | |
|   I_List<Statement> transient_cursor_list;
 | |
|   Statement *last_found_statement;
 | |
| };
 | |
| 
 | |
| struct st_savepoint {
 | |
|   struct st_savepoint *prev;
 | |
|   char                *name;
 | |
|   uint                 length, nht;
 | |
| };
 | |
| 
 | |
| enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED};
 | |
| extern const char *xa_state_names[];
 | |
| 
 | |
| typedef struct st_xid_state {
 | |
|   /* For now, this is only used to catch duplicated external xids */
 | |
|   XID  xid;                           // transaction identifier
 | |
|   enum xa_states xa_state;            // used by external XA only
 | |
|   bool in_thd;
 | |
| } XID_STATE;
 | |
| 
 | |
| extern pthread_mutex_t LOCK_xid_cache;
 | |
| extern HASH xid_cache;
 | |
| bool xid_cache_init(void);
 | |
| void xid_cache_free(void);
 | |
| XID_STATE *xid_cache_search(XID *xid);
 | |
| bool xid_cache_insert(XID *xid, enum xa_states xa_state);
 | |
| bool xid_cache_insert(XID_STATE *xid_state);
 | |
| void xid_cache_delete(XID_STATE *xid_state);
 | |
| 
 | |
| /**
 | |
|   @class Security_context
 | |
|   @brief A set of THD members describing the current authenticated user.
 | |
| */
 | |
| 
 | |
| class Security_context {
 | |
| public:
 | |
|   Security_context() {}                       /* Remove gcc warning */
 | |
|   /*
 | |
|     host - host of the client
 | |
|     user - user of the client, set to NULL until the user has been read from
 | |
|     the connection
 | |
|     priv_user - The user privilege we are using. May be "" for anonymous user.
 | |
|     ip - client IP
 | |
|   */
 | |
|   char   *host, *user, *priv_user, *ip;
 | |
|   /* The host privilege we are using */
 | |
|   char   priv_host[MAX_HOSTNAME];
 | |
|   /* points to host if host is available, otherwise points to ip */
 | |
|   const char *host_or_ip;
 | |
|   ulong master_access;                 /* Global privileges from mysql.user */
 | |
|   ulong db_access;                     /* Privileges for current db */
 | |
| 
 | |
|   void init();
 | |
|   void destroy();
 | |
|   void skip_grants();
 | |
|   inline char *priv_host_name()
 | |
|   {
 | |
|     return (*priv_host ? priv_host : (char *)"%");
 | |
|   }
 | |
|   
 | |
|   bool set_user(char *user_arg);
 | |
| 
 | |
| #ifndef NO_EMBEDDED_ACCESS_CHECKS
 | |
|   bool
 | |
|   change_security_context(THD *thd,
 | |
|                           LEX_STRING *definer_user,
 | |
|                           LEX_STRING *definer_host,
 | |
|                           LEX_STRING *db,
 | |
|                           Security_context **backup);
 | |
| 
 | |
|   void
 | |
|   restore_security_context(THD *thd, Security_context *backup);
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   A registry for item tree transformations performed during
 | |
|   query optimization. We register only those changes which require
 | |
|   a rollback to re-execute a prepared statement or stored procedure
 | |
|   yet another time.
 | |
| */
 | |
| 
 | |
| struct Item_change_record;
 | |
| typedef I_List<Item_change_record> Item_change_list;
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Type of prelocked mode.
 | |
|   See comment for THD::prelocked_mode for complete description.
 | |
| */
 | |
| 
 | |
| enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
 | |
|                           PRELOCKED_UNDER_LOCK_TABLES= 2};
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Class that holds information about tables which were opened and locked
 | |
|   by the thread. It is also used to save/restore this information in
 | |
|   push_open_tables_state()/pop_open_tables_state().
 | |
| */
 | |
| 
 | |
| class Open_tables_state
 | |
| {
 | |
| public:
 | |
|   /*
 | |
|     open_tables - list of regular tables in use by this thread
 | |
|     temporary_tables - list of temp tables in use by this thread
 | |
|     handler_tables - list of tables that were opened with HANDLER OPEN
 | |
|      and are still in use by this thread
 | |
|   */
 | |
|   TABLE *open_tables, *temporary_tables, *handler_tables, *derived_tables;
 | |
|   /*
 | |
|     During a MySQL session, one can lock tables in two modes: automatic
 | |
|     or manual. In automatic mode all necessary tables are locked just before
 | |
|     statement execution, and all acquired locks are stored in 'lock'
 | |
|     member. Unlocking takes place automatically as well, when the
 | |
|     statement ends.
 | |
|     Manual mode comes into play when a user issues a 'LOCK TABLES'
 | |
|     statement. In this mode the user can only use the locked tables.
 | |
|     Trying to use any other tables will give an error. The locked tables are
 | |
|     stored in 'locked_tables' member.  Manual locking is described in
 | |
|     the 'LOCK_TABLES' chapter of the MySQL manual.
 | |
|     See also lock_tables() for details.
 | |
|   */
 | |
|   MYSQL_LOCK *lock;
 | |
|   /*
 | |
|     Tables that were locked with explicit or implicit LOCK TABLES.
 | |
|     (Implicit LOCK TABLES happens when we are prelocking tables for
 | |
|      execution of statement which uses stored routines. See description
 | |
|      THD::prelocked_mode for more info.)
 | |
|   */
 | |
|   MYSQL_LOCK *locked_tables;
 | |
| 
 | |
|   /*
 | |
|     CREATE-SELECT keeps an extra lock for the table being
 | |
|     created. This field is used to keep the extra lock available for
 | |
|     lower level routines, which would otherwise miss that lock.
 | |
|    */
 | |
|   MYSQL_LOCK *extra_lock;
 | |
| 
 | |
|   /*
 | |
|     prelocked_mode_type enum and prelocked_mode member are used for
 | |
|     indicating whenever "prelocked mode" is on, and what type of
 | |
|     "prelocked mode" is it.
 | |
| 
 | |
|     Prelocked mode is used for execution of queries which explicitly
 | |
|     or implicitly (via views or triggers) use functions, thus may need
 | |
|     some additional tables (mentioned in query table list) for their
 | |
|     execution.
 | |
| 
 | |
|     First open_tables() call for such query will analyse all functions
 | |
|     used by it and add all additional tables to table its list. It will
 | |
|     also mark this query as requiring prelocking. After that lock_tables()
 | |
|     will issue implicit LOCK TABLES for the whole table list and change
 | |
|     thd::prelocked_mode to non-0. All queries called in functions invoked
 | |
|     by the main query will use prelocked tables. Non-0 prelocked_mode
 | |
|     will also surpress mentioned analysys in those queries thus saving
 | |
|     cycles. Prelocked mode will be turned off once close_thread_tables()
 | |
|     for the main query will be called.
 | |
| 
 | |
|     Note: Since not all "tables" present in table list are really locked
 | |
|     thd::prelocked_mode does not imply thd::locked_tables.
 | |
|   */
 | |
|   prelocked_mode_type prelocked_mode;
 | |
|   ulong	version;
 | |
|   uint current_tablenr;
 | |
| 
 | |
|   enum enum_flags {
 | |
|     BACKUPS_AVAIL = (1U << 0)     /* There are backups available */
 | |
|   };
 | |
| 
 | |
|   /*
 | |
|     Flags with information about the open tables state.
 | |
|   */
 | |
|   uint state_flags;
 | |
| 
 | |
|   /*
 | |
|     This constructor serves for creation of Open_tables_state instances
 | |
|     which are used as backup storage.
 | |
|   */
 | |
|   Open_tables_state() : state_flags(0U) { }
 | |
| 
 | |
|   Open_tables_state(ulong version_arg);
 | |
| 
 | |
|   void set_open_tables_state(Open_tables_state *state)
 | |
|   {
 | |
|     *this= *state;
 | |
|   }
 | |
| 
 | |
|   void reset_open_tables_state()
 | |
|   {
 | |
|     open_tables= temporary_tables= handler_tables= derived_tables= 0;
 | |
|     extra_lock= lock= locked_tables= 0;
 | |
|     prelocked_mode= NON_PRELOCKED;
 | |
|     state_flags= 0U;
 | |
|   }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   @class Sub_statement_state
 | |
|   @brief Used to save context when executing a function or trigger
 | |
| */
 | |
| 
 | |
| /* Defines used for Sub_statement_state::in_sub_stmt */
 | |
| 
 | |
| #define SUB_STMT_TRIGGER 1
 | |
| #define SUB_STMT_FUNCTION 2
 | |
| 
 | |
| 
 | |
| class Sub_statement_state
 | |
| {
 | |
| public:
 | |
|   ulonglong options;
 | |
|   ulonglong first_successful_insert_id_in_prev_stmt;
 | |
|   ulonglong first_successful_insert_id_in_cur_stmt, insert_id_for_cur_row;
 | |
|   Discrete_interval auto_inc_interval_for_cur_row;
 | |
|   ulonglong limit_found_rows;
 | |
|   ha_rows    cuted_fields, sent_row_count, examined_row_count;
 | |
|   ulong client_capabilities;
 | |
|   uint in_sub_stmt;
 | |
|   bool enable_slow_log;
 | |
|   bool last_insert_id_used;
 | |
|   my_bool no_send_ok;
 | |
|   SAVEPOINT *savepoints;
 | |
| };
 | |
| 
 | |
| 
 | |
| /* Flags for the THD::system_thread variable */
 | |
| enum enum_thread_type
 | |
| {
 | |
|   NON_SYSTEM_THREAD= 0,
 | |
|   SYSTEM_THREAD_DELAYED_INSERT= 1,
 | |
|   SYSTEM_THREAD_SLAVE_IO= 2,
 | |
|   SYSTEM_THREAD_SLAVE_SQL= 4,
 | |
|   SYSTEM_THREAD_NDBCLUSTER_BINLOG= 8,
 | |
|   SYSTEM_THREAD_EVENT_SCHEDULER= 16,
 | |
|   SYSTEM_THREAD_EVENT_WORKER= 32
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This class represents the interface for internal error handlers.
 | |
|   Internal error handlers are exception handlers used by the server
 | |
|   implementation.
 | |
| */
 | |
| class Internal_error_handler
 | |
| {
 | |
| protected:
 | |
|   Internal_error_handler() {}
 | |
|   virtual ~Internal_error_handler() {}
 | |
| 
 | |
| public:
 | |
|   /**
 | |
|     Handle an error condition.
 | |
|     This method can be implemented by a subclass to achieve any of the
 | |
|     following:
 | |
|     - mask an error internally, prevent exposing it to the user,
 | |
|     - mask an error and throw another one instead.
 | |
|     When this method returns true, the error condition is considered
 | |
|     'handled', and will not be propagated to upper layers.
 | |
|     It is the responsability of the code installing an internal handler
 | |
|     to then check for trapped conditions, and implement logic to recover
 | |
|     from the anticipated conditions trapped during runtime.
 | |
| 
 | |
|     This mechanism is similar to C++ try/throw/catch:
 | |
|     - 'try' correspond to <code>THD::push_internal_handler()</code>,
 | |
|     - 'throw' correspond to <code>my_error()</code>,
 | |
|     which invokes <code>my_message_sql()</code>,
 | |
|     - 'catch' correspond to checking how/if an internal handler was invoked,
 | |
|     before removing it from the exception stack with
 | |
|     <code>THD::pop_internal_handler()</code>.
 | |
| 
 | |
|     @param sql_errno the error number
 | |
|     @param level the error level
 | |
|     @param thd the calling thread
 | |
|     @return true if the error is handled
 | |
|   */
 | |
|   virtual bool handle_error(uint sql_errno,
 | |
|                             MYSQL_ERROR::enum_warning_level level,
 | |
|                             THD *thd) = 0;
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   @class THD
 | |
|   For each client connection we create a separate thread with THD serving as
 | |
|   a thread/connection descriptor
 | |
| */
 | |
| 
 | |
| class THD :public Statement,
 | |
|            public Open_tables_state
 | |
| {
 | |
| public:
 | |
|   /* Used to execute base64 coded binlog events in MySQL server */
 | |
|   RELAY_LOG_INFO* rli_fake;
 | |
| 
 | |
|   /*
 | |
|     Constant for THD::where initialization in the beginning of every query.
 | |
| 
 | |
|     It's needed because we do not save/restore THD::where normally during
 | |
|     primary (non subselect) query execution.
 | |
|   */
 | |
|   static const char * const DEFAULT_WHERE;
 | |
| 
 | |
| #ifdef EMBEDDED_LIBRARY
 | |
|   struct st_mysql  *mysql;
 | |
|   unsigned long	 client_stmt_id;
 | |
|   unsigned long  client_param_count;
 | |
|   struct st_mysql_bind *client_params;
 | |
|   char *extra_data;
 | |
|   ulong extra_length;
 | |
|   struct st_mysql_data *cur_data;
 | |
|   struct st_mysql_data *first_data;
 | |
|   struct st_mysql_data **data_tail;
 | |
|   void clear_data_list();
 | |
|   struct st_mysql_data *alloc_new_dataset();
 | |
|   /*
 | |
|     In embedded server it points to the statement that is processed
 | |
|     in the current query. We store some results directly in statement
 | |
|     fields then.
 | |
|   */
 | |
|   struct st_mysql_stmt *current_stmt;
 | |
| #endif
 | |
|   NET	  net;				// client connection descriptor
 | |
|   MEM_ROOT warn_root;			// For warnings and errors
 | |
|   Protocol *protocol;			// Current protocol
 | |
|   Protocol_text   protocol_text;	// Normal protocol
 | |
|   Protocol_binary protocol_binary;	// Binary protocol
 | |
|   HASH    user_vars;			// hash for user variables
 | |
|   String  packet;			// dynamic buffer for network I/O
 | |
|   String  convert_buffer;               // buffer for charset conversions
 | |
|   struct  sockaddr_in remote;		// client socket address
 | |
|   struct  rand_struct rand;		// used for authentication
 | |
|   struct  system_variables variables;	// Changeable local variables
 | |
|   struct  system_status_var status_var; // Per thread statistic vars
 | |
|   struct  system_status_var *initial_status_var; /* used by show status */
 | |
|   THR_LOCK_INFO lock_info;              // Locking info of this thread
 | |
|   THR_LOCK_OWNER main_lock_id;          // To use for conventional queries
 | |
|   THR_LOCK_OWNER *lock_id;              // If not main_lock_id, points to
 | |
|                                         // the lock_id of a cursor.
 | |
|   pthread_mutex_t LOCK_delete;		// Locked before thd is deleted
 | |
|   /* all prepared statements and cursors of this connection */
 | |
|   Statement_map stmt_map;
 | |
|   /*
 | |
|     A pointer to the stack frame of handle_one_connection(),
 | |
|     which is called first in the thread for handling a client
 | |
|   */
 | |
|   char	  *thread_stack;
 | |
| 
 | |
|   /*
 | |
|     db - currently selected database
 | |
|     catalog - currently selected catalog
 | |
|     WARNING: some members of THD (currently 'db', 'catalog' and 'query')  are
 | |
|     set and alloced by the slave SQL thread (for the THD of that thread); that
 | |
|     thread is (and must remain, for now) the only responsible for freeing these
 | |
|     3 members. If you add members here, and you add code to set them in
 | |
|     replication, don't forget to free_them_and_set_them_to_0 in replication
 | |
|     properly. For details see the 'err:' label of the handle_slave_sql()
 | |
|     in sql/slave.cc.
 | |
|    */
 | |
|   char   *db, *catalog;
 | |
|   Security_context main_security_ctx;
 | |
|   Security_context *security_ctx;
 | |
| 
 | |
|   /* remote (peer) port */
 | |
|   uint16 peer_port;
 | |
|   /*
 | |
|     Points to info-string that we show in SHOW PROCESSLIST
 | |
|     You are supposed to update thd->proc_info only if you have coded
 | |
|     a time-consuming piece that MySQL can get stuck in for a long time.
 | |
|   */
 | |
|   const char *proc_info;
 | |
| 
 | |
|   ulong client_capabilities;		/* What the client supports */
 | |
|   ulong max_client_packet_length;
 | |
| 
 | |
|   HASH		handler_tables_hash;
 | |
|   /*
 | |
|     One thread can hold up to one named user-level lock. This variable
 | |
|     points to a lock object if the lock is present. See item_func.cc and
 | |
|     chapter 'Miscellaneous functions', for functions GET_LOCK, RELEASE_LOCK. 
 | |
|   */
 | |
|   User_level_lock *ull;
 | |
| #ifndef DBUG_OFF
 | |
|   uint dbug_sentry; // watch out for memory corruption
 | |
| #endif
 | |
|   struct st_my_thread_var *mysys_var;
 | |
|   /*
 | |
|     Type of current query: COM_STMT_PREPARE, COM_QUERY, etc. Set from
 | |
|     first byte of the packet in do_command()
 | |
|   */
 | |
|   enum enum_server_command command;
 | |
|   uint32     server_id;
 | |
|   uint32     file_id;			// for LOAD DATA INFILE
 | |
|   /*
 | |
|     Used in error messages to tell user in what part of MySQL we found an
 | |
|     error. E. g. when where= "having clause", if fix_fields() fails, user
 | |
|     will know that the error was in having clause.
 | |
|   */
 | |
|   const char *where;
 | |
|   time_t     start_time,time_after_lock,user_time;
 | |
|   time_t     connect_time,thr_create_time; // track down slow pthread_create
 | |
|   thr_lock_type update_lock_default;
 | |
|   Delayed_insert *di;
 | |
| 
 | |
|   /* <> 0 if we are inside of trigger or stored function. */
 | |
|   uint in_sub_stmt;
 | |
| 
 | |
|   /* container for handler's private per-connection data */
 | |
|   void *ha_data[MAX_HA];
 | |
| 
 | |
| #ifndef MYSQL_CLIENT
 | |
|   int binlog_setup_trx_data();
 | |
| 
 | |
|   /*
 | |
|     Public interface to write RBR events to the binlog
 | |
|   */
 | |
|   void binlog_start_trans_and_stmt();
 | |
|   int binlog_flush_transaction_cache();
 | |
|   void binlog_set_stmt_begin();
 | |
|   int binlog_write_table_map(TABLE *table, bool is_transactional);
 | |
|   int binlog_write_row(TABLE* table, bool is_transactional,
 | |
|                        MY_BITMAP const* cols, size_t colcnt,
 | |
|                        const uchar *buf);
 | |
|   int binlog_delete_row(TABLE* table, bool is_transactional,
 | |
|                         MY_BITMAP const* cols, size_t colcnt,
 | |
|                         const uchar *buf);
 | |
|   int binlog_update_row(TABLE* table, bool is_transactional,
 | |
|                         MY_BITMAP const* cols, size_t colcnt,
 | |
|                         const uchar *old_data, const uchar *new_data);
 | |
| 
 | |
|   void set_server_id(uint32 sid) { server_id = sid; }
 | |
| 
 | |
|   /*
 | |
|     Member functions to handle pending event for row-level logging.
 | |
|   */
 | |
|   template <class RowsEventT> Rows_log_event*
 | |
|     binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
 | |
|                                       MY_BITMAP const* cols,
 | |
|                                       size_t colcnt,
 | |
|                                       size_t needed,
 | |
|                                       bool is_transactional,
 | |
| 				      RowsEventT* hint);
 | |
|   Rows_log_event* binlog_get_pending_rows_event() const;
 | |
|   void            binlog_set_pending_rows_event(Rows_log_event* ev);
 | |
|   int binlog_flush_pending_rows_event(bool stmt_end);
 | |
|   void binlog_delete_pending_rows_event();
 | |
| 
 | |
| private:
 | |
|   uint binlog_table_maps; // Number of table maps currently in the binlog
 | |
| public:
 | |
|   uint get_binlog_table_maps() const {
 | |
|     return binlog_table_maps;
 | |
|   }
 | |
| #endif /* MYSQL_CLIENT */
 | |
| 
 | |
| public:
 | |
| 
 | |
|   struct st_transactions {
 | |
|     SAVEPOINT *savepoints;
 | |
|     THD_TRANS all;			// Trans since BEGIN WORK
 | |
|     THD_TRANS stmt;			// Trans for current statement
 | |
|     bool on;                            // see ha_enable_transaction()
 | |
|     XID  xid;                           // transaction identifier
 | |
|     enum xa_states xa_state;            // used by external XA only
 | |
|     XID_STATE xid_state;
 | |
|     Rows_log_event *m_pending_rows_event;
 | |
| 
 | |
|     /*
 | |
|        Tables changed in transaction (that must be invalidated in query cache).
 | |
|        List contain only transactional tables, that not invalidated in query
 | |
|        cache (instead of full list of changed in transaction tables).
 | |
|     */
 | |
|     CHANGED_TABLE_LIST* changed_tables;
 | |
|     MEM_ROOT mem_root; // Transaction-life memory allocation pool
 | |
|     void cleanup()
 | |
|     {
 | |
|       changed_tables= 0;
 | |
|       savepoints= 0;
 | |
| #ifdef USING_TRANSACTIONS
 | |
|       free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
 | |
| #endif
 | |
|     }
 | |
|     st_transactions()
 | |
|     {
 | |
| #ifdef USING_TRANSACTIONS
 | |
|       bzero((char*)this, sizeof(*this));
 | |
|       xid_state.xid.null();
 | |
|       init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
 | |
| #else
 | |
|       xid_state.xa_state= XA_NOTR;
 | |
| #endif
 | |
|     }
 | |
|   } transaction;
 | |
|   Field      *dup_field;
 | |
| #ifndef __WIN__
 | |
|   sigset_t signals;
 | |
| #endif
 | |
| #ifdef SIGNAL_WITH_VIO_CLOSE
 | |
|   Vio* active_vio;
 | |
| #endif
 | |
|   /*
 | |
|     This is to track items changed during execution of a prepared
 | |
|     statement/stored procedure. It's created by
 | |
|     register_item_tree_change() in memory root of THD, and freed in
 | |
|     rollback_item_tree_changes(). For conventional execution it's always
 | |
|     empty.
 | |
|   */
 | |
|   Item_change_list change_list;
 | |
| 
 | |
|   /*
 | |
|     A permanent memory area of the statement. For conventional
 | |
|     execution, the parsed tree and execution runtime reside in the same
 | |
|     memory root. In this case stmt_arena points to THD. In case of
 | |
|     a prepared statement or a stored procedure statement, thd->mem_root
 | |
|     conventionally points to runtime memory, and thd->stmt_arena
 | |
|     points to the memory of the PS/SP, where the parsed tree of the
 | |
|     statement resides. Whenever you need to perform a permanent
 | |
|     transformation of a parsed tree, you should allocate new memory in
 | |
|     stmt_arena, to allow correct re-execution of PS/SP.
 | |
|     Note: in the parser, stmt_arena == thd, even for PS/SP.
 | |
|   */
 | |
|   Query_arena *stmt_arena;
 | |
|   /* Tells if LAST_INSERT_ID(#) was called for the current statement */
 | |
|   bool arg_of_last_insert_id_function;
 | |
|   /*
 | |
|     ALL OVER THIS FILE, "insert_id" means "*automatically generated* value for
 | |
|     insertion into an auto_increment column".
 | |
|   */
 | |
|   /*
 | |
|     This is the first autogenerated insert id which was *successfully*
 | |
|     inserted by the previous statement (exactly, if the previous statement
 | |
|     didn't successfully insert an autogenerated insert id, then it's the one
 | |
|     of the statement before, etc).
 | |
|     It can also be set by SET LAST_INSERT_ID=# or SELECT LAST_INSERT_ID(#).
 | |
|     It is returned by LAST_INSERT_ID().
 | |
|   */
 | |
|   ulonglong  first_successful_insert_id_in_prev_stmt;
 | |
|   /*
 | |
|     Variant of the above, used for storing in statement-based binlog. The
 | |
|     difference is that the one above can change as the execution of a stored
 | |
|     function progresses, while the one below is set once and then does not
 | |
|     change (which is the value which statement-based binlog needs).
 | |
|   */
 | |
|   ulonglong  first_successful_insert_id_in_prev_stmt_for_binlog;
 | |
|   /*
 | |
|     This is the first autogenerated insert id which was *successfully*
 | |
|     inserted by the current statement. It is maintained only to set
 | |
|     first_successful_insert_id_in_prev_stmt when statement ends.
 | |
|   */
 | |
|   ulonglong  first_successful_insert_id_in_cur_stmt;
 | |
|   /*
 | |
|     We follow this logic:
 | |
|     - when stmt starts, first_successful_insert_id_in_prev_stmt contains the
 | |
|     first insert id successfully inserted by the previous stmt.
 | |
|     - as stmt makes progress, handler::insert_id_for_cur_row changes; every
 | |
|     time get_auto_increment() is called, auto_inc_intervals_for_binlog is
 | |
|     augmented with the reserved interval (if statement-based binlogging).
 | |
|     - at first successful insertion of an autogenerated value,
 | |
|     first_successful_insert_id_in_cur_stmt is set to
 | |
|     handler::insert_id_for_cur_row.
 | |
|     - when stmt goes to binlog, auto_inc_intervals_for_binlog is
 | |
|     binlogged if non-empty.
 | |
|     - when stmt ends, first_successful_insert_id_in_prev_stmt is set to
 | |
|     first_successful_insert_id_in_cur_stmt.
 | |
|   */
 | |
|   /*
 | |
|     stmt_depends_on_first_successful_insert_id_in_prev_stmt is set when
 | |
|     LAST_INSERT_ID() is used by a statement.
 | |
|     If it is set, first_successful_insert_id_in_prev_stmt_for_binlog will be
 | |
|     stored in the statement-based binlog.
 | |
|     This variable is CUMULATIVE along the execution of a stored function or
 | |
|     trigger: if one substatement sets it to 1 it will stay 1 until the
 | |
|     function/trigger ends, thus making sure that
 | |
|     first_successful_insert_id_in_prev_stmt_for_binlog does not change anymore
 | |
|     and is propagated to the caller for binlogging.
 | |
|   */
 | |
|   bool       stmt_depends_on_first_successful_insert_id_in_prev_stmt;
 | |
|   /*
 | |
|     List of auto_increment intervals reserved by the thread so far, for
 | |
|     storage in the statement-based binlog.
 | |
|     Note that its minimum is not first_successful_insert_id_in_cur_stmt:
 | |
|     assuming a table with an autoinc column, and this happens:
 | |
|     INSERT INTO ... VALUES(3);
 | |
|     SET INSERT_ID=3; INSERT IGNORE ... VALUES (NULL);
 | |
|     then the latter INSERT will insert no rows
 | |
|     (first_successful_insert_id_in_cur_stmt == 0), but storing "INSERT_ID=3"
 | |
|     in the binlog is still needed; the list's minimum will contain 3.
 | |
|   */
 | |
|   Discrete_intervals_list auto_inc_intervals_in_cur_stmt_for_binlog;
 | |
|   /* Used by replication and SET INSERT_ID */
 | |
|   Discrete_intervals_list auto_inc_intervals_forced;
 | |
|   /*
 | |
|     There is BUG#19630 where statement-based replication of stored
 | |
|     functions/triggers with two auto_increment columns breaks.
 | |
|     We however ensure that it works when there is 0 or 1 auto_increment
 | |
|     column; our rules are
 | |
|     a) on master, while executing a top statement involving substatements,
 | |
|     first top- or sub- statement to generate auto_increment values wins the
 | |
|     exclusive right to see its values be written to binlog (the write
 | |
|     will be done by the statement or its caller), and the losers won't see
 | |
|     their values be written to binlog.
 | |
|     b) on slave, while replicating a top statement involving substatements,
 | |
|     first top- or sub- statement to need to read auto_increment values from
 | |
|     the master's binlog wins the exclusive right to read them (so the losers
 | |
|     won't read their values from binlog but instead generate on their own).
 | |
|     a) implies that we mustn't backup/restore
 | |
|     auto_inc_intervals_in_cur_stmt_for_binlog.
 | |
|     b) implies that we mustn't backup/restore auto_inc_intervals_forced.
 | |
| 
 | |
|     If there are more than 1 auto_increment columns, then intervals for
 | |
|     different columns may mix into the
 | |
|     auto_inc_intervals_in_cur_stmt_for_binlog list, which is logically wrong,
 | |
|     but there is no point in preventing this mixing by preventing intervals
 | |
|     from the secondly inserted column to come into the list, as such
 | |
|     prevention would be wrong too.
 | |
|     What will happen in the case of
 | |
|     INSERT INTO t1 (auto_inc) VALUES(NULL);
 | |
|     where t1 has a trigger which inserts into an auto_inc column of t2, is
 | |
|     that in binlog we'll store the interval of t1 and the interval of t2 (when
 | |
|     we store intervals, soon), then in slave, t1 will use both intervals, t2
 | |
|     will use none; if t1 inserts the same number of rows as on master,
 | |
|     normally the 2nd interval will not be used by t1, which is fine. t2's
 | |
|     values will be wrong if t2's internal auto_increment counter is different
 | |
|     from what it was on master (which is likely). In 5.1, in mixed binlogging
 | |
|     mode, row-based binlogging is used for such cases where two
 | |
|     auto_increment columns are inserted.
 | |
|   */
 | |
|   inline void record_first_successful_insert_id_in_cur_stmt(ulonglong id)
 | |
|   {
 | |
|     if (first_successful_insert_id_in_cur_stmt == 0)
 | |
|       first_successful_insert_id_in_cur_stmt= id;
 | |
|   }
 | |
|   inline ulonglong read_first_successful_insert_id_in_prev_stmt(void)
 | |
|   {
 | |
|     if (!stmt_depends_on_first_successful_insert_id_in_prev_stmt)
 | |
|     {
 | |
|       /* It's the first time we read it */
 | |
|       first_successful_insert_id_in_prev_stmt_for_binlog=
 | |
|         first_successful_insert_id_in_prev_stmt;
 | |
|       stmt_depends_on_first_successful_insert_id_in_prev_stmt= 1;
 | |
|     }
 | |
|     return first_successful_insert_id_in_prev_stmt;
 | |
|   }
 | |
|   /*
 | |
|     Used by Intvar_log_event::do_apply_event() and by "SET INSERT_ID=#"
 | |
|     (mysqlbinlog). We'll soon add a variant which can take many intervals in
 | |
|     argument.
 | |
|   */
 | |
|   inline void force_one_auto_inc_interval(ulonglong next_id)
 | |
|   {
 | |
|     auto_inc_intervals_forced.empty(); // in case of multiple SET INSERT_ID
 | |
|     auto_inc_intervals_forced.append(next_id, ULONGLONG_MAX, 0);
 | |
|   }
 | |
| 
 | |
|   ulonglong  limit_found_rows;
 | |
|   ulonglong  options;           /* Bitmap of states */
 | |
|   longlong   row_count_func;	/* For the ROW_COUNT() function */
 | |
|   ha_rows    cuted_fields,
 | |
|              sent_row_count, examined_row_count;
 | |
|   /*
 | |
|     The set of those tables whose fields are referenced in all subqueries
 | |
|     of the query.
 | |
|     TODO: possibly this it is incorrect to have used tables in THD because
 | |
|     with more than one subquery, it is not clear what does the field mean.
 | |
|   */
 | |
|   table_map  used_tables;
 | |
|   USER_CONN *user_connect;
 | |
|   CHARSET_INFO *db_charset;
 | |
|   /*
 | |
|     FIXME: this, and some other variables like 'count_cuted_fields'
 | |
|     maybe should be statement/cursor local, that is, moved to Statement
 | |
|     class. With current implementation warnings produced in each prepared
 | |
|     statement/cursor settle here.
 | |
|   */
 | |
|   List	     <MYSQL_ERROR> warn_list;
 | |
|   uint	     warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
 | |
|   uint	     total_warn_count;
 | |
|   /*
 | |
|     Id of current query. Statement can be reused to execute several queries
 | |
|     query_id is global in context of the whole MySQL server.
 | |
|     ID is automatically generated from mutex-protected counter.
 | |
|     It's used in handler code for various purposes: to check which columns
 | |
|     from table are necessary for this select, to check if it's necessary to
 | |
|     update auto-updatable fields (like auto_increment and timestamp).
 | |
|   */
 | |
|   query_id_t query_id, warn_id;
 | |
|   ulong      col_access;
 | |
| 
 | |
| #ifdef ERROR_INJECT_SUPPORT
 | |
|   ulong      error_inject_value;
 | |
| #endif
 | |
|   /* Statement id is thread-wide. This counter is used to generate ids */
 | |
|   ulong      statement_id_counter;
 | |
|   ulong	     rand_saved_seed1, rand_saved_seed2;
 | |
|   ulong      row_count;  // Row counter, mainly for errors and warnings
 | |
|   pthread_t  real_id;                           /* For debugging */
 | |
|   my_thread_id  thread_id;
 | |
|   uint	     tmp_table, global_read_lock;
 | |
|   uint	     server_status,open_options;
 | |
|   enum enum_thread_type system_thread;
 | |
|   uint       db_length;
 | |
|   uint       select_number;             //number of select (used for EXPLAIN)
 | |
|   /* variables.transaction_isolation is reset to this after each commit */
 | |
|   enum_tx_isolation session_tx_isolation;
 | |
|   enum_check_fields count_cuted_fields;
 | |
| 
 | |
|   DYNAMIC_ARRAY user_var_events;        /* For user variables replication */
 | |
|   MEM_ROOT      *user_var_events_alloc; /* Allocate above array elements here */
 | |
| 
 | |
|   enum killed_state
 | |
|   {
 | |
|     NOT_KILLED=0,
 | |
|     KILL_BAD_DATA=1,
 | |
|     KILL_CONNECTION=ER_SERVER_SHUTDOWN,
 | |
|     KILL_QUERY=ER_QUERY_INTERRUPTED,
 | |
|     KILLED_NO_VALUE      /* means neither of the states */
 | |
|   };
 | |
|   killed_state volatile killed;
 | |
| 
 | |
|   /* scramble - random string sent to client on handshake */
 | |
|   char	     scramble[SCRAMBLE_LENGTH+1];
 | |
| 
 | |
|   bool       slave_thread, one_shot_set;
 | |
|   /* tells if current statement should binlog row-based(1) or stmt-based(0) */
 | |
|   bool       current_stmt_binlog_row_based;
 | |
|   bool	     locked, some_tables_deleted;
 | |
|   bool       last_cuted_field;
 | |
|   bool	     no_errors, password, is_fatal_error;
 | |
|   bool	     query_start_used, rand_used, time_zone_used;
 | |
|   /* for IS NULL => = last_insert_id() fix in remove_eq_conds() */
 | |
|   bool       substitute_null_with_insert_id;
 | |
|   bool	     in_lock_tables;
 | |
|   bool       query_error, bootstrap, cleanup_done;
 | |
|   bool	     tmp_table_used;
 | |
|   bool	     charset_is_system_charset, charset_is_collation_connection;
 | |
|   bool       charset_is_character_set_filesystem;
 | |
|   bool       enable_slow_log;   /* enable slow log for current statement */
 | |
|   struct {
 | |
|     bool all:1;
 | |
|     bool stmt:1;
 | |
|   } no_trans_update;
 | |
|   bool	     abort_on_warning;
 | |
|   bool 	     got_warning;       /* Set on call to push_warning() */
 | |
|   bool	     no_warnings_for_error; /* no warnings on call to my_error() */
 | |
|   /* set during loop of derived table processing */
 | |
|   bool       derived_tables_processing;
 | |
|   my_bool    tablespace_op;	/* This is TRUE in DISCARD/IMPORT TABLESPACE */
 | |
| 
 | |
|   sp_rcontext *spcont;		// SP runtime context
 | |
|   sp_cache   *sp_proc_cache;
 | |
|   sp_cache   *sp_func_cache;
 | |
| 
 | |
|   /*
 | |
|     If we do a purge of binary logs, log index info of the threads
 | |
|     that are currently reading it needs to be adjusted. To do that
 | |
|     each thread that is using LOG_INFO needs to adjust the pointer to it
 | |
|   */
 | |
|   LOG_INFO*  current_linfo;
 | |
|   NET*       slave_net;			// network connection from slave -> m.
 | |
|   /* Used by the sys_var class to store temporary values */
 | |
|   union
 | |
|   {
 | |
|     my_bool   my_bool_value;
 | |
|     long      long_value;
 | |
|     ulong     ulong_value;
 | |
|     ulonglong ulonglong_value;
 | |
|   } sys_var_tmp;
 | |
|   
 | |
|   struct {
 | |
|     /* 
 | |
|       If true, mysql_bin_log::write(Log_event) call will not write events to 
 | |
|       binlog, and maintain 2 below variables instead (use
 | |
|       mysql_bin_log.start_union_events to turn this on)
 | |
|     */
 | |
|     bool do_union;
 | |
|     /*
 | |
|       If TRUE, at least one mysql_bin_log::write(Log_event) call has been
 | |
|       made after last mysql_bin_log.start_union_events() call.
 | |
|     */
 | |
|     bool unioned_events;
 | |
|     /*
 | |
|       If TRUE, at least one mysql_bin_log::write(Log_event e), where 
 | |
|       e.cache_stmt == TRUE call has been made after last 
 | |
|       mysql_bin_log.start_union_events() call.
 | |
|     */
 | |
|     bool unioned_events_trans;
 | |
|     
 | |
|     /* 
 | |
|       'queries' (actually SP statements) that run under inside this binlog
 | |
|       union have thd->query_id >= first_query_id.
 | |
|     */
 | |
|     query_id_t first_query_id;
 | |
|   } binlog_evt_union;
 | |
| 
 | |
|   /**
 | |
|     Character input stream consumed by the lexical analyser,
 | |
|     used during parsing.
 | |
|     Note that since the parser is not re-entrant, we keep only one input
 | |
|     stream here. This member is valid only when executing code during parsing,
 | |
|     and may point to invalid memory after that.
 | |
|   */
 | |
|   Lex_input_stream *m_lip;
 | |
| 
 | |
| #ifdef WITH_PARTITION_STORAGE_ENGINE
 | |
|   partition_info *work_part_info;
 | |
| #endif
 | |
| 
 | |
|   THD();
 | |
|   ~THD();
 | |
| 
 | |
|   void init(void);
 | |
|   /*
 | |
|     Initialize memory roots necessary for query processing and (!)
 | |
|     pre-allocate memory for it. We can't do that in THD constructor because
 | |
|     there are use cases (acl_init, delayed inserts, watcher threads,
 | |
|     killing mysqld) where it's vital to not allocate excessive and not used
 | |
|     memory. Note, that we still don't return error from init_for_queries():
 | |
|     if preallocation fails, we should notice that at the first call to
 | |
|     alloc_root. 
 | |
|   */
 | |
|   void init_for_queries();
 | |
|   void change_user(void);
 | |
|   void cleanup(void);
 | |
|   void cleanup_after_query();
 | |
|   bool store_globals();
 | |
| #ifdef SIGNAL_WITH_VIO_CLOSE
 | |
|   inline void set_active_vio(Vio* vio)
 | |
|   {
 | |
|     pthread_mutex_lock(&LOCK_delete);
 | |
|     active_vio = vio;
 | |
|     pthread_mutex_unlock(&LOCK_delete);
 | |
|   }
 | |
|   inline void clear_active_vio()
 | |
|   {
 | |
|     pthread_mutex_lock(&LOCK_delete);
 | |
|     active_vio = 0;
 | |
|     pthread_mutex_unlock(&LOCK_delete);
 | |
|   }
 | |
|   void close_active_vio();
 | |
| #endif
 | |
|   void awake(THD::killed_state state_to_set);
 | |
| 
 | |
| #ifndef MYSQL_CLIENT
 | |
|   enum enum_binlog_query_type {
 | |
|     /*
 | |
|       The query can be logged row-based or statement-based
 | |
|     */
 | |
|     ROW_QUERY_TYPE,
 | |
|     
 | |
|     /*
 | |
|       The query has to be logged statement-based
 | |
|     */
 | |
|     STMT_QUERY_TYPE,
 | |
|     
 | |
|     /*
 | |
|       The query represents a change to a table in the "mysql"
 | |
|       database and is currently mapped to ROW_QUERY_TYPE.
 | |
|     */
 | |
|     MYSQL_QUERY_TYPE,
 | |
|     QUERY_TYPE_COUNT
 | |
|   };
 | |
|   
 | |
|   int binlog_query(enum_binlog_query_type qtype,
 | |
|                    char const *query, ulong query_len,
 | |
|                    bool is_trans, bool suppress_use,
 | |
|                    THD::killed_state killed_err_arg= THD::KILLED_NO_VALUE);
 | |
| #endif
 | |
| 
 | |
|   /*
 | |
|     For enter_cond() / exit_cond() to work the mutex must be got before
 | |
|     enter_cond(); this mutex is then released by exit_cond().
 | |
|     Usage must be: lock mutex; enter_cond(); your code; exit_cond().
 | |
|   */
 | |
|   inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t* mutex,
 | |
| 			  const char* msg)
 | |
|   {
 | |
|     const char* old_msg = proc_info;
 | |
|     safe_mutex_assert_owner(mutex);
 | |
|     mysys_var->current_mutex = mutex;
 | |
|     mysys_var->current_cond = cond;
 | |
|     proc_info = msg;
 | |
|     return old_msg;
 | |
|   }
 | |
|   inline void exit_cond(const char* old_msg)
 | |
|   {
 | |
|     /*
 | |
|       Putting the mutex unlock in exit_cond() ensures that
 | |
|       mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is
 | |
|       locked (if that would not be the case, you'll get a deadlock if someone
 | |
|       does a THD::awake() on you).
 | |
|     */
 | |
|     pthread_mutex_unlock(mysys_var->current_mutex);
 | |
|     pthread_mutex_lock(&mysys_var->mutex);
 | |
|     mysys_var->current_mutex = 0;
 | |
|     mysys_var->current_cond = 0;
 | |
|     proc_info = old_msg;
 | |
|     pthread_mutex_unlock(&mysys_var->mutex);
 | |
|   }
 | |
|   inline time_t query_start() { query_start_used=1; return start_time; }
 | |
|   inline void	set_time()    { if (user_time) start_time=time_after_lock=user_time; else time_after_lock=time(&start_time); }
 | |
|   inline void	end_time()    { time(&start_time); }
 | |
|   inline void	set_time(time_t t) { time_after_lock=start_time=user_time=t; }
 | |
|   inline void	lock_time()   { time(&time_after_lock); }
 | |
|   inline ulonglong found_rows(void)
 | |
|   {
 | |
|     return limit_found_rows;
 | |
|   }
 | |
|   inline bool active_transaction()
 | |
|   {
 | |
| #ifdef USING_TRANSACTIONS
 | |
|     return server_status & SERVER_STATUS_IN_TRANS;
 | |
| #else
 | |
|     return 0;
 | |
| #endif
 | |
|   }
 | |
|   inline bool fill_derived_tables()
 | |
|   {
 | |
|     return !stmt_arena->is_stmt_prepare() && !lex->only_view_structure();
 | |
|   }
 | |
|   inline bool fill_information_schema_tables()
 | |
|   {
 | |
|     return !stmt_arena->is_stmt_prepare();
 | |
|   }
 | |
|   inline void* trans_alloc(unsigned int size)
 | |
|   {
 | |
|     return alloc_root(&transaction.mem_root,size);
 | |
|   }
 | |
| 
 | |
|   bool convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
 | |
| 		      const char *from, uint from_length,
 | |
| 		      CHARSET_INFO *from_cs);
 | |
| 
 | |
|   bool convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs);
 | |
| 
 | |
|   void add_changed_table(TABLE *table);
 | |
|   void add_changed_table(const char *key, long key_length);
 | |
|   CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length);
 | |
|   int send_explain_fields(select_result *result);
 | |
| #ifndef EMBEDDED_LIBRARY
 | |
|   inline void clear_error()
 | |
|   {
 | |
|     DBUG_ENTER("clear_error");
 | |
|     net.last_error[0]= 0;
 | |
|     net.last_errno= 0;
 | |
|     net.report_error= 0;
 | |
|     query_error= 0;
 | |
|     DBUG_VOID_RETURN;
 | |
|   }
 | |
|   inline bool vio_ok() const { return net.vio != 0; }
 | |
| #else
 | |
|   void clear_error();
 | |
|   inline bool vio_ok() const { return true; }
 | |
| #endif
 | |
|   inline void fatal_error()
 | |
|   {
 | |
|     is_fatal_error= 1;
 | |
|     net.report_error= 1;
 | |
|     DBUG_PRINT("error",("Fatal error set"));
 | |
|   }
 | |
|   inline CHARSET_INFO *charset() { return variables.character_set_client; }
 | |
|   void update_charset();
 | |
| 
 | |
|   inline Query_arena *activate_stmt_arena_if_needed(Query_arena *backup)
 | |
|   {
 | |
|     /*
 | |
|       Use the persistent arena if we are in a prepared statement or a stored
 | |
|       procedure statement and we have not already changed to use this arena.
 | |
|     */
 | |
|     if (!stmt_arena->is_conventional() && mem_root != stmt_arena->mem_root)
 | |
|     {
 | |
|       set_n_backup_active_arena(stmt_arena, backup);
 | |
|       return stmt_arena;
 | |
|     }
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   void change_item_tree(Item **place, Item *new_value)
 | |
|   {
 | |
|     /* TODO: check for OOM condition here */
 | |
|     if (!stmt_arena->is_conventional())
 | |
|       nocheck_register_item_tree_change(place, *place, mem_root);
 | |
|     *place= new_value;
 | |
|   }
 | |
|   void nocheck_register_item_tree_change(Item **place, Item *old_value,
 | |
|                                          MEM_ROOT *runtime_memroot);
 | |
|   void rollback_item_tree_changes();
 | |
| 
 | |
|   /*
 | |
|     Cleanup statement parse state (parse tree, lex) and execution
 | |
|     state after execution of a non-prepared SQL statement.
 | |
|   */
 | |
|   void end_statement();
 | |
|   inline int killed_errno() const
 | |
|   {
 | |
|     killed_state killed_val; /* to cache the volatile 'killed' */
 | |
|     return (killed_val= killed) != KILL_BAD_DATA ? killed_val : 0;
 | |
|   }
 | |
|   inline void send_kill_message() const
 | |
|   {
 | |
|     int err= killed_errno();
 | |
|     if (err)
 | |
|       my_message(err, ER(err), MYF(0));
 | |
|   }
 | |
|   /* return TRUE if we will abort query if we make a warning now */
 | |
|   inline bool really_abort_on_warning()
 | |
|   {
 | |
|     return (abort_on_warning &&
 | |
|             (!no_trans_update.stmt ||
 | |
|              (variables.sql_mode & MODE_STRICT_ALL_TABLES)));
 | |
|   }
 | |
|   void set_status_var_init();
 | |
|   bool is_context_analysis_only()
 | |
|     { return stmt_arena->is_stmt_prepare() || lex->view_prepare_mode; }
 | |
|   void reset_n_backup_open_tables_state(Open_tables_state *backup);
 | |
|   void restore_backup_open_tables_state(Open_tables_state *backup);
 | |
|   void reset_sub_statement_state(Sub_statement_state *backup, uint new_state);
 | |
|   void restore_sub_statement_state(Sub_statement_state *backup);
 | |
|   void set_n_backup_active_arena(Query_arena *set, Query_arena *backup);
 | |
|   void restore_active_arena(Query_arena *set, Query_arena *backup);
 | |
|   inline void set_current_stmt_binlog_row_based_if_mixed()
 | |
|   {
 | |
|     /*
 | |
|       If in a stored/function trigger, the caller should already have done the
 | |
|       change. We test in_sub_stmt to prevent introducing bugs where people
 | |
|       wouldn't ensure that, and would switch to row-based mode in the middle
 | |
|       of executing a stored function/trigger (which is too late, see also
 | |
|       reset_current_stmt_binlog_row_based()); this condition will make their
 | |
|       tests fail and so force them to propagate the
 | |
|       lex->binlog_row_based_if_mixed upwards to the caller.
 | |
|     */
 | |
|     if ((variables.binlog_format == BINLOG_FORMAT_MIXED) &&
 | |
|         (in_sub_stmt == 0))
 | |
|       current_stmt_binlog_row_based= TRUE;
 | |
|   }
 | |
|   inline void set_current_stmt_binlog_row_based()
 | |
|   {
 | |
|     current_stmt_binlog_row_based= TRUE;
 | |
|   }
 | |
|   inline void clear_current_stmt_binlog_row_based()
 | |
|   {
 | |
|     current_stmt_binlog_row_based= FALSE;
 | |
|   }
 | |
|   inline void reset_current_stmt_binlog_row_based()
 | |
|   {
 | |
|     /*
 | |
|       If there are temporary tables, don't reset back to
 | |
|       statement-based. Indeed it could be that:
 | |
|       CREATE TEMPORARY TABLE t SELECT UUID(); # row-based
 | |
|       # and row-based does not store updates to temp tables
 | |
|       # in the binlog.
 | |
|       INSERT INTO u SELECT * FROM t; # stmt-based
 | |
|       and then the INSERT will fail as data inserted into t was not logged.
 | |
|       So we continue with row-based until the temp table is dropped.
 | |
|       If we are in a stored function or trigger, we mustn't reset in the
 | |
|       middle of its execution (as the binary logging way of a stored function
 | |
|       or trigger is decided when it starts executing, depending for example on
 | |
|       the caller (for a stored function: if caller is SELECT or
 | |
|       INSERT/UPDATE/DELETE...).
 | |
| 
 | |
|       Don't reset binlog format for NDB binlog injector thread.
 | |
|     */
 | |
|     if ((temporary_tables == NULL) && (in_sub_stmt == 0) &&
 | |
|         (system_thread != SYSTEM_THREAD_NDBCLUSTER_BINLOG))
 | |
|     {
 | |
|       current_stmt_binlog_row_based= 
 | |
|         test(variables.binlog_format == BINLOG_FORMAT_ROW);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /*
 | |
|     Initialize the current database from a NULL-terminated string with length
 | |
|     If we run out of memory, we free the current database and return TRUE.
 | |
|     This way the user will notice the error as there will be no current
 | |
|     database selected (in addition to the error message set by malloc).
 | |
|   */
 | |
|   bool set_db(const char *new_db, size_t new_db_len)
 | |
|   {
 | |
|     /* Do not reallocate memory if current chunk is big enough. */
 | |
|     if (db && new_db && db_length >= new_db_len)
 | |
|       memcpy(db, new_db, new_db_len+1);
 | |
|     else
 | |
|     {
 | |
|       x_free(db);
 | |
|       db= new_db ? my_strndup(new_db, new_db_len, MYF(MY_WME)) : NULL;
 | |
|     }
 | |
|     db_length= db ? new_db_len : 0;
 | |
|     return new_db && !db;
 | |
|   }
 | |
|   void reset_db(char *new_db, size_t new_db_len)
 | |
|   {
 | |
|     db= new_db;
 | |
|     db_length= new_db_len;
 | |
|   }
 | |
|   /*
 | |
|     Copy the current database to the argument. Use the current arena to
 | |
|     allocate memory for a deep copy: current database may be freed after
 | |
|     a statement is parsed but before it's executed.
 | |
|   */
 | |
|   bool copy_db_to(char **p_db, size_t *p_db_length)
 | |
|   {
 | |
|     if (db == NULL)
 | |
|     {
 | |
|       my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
 | |
|       return TRUE;
 | |
|     }
 | |
|     *p_db= strmake(db, db_length);
 | |
|     *p_db_length= db_length;
 | |
|     return FALSE;
 | |
|   }
 | |
|   thd_scheduler scheduler;
 | |
| 
 | |
| public:
 | |
|   /**
 | |
|     Add an internal error handler to the thread execution context.
 | |
|     @param handler the exception handler to add
 | |
|   */
 | |
|   void push_internal_handler(Internal_error_handler *handler);
 | |
| 
 | |
|   /**
 | |
|     Handle an error condition.
 | |
|     @param sql_errno the error number
 | |
|     @param level the error level
 | |
|     @return true if the error is handled
 | |
|   */
 | |
|   virtual bool handle_error(uint sql_errno,
 | |
|                             MYSQL_ERROR::enum_warning_level level);
 | |
| 
 | |
|   /**
 | |
|     Remove the error handler last pushed.
 | |
|   */
 | |
|   void pop_internal_handler();
 | |
| 
 | |
| private:
 | |
|   /** The current internal error handler for this thread, or NULL. */
 | |
|   Internal_error_handler *m_internal_handler;
 | |
|   /**
 | |
|     The lex to hold the parsed tree of conventional (non-prepared) queries.
 | |
|     Whereas for prepared and stored procedure statements we use an own lex
 | |
|     instance for each new query, for conventional statements we reuse
 | |
|     the same lex. (@see mysql_parse for details).
 | |
|   */
 | |
|   LEX main_lex;
 | |
|   /**
 | |
|     This memory root is used for two purposes:
 | |
|     - for conventional queries, to allocate structures stored in main_lex
 | |
|     during parsing, and allocate runtime data (execution plan, etc.)
 | |
|     during execution.
 | |
|     - for prepared queries, only to allocate runtime data. The parsed
 | |
|     tree itself is reused between executions and thus is stored elsewhere.
 | |
|   */
 | |
|   MEM_ROOT main_mem_root;
 | |
| };
 | |
| 
 | |
| 
 | |
| #define tmp_disable_binlog(A)       \
 | |
|   {ulonglong tmp_disable_binlog__save_options= (A)->options; \
 | |
|   (A)->options&= ~OPTION_BIN_LOG
 | |
| 
 | |
| #define reenable_binlog(A)   (A)->options= tmp_disable_binlog__save_options;}
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Used to hold information about file and file structure in exchange
 | |
|   via non-DB file (...INTO OUTFILE..., ...LOAD DATA...)
 | |
|   XXX: We never call destructor for objects of this class.
 | |
| */
 | |
| 
 | |
| class sql_exchange :public Sql_alloc
 | |
| {
 | |
| public:
 | |
|   char *file_name;
 | |
|   String *field_term,*enclosed,*line_term,*line_start,*escaped;
 | |
|   bool opt_enclosed;
 | |
|   bool dumpfile;
 | |
|   ulong skip_lines;
 | |
|   CHARSET_INFO *cs;
 | |
|   sql_exchange(char *name,bool dumpfile_flag);
 | |
| };
 | |
| 
 | |
| #include "log_event.h"
 | |
| 
 | |
| /*
 | |
|   This is used to get result from a select
 | |
| */
 | |
| 
 | |
| class JOIN;
 | |
| 
 | |
| class select_result :public Sql_alloc {
 | |
| protected:
 | |
|   THD *thd;
 | |
|   SELECT_LEX_UNIT *unit;
 | |
| public:
 | |
|   select_result();
 | |
|   virtual ~select_result() {};
 | |
|   virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u)
 | |
|   {
 | |
|     unit= u;
 | |
|     return 0;
 | |
|   }
 | |
|   virtual int prepare2(void) { return 0; }
 | |
|   /*
 | |
|     Because of peculiarities of prepared statements protocol
 | |
|     we need to know number of columns in the result set (if
 | |
|     there is a result set) apart from sending columns metadata.
 | |
|   */
 | |
|   virtual uint field_count(List<Item> &fields) const
 | |
|   { return fields.elements; }
 | |
|   virtual bool send_fields(List<Item> &list, uint flags)=0;
 | |
|   virtual bool send_data(List<Item> &items)=0;
 | |
|   virtual bool initialize_tables (JOIN *join=0) { return 0; }
 | |
|   virtual void send_error(uint errcode,const char *err);
 | |
|   virtual bool send_eof()=0;
 | |
|   /**
 | |
|     Check if this query returns a result set and therefore is allowed in
 | |
|     cursors and set an error message if it is not the case.
 | |
| 
 | |
|     @retval FALSE     success
 | |
|     @retval TRUE      error, an error message is set
 | |
|   */
 | |
|   virtual bool check_simple_select() const;
 | |
|   virtual void abort() {}
 | |
|   /*
 | |
|     Cleanup instance of this class for next execution of a prepared
 | |
|     statement/stored procedure.
 | |
|   */
 | |
|   virtual void cleanup();
 | |
|   void set_thd(THD *thd_arg) { thd= thd_arg; }
 | |
| #ifdef EMBEDDED_LIBRARY
 | |
|   virtual void begin_dataset() {}
 | |
| #else
 | |
|   void begin_dataset() {}
 | |
| #endif
 | |
| };
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Base class for select_result descendands which intercept and
 | |
|   transform result set rows. As the rows are not sent to the client,
 | |
|   sending of result set metadata should be suppressed as well.
 | |
| */
 | |
| 
 | |
| class select_result_interceptor: public select_result
 | |
| {
 | |
| public:
 | |
|   select_result_interceptor() {}              /* Remove gcc warning */
 | |
|   uint field_count(List<Item> &fields) const { return 0; }
 | |
|   bool send_fields(List<Item> &fields, uint flag) { return FALSE; }
 | |
| };
 | |
| 
 | |
| 
 | |
| class select_send :public select_result {
 | |
|   int status;
 | |
| public:
 | |
|   select_send() :status(0) {}
 | |
|   bool send_fields(List<Item> &list, uint flags);
 | |
|   bool send_data(List<Item> &items);
 | |
|   bool send_eof();
 | |
|   virtual bool check_simple_select() const { return FALSE; }
 | |
|   void abort();
 | |
| };
 | |
| 
 | |
| 
 | |
| class select_to_file :public select_result_interceptor {
 | |
| protected:
 | |
|   sql_exchange *exchange;
 | |
|   File file;
 | |
|   IO_CACHE cache;
 | |
|   ha_rows row_count;
 | |
|   char path[FN_REFLEN];
 | |
| 
 | |
| public:
 | |
|   select_to_file(sql_exchange *ex) :exchange(ex), file(-1),row_count(0L)
 | |
|   { path[0]=0; }
 | |
|   ~select_to_file();
 | |
|   void send_error(uint errcode,const char *err);
 | |
|   bool send_eof();
 | |
|   void cleanup();
 | |
| };
 | |
| 
 | |
| 
 | |
| class select_export :public select_to_file {
 | |
|   uint field_term_length;
 | |
|   int field_sep_char,escape_char,line_sep_char;
 | |
|   bool fixed_row_size;
 | |
| public:
 | |
|   select_export(sql_exchange *ex) :select_to_file(ex) {}
 | |
|   ~select_export();
 | |
|   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
 | |
|   bool send_data(List<Item> &items);
 | |
| };
 | |
| 
 | |
| 
 | |
| class select_dump :public select_to_file {
 | |
| public:
 | |
|   select_dump(sql_exchange *ex) :select_to_file(ex) {}
 | |
|   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
 | |
|   bool send_data(List<Item> &items);
 | |
| };
 | |
| 
 | |
| 
 | |
| class select_insert :public select_result_interceptor {
 | |
|  public:
 | |
|   TABLE_LIST *table_list;
 | |
|   TABLE *table;
 | |
|   List<Item> *fields;
 | |
|   ulonglong autoinc_value_of_last_inserted_row; // autogenerated or not
 | |
|   COPY_INFO info;
 | |
|   bool insert_into_view;
 | |
| 
 | |
|   select_insert(TABLE_LIST *table_list_par,
 | |
| 		TABLE *table_par, List<Item> *fields_par,
 | |
| 		List<Item> *update_fields, List<Item> *update_values,
 | |
| 		enum_duplicates duplic, bool ignore);
 | |
|   ~select_insert();
 | |
|   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
 | |
|   int prepare2(void);
 | |
|   bool send_data(List<Item> &items);
 | |
|   virtual void store_values(List<Item> &values);
 | |
|   virtual bool can_rollback_data() { return 0; }
 | |
|   void send_error(uint errcode,const char *err);
 | |
|   bool send_eof();
 | |
|   /* not implemented: select_insert is never re-used in prepared statements */
 | |
|   void cleanup();
 | |
| };
 | |
| 
 | |
| 
 | |
| class select_create: public select_insert {
 | |
|   ORDER *group;
 | |
|   TABLE_LIST *create_table;
 | |
|   HA_CREATE_INFO *create_info;
 | |
|   Alter_info *alter_info;
 | |
|   Field **field;
 | |
| public:
 | |
|   select_create(TABLE_LIST *table_arg,
 | |
|                 HA_CREATE_INFO *create_info_arg,
 | |
|                 Alter_info *alter_info_arg,
 | |
|                 List<Item> &select_fields,
 | |
|                 enum_duplicates duplic, bool ignore)
 | |
|     :select_insert(NULL, NULL, &select_fields, 0, 0, duplic, ignore),
 | |
|     create_table(table_arg),
 | |
|     create_info(create_info_arg),
 | |
|     alter_info(alter_info_arg)
 | |
|   {}
 | |
|   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
 | |
| 
 | |
|   void binlog_show_create_table(TABLE **tables, uint count);
 | |
|   void store_values(List<Item> &values);
 | |
|   void send_error(uint errcode,const char *err);
 | |
|   bool send_eof();
 | |
|   void abort();
 | |
|   virtual bool can_rollback_data() { return 1; }
 | |
| 
 | |
|   // Needed for access from local class MY_HOOKS in prepare(), since thd is proteted.
 | |
|   const THD *get_thd(void) { return thd; }
 | |
|   const HA_CREATE_INFO *get_create_info() { return create_info; };
 | |
| };
 | |
| 
 | |
| #include <myisam.h>
 | |
| 
 | |
| /* 
 | |
|   Param to create temporary tables when doing SELECT:s 
 | |
|   NOTE
 | |
|     This structure is copied using memcpy as a part of JOIN.
 | |
| */
 | |
| 
 | |
| class TMP_TABLE_PARAM :public Sql_alloc
 | |
| {
 | |
| private:
 | |
|   /* Prevent use of these (not safe because of lists and copy_field) */
 | |
|   TMP_TABLE_PARAM(const TMP_TABLE_PARAM &);
 | |
|   void operator=(TMP_TABLE_PARAM &);
 | |
| 
 | |
| public:
 | |
|   List<Item> copy_funcs;
 | |
|   List<Item> save_copy_funcs;
 | |
|   Copy_field *copy_field, *copy_field_end;
 | |
|   Copy_field *save_copy_field, *save_copy_field_end;
 | |
|   uchar	    *group_buff;
 | |
|   Item	    **items_to_copy;			/* Fields in tmp table */
 | |
|   MI_COLUMNDEF *recinfo,*start_recinfo;
 | |
|   KEY *keyinfo;
 | |
|   ha_rows end_write_records;
 | |
|   uint	field_count,sum_func_count,func_count;
 | |
|   uint  hidden_field_count;
 | |
|   uint	group_parts,group_length,group_null_parts;
 | |
|   uint	quick_group;
 | |
|   bool  using_indirect_summary_function;
 | |
|   /* If >0 convert all blob fields to varchar(convert_blob_length) */
 | |
|   uint  convert_blob_length; 
 | |
|   CHARSET_INFO *table_charset; 
 | |
|   bool schema_table;
 | |
|   /*
 | |
|     True if GROUP BY and its aggregate functions are already computed
 | |
|     by a table access method (e.g. by loose index scan). In this case
 | |
|     query execution should not perform aggregation and should treat
 | |
|     aggregate functions as normal functions.
 | |
|   */
 | |
|   bool precomputed_group_by;
 | |
|   bool force_copy_fields;
 | |
| 
 | |
|   TMP_TABLE_PARAM()
 | |
|     :copy_field(0), group_parts(0),
 | |
|      group_length(0), group_null_parts(0), convert_blob_length(0),
 | |
|      schema_table(0), precomputed_group_by(0), force_copy_fields(0)
 | |
|   {}
 | |
|   ~TMP_TABLE_PARAM()
 | |
|   {
 | |
|     cleanup();
 | |
|   }
 | |
|   void init(void);
 | |
|   inline void cleanup(void)
 | |
|   {
 | |
|     if (copy_field)				/* Fix for Intel compiler */
 | |
|     {
 | |
|       delete [] copy_field;
 | |
|       save_copy_field= copy_field= 0;
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| class select_union :public select_result_interceptor
 | |
| {
 | |
|   TMP_TABLE_PARAM tmp_table_param;
 | |
| public:
 | |
|   TABLE *table;
 | |
| 
 | |
|   select_union() :table(0) {}
 | |
|   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
 | |
|   bool send_data(List<Item> &items);
 | |
|   bool send_eof();
 | |
|   bool flush();
 | |
| 
 | |
|   bool create_result_table(THD *thd, List<Item> *column_types,
 | |
|                            bool is_distinct, ulonglong options,
 | |
|                            const char *alias);
 | |
| };
 | |
| 
 | |
| /* Base subselect interface class */
 | |
| class select_subselect :public select_result_interceptor
 | |
| {
 | |
| protected:
 | |
|   Item_subselect *item;
 | |
| public:
 | |
|   select_subselect(Item_subselect *item);
 | |
|   bool send_data(List<Item> &items)=0;
 | |
|   bool send_eof() { return 0; };
 | |
| };
 | |
| 
 | |
| /* Single value subselect interface class */
 | |
| class select_singlerow_subselect :public select_subselect
 | |
| {
 | |
| public:
 | |
|   select_singlerow_subselect(Item_subselect *item_arg)
 | |
|     :select_subselect(item_arg)
 | |
|   {}
 | |
|   bool send_data(List<Item> &items);
 | |
| };
 | |
| 
 | |
| /* used in independent ALL/ANY optimisation */
 | |
| class select_max_min_finder_subselect :public select_subselect
 | |
| {
 | |
|   Item_cache *cache;
 | |
|   bool (select_max_min_finder_subselect::*op)();
 | |
|   bool fmax;
 | |
| public:
 | |
|   select_max_min_finder_subselect(Item_subselect *item_arg, bool mx)
 | |
|     :select_subselect(item_arg), cache(0), fmax(mx)
 | |
|   {}
 | |
|   void cleanup();
 | |
|   bool send_data(List<Item> &items);
 | |
|   bool cmp_real();
 | |
|   bool cmp_int();
 | |
|   bool cmp_decimal();
 | |
|   bool cmp_str();
 | |
| };
 | |
| 
 | |
| /* EXISTS subselect interface class */
 | |
| class select_exists_subselect :public select_subselect
 | |
| {
 | |
| public:
 | |
|   select_exists_subselect(Item_subselect *item_arg)
 | |
|     :select_subselect(item_arg){}
 | |
|   bool send_data(List<Item> &items);
 | |
| };
 | |
| 
 | |
| /* Structs used when sorting */
 | |
| 
 | |
| typedef struct st_sort_field {
 | |
|   Field *field;				/* Field to sort */
 | |
|   Item	*item;				/* Item if not sorting fields */
 | |
|   uint	 length;			/* Length of sort field */
 | |
|   uint   suffix_length;                 /* Length suffix (0-4) */
 | |
|   Item_result result_type;		/* Type of item */
 | |
|   bool reverse;				/* if descending sort */
 | |
|   bool need_strxnfrm;			/* If we have to use strxnfrm() */
 | |
| } SORT_FIELD;
 | |
| 
 | |
| 
 | |
| typedef struct st_sort_buffer {
 | |
|   uint index;					/* 0 or 1 */
 | |
|   uint sort_orders;
 | |
|   uint change_pos;				/* If sort-fields changed */
 | |
|   char **buff;
 | |
|   SORT_FIELD *sortorder;
 | |
| } SORT_BUFFER;
 | |
| 
 | |
| /* Structure for db & table in sql_yacc */
 | |
| 
 | |
| class Table_ident :public Sql_alloc
 | |
| {
 | |
| public:
 | |
|   LEX_STRING db;
 | |
|   LEX_STRING table;
 | |
|   SELECT_LEX_UNIT *sel;
 | |
|   inline Table_ident(THD *thd, LEX_STRING db_arg, LEX_STRING table_arg,
 | |
| 		     bool force)
 | |
|     :table(table_arg), sel((SELECT_LEX_UNIT *)0)
 | |
|   {
 | |
|     if (!force && (thd->client_capabilities & CLIENT_NO_SCHEMA))
 | |
|       db.str=0;
 | |
|     else
 | |
|       db= db_arg;
 | |
|   }
 | |
|   inline Table_ident(LEX_STRING table_arg) 
 | |
|     :table(table_arg), sel((SELECT_LEX_UNIT *)0)
 | |
|   {
 | |
|     db.str=0;
 | |
|   }
 | |
|   /*
 | |
|     This constructor is used only for the case when we create a derived
 | |
|     table. A derived table has no name and doesn't belong to any database.
 | |
|     Later, if there was an alias specified for the table, it will be set
 | |
|     by add_table_to_list.
 | |
|   */
 | |
|   inline Table_ident(SELECT_LEX_UNIT *s) : sel(s)
 | |
|   {
 | |
|     /* We must have a table name here as this is used with add_table_to_list */
 | |
|     db.str= empty_c_string;                    /* a subject to casedn_str */
 | |
|     db.length= 0;
 | |
|     table.str= internal_table_name;
 | |
|     table.length=1;
 | |
|   }
 | |
|   bool is_derived_table() const { return test(sel); }
 | |
|   inline void change_db(char *db_name)
 | |
|   {
 | |
|     db.str= db_name; db.length= (uint) strlen(db_name);
 | |
|   }
 | |
| };
 | |
| 
 | |
| // this is needed for user_vars hash
 | |
| class user_var_entry
 | |
| {
 | |
|  public:
 | |
|   user_var_entry() {}                         /* Remove gcc warning */
 | |
|   LEX_STRING name;
 | |
|   char *value;
 | |
|   ulong length;
 | |
|   query_id_t update_query_id, used_query_id;
 | |
|   Item_result type;
 | |
|   bool unsigned_flag;
 | |
| 
 | |
|   double val_real(my_bool *null_value);
 | |
|   longlong val_int(my_bool *null_value);
 | |
|   String *val_str(my_bool *null_value, String *str, uint decimals);
 | |
|   my_decimal *val_decimal(my_bool *null_value, my_decimal *result);
 | |
|   DTCollation collation;
 | |
| };
 | |
| 
 | |
| /*
 | |
|    Unique -- class for unique (removing of duplicates). 
 | |
|    Puts all values to the TREE. If the tree becomes too big,
 | |
|    it's dumped to the file. User can request sorted values, or
 | |
|    just iterate through them. In the last case tree merging is performed in
 | |
|    memory simultaneously with iteration, so it should be ~2-3x faster.
 | |
|  */
 | |
| 
 | |
| class Unique :public Sql_alloc
 | |
| {
 | |
|   DYNAMIC_ARRAY file_ptrs;
 | |
|   ulong max_elements;
 | |
|   ulonglong max_in_memory_size;
 | |
|   IO_CACHE file;
 | |
|   TREE tree;
 | |
|   uchar *record_pointers;
 | |
|   bool flush();
 | |
|   uint size;
 | |
| 
 | |
| public:
 | |
|   ulong elements;
 | |
|   Unique(qsort_cmp2 comp_func, void *comp_func_fixed_arg,
 | |
| 	 uint size_arg, ulonglong max_in_memory_size_arg);
 | |
|   ~Unique();
 | |
|   ulong elements_in_tree() { return tree.elements_in_tree; }
 | |
|   inline bool unique_add(void *ptr)
 | |
|   {
 | |
|     DBUG_ENTER("unique_add");
 | |
|     DBUG_PRINT("info", ("tree %u - %lu", tree.elements_in_tree, max_elements));
 | |
|     if (tree.elements_in_tree > max_elements && flush())
 | |
|       DBUG_RETURN(1);
 | |
|     DBUG_RETURN(!tree_insert(&tree, ptr, 0, tree.custom_arg));
 | |
|   }
 | |
| 
 | |
|   bool get(TABLE *table);
 | |
|   static double get_use_cost(uint *buffer, uint nkeys, uint key_size, 
 | |
|                              ulonglong max_in_memory_size);
 | |
|   inline static int get_cost_calc_buff_size(ulong nkeys, uint key_size, 
 | |
|                                             ulonglong max_in_memory_size)
 | |
|   {
 | |
|     register ulonglong max_elems_in_tree=
 | |
|       (1 + max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+key_size));
 | |
|     return (int) (sizeof(uint)*(1 + nkeys/max_elems_in_tree));
 | |
|   }
 | |
| 
 | |
|   void reset();
 | |
|   bool walk(tree_walk_action action, void *walk_action_arg);
 | |
| 
 | |
|   friend int unique_write_to_file(uchar* key, element_count count, Unique *unique);
 | |
|   friend int unique_write_to_ptrs(uchar* key, element_count count, Unique *unique);
 | |
| };
 | |
| 
 | |
| 
 | |
| class multi_delete :public select_result_interceptor
 | |
| {
 | |
|   TABLE_LIST *delete_tables, *table_being_deleted;
 | |
|   Unique **tempfiles;
 | |
|   ha_rows deleted, found;
 | |
|   uint num_of_tables;
 | |
|   int error;
 | |
|   bool do_delete;
 | |
|   /* True if at least one table we delete from is transactional */
 | |
|   bool transactional_tables;
 | |
|   /* True if at least one table we delete from is not transactional */
 | |
|   bool normal_tables;
 | |
|   bool delete_while_scanning;
 | |
| 
 | |
| public:
 | |
|   multi_delete(TABLE_LIST *dt, uint num_of_tables);
 | |
|   ~multi_delete();
 | |
|   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
 | |
|   bool send_data(List<Item> &items);
 | |
|   bool initialize_tables (JOIN *join);
 | |
|   void send_error(uint errcode,const char *err);
 | |
|   int  do_deletes();
 | |
|   bool send_eof();
 | |
| };
 | |
| 
 | |
| 
 | |
| class multi_update :public select_result_interceptor
 | |
| {
 | |
|   TABLE_LIST *all_tables; /* query/update command tables */
 | |
|   TABLE_LIST *leaves;     /* list of leves of join table tree */
 | |
|   TABLE_LIST *update_tables, *table_being_updated;
 | |
|   TABLE **tmp_tables, *main_table, *table_to_update;
 | |
|   TMP_TABLE_PARAM *tmp_table_param;
 | |
|   ha_rows updated, found;
 | |
|   List <Item> *fields, *values;
 | |
|   List <Item> **fields_for_table, **values_for_table;
 | |
|   uint table_count;
 | |
|   Copy_field *copy_field;
 | |
|   enum enum_duplicates handle_duplicates;
 | |
|   bool do_update, trans_safe;
 | |
|   /* True if the update operation has made a change in a transactional table */
 | |
|   bool transactional_tables;
 | |
|   bool ignore;
 | |
| 
 | |
| public:
 | |
|   multi_update(TABLE_LIST *ut, TABLE_LIST *leaves_list,
 | |
| 	       List<Item> *fields, List<Item> *values,
 | |
| 	       enum_duplicates handle_duplicates, bool ignore);
 | |
|   ~multi_update();
 | |
|   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
 | |
|   bool send_data(List<Item> &items);
 | |
|   bool initialize_tables (JOIN *join);
 | |
|   void send_error(uint errcode,const char *err);
 | |
|   int  do_updates (bool from_send_error);
 | |
|   bool send_eof();
 | |
| };
 | |
| 
 | |
| class my_var : public Sql_alloc  {
 | |
| public:
 | |
|   LEX_STRING s;
 | |
| #ifndef DBUG_OFF
 | |
|   /*
 | |
|     Routine to which this Item_splocal belongs. Used for checking if correct
 | |
|     runtime context is used for variable handling.
 | |
|   */
 | |
|   sp_head *sp;
 | |
| #endif
 | |
|   bool local;
 | |
|   uint offset;
 | |
|   enum_field_types type;
 | |
|   my_var (LEX_STRING& j, bool i, uint o, enum_field_types t)
 | |
|     :s(j), local(i), offset(o), type(t)
 | |
|   {}
 | |
|   ~my_var() {}
 | |
| };
 | |
| 
 | |
| class select_dumpvar :public select_result_interceptor {
 | |
|   ha_rows row_count;
 | |
| public:
 | |
|   List<my_var> var_list;
 | |
|   select_dumpvar()  { var_list.empty(); row_count= 0;}
 | |
|   ~select_dumpvar() {}
 | |
|   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
 | |
|   bool send_data(List<Item> &items);
 | |
|   bool send_eof();
 | |
|   virtual bool check_simple_select() const;
 | |
|   void cleanup();
 | |
| };
 | |
| 
 | |
| /* Bits in sql_command_flags */
 | |
| 
 | |
| #define CF_CHANGES_DATA		1
 | |
| #define CF_HAS_ROW_COUNT	2
 | |
| #define CF_STATUS_COMMAND	4
 | |
| #define CF_SHOW_TABLE_COMMAND	8
 | |
| 
 | |
| /* Functions in sql_class.cc */
 | |
| 
 | |
| void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var);
 | |
| void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
 | |
|                         STATUS_VAR *dec_var);
 | |
| #endif /* MYSQL_SERVER */
 | 
