mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-30 04:26:45 +03:00 
			
		
		
		
	ALTER TABLE AND/OR PLUGIN/SEMISYNC If a plugin was uninstalled, thread local values for plugin variables of string type with PLUGIN_VAR_MEMALLOC flag were not freed. With this patch these variables are freed when thread is done (like all other variables).
		
			
				
	
	
		
			3674 lines
		
	
	
		
			118 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
			
		
		
	
	
			3674 lines
		
	
	
		
			118 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
	
	
| /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or modify
 | |
|    it under the terms of the GNU General Public License as published by
 | |
|    the Free Software Foundation; version 2 of the License.
 | |
| 
 | |
|    This program is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|    GNU General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU General Public License
 | |
|    along with this program; if not, write to the Free Software
 | |
|    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 | |
| 
 | |
| 
 | |
| #ifndef SQL_CLASS_INCLUDED
 | |
| #define SQL_CLASS_INCLUDED
 | |
| 
 | |
| /* Classes in mysql */
 | |
| 
 | |
| #ifdef USE_PRAGMA_INTERFACE
 | |
| #pragma interface			/* gcc class implementation */
 | |
| #endif
 | |
| 
 | |
| #include "my_global.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
 | |
| #ifdef MYSQL_SERVER
 | |
| #include "unireg.h"                    // REQUIRED: for other includes
 | |
| #endif
 | |
| #include "sql_const.h"
 | |
| #include <mysql/plugin_audit.h>
 | |
| #include "log.h"
 | |
| #include "rpl_tblmap.h"
 | |
| #include "mdl.h"
 | |
| #include "sql_locale.h"                         /* my_locale_st */
 | |
| #include "sql_profile.h"                   /* PROFILING */
 | |
| #include "scheduler.h"                     /* thd_scheduler */
 | |
| #include "protocol.h"             /* Protocol_text, Protocol_binary */
 | |
| #include "violite.h"              /* vio_is_connected */
 | |
| #include "thr_lock.h"             /* thr_lock_type, THR_LOCK_DATA,
 | |
|                                      THR_LOCK_INFO */
 | |
| 
 | |
| 
 | |
| class Reprepare_observer;
 | |
| class Relay_log_info;
 | |
| 
 | |
| class Query_log_event;
 | |
| class Load_log_event;
 | |
| class Slave_log_event;
 | |
| class sp_rcontext;
 | |
| class sp_cache;
 | |
| class Parser_state;
 | |
| class Rows_log_event;
 | |
| class Sroutine_hash_entry;
 | |
| class User_level_lock;
 | |
| class user_var_entry;
 | |
| 
 | |
| 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_slave_exec_mode { SLAVE_EXEC_MODE_STRICT,
 | |
|                             SLAVE_EXEC_MODE_IDEMPOTENT,
 | |
|                             SLAVE_EXEC_MODE_LAST_BIT};
 | |
| enum enum_slave_type_conversions { SLAVE_TYPE_CONVERSIONS_ALL_LOSSY,
 | |
|                                    SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY};
 | |
| enum enum_mark_columns
 | |
| { MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE};
 | |
| enum enum_filetype { FILETYPE_CSV, FILETYPE_XML };
 | |
| 
 | |
| /* Bits for different SQL modes modes (including ANSI mode) */
 | |
| #define MODE_REAL_AS_FLOAT              1
 | |
| #define MODE_PIPES_AS_CONCAT            2
 | |
| #define MODE_ANSI_QUOTES                4
 | |
| #define MODE_IGNORE_SPACE               8
 | |
| #define MODE_NOT_USED                   16
 | |
| #define MODE_ONLY_FULL_GROUP_BY         32
 | |
| #define MODE_NO_UNSIGNED_SUBTRACTION    64
 | |
| #define MODE_NO_DIR_IN_CREATE           128
 | |
| #define MODE_POSTGRESQL                 256
 | |
| #define MODE_ORACLE                     512
 | |
| #define MODE_MSSQL                      1024
 | |
| #define MODE_DB2                        2048
 | |
| #define MODE_MAXDB                      4096
 | |
| #define MODE_NO_KEY_OPTIONS             8192
 | |
| #define MODE_NO_TABLE_OPTIONS           16384
 | |
| #define MODE_NO_FIELD_OPTIONS           32768
 | |
| #define MODE_MYSQL323                   65536L
 | |
| #define MODE_MYSQL40                    (MODE_MYSQL323*2)
 | |
| #define MODE_ANSI                       (MODE_MYSQL40*2)
 | |
| #define MODE_NO_AUTO_VALUE_ON_ZERO      (MODE_ANSI*2)
 | |
| #define MODE_NO_BACKSLASH_ESCAPES       (MODE_NO_AUTO_VALUE_ON_ZERO*2)
 | |
| #define MODE_STRICT_TRANS_TABLES        (MODE_NO_BACKSLASH_ESCAPES*2)
 | |
| #define MODE_STRICT_ALL_TABLES          (MODE_STRICT_TRANS_TABLES*2)
 | |
| #define MODE_NO_ZERO_IN_DATE            (MODE_STRICT_ALL_TABLES*2)
 | |
| #define MODE_NO_ZERO_DATE               (MODE_NO_ZERO_IN_DATE*2)
 | |
| #define MODE_INVALID_DATES              (MODE_NO_ZERO_DATE*2)
 | |
| #define MODE_ERROR_FOR_DIVISION_BY_ZERO (MODE_INVALID_DATES*2)
 | |
| #define MODE_TRADITIONAL                (MODE_ERROR_FOR_DIVISION_BY_ZERO*2)
 | |
| #define MODE_NO_AUTO_CREATE_USER        (MODE_TRADITIONAL*2)
 | |
| #define MODE_HIGH_NOT_PRECEDENCE        (MODE_NO_AUTO_CREATE_USER*2)
 | |
| #define MODE_NO_ENGINE_SUBSTITUTION     (MODE_HIGH_NOT_PRECEDENCE*2)
 | |
| #define MODE_PAD_CHAR_TO_FULL_LENGTH    (ULL(1) << 31)
 | |
| 
 | |
| extern char internal_table_name[2];
 | |
| extern char empty_c_string[1];
 | |
| extern MYSQL_PLUGIN_IMPORT const char **errmesg;
 | |
| 
 | |
| extern bool volatile shutdown_in_progress;
 | |
| 
 | |
| extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd);
 | |
| extern "C" char **thd_query(MYSQL_THD thd);
 | |
| 
 | |
| /**
 | |
|   @class CSET_STRING
 | |
|   @brief Character set armed LEX_STRING
 | |
| */
 | |
| class CSET_STRING
 | |
| {
 | |
| private:
 | |
|   LEX_STRING string;
 | |
|   CHARSET_INFO *cs;
 | |
| public:
 | |
|   CSET_STRING() : cs(&my_charset_bin)
 | |
|   {
 | |
|     string.str= NULL;
 | |
|     string.length= 0;
 | |
|   }
 | |
|   CSET_STRING(char *str_arg, size_t length_arg, CHARSET_INFO *cs_arg) :
 | |
|   cs(cs_arg)
 | |
|   {
 | |
|     DBUG_ASSERT(cs_arg != NULL);
 | |
|     string.str= str_arg;
 | |
|     string.length= length_arg;
 | |
|   }
 | |
| 
 | |
|   inline char *str() const { return string.str; }
 | |
|   inline uint32 length() const { return string.length; }
 | |
|   CHARSET_INFO *charset() const { return cs; }
 | |
| 
 | |
|   friend LEX_STRING * thd_query_string (MYSQL_THD thd);
 | |
|   friend char **thd_query(MYSQL_THD thd);
 | |
| };
 | |
| 
 | |
| 
 | |
| #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 ulong 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;
 | |
|   bool unsigned_flag;
 | |
| } BINLOG_USER_VAR_EVENT;
 | |
| 
 | |
| /*
 | |
|   The COPY_INFO structure is used by INSERT/REPLACE code.
 | |
|   The schema of the row counting by the INSERT/INSERT ... ON DUPLICATE KEY
 | |
|   UPDATE code:
 | |
|     If a row is inserted then the copied variable is incremented.
 | |
|     If a row is updated by the INSERT ... ON DUPLICATE KEY UPDATE and the
 | |
|       new data differs from the old one then the copied and the updated
 | |
|       variables are incremented.
 | |
|     The touched variable is incremented if a row was touched by the update part
 | |
|       of the INSERT ... ON DUPLICATE KEY UPDATE no matter whether the row
 | |
|       was actually changed or not.
 | |
| */
 | |
| typedef struct st_copy_info {
 | |
|   ha_rows records; /**< Number of processed records */
 | |
|   ha_rows deleted; /**< Number of deleted records */
 | |
|   ha_rows updated; /**< Number of updated records */
 | |
|   ha_rows copied;  /**< Number of copied records */
 | |
|   ha_rows error_count;
 | |
|   ha_rows touched; /* Number of touched records */
 | |
|   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:
 | |
|   LEX_STRING field_name;
 | |
|   uint length;
 | |
|   Key_part_spec(const LEX_STRING &name, uint len)
 | |
|     : field_name(name), length(len)
 | |
|   {}
 | |
|   Key_part_spec(const char *name, const size_t name_len, uint len)
 | |
|     : length(len)
 | |
|   { field_name.str= (char *)name; field_name.length= name_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;
 | |
|   LEX_STRING name;
 | |
|   bool generated;
 | |
| 
 | |
|   Key(enum Keytype type_par, const LEX_STRING &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(enum Keytype type_par, const char *name_arg, size_t name_len_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),
 | |
|     generated(generated_arg)
 | |
|   {
 | |
|     name.str= (char *)name_arg;
 | |
|     name.length= name_len_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 LEX_STRING &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(ref_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) {}
 | |
| };
 | |
| 
 | |
| class MY_LOCALE;
 | |
| 
 | |
| /**
 | |
|   Query_cache_tls -- query cache thread local data.
 | |
| */
 | |
| 
 | |
| struct Query_cache_block;
 | |
| 
 | |
| struct Query_cache_tls
 | |
| {
 | |
|   /*
 | |
|     'first_query_block' should be accessed only via query cache
 | |
|     functions and methods to maintain proper locking.
 | |
|   */
 | |
|   Query_cache_block *first_query_block;
 | |
|   void set_first_query_block(Query_cache_block *first_query_block_arg)
 | |
|   {
 | |
|     first_query_block= first_query_block_arg;
 | |
|   }
 | |
| 
 | |
|   Query_cache_tls() :first_query_block(NULL) {}
 | |
| };
 | |
| 
 | |
| /* SIGNAL / RESIGNAL / GET DIAGNOSTICS */
 | |
| 
 | |
| /**
 | |
|   This enumeration list all the condition item names of a condition in the
 | |
|   SQL condition area.
 | |
| */
 | |
| typedef enum enum_diag_condition_item_name
 | |
| {
 | |
|   /*
 | |
|     Conditions that can be set by the user (SIGNAL/RESIGNAL),
 | |
|     and by the server implementation.
 | |
|   */
 | |
| 
 | |
|   DIAG_CLASS_ORIGIN= 0,
 | |
|   FIRST_DIAG_SET_PROPERTY= DIAG_CLASS_ORIGIN,
 | |
|   DIAG_SUBCLASS_ORIGIN= 1,
 | |
|   DIAG_CONSTRAINT_CATALOG= 2,
 | |
|   DIAG_CONSTRAINT_SCHEMA= 3,
 | |
|   DIAG_CONSTRAINT_NAME= 4,
 | |
|   DIAG_CATALOG_NAME= 5,
 | |
|   DIAG_SCHEMA_NAME= 6,
 | |
|   DIAG_TABLE_NAME= 7,
 | |
|   DIAG_COLUMN_NAME= 8,
 | |
|   DIAG_CURSOR_NAME= 9,
 | |
|   DIAG_MESSAGE_TEXT= 10,
 | |
|   DIAG_MYSQL_ERRNO= 11,
 | |
|   LAST_DIAG_SET_PROPERTY= DIAG_MYSQL_ERRNO
 | |
| } Diag_condition_item_name;
 | |
| 
 | |
| /**
 | |
|   Name of each diagnostic condition item.
 | |
|   This array is indexed by Diag_condition_item_name.
 | |
| */
 | |
| extern const LEX_STRING Diag_condition_item_names[];
 | |
| 
 | |
| #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)
 | |
| 
 | |
| typedef 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 */
 | |
|   LIST *dynamic_variables_allocs; /* memory hunks for PLUGIN_VAR_MEMALLOC */
 | |
|   
 | |
|   ulonglong max_heap_table_size;
 | |
|   ulonglong tmp_table_size;
 | |
|   ulonglong long_query_time;
 | |
|   ulonglong optimizer_switch;
 | |
|   ulonglong sql_mode; ///< which non-standard SQL behaviour should be enabled
 | |
|   ulonglong option_bits; ///< OPTION_xxx constants, e.g. OPTION_PROFILING
 | |
|   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 lock_wait_timeout;
 | |
|   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 min_examined_row_limit;
 | |
|   ulong multi_range_count;
 | |
|   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 profiling_history_size;
 | |
|   ulong read_buff_size;
 | |
|   ulong read_rnd_buff_size;
 | |
|   ulong div_precincrement;
 | |
|   ulong sortbuff_size;
 | |
|   ulong max_sp_recursion_depth;
 | |
|   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 binlog_format; ///< binlog format for this thd (see enum_binlog_format)
 | |
|   my_bool binlog_direct_non_trans_update;
 | |
|   my_bool sql_log_bin;
 | |
|   ulong completion_type;
 | |
|   ulong query_cache_type;
 | |
|   ulong tx_isolation;
 | |
|   ulong updatable_views_with_limit;
 | |
|   uint max_user_connections;
 | |
|   /**
 | |
|     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;
 | |
|   my_bool query_cache_wlock_invalidate;
 | |
|   my_bool engine_condition_pushdown;
 | |
|   my_bool keep_files_on_create;
 | |
| 
 | |
|   my_bool old_alter_table;
 | |
|   my_bool old_passwords;
 | |
|   my_bool big_tables;
 | |
| 
 | |
|   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;
 | |
| 
 | |
|   /* Error messages */
 | |
|   MY_LOCALE *lc_messages;
 | |
|   /* Locale Support */
 | |
|   MY_LOCALE *lc_time_names;
 | |
| 
 | |
|   Time_zone *time_zone;
 | |
| 
 | |
|   my_bool sysdate_is_now;
 | |
| 
 | |
|   double long_query_time_double;
 | |
| 
 | |
| } SV;
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Per thread status variables.
 | |
|   Must be long/ulong up to last_system_status_var so that
 | |
|   add_to_status/add_diff_to_status can work.
 | |
| */
 | |
| 
 | |
| typedef struct system_status_var
 | |
| {
 | |
|   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_reprepare;
 | |
|   ulong com_stmt_execute;
 | |
|   ulong com_stmt_send_long_data;
 | |
|   ulong com_stmt_fetch;
 | |
|   ulong com_stmt_reset;
 | |
|   ulong com_stmt_close;
 | |
|   /*
 | |
|     Number of statements sent from the client
 | |
|   */
 | |
|   ulong questions;
 | |
| 
 | |
|   ulonglong bytes_received;
 | |
|   ulonglong bytes_sent;
 | |
|   /*
 | |
|     IMPORTANT!
 | |
|     SEE last_system_status_var DEFINITION BELOW.
 | |
|     Below 'last_system_status_var' are all variables that cannot be handled
 | |
|     automatically by add_to_status()/add_diff_to_status().
 | |
|   */
 | |
|   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 questions
 | |
| 
 | |
| void mark_transaction_to_rollback(THD *thd, bool all);
 | |
| 
 | |
| #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; is_reprepared= FALSE;
 | |
| #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. */
 | |
|   bool is_reprepared;
 | |
| #endif
 | |
|   /*
 | |
|     The states relfects three diffrent life cycles for three
 | |
|     different types of statements:
 | |
|     Prepared statement: STMT_INITIALIZED -> STMT_PREPARED -> STMT_EXECUTED.
 | |
|     Stored procedure:   STMT_INITIALIZED_FOR_SP -> STMT_EXECUTED.
 | |
|     Other statements:   STMT_CONVENTIONAL_EXECUTION never changes.
 | |
|   */
 | |
|   enum enum_state
 | |
|   {
 | |
|     STMT_INITIALIZED= 0, STMT_INITIALIZED_FOR_SP= 1, STMT_PREPARED= 2,
 | |
|     STMT_CONVENTIONAL_EXECUTION= 3, STMT_EXECUTED= 4, STMT_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 == STMT_INITIALIZED; }
 | |
|   inline bool is_stmt_prepare_or_first_sp_execute() const
 | |
|   { return (int)state < (int)STMT_PREPARED; }
 | |
|   inline bool is_stmt_prepare_or_first_stmt_execute() const
 | |
|   { return (int)state <= (int)STMT_PREPARED; }
 | |
|   inline bool is_conventional() const
 | |
|   { return state == STMT_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 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 if we set query = NULL, we must at the same time set
 | |
|     query_length = 0, and protect the whole operation with
 | |
|     LOCK_thd_data mutex. To avoid crashes in races, if we do not
 | |
|     know that thd->query cannot change at the moment, we should print
 | |
|     thd->query like this:
 | |
|       (1) reserve the LOCK_thd_data mutex;
 | |
|       (2) print or copy the value of query and query_length
 | |
|       (3) release LOCK_thd_data mutex.
 | |
|     This printing is needed at least in SHOW PROCESSLIST and SHOW
 | |
|     ENGINE INNODB STATUS.
 | |
|   */
 | |
|   CSET_STRING query_string;
 | |
| 
 | |
|   inline char *query() const { return query_string.str(); }
 | |
|   inline uint32 query_length() const { return query_string.length(); }
 | |
|   CHARSET_INFO *query_charset() const { return query_string.charset(); }
 | |
|   void set_query_inner(const CSET_STRING &string_arg)
 | |
|   {
 | |
|     query_string= string_arg;
 | |
|   }
 | |
|   void set_query_inner(char *query_arg, uint32 query_length_arg,
 | |
|                        CHARSET_INFO *cs_arg)
 | |
|   {
 | |
|     set_query_inner(CSET_STRING(query_arg, query_length_arg, cs_arg));
 | |
|   }
 | |
|   void reset_query_inner()
 | |
|   {
 | |
|     set_query_inner(CSET_STRING());
 | |
|   }
 | |
|   /**
 | |
|     Name of the current (default) database.
 | |
| 
 | |
|     If there is the current (default) database, "db" contains its name. If
 | |
|     there is no current (default) database, "db" is NULL and "db_length" is
 | |
|     0. In other words, "db", "db_length" must either be NULL, or contain a
 | |
|     valid database name.
 | |
| 
 | |
|     @note this attribute is 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 this member.
 | |
|   */
 | |
| 
 | |
|   char *db;
 | |
|   size_t db_length;
 | |
| 
 | |
| 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 */
 | |
|   virtual 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*)my_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 *) my_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;
 | |
|   Ha_trx_info         *ha_list;
 | |
|   /** State of metadata locks before this savepoint was set. */
 | |
|   MDL_savepoint        mdl_savepoint;
 | |
| };
 | |
| 
 | |
| enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED, XA_ROLLBACK_ONLY};
 | |
| 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;
 | |
|   /* Error reported by the Resource Manager (RM) to the Transaction Manager. */
 | |
|   uint rm_error;
 | |
| } XID_STATE;
 | |
| 
 | |
| extern mysql_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, *ip;
 | |
|   char   priv_user[USERNAME_LENGTH];
 | |
|   char   proxy_user[USERNAME_LENGTH + MAX_HOSTNAME + 5];
 | |
|   /* The host privilege we are using */
 | |
|   char   priv_host[MAX_HOSTNAME];
 | |
|   /* The external user (if available) */
 | |
|   char   *external_user;
 | |
|   /* 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
 | |
|   bool user_matches(Security_context *);
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   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 locked tables mode.
 | |
|   See comment for THD::locked_tables_mode for complete description.
 | |
| */
 | |
| 
 | |
| enum enum_locked_tables_mode
 | |
| {
 | |
|   LTM_NONE= 0,
 | |
|   LTM_LOCK_TABLES,
 | |
|   LTM_PRELOCKED,
 | |
|   LTM_PRELOCKED_UNDER_LOCK_TABLES
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   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:
 | |
|   /**
 | |
|     As part of class THD, this member is set during execution
 | |
|     of a prepared statement. When it is set, it is used
 | |
|     by the locking subsystem to report a change in table metadata.
 | |
| 
 | |
|     When Open_tables_state part of THD is reset to open
 | |
|     a system or INFORMATION_SCHEMA table, the member is cleared
 | |
|     to avoid spurious ER_NEED_REPREPARE errors -- system and
 | |
|     INFORMATION_SCHEMA tables are not subject to metadata version
 | |
|     tracking.
 | |
|     @sa check_and_update_table_version()
 | |
|   */
 | |
|   Reprepare_observer *m_reprepare_observer;
 | |
| 
 | |
|   /**
 | |
|     List of regular tables in use by this thread. Contains temporary and
 | |
|     base tables that were opened with @see open_tables().
 | |
|   */
 | |
|   TABLE *open_tables;
 | |
|   /**
 | |
|     List of temporary tables used by this thread. Contains user-level
 | |
|     temporary tables, created with CREATE TEMPORARY TABLE, and
 | |
|     internal temporary tables, created, e.g., to resolve a SELECT,
 | |
|     or for an intermediate table used in ALTER.
 | |
|     XXX Why are internal temporary tables added to this list?
 | |
|   */
 | |
|   TABLE *temporary_tables;
 | |
|   TABLE *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 also stored in this member, however,
 | |
|     thd->locked_tables_mode is turned on.  Manual locking is described in
 | |
|     the 'LOCK_TABLES' chapter of the MySQL manual.
 | |
|     See also lock_tables() for details.
 | |
|   */
 | |
|   MYSQL_LOCK *lock;
 | |
| 
 | |
|   /*
 | |
|     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;
 | |
| 
 | |
|   /*
 | |
|     Enum enum_locked_tables_mode and locked_tables_mode member are
 | |
|     used to indicate whether the so-called "locked tables mode" is on,
 | |
|     and what kind of mode is active.
 | |
| 
 | |
|     Locked tables mode is used when it's necessary to open and
 | |
|     lock many tables at once, for usage across multiple
 | |
|     (sub-)statements.
 | |
|     This may be necessary either for queries that use stored functions
 | |
|     and triggers, in which case the statements inside functions and
 | |
|     triggers may be executed many times, or for implementation of
 | |
|     LOCK TABLES, in which case the opened tables are reused by all
 | |
|     subsequent statements until a call to UNLOCK TABLES.
 | |
| 
 | |
|     The kind of locked tables mode employed for stored functions and
 | |
|     triggers is also called "prelocked mode".
 | |
|     In this mode, first open_tables() call to open the tables used
 | |
|     in a statement analyses all functions used by the statement
 | |
|     and adds all indirectly used tables to the list of tables to
 | |
|     open and lock.
 | |
|     It also marks the parse tree of the statement as requiring
 | |
|     prelocking. After that, lock_tables() locks the entire list
 | |
|     of tables and changes THD::locked_tables_modeto LTM_PRELOCKED.
 | |
|     All statements executed inside functions or triggers
 | |
|     use the prelocked tables, instead of opening their own ones.
 | |
|     Prelocked mode is turned off automatically once close_thread_tables()
 | |
|     of the main statement is called.
 | |
|   */
 | |
|   enum enum_locked_tables_mode locked_tables_mode;
 | |
|   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 initializes Open_tables_state instance which can only
 | |
|      be used as backup storage. To prepare Open_tables_state instance for
 | |
|      operations which open/lock/close tables (e.g. open_table()) one has to
 | |
|      call init_open_tables_state().
 | |
|   */
 | |
|   Open_tables_state() : state_flags(0U) { }
 | |
| 
 | |
|   void set_open_tables_state(Open_tables_state *state)
 | |
|   {
 | |
|     *this= *state;
 | |
|   }
 | |
| 
 | |
|   void reset_open_tables_state(THD *thd)
 | |
|   {
 | |
|     open_tables= temporary_tables= derived_tables= 0;
 | |
|     extra_lock= lock= 0;
 | |
|     locked_tables_mode= LTM_NONE;
 | |
|     state_flags= 0U;
 | |
|     m_reprepare_observer= NULL;
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Storage for backup of Open_tables_state. Must
 | |
|   be used only to open system tables (TABLE_CATEGORY_SYSTEM
 | |
|   and TABLE_CATEGORY_LOG).
 | |
| */
 | |
| 
 | |
| class Open_tables_backup: public Open_tables_state
 | |
| {
 | |
| public:
 | |
|   /**
 | |
|     When we backup the open tables state to open a system
 | |
|     table or tables, we want to save state of metadata
 | |
|     locks which were acquired before the backup. It is used
 | |
|     to release metadata locks on system tables after they are
 | |
|     no longer used.
 | |
|   */
 | |
|   MDL_savepoint mdl_system_tables_svp;
 | |
| };
 | |
| 
 | |
| /**
 | |
|   @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 option_bits;
 | |
|   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;
 | |
|   Discrete_intervals_list auto_inc_intervals_forced;
 | |
|   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;
 | |
|   SAVEPOINT *savepoints;
 | |
|   enum enum_check_fields count_cuted_fields;
 | |
| };
 | |
| 
 | |
| 
 | |
| /* 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
 | |
| };
 | |
| 
 | |
| inline char const *
 | |
| show_system_thread(enum_thread_type thread)
 | |
| {
 | |
| #define RETURN_NAME_AS_STRING(NAME) case (NAME): return #NAME
 | |
|   switch (thread) {
 | |
|     static char buf[64];
 | |
|     RETURN_NAME_AS_STRING(NON_SYSTEM_THREAD);
 | |
|     RETURN_NAME_AS_STRING(SYSTEM_THREAD_DELAYED_INSERT);
 | |
|     RETURN_NAME_AS_STRING(SYSTEM_THREAD_SLAVE_IO);
 | |
|     RETURN_NAME_AS_STRING(SYSTEM_THREAD_SLAVE_SQL);
 | |
|     RETURN_NAME_AS_STRING(SYSTEM_THREAD_NDBCLUSTER_BINLOG);
 | |
|     RETURN_NAME_AS_STRING(SYSTEM_THREAD_EVENT_SCHEDULER);
 | |
|     RETURN_NAME_AS_STRING(SYSTEM_THREAD_EVENT_WORKER);
 | |
|   default:
 | |
|     sprintf(buf, "<UNKNOWN SYSTEM THREAD: %d>", thread);
 | |
|     return buf;
 | |
|   }
 | |
| #undef RETURN_NAME_AS_STRING
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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() :
 | |
|     m_prev_internal_handler(NULL)
 | |
|   {}
 | |
| 
 | |
|   virtual ~Internal_error_handler() {}
 | |
| 
 | |
| public:
 | |
|   /**
 | |
|     Handle a sql condition.
 | |
|     This method can be implemented by a subclass to achieve any of the
 | |
|     following:
 | |
|     - mask a warning/error internally, prevent exposing it to the user,
 | |
|     - mask a warning/error and throw another one instead.
 | |
|     When this method returns true, the sql 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 thd the calling thread
 | |
|     @param cond the condition raised.
 | |
|     @return true if the condition is handled
 | |
|   */
 | |
|   virtual bool handle_condition(THD *thd,
 | |
|                                 uint sql_errno,
 | |
|                                 const char* sqlstate,
 | |
|                                 MYSQL_ERROR::enum_warning_level level,
 | |
|                                 const char* msg,
 | |
|                                 MYSQL_ERROR ** cond_hdl) = 0;
 | |
| 
 | |
| private:
 | |
|   Internal_error_handler *m_prev_internal_handler;
 | |
|   friend class THD;
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Implements the trivial error handler which cancels all error states
 | |
|   and prevents an SQLSTATE to be set.
 | |
| */
 | |
| 
 | |
| class Dummy_error_handler : public Internal_error_handler
 | |
| {
 | |
| public:
 | |
|   bool handle_condition(THD *thd,
 | |
|                         uint sql_errno,
 | |
|                         const char* sqlstate,
 | |
|                         MYSQL_ERROR::enum_warning_level level,
 | |
|                         const char* msg,
 | |
|                         MYSQL_ERROR ** cond_hdl)
 | |
|   {
 | |
|     /* Ignore error */
 | |
|     return TRUE;
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This class is an internal error handler implementation for
 | |
|   DROP TABLE statements. The thing is that there may be warnings during
 | |
|   execution of these statements, which should not be exposed to the user.
 | |
|   This class is intended to silence such warnings.
 | |
| */
 | |
| 
 | |
| class Drop_table_error_handler : public Internal_error_handler
 | |
| {
 | |
| public:
 | |
|   Drop_table_error_handler() {}
 | |
| 
 | |
| public:
 | |
|   bool handle_condition(THD *thd,
 | |
|                         uint sql_errno,
 | |
|                         const char* sqlstate,
 | |
|                         MYSQL_ERROR::enum_warning_level level,
 | |
|                         const char* msg,
 | |
|                         MYSQL_ERROR ** cond_hdl);
 | |
| 
 | |
| private:
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Tables that were locked with LOCK TABLES statement.
 | |
| 
 | |
|   Encapsulates a list of TABLE_LIST instances for tables
 | |
|   locked by LOCK TABLES statement, memory root for metadata locks,
 | |
|   and, generally, the context of LOCK TABLES statement.
 | |
| 
 | |
|   In LOCK TABLES mode, the locked tables are kept open between
 | |
|   statements.
 | |
|   Therefore, we can't allocate metadata locks on execution memory
 | |
|   root -- as well as tables, the locks need to stay around till
 | |
|   UNLOCK TABLES is called.
 | |
|   The locks are allocated in the memory root encapsulated in this
 | |
|   class.
 | |
| 
 | |
|   Some SQL commands, like FLUSH TABLE or ALTER TABLE, demand that
 | |
|   the tables they operate on are closed, at least temporarily.
 | |
|   This class encapsulates a list of TABLE_LIST instances, one
 | |
|   for each base table from LOCK TABLES list,
 | |
|   which helps conveniently close the TABLEs when it's necessary
 | |
|   and later reopen them.
 | |
| 
 | |
|   Implemented in sql_base.cc
 | |
| */
 | |
| 
 | |
| class Locked_tables_list
 | |
| {
 | |
| private:
 | |
|   MEM_ROOT m_locked_tables_root;
 | |
|   TABLE_LIST *m_locked_tables;
 | |
|   TABLE_LIST **m_locked_tables_last;
 | |
|   /** An auxiliary array used only in reopen_tables(). */
 | |
|   TABLE **m_reopen_array;
 | |
|   /**
 | |
|     Count the number of tables in m_locked_tables list. We can't
 | |
|     rely on thd->lock->table_count because it excludes
 | |
|     non-transactional temporary tables. We need to know
 | |
|     an exact number of TABLE objects.
 | |
|   */
 | |
|   size_t m_locked_tables_count;
 | |
| public:
 | |
|   Locked_tables_list()
 | |
|     :m_locked_tables(NULL),
 | |
|     m_locked_tables_last(&m_locked_tables),
 | |
|     m_reopen_array(NULL),
 | |
|     m_locked_tables_count(0)
 | |
|   {
 | |
|     init_sql_alloc(&m_locked_tables_root, MEM_ROOT_BLOCK_SIZE, 0);
 | |
|   }
 | |
|   void unlock_locked_tables(THD *thd);
 | |
|   ~Locked_tables_list()
 | |
|   {
 | |
|     unlock_locked_tables(0);
 | |
|   }
 | |
|   bool init_locked_tables(THD *thd);
 | |
|   TABLE_LIST *locked_tables() { return m_locked_tables; }
 | |
|   void unlink_from_list(THD *thd, TABLE_LIST *table_list,
 | |
|                         bool remove_from_locked_tables);
 | |
|   void unlink_all_closed_tables(THD *thd,
 | |
|                                 MYSQL_LOCK *lock,
 | |
|                                 size_t reopen_count);
 | |
|   bool reopen_tables(THD *thd);
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Storage engine specific thread local data.
 | |
| */
 | |
| 
 | |
| struct Ha_data
 | |
| {
 | |
|   /**
 | |
|     Storage engine specific thread local data.
 | |
|     Lifetime: one user connection.
 | |
|   */
 | |
|   void *ha_ptr;
 | |
|   /**
 | |
|     0: Life time: one statement within a transaction. If @@autocommit is
 | |
|     on, also represents the entire transaction.
 | |
|     @sa trans_register_ha()
 | |
| 
 | |
|     1: Life time: one transaction within a connection.
 | |
|     If the storage engine does not participate in a transaction,
 | |
|     this should not be used.
 | |
|     @sa trans_register_ha()
 | |
|   */
 | |
|   Ha_trx_info ha_info[2];
 | |
|   /**
 | |
|     NULL: engine is not bound to this thread
 | |
|     non-NULL: engine is bound to this thread, engine shutdown forbidden
 | |
|   */
 | |
|   plugin_ref lock;
 | |
|   Ha_data() :ha_ptr(NULL) {}
 | |
| };
 | |
| 
 | |
| /**
 | |
|   An instance of the global read lock in a connection.
 | |
|   Implemented in lock.cc.
 | |
| */
 | |
| 
 | |
| class Global_read_lock
 | |
| {
 | |
| public:
 | |
|   enum enum_grl_state
 | |
|   {
 | |
|     GRL_NONE,
 | |
|     GRL_ACQUIRED,
 | |
|     GRL_ACQUIRED_AND_BLOCKS_COMMIT
 | |
|   };
 | |
| 
 | |
|   Global_read_lock()
 | |
|     : m_state(GRL_NONE),
 | |
|       m_mdl_global_shared_lock(NULL),
 | |
|       m_mdl_blocks_commits_lock(NULL)
 | |
|   {}
 | |
| 
 | |
|   bool lock_global_read_lock(THD *thd);
 | |
|   void unlock_global_read_lock(THD *thd);
 | |
|   /**
 | |
|     Check if this connection can acquire protection against GRL and
 | |
|     emit error if otherwise.
 | |
|   */
 | |
|   bool can_acquire_protection() const
 | |
|   {
 | |
|     if (m_state)
 | |
|     {
 | |
|       my_error(ER_CANT_UPDATE_WITH_READLOCK, MYF(0));
 | |
|       return TRUE;
 | |
|     }
 | |
|     return FALSE;
 | |
|   }
 | |
|   bool make_global_read_lock_block_commit(THD *thd);
 | |
|   bool is_acquired() const { return m_state != GRL_NONE; }
 | |
|   void set_explicit_lock_duration(THD *thd);
 | |
| private:
 | |
|   enum_grl_state m_state;
 | |
|   /**
 | |
|     In order to acquire the global read lock, the connection must
 | |
|     acquire shared metadata lock in GLOBAL namespace, to prohibit
 | |
|     all DDL.
 | |
|   */
 | |
|   MDL_ticket *m_mdl_global_shared_lock;
 | |
|   /**
 | |
|     Also in order to acquire the global read lock, the connection
 | |
|     must acquire a shared metadata lock in COMMIT namespace, to
 | |
|     prohibit commits.
 | |
|   */
 | |
|   MDL_ticket *m_mdl_blocks_commits_lock;
 | |
| };
 | |
| 
 | |
| 
 | |
| extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
 | |
| 
 | |
| /**
 | |
|   @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
 | |
| {
 | |
| private:
 | |
|   inline bool is_stmt_prepare() const
 | |
|   { DBUG_ASSERT(0); return Statement::is_stmt_prepare(); }
 | |
| 
 | |
|   inline bool is_stmt_prepare_or_first_sp_execute() const
 | |
|   { DBUG_ASSERT(0); return Statement::is_stmt_prepare_or_first_sp_execute(); }
 | |
| 
 | |
|   inline bool is_stmt_prepare_or_first_stmt_execute() const
 | |
|   { DBUG_ASSERT(0); return Statement::is_stmt_prepare_or_first_stmt_execute(); }
 | |
| 
 | |
|   inline bool is_conventional() const
 | |
|   { DBUG_ASSERT(0); return Statement::is_conventional(); }
 | |
| 
 | |
| public:
 | |
|   MDL_context mdl_context;
 | |
| 
 | |
|   /* Used to execute base64 coded binlog events in MySQL server */
 | |
|   Relay_log_info* rli_fake;
 | |
| 
 | |
|   void reset_for_next_command();
 | |
|   /*
 | |
|     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
 | |
| #ifdef HAVE_QUERY_CACHE
 | |
|   Query_cache_tls query_cache_tls;
 | |
| #endif
 | |
|   NET	  net;				// client connection descriptor
 | |
|   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  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
 | |
|   /**
 | |
|     Protects THD data accessed from other threads:
 | |
|     - thd->query and thd->query_length (used by SHOW ENGINE
 | |
|       INNODB STATUS and SHOW PROCESSLIST
 | |
|     - thd->mysys_var (used by KILL statement and shutdown).
 | |
|     Is locked when THD is deleted.
 | |
|   */
 | |
|   mysql_mutex_t LOCK_thd_data;
 | |
| 
 | |
|   /* 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;
 | |
| 
 | |
|   /**
 | |
|     Currently selected catalog.
 | |
|   */
 | |
|   char *catalog;
 | |
| 
 | |
|   /**
 | |
|     @note
 | |
|     Some members of THD (currently 'Statement::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.
 | |
| 
 | |
|     @see handle_slave_sql
 | |
|   */
 | |
| 
 | |
|   Security_context main_security_ctx;
 | |
|   Security_context *security_ctx;
 | |
| 
 | |
|   /*
 | |
|     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.
 | |
| 
 | |
|     Set it using the  thd_proc_info(THD *thread, const char *message)
 | |
|     macro/function.
 | |
| 
 | |
|     This member is accessed and assigned without any synchronization.
 | |
|     Therefore, it may point only to constant (statically
 | |
|     allocated) strings, which memory won't go away over time.
 | |
|   */
 | |
|   const char *proc_info;
 | |
| 
 | |
|   /*
 | |
|     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;
 | |
| 
 | |
|   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
 | |
|   /* remote (peer) port */
 | |
|   uint16 peer_port;
 | |
|   time_t     start_time, user_time;
 | |
|   // track down slow pthread_create
 | |
|   ulonglong  prior_thr_create_utime, thr_create_utime;
 | |
|   ulonglong  start_utime, utime_after_lock;
 | |
| 
 | |
|   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 */
 | |
|   Ha_data 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();
 | |
|   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(bool is_transactional) const;
 | |
|   void binlog_set_pending_rows_event(Rows_log_event* ev, bool is_transactional);
 | |
|   inline int binlog_flush_pending_rows_event(bool stmt_end)
 | |
|   {
 | |
|     return (binlog_flush_pending_rows_event(stmt_end, FALSE) || 
 | |
|             binlog_flush_pending_rows_event(stmt_end, TRUE));
 | |
|   }
 | |
|   int binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional);
 | |
|   int binlog_remove_pending_rows_event(bool clear_maps, bool is_transactional);
 | |
| 
 | |
|   /**
 | |
|     Determine the binlog format of the current statement.
 | |
| 
 | |
|     @retval 0 if the current statement will be logged in statement
 | |
|     format.
 | |
|     @retval nonzero if the current statement will be logged in row
 | |
|     format.
 | |
|    */
 | |
|   int is_current_stmt_binlog_format_row() const {
 | |
|     DBUG_ASSERT(current_stmt_binlog_format == BINLOG_FORMAT_STMT ||
 | |
|                 current_stmt_binlog_format == BINLOG_FORMAT_ROW);
 | |
|     return current_stmt_binlog_format == BINLOG_FORMAT_ROW;
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   /**
 | |
|     Indicates the format in which the current statement will be
 | |
|     logged.  This can only be set from @c decide_logging_format().
 | |
|   */
 | |
|   enum_binlog_format current_stmt_binlog_format;
 | |
| 
 | |
|   /**
 | |
|     Bit field for the state of binlog warnings.
 | |
| 
 | |
|     The first Lex::BINLOG_STMT_UNSAFE_COUNT bits list all types of
 | |
|     unsafeness that the current statement has.
 | |
| 
 | |
|     This must be a member of THD and not of LEX, because warnings are
 | |
|     detected and issued in different places (@c
 | |
|     decide_logging_format() and @c binlog_query(), respectively).
 | |
|     Between these calls, the THD->lex object may change; e.g., if a
 | |
|     stored routine is invoked.  Only THD persists between the calls.
 | |
|   */
 | |
|   uint32 binlog_unsafe_warning_flags;
 | |
| 
 | |
|   /*
 | |
|     Number of outstanding table maps, i.e., table maps in the
 | |
|     transaction cache.
 | |
|   */
 | |
|   uint binlog_table_maps;
 | |
| public:
 | |
|   void issue_unsafe_warnings();
 | |
| 
 | |
|   uint get_binlog_table_maps() const {
 | |
|     return binlog_table_maps;
 | |
|   }
 | |
|   void clear_binlog_table_maps() {
 | |
|     binlog_table_maps= 0;
 | |
|   }
 | |
| #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_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;
 | |
|       /*
 | |
|         If rm_error is raised, it means that this piece of a distributed
 | |
|         transaction has failed and must be rolled back. But the user must
 | |
|         rollback it explicitly, so don't start a new distributed XA until
 | |
|         then.
 | |
|       */
 | |
|       if (!xid_state.rm_error)
 | |
|         xid_state.xid.null();
 | |
|       free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
 | |
|     }
 | |
|     my_bool is_active()
 | |
|     {
 | |
|       return (all.ha_list != NULL);
 | |
|     }
 | |
|     st_transactions()
 | |
|     {
 | |
|       bzero((char*)this, sizeof(*this));
 | |
|       xid_state.xid.null();
 | |
|       init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
 | |
|     }
 | |
|   } transaction;
 | |
|   Global_read_lock global_read_lock;
 | |
|   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;
 | |
| 
 | |
|   /*
 | |
|     map for tables that will be updated for a multi-table update query
 | |
|     statement, for other query statements, this will be zero.
 | |
|   */
 | |
|   table_map table_map_for_update;
 | |
| 
 | |
|   /* 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_in_cur_stmt_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_in_cur_stmt_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.
 | |
|     This variable is cumulative: if several statements are written to binlog
 | |
|     as one (stored functions or triggers are used) this list is the
 | |
|     concatenation of all intervals reserved by all statements.
 | |
|   */
 | |
|   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_arg)
 | |
|   {
 | |
|     if (first_successful_insert_id_in_cur_stmt == 0)
 | |
|       first_successful_insert_id_in_cur_stmt= id_arg;
 | |
|   }
 | |
|   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;
 | |
| 
 | |
| private:
 | |
|   /**
 | |
|     Stores the result of ROW_COUNT() function.
 | |
| 
 | |
|     ROW_COUNT() function is a MySQL extention, but we try to keep it
 | |
|     similar to ROW_COUNT member of the GET DIAGNOSTICS stack of the SQL
 | |
|     standard (see SQL99, part 2, search for ROW_COUNT). It's value is
 | |
|     implementation defined for anything except INSERT, DELETE, UPDATE.
 | |
| 
 | |
|     ROW_COUNT is assigned according to the following rules:
 | |
| 
 | |
|       - In my_ok():
 | |
|         - for DML statements: to the number of affected rows;
 | |
|         - for DDL statements: to 0.
 | |
| 
 | |
|       - In my_eof(): to -1 to indicate that there was a result set.
 | |
| 
 | |
|         We derive this semantics from the JDBC specification, where int
 | |
|         java.sql.Statement.getUpdateCount() is defined to (sic) "return the
 | |
|         current result as an update count; if the result is a ResultSet
 | |
|         object or there are no more results, -1 is returned".
 | |
| 
 | |
|       - In my_error(): to -1 to be compatible with the MySQL C API and
 | |
|         MySQL ODBC driver.
 | |
| 
 | |
|       - For SIGNAL statements: to 0 per WL#2110 specification (see also
 | |
|         sql_signal.cc comment). Zero is used since that's the "default"
 | |
|         value of ROW_COUNT in the diagnostics area.
 | |
|   */
 | |
| 
 | |
|   longlong m_row_count_func;    /* For the ROW_COUNT() function */
 | |
| 
 | |
| public:
 | |
|   inline longlong get_row_count_func() const
 | |
|   {
 | |
|     return m_row_count_func;
 | |
|   }
 | |
| 
 | |
|   inline void set_row_count_func(longlong row_count_func)
 | |
|   {
 | |
|     m_row_count_func= row_count_func;
 | |
|   }
 | |
| 
 | |
|   ha_rows    cuted_fields;
 | |
| 
 | |
|   /*
 | |
|     number of rows we actually sent to the client, including "synthetic"
 | |
|     rows in ROLLUP etc.
 | |
|   */
 | |
|   ha_rows    sent_row_count;
 | |
| 
 | |
|   /**
 | |
|     Number of rows read and/or evaluated for a statement. Used for
 | |
|     slow log reporting.
 | |
| 
 | |
|     An examined row is defined as a row that is read and/or evaluated
 | |
|     according to a statement condition, including in
 | |
|     create_sort_index(). Rows may be counted more than once, e.g., a
 | |
|     statement including ORDER BY could possibly evaluate the row in
 | |
|     filesort() before reading it for e.g. update.
 | |
|   */
 | |
|   ha_rows    examined_row_count;
 | |
| 
 | |
|   USER_CONN *user_connect;
 | |
|   CHARSET_INFO *db_charset;
 | |
|   Warning_info *warning_info;
 | |
|   Diagnostics_area *stmt_da;
 | |
| #if defined(ENABLED_PROFILING)
 | |
|   PROFILING  profiling;
 | |
| #endif
 | |
| 
 | |
|   /*
 | |
|     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;
 | |
|   ulong      col_access;
 | |
| 
 | |
|   /* Statement id is thread-wide. This counter is used to generate ids */
 | |
|   ulong      statement_id_counter;
 | |
|   ulong	     rand_saved_seed1, rand_saved_seed2;
 | |
|   pthread_t  real_id;                           /* For debugging */
 | |
|   my_thread_id  thread_id;
 | |
|   uint	     tmp_table;
 | |
|   uint	     server_status,open_options;
 | |
|   enum enum_thread_type system_thread;
 | |
|   uint       select_number;             //number of select (used for EXPLAIN)
 | |
|   /*
 | |
|     Current or next transaction isolation level.
 | |
|     When a connection is established, the value is taken from
 | |
|     @@session.tx_isolation (default transaction isolation for
 | |
|     the session), which is in turn taken from @@global.tx_isolation
 | |
|     (the global value).
 | |
|     If there is no transaction started, this variable
 | |
|     holds the value of the next transaction's isolation level.
 | |
|     When a transaction starts, the value stored in this variable
 | |
|     becomes "actual".
 | |
|     At transaction commit or rollback, we assign this variable
 | |
|     again from @@session.tx_isolation.
 | |
|     The only statement that can otherwise change the value
 | |
|     of this variable is SET TRANSACTION ISOLATION LEVEL.
 | |
|     Its purpose is to effect the isolation level of the next
 | |
|     transaction in this session. When this statement is executed,
 | |
|     the value in this variable is changed. However, since
 | |
|     this statement is only allowed when there is no active
 | |
|     transaction, this assignment (naturally) only affects the
 | |
|     upcoming transaction.
 | |
|     At the end of the current active transaction the value is
 | |
|     be reset again from @@session.tx_isolation, as described
 | |
|     above.
 | |
|   */
 | |
|   enum_tx_isolation 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 */
 | |
| 
 | |
|   /*
 | |
|     If checking this in conjunction with a wait condition, please
 | |
|     include a check after enter_cond() if you want to avoid a race
 | |
|     condition. For details see the implementation of awake(),
 | |
|     especially the "broadcast" part.
 | |
|   */
 | |
|   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;
 | |
|   bool	     no_errors;
 | |
|   uchar      password;
 | |
|   /**
 | |
|     Set to TRUE if execution of the current compound statement
 | |
|     can not continue. In particular, disables activation of
 | |
|     CONTINUE or EXIT handlers of stored routines.
 | |
|     Reset in the end of processing of the current user request, in
 | |
|     @see mysql_reset_thd_for_next_command().
 | |
|   */
 | |
|   bool is_fatal_error;
 | |
|   /**
 | |
|     Set by a storage engine to request the entire
 | |
|     transaction (that possibly spans multiple engines) to
 | |
|     rollback. Reset in ha_rollback.
 | |
|   */
 | |
|   bool       transaction_rollback_request;
 | |
|   /**
 | |
|     TRUE if we are in a sub-statement and the current error can
 | |
|     not be safely recovered until we left the sub-statement mode.
 | |
|     In particular, disables activation of CONTINUE and EXIT
 | |
|     handlers inside sub-statements. E.g. if it is a deadlock
 | |
|     error and requires a transaction-wide rollback, this flag is
 | |
|     raised (traditionally, MySQL first has to close all the reads
 | |
|     via @see handler::ha_index_or_rnd_end() and only then perform
 | |
|     the rollback).
 | |
|     Reset to FALSE when we leave the sub-statement mode.
 | |
|   */
 | |
|   bool       is_fatal_sub_stmt_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;
 | |
|   /**
 | |
|     True if a slave error. Causes the slave to stop. Not the same
 | |
|     as the statement execution error (is_error()), since
 | |
|     a statement may be expected to return an error, e.g. because
 | |
|     it returned an error on master, and this is OK on the slave.
 | |
|   */
 | |
|   bool       is_slave_error;
 | |
|   bool       bootstrap, cleanup_done;
 | |
|   
 | |
|   /**  is set if some thread specific value(s) used in a statement. */
 | |
|   bool       thread_specific_used;
 | |
|   /**  
 | |
|     is set if a statement accesses a temporary table created through
 | |
|     CREATE TEMPORARY TABLE. 
 | |
|   */
 | |
|   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 */
 | |
|   bool	     abort_on_warning;
 | |
|   bool 	     got_warning;       /* Set on call to push_warning() */
 | |
|   /* 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;
 | |
| 
 | |
|   /** number of name_const() substitutions, see sp_head.cc:subst_spvars() */
 | |
|   uint       query_name_consts;
 | |
| 
 | |
|   /*
 | |
|     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;
 | |
| 
 | |
|   /**
 | |
|     Internal parser state.
 | |
|     Note that since the parser is not re-entrant, we keep only one parser
 | |
|     state here. This member is valid only when executing code during parsing.
 | |
|   */
 | |
|   Parser_state *m_parser_state;
 | |
| 
 | |
|   Locked_tables_list locked_tables_list;
 | |
| 
 | |
| #ifdef WITH_PARTITION_STORAGE_ENGINE
 | |
|   partition_info *work_part_info;
 | |
| #endif
 | |
| 
 | |
| #ifndef EMBEDDED_LIBRARY
 | |
|   /**
 | |
|     Array of active audit plugins which have been used by this THD.
 | |
|     This list is later iterated to invoke release_thd() on those
 | |
|     plugins.
 | |
|   */
 | |
|   DYNAMIC_ARRAY audit_class_plugins;
 | |
|   /**
 | |
|     Array of bits indicating which audit classes have already been
 | |
|     added to the list of audit plugins which are currently in use.
 | |
|   */
 | |
|   unsigned long audit_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
 | |
| #endif
 | |
| 
 | |
| #if defined(ENABLED_DEBUG_SYNC)
 | |
|   /* Debug Sync facility. See debug_sync.cc. */
 | |
|   struct st_debug_sync_control *debug_sync_control;
 | |
| #endif /* defined(ENABLED_DEBUG_SYNC) */
 | |
|   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();
 | |
|   bool restore_globals();
 | |
| #ifdef SIGNAL_WITH_VIO_CLOSE
 | |
|   inline void set_active_vio(Vio* vio)
 | |
|   {
 | |
|     mysql_mutex_lock(&LOCK_thd_data);
 | |
|     active_vio = vio;
 | |
|     mysql_mutex_unlock(&LOCK_thd_data);
 | |
|   }
 | |
|   inline void clear_active_vio()
 | |
|   {
 | |
|     mysql_mutex_lock(&LOCK_thd_data);
 | |
|     active_vio = 0;
 | |
|     mysql_mutex_unlock(&LOCK_thd_data);
 | |
|   }
 | |
|   void close_active_vio();
 | |
| #endif
 | |
|   void awake(THD::killed_state state_to_set);
 | |
| 
 | |
|   /** Disconnect the associated communication endpoint. */
 | |
|   void disconnect();
 | |
| 
 | |
| #ifndef MYSQL_CLIENT
 | |
|   enum enum_binlog_query_type {
 | |
|     /* The query can be logged in row format or in statement format. */
 | |
|     ROW_QUERY_TYPE,
 | |
|     
 | |
|     /* The query has to be logged in statement format. */
 | |
|     STMT_QUERY_TYPE,
 | |
|     
 | |
|     QUERY_TYPE_COUNT
 | |
|   };
 | |
|   
 | |
|   int binlog_query(enum_binlog_query_type qtype,
 | |
|                    char const *query, ulong query_len, bool is_trans,
 | |
|                    bool direct, bool suppress_use,
 | |
|                    int errcode);
 | |
| #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(mysql_cond_t *cond, mysql_mutex_t* mutex,
 | |
|                                 const char* msg)
 | |
|   {
 | |
|     const char* old_msg = proc_info;
 | |
|     mysql_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 thd->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).
 | |
|     */
 | |
|     mysql_mutex_unlock(mysys_var->current_mutex);
 | |
|     mysql_mutex_lock(&mysys_var->mutex);
 | |
|     mysys_var->current_mutex = 0;
 | |
|     mysys_var->current_cond = 0;
 | |
|     proc_info = old_msg;
 | |
|     mysql_mutex_unlock(&mysys_var->mutex);
 | |
|     return;
 | |
|   }
 | |
|   inline time_t query_start() { query_start_used=1; return start_time; }
 | |
|   inline void set_time()
 | |
|   {
 | |
|     if (user_time)
 | |
|     {
 | |
|       start_time= user_time;
 | |
|       start_utime= utime_after_lock= my_micro_time();
 | |
|     }
 | |
|     else
 | |
|       start_utime= utime_after_lock= my_micro_time_and_time(&start_time);
 | |
|   }
 | |
|   inline void	set_current_time()    { start_time= my_time(MY_WME); }
 | |
|   inline void	set_time(time_t t)
 | |
|   {
 | |
|     start_time= user_time= t;
 | |
|     start_utime= utime_after_lock= my_micro_time();
 | |
|   }
 | |
|   /*TODO: this will be obsolete when we have support for 64 bit my_time_t */
 | |
|   inline bool	is_valid_time() 
 | |
|   { 
 | |
|     return (IS_TIME_T_VALID_FOR_TIMESTAMP(start_time));
 | |
|   }
 | |
|   void set_time_after_lock()  { utime_after_lock= my_micro_time(); }
 | |
|   ulonglong current_utime()  { return my_micro_time(); }
 | |
|   /**
 | |
|    Update server status after execution of a top level statement.
 | |
| 
 | |
|    Currently only checks if a query was slow, and assigns
 | |
|    the status accordingly.
 | |
|    Evaluate the current time, and if it exceeds the long-query-time
 | |
|    setting, mark the query as slow.
 | |
|   */
 | |
|   void update_server_status()
 | |
|   {
 | |
|     ulonglong end_utime_of_query= current_utime();
 | |
|     if (end_utime_of_query > utime_after_lock + variables.long_query_time)
 | |
|       server_status|= SERVER_QUERY_WAS_SLOW;
 | |
|   }
 | |
|   inline ulonglong found_rows(void)
 | |
|   {
 | |
|     return limit_found_rows;
 | |
|   }
 | |
|   /**
 | |
|     Returns TRUE if session is in a multi-statement transaction mode.
 | |
| 
 | |
|     OPTION_NOT_AUTOCOMMIT: When autocommit is off, a multi-statement
 | |
|     transaction is implicitly started on the first statement after a
 | |
|     previous transaction has been ended.
 | |
| 
 | |
|     OPTION_BEGIN: Regardless of the autocommit status, a multi-statement
 | |
|     transaction can be explicitly started with the statements "START
 | |
|     TRANSACTION", "BEGIN [WORK]", "[COMMIT | ROLLBACK] AND CHAIN", etc.
 | |
| 
 | |
|     Note: this doesn't tell you whether a transaction is active.
 | |
|     A session can be in multi-statement transaction mode, and yet
 | |
|     have no active transaction, e.g., in case of:
 | |
|     set @@autocommit=0;
 | |
|     set @a= 3;                                     <-- these statements don't
 | |
|     set transaction isolation level serializable;  <-- start an active
 | |
|     flush tables;                                  <-- transaction
 | |
| 
 | |
|     I.e. for the above scenario this function returns TRUE, even
 | |
|     though no active transaction has begun.
 | |
|     @sa in_active_multi_stmt_transaction()
 | |
|   */
 | |
|   inline bool in_multi_stmt_transaction_mode()
 | |
|   {
 | |
|     return variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN);
 | |
|   }
 | |
|   /**
 | |
|     TRUE if the session is in a multi-statement transaction mode
 | |
|     (@sa in_multi_stmt_transaction_mode()) *and* there is an
 | |
|     active transaction, i.e. there is an explicit start of a
 | |
|     transaction with BEGIN statement, or implicit with a
 | |
|     statement that uses a transactional engine.
 | |
| 
 | |
|     For example, these scenarios don't start an active transaction
 | |
|     (even though the server is in multi-statement transaction mode):
 | |
| 
 | |
|     set @@autocommit=0;
 | |
|     select * from nontrans_table;
 | |
|     set @var=TRUE;
 | |
|     flush tables;
 | |
| 
 | |
|     Note, that even for a statement that starts a multi-statement
 | |
|     transaction (i.e. select * from trans_table), this
 | |
|     flag won't be set until we open the statement's tables
 | |
|     and the engines register themselves for the transaction
 | |
|     (see trans_register_ha()),
 | |
|     hence this method is reliable to use only after
 | |
|     open_tables() has completed.
 | |
| 
 | |
|     Why do we need a flag?
 | |
|     ----------------------
 | |
|     We need to maintain a (at first glance redundant)
 | |
|     session flag, rather than looking at thd->transaction.all.ha_list
 | |
|     because of explicit start of a transaction with BEGIN. 
 | |
| 
 | |
|     I.e. in case of
 | |
|     BEGIN;
 | |
|     select * from nontrans_t1; <-- in_active_multi_stmt_transaction() is true
 | |
|   */
 | |
|   inline bool in_active_multi_stmt_transaction()
 | |
|   {
 | |
|     return server_status & SERVER_STATUS_IN_TRANS;
 | |
|   }
 | |
|   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);
 | |
|   }
 | |
| 
 | |
|   LEX_STRING *make_lex_string(LEX_STRING *lex_str,
 | |
|                               const char* str, uint length,
 | |
|                               bool allocate_lex_string);
 | |
| 
 | |
|   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);
 | |
| 
 | |
|   /**
 | |
|     Clear the current error, if any.
 | |
|     We do not clear is_fatal_error or is_fatal_sub_stmt_error since we
 | |
|     assume this is never called if the fatal error is set.
 | |
|     @todo: To silence an error, one should use Internal_error_handler
 | |
|     mechanism. In future this function will be removed.
 | |
|   */
 | |
|   inline void clear_error()
 | |
|   {
 | |
|     DBUG_ENTER("clear_error");
 | |
|     if (stmt_da->is_error())
 | |
|       stmt_da->reset_diagnostics_area();
 | |
|     is_slave_error= 0;
 | |
|     DBUG_VOID_RETURN;
 | |
|   }
 | |
| #ifndef EMBEDDED_LIBRARY
 | |
|   inline bool vio_ok() const { return net.vio != 0; }
 | |
|   /** Return FALSE if connection to client is broken. */
 | |
|   bool is_connected()
 | |
|   {
 | |
|     /*
 | |
|       All system threads (e.g., the slave IO thread) are connected but
 | |
|       not using vio. So this function always returns true for all
 | |
|       system threads.
 | |
|     */
 | |
|     return system_thread || (vio_ok() ? vio_is_connected(net.vio) : FALSE);
 | |
|   }
 | |
| #else
 | |
|   inline bool vio_ok() const { return TRUE; }
 | |
|   inline bool is_connected() { return TRUE; }
 | |
| #endif
 | |
|   /**
 | |
|     Mark the current error as fatal. Warning: this does not
 | |
|     set any error, it sets a property of the error, so must be
 | |
|     followed or prefixed with my_error().
 | |
|   */
 | |
|   inline void fatal_error()
 | |
|   {
 | |
|     DBUG_ASSERT(stmt_da->is_error() || killed);
 | |
|     is_fatal_error= 1;
 | |
|     DBUG_PRINT("error",("Fatal error set"));
 | |
|   }
 | |
|   /**
 | |
|     TRUE if there is an error in the error stack.
 | |
| 
 | |
|     Please use this method instead of direct access to
 | |
|     net.report_error.
 | |
| 
 | |
|     If TRUE, the current (sub)-statement should be aborted.
 | |
|     The main difference between this member and is_fatal_error
 | |
|     is that a fatal error can not be handled by a stored
 | |
|     procedure continue handler, whereas a normal error can.
 | |
| 
 | |
|     To raise this flag, use my_error().
 | |
|   */
 | |
|   inline bool is_error() const { return stmt_da->is_error(); }
 | |
|   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)
 | |
|     {
 | |
|       if ((err == KILL_CONNECTION) && !shutdown_in_progress)
 | |
|         err = KILL_QUERY;
 | |
|       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 &&
 | |
|             (!transaction.stmt.modified_non_trans_table ||
 | |
|              (variables.sql_mode & MODE_STRICT_ALL_TABLES)));
 | |
|   }
 | |
|   void set_status_var_init();
 | |
|   void reset_n_backup_open_tables_state(Open_tables_backup *backup);
 | |
|   void restore_backup_open_tables_state(Open_tables_backup *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);
 | |
| 
 | |
|   /*
 | |
|     @todo Make these methods private or remove them completely.  Only
 | |
|     decide_logging_format should call them. /Sven
 | |
|   */
 | |
|   inline void set_current_stmt_binlog_format_row_if_mixed()
 | |
|   {
 | |
|     DBUG_ENTER("set_current_stmt_binlog_format_row_if_mixed");
 | |
|     /*
 | |
|       This should only be called from decide_logging_format.
 | |
| 
 | |
|       @todo Once we have ensured this, uncomment the following
 | |
|       statement, remove the big comment below that, and remove the
 | |
|       in_sub_stmt==0 condition from the following 'if'.
 | |
|     */
 | |
|     /* DBUG_ASSERT(in_sub_stmt == 0); */
 | |
|     /*
 | |
|       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_format_row()); 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))
 | |
|       set_current_stmt_binlog_format_row();
 | |
| 
 | |
|     DBUG_VOID_RETURN;
 | |
|   }
 | |
|   inline void set_current_stmt_binlog_format_row()
 | |
|   {
 | |
|     DBUG_ENTER("set_current_stmt_binlog_format_row");
 | |
|     current_stmt_binlog_format= BINLOG_FORMAT_ROW;
 | |
|     DBUG_VOID_RETURN;
 | |
|   }
 | |
|   inline void clear_current_stmt_binlog_format_row()
 | |
|   {
 | |
|     DBUG_ENTER("clear_current_stmt_binlog_format_row");
 | |
|     current_stmt_binlog_format= BINLOG_FORMAT_STMT;
 | |
|     DBUG_VOID_RETURN;
 | |
|   }
 | |
|   inline void reset_current_stmt_binlog_format_row()
 | |
|   {
 | |
|     DBUG_ENTER("reset_current_stmt_binlog_format_row");
 | |
|     /*
 | |
|       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...).
 | |
|     */
 | |
|     DBUG_PRINT("debug",
 | |
|                ("temporary_tables: %s, in_sub_stmt: %s, system_thread: %s",
 | |
|                 YESNO(temporary_tables), YESNO(in_sub_stmt),
 | |
|                 show_system_thread(system_thread)));
 | |
|     if (in_sub_stmt == 0)
 | |
|     {
 | |
|       if (variables.binlog_format == BINLOG_FORMAT_ROW)
 | |
|         set_current_stmt_binlog_format_row();
 | |
|       else if (temporary_tables == NULL)
 | |
|         clear_current_stmt_binlog_format_row();
 | |
|     }
 | |
|     DBUG_VOID_RETURN;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|     Set the current database; use deep copy of C-string.
 | |
| 
 | |
|     @param new_db     a pointer to the new database name.
 | |
|     @param new_db_len length of the new database name.
 | |
| 
 | |
|     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).
 | |
| 
 | |
|     @note This operation just sets {db, db_length}. Switching the current
 | |
|     database usually involves other actions, like switching other database
 | |
|     attributes including security context. In the future, this operation
 | |
|     will be made private and more convenient interface will be provided.
 | |
| 
 | |
|     @return Operation status
 | |
|       @retval FALSE Success
 | |
|       @retval TRUE  Out-of-memory error
 | |
|   */
 | |
|   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
 | |
|     {
 | |
|       my_free(db);
 | |
|       if (new_db)
 | |
|         db= my_strndup(new_db, new_db_len, MYF(MY_WME | ME_FATALERROR));
 | |
|       else
 | |
|         db= NULL;
 | |
|     }
 | |
|     db_length= db ? new_db_len : 0;
 | |
|     return new_db && !db;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|     Set the current database; use shallow copy of C-string.
 | |
| 
 | |
|     @param new_db     a pointer to the new database name.
 | |
|     @param new_db_len length of the new database name.
 | |
| 
 | |
|     @note This operation just sets {db, db_length}. Switching the current
 | |
|     database usually involves other actions, like switching other database
 | |
|     attributes including security context. In the future, this operation
 | |
|     will be made private and more convenient interface will be provided.
 | |
|   */
 | |
|   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:
 | |
|   inline Internal_error_handler *get_internal_handler()
 | |
|   { return m_internal_handler; }
 | |
| 
 | |
|   /**
 | |
|     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 a sql condition.
 | |
|     @param sql_errno the condition error number
 | |
|     @param sqlstate the condition sqlstate
 | |
|     @param level the condition level
 | |
|     @param msg the condition message text
 | |
|     @param[out] cond_hdl the sql condition raised, if any
 | |
|     @return true if the condition is handled
 | |
|   */
 | |
|   virtual bool handle_condition(uint sql_errno,
 | |
|                                 const char* sqlstate,
 | |
|                                 MYSQL_ERROR::enum_warning_level level,
 | |
|                                 const char* msg,
 | |
|                                 MYSQL_ERROR ** cond_hdl);
 | |
| 
 | |
|   /**
 | |
|     Remove the error handler last pushed.
 | |
|   */
 | |
|   Internal_error_handler *pop_internal_handler();
 | |
| 
 | |
|   /**
 | |
|     Raise an exception condition.
 | |
|     @param code the MYSQL_ERRNO error code of the error
 | |
|   */
 | |
|   void raise_error(uint code);
 | |
| 
 | |
|   /**
 | |
|     Raise an exception condition, with a formatted message.
 | |
|     @param code the MYSQL_ERRNO error code of the error
 | |
|   */
 | |
|   void raise_error_printf(uint code, ...);
 | |
| 
 | |
|   /**
 | |
|     Raise a completion condition (warning).
 | |
|     @param code the MYSQL_ERRNO error code of the warning
 | |
|   */
 | |
|   void raise_warning(uint code);
 | |
| 
 | |
|   /**
 | |
|     Raise a completion condition (warning), with a formatted message.
 | |
|     @param code the MYSQL_ERRNO error code of the warning
 | |
|   */
 | |
|   void raise_warning_printf(uint code, ...);
 | |
| 
 | |
|   /**
 | |
|     Raise a completion condition (note), with a fixed message.
 | |
|     @param code the MYSQL_ERRNO error code of the note
 | |
|   */
 | |
|   void raise_note(uint code);
 | |
| 
 | |
|   /**
 | |
|     Raise an completion condition (note), with a formatted message.
 | |
|     @param code the MYSQL_ERRNO error code of the note
 | |
|   */
 | |
|   void raise_note_printf(uint code, ...);
 | |
| 
 | |
| private:
 | |
|   /*
 | |
|     Only the implementation of the SIGNAL and RESIGNAL statements
 | |
|     is permitted to raise SQL conditions in a generic way,
 | |
|     or to raise them by bypassing handlers (RESIGNAL).
 | |
|     To raise a SQL condition, the code should use the public
 | |
|     raise_error() or raise_warning() methods provided by class THD.
 | |
|   */
 | |
|   friend class Signal_common;
 | |
|   friend class Signal_statement;
 | |
|   friend class Resignal_statement;
 | |
|   friend void push_warning(THD*, MYSQL_ERROR::enum_warning_level, uint, const char*);
 | |
|   friend void my_message_sql(uint, const char *, myf);
 | |
| 
 | |
|   /**
 | |
|     Raise a generic SQL condition.
 | |
|     @param sql_errno the condition error number
 | |
|     @param sqlstate the condition SQLSTATE
 | |
|     @param level the condition level
 | |
|     @param msg the condition message text
 | |
|     @return The condition raised, or NULL
 | |
|   */
 | |
|   MYSQL_ERROR*
 | |
|   raise_condition(uint sql_errno,
 | |
|                   const char* sqlstate,
 | |
|                   MYSQL_ERROR::enum_warning_level level,
 | |
|                   const char* msg);
 | |
| 
 | |
| public:
 | |
|   /** Overloaded to guard query/query_length fields */
 | |
|   virtual void set_statement(Statement *stmt);
 | |
| 
 | |
|   /**
 | |
|     Assign a new value to thd->query and thd->query_id and mysys_var.
 | |
|     Protected with LOCK_thd_data mutex.
 | |
|   */
 | |
|   void set_query(char *query_arg, uint32 query_length_arg,
 | |
|                  CHARSET_INFO *cs_arg)
 | |
|   {
 | |
|     set_query(CSET_STRING(query_arg, query_length_arg, cs_arg));
 | |
|   }
 | |
|   void set_query(char *query_arg, uint32 query_length_arg) /*Mutex protected*/
 | |
|   {
 | |
|     set_query(CSET_STRING(query_arg, query_length_arg, charset()));
 | |
|   }
 | |
|   void set_query(const CSET_STRING &str); /* Mutex protected */
 | |
|   void reset_query()               /* Mutex protected */
 | |
|   { set_query(CSET_STRING()); }
 | |
|   void set_query_and_id(char *query_arg, uint32 query_length_arg,
 | |
|                         CHARSET_INFO *cs, query_id_t new_query_id);
 | |
|   void set_query_id(query_id_t new_query_id);
 | |
|   void set_open_tables(TABLE *open_tables_arg)
 | |
|   {
 | |
|     mysql_mutex_lock(&LOCK_thd_data);
 | |
|     open_tables= open_tables_arg;
 | |
|     mysql_mutex_unlock(&LOCK_thd_data);
 | |
|   }
 | |
|   void set_mysys_var(struct st_my_thread_var *new_mysys_var);
 | |
|   void enter_locked_tables_mode(enum_locked_tables_mode mode_arg)
 | |
|   {
 | |
|     DBUG_ASSERT(locked_tables_mode == LTM_NONE);
 | |
| 
 | |
|     if (mode_arg == LTM_LOCK_TABLES)
 | |
|     {
 | |
|       /*
 | |
|         When entering LOCK TABLES mode we should set explicit duration
 | |
|         for all metadata locks acquired so far in order to avoid releasing
 | |
|         them till UNLOCK TABLES statement.
 | |
|         We don't do this when entering prelocked mode since sub-statements
 | |
|         don't release metadata locks and restoring status-quo after leaving
 | |
|         prelocking mode gets complicated.
 | |
|       */
 | |
|       mdl_context.set_explicit_duration_for_all_locks();
 | |
|     }
 | |
| 
 | |
|     locked_tables_mode= mode_arg;
 | |
|   }
 | |
|   void leave_locked_tables_mode();
 | |
|   int decide_logging_format(TABLE_LIST *tables);
 | |
|   void binlog_invoker() { m_binlog_invoker= TRUE; }
 | |
|   bool need_binlog_invoker() { return m_binlog_invoker; }
 | |
|   void get_definer(LEX_USER *definer);
 | |
|   void set_invoker(const LEX_STRING *user, const LEX_STRING *host)
 | |
|   {
 | |
|     invoker_user= *user;
 | |
|     invoker_host= *host;
 | |
|   }
 | |
|   LEX_STRING get_invoker_user() { return invoker_user; }
 | |
|   LEX_STRING get_invoker_host() { return invoker_host; }
 | |
|   bool has_invoker() { return invoker_user.length > 0; }
 | |
| 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;
 | |
|   Warning_info main_warning_info;
 | |
|   Diagnostics_area main_da;
 | |
| 
 | |
|   /**
 | |
|     It will be set TURE if CURRENT_USER() is called in account management
 | |
|     statements or default definer is set in CREATE/ALTER SP, SF, Event,
 | |
|     TRIGGER or VIEW statements.
 | |
| 
 | |
|     Current user will be binlogged into Query_log_event if current_user_used
 | |
|     is TRUE; It will be stored into invoker_host and invoker_user by SQL thread.
 | |
|    */
 | |
|   bool m_binlog_invoker;
 | |
| 
 | |
|   /**
 | |
|     It points to the invoker in the Query_log_event.
 | |
|     SQL thread use it as the default definer in CREATE/ALTER SP, SF, Event,
 | |
|     TRIGGER or VIEW statements or current user in account management
 | |
|     statements if it is not NULL.
 | |
|    */
 | |
|   LEX_STRING invoker_user;
 | |
|   LEX_STRING invoker_host;
 | |
| };
 | |
| 
 | |
| 
 | |
| /** A short cut for thd->stmt_da->set_ok_status(). */
 | |
| 
 | |
| inline void
 | |
| my_ok(THD *thd, ulonglong affected_rows= 0, ulonglong id= 0,
 | |
|         const char *message= NULL)
 | |
| {
 | |
|   thd->set_row_count_func(affected_rows);
 | |
|   thd->stmt_da->set_ok_status(thd, affected_rows, id, message);
 | |
| }
 | |
| 
 | |
| 
 | |
| /** A short cut for thd->stmt_da->set_eof_status(). */
 | |
| 
 | |
| inline void
 | |
| my_eof(THD *thd)
 | |
| {
 | |
|   thd->set_row_count_func(-1);
 | |
|   thd->stmt_da->set_eof_status(thd);
 | |
| }
 | |
| 
 | |
| #define tmp_disable_binlog(A)       \
 | |
|   {ulonglong tmp_disable_binlog__save_options= (A)->variables.option_bits; \
 | |
|   (A)->variables.option_bits&= ~OPTION_BIN_LOG
 | |
| 
 | |
| #define reenable_binlog(A)   (A)->variables.option_bits= tmp_disable_binlog__save_options;}
 | |
| 
 | |
| 
 | |
| LEX_STRING *
 | |
| make_lex_string_root(MEM_ROOT *mem_root,
 | |
|                      LEX_STRING *lex_str, const char* str, uint length,
 | |
|                      bool allocate_lex_string);
 | |
| 
 | |
| /*
 | |
|   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:
 | |
|   enum enum_filetype filetype; /* load XML, Added by Arnold & Erik */
 | |
|   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,
 | |
|                enum_filetype filetype_arg= FILETYPE_CSV);
 | |
|   bool escaped_given(void);
 | |
| };
 | |
| 
 | |
| /*
 | |
|   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_result_set_metadata(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_result_set() {}
 | |
|   /*
 | |
|     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_result_set_metadata(List<Item> &fields, uint flag) { return FALSE; }
 | |
| };
 | |
| 
 | |
| 
 | |
| class select_send :public select_result {
 | |
|   /**
 | |
|     True if we have sent result set metadata to the client.
 | |
|     In this case the client always expects us to end the result
 | |
|     set with an eof or error packet
 | |
|   */
 | |
|   bool is_result_set_started;
 | |
| public:
 | |
|   select_send() :is_result_set_started(FALSE) {}
 | |
|   bool send_result_set_metadata(List<Item> &list, uint flags);
 | |
|   bool send_data(List<Item> &items);
 | |
|   bool send_eof();
 | |
|   virtual bool check_simple_select() const { return FALSE; }
 | |
|   void abort_result_set();
 | |
|   virtual void cleanup();
 | |
| };
 | |
| 
 | |
| 
 | |
| 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();
 | |
| };
 | |
| 
 | |
| 
 | |
| #define ESCAPE_CHARS "ntrb0ZN" // keep synchronous with READ_INFO::unescape
 | |
| 
 | |
| 
 | |
| /*
 | |
|  List of all possible characters of a numeric value text representation.
 | |
| */
 | |
| #define NUMERIC_CHARS ".0123456789e+-"
 | |
| 
 | |
| 
 | |
| class select_export :public select_to_file {
 | |
|   uint field_term_length;
 | |
|   int field_sep_char,escape_char,line_sep_char;
 | |
|   int field_term_char; // first char of FIELDS TERMINATED BY or MAX_INT
 | |
|   /*
 | |
|     The is_ambiguous_field_sep field is true if a value of the field_sep_char
 | |
|     field is one of the 'n', 't', 'r' etc characters
 | |
|     (see the READ_INFO::unescape method and the ESCAPE_CHARS constant value).
 | |
|   */
 | |
|   bool is_ambiguous_field_sep;
 | |
|   /*
 | |
|      The is_ambiguous_field_term is true if field_sep_char contains the first
 | |
|      char of the FIELDS TERMINATED BY (ENCLOSED BY is empty), and items can
 | |
|      contain this character.
 | |
|   */
 | |
|   bool is_ambiguous_field_term;
 | |
|   /*
 | |
|     The is_unsafe_field_sep field is true if a value of the field_sep_char
 | |
|     field is one of the '0'..'9', '+', '-', '.' and 'e' characters
 | |
|     (see the NUMERIC_CHARS constant value).
 | |
|   */
 | |
|   bool is_unsafe_field_sep;
 | |
|   bool fixed_row_size;
 | |
|   CHARSET_INFO *write_cs; // output charset
 | |
| 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);
 | |
|   virtual 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();
 | |
|   virtual void abort_result_set();
 | |
|   /* 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;
 | |
|   TABLE_LIST *select_tables;
 | |
|   Alter_info *alter_info;
 | |
|   Field **field;
 | |
|   /* lock data for tmp table */
 | |
|   MYSQL_LOCK *m_lock;
 | |
|   /* m_lock or thd->extra_lock */
 | |
|   MYSQL_LOCK **m_plock;
 | |
| public:
 | |
|   select_create (TABLE_LIST *table_arg,
 | |
| 		 HA_CREATE_INFO *create_info_par,
 | |
|                  Alter_info *alter_info_arg,
 | |
| 		 List<Item> &select_fields,enum_duplicates duplic, bool ignore,
 | |
|                  TABLE_LIST *select_tables_arg)
 | |
|     :select_insert (NULL, NULL, &select_fields, 0, 0, duplic, ignore),
 | |
|     create_table(table_arg),
 | |
|     create_info(create_info_par),
 | |
|     select_tables(select_tables_arg),
 | |
|     alter_info(alter_info_arg),
 | |
|     m_plock(NULL)
 | |
|     {}
 | |
|   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
 | |
| 
 | |
|   int 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();
 | |
|   virtual void abort_result_set();
 | |
|   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; };
 | |
|   int prepare2(void) { return 0; }
 | |
| };
 | |
| 
 | |
| #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;
 | |
|   /**
 | |
|     Number of normal fields in the query, including those referred to
 | |
|     from aggregate functions. Hence, "SELECT `field1`,
 | |
|     SUM(`field2`) from t1" sets this counter to 2.
 | |
| 
 | |
|     @see count_field_types
 | |
|   */
 | |
|   uint	field_count; 
 | |
|   /**
 | |
|     Number of fields in the query that have functions. Includes both
 | |
|     aggregate functions (e.g., SUM) and non-aggregates (e.g., RAND).
 | |
|     Also counts functions referred to from aggregate functions, i.e.,
 | |
|     "SELECT SUM(RAND())" sets this counter to 2.
 | |
| 
 | |
|     @see count_field_types
 | |
|   */
 | |
|   uint  func_count;  
 | |
|   /**
 | |
|     Number of fields in the query that have aggregate functions. Note
 | |
|     that the optimizer may choose to optimize away these fields by
 | |
|     replacing them with constants, in which case sum_func_count will
 | |
|     need to be updated.
 | |
| 
 | |
|     @see opt_sum_query, count_field_types
 | |
|   */
 | |
|   uint  sum_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) const;
 | |
|   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);
 | |
| 
 | |
|   uint get_size() const { return size; }
 | |
|   ulonglong get_max_in_memory_size() const { return max_in_memory_size; }
 | |
| 
 | |
|   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;
 | |
|   /*
 | |
|      error handling (rollback and binlogging) can happen in send_eof()
 | |
|      so that afterward send_error() needs to find out that.
 | |
|   */
 | |
|   bool error_handled;
 | |
| 
 | |
| 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();
 | |
|   int do_table_deletes(TABLE *table, bool ignore);
 | |
|   bool send_eof();
 | |
|   inline ha_rows num_deleted()
 | |
|   {
 | |
|     return deleted;
 | |
|   }
 | |
|   virtual void abort_result_set();
 | |
| };
 | |
| 
 | |
| 
 | |
| 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;
 | |
|   /*
 | |
|    List of tables referenced in the CHECK OPTION condition of
 | |
|    the updated view excluding the updated table. 
 | |
|   */
 | |
|   List <TABLE> unupdated_check_opt_tables;
 | |
|   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;
 | |
|   /* 
 | |
|      error handling (rollback and binlogging) can happen in send_eof()
 | |
|      so that afterward send_error() needs to find out that.
 | |
|   */
 | |
|   bool error_handled;
 | |
| 
 | |
| 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 send_eof();
 | |
|   inline ha_rows num_found()
 | |
|   {
 | |
|     return found;
 | |
|   }
 | |
|   inline ha_rows num_updated()
 | |
|   {
 | |
|     return updated;
 | |
|   }
 | |
|   virtual void abort_result_set();
 | |
| };
 | |
| 
 | |
| 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           (1U << 0)
 | |
| /* The 2nd bit is unused -- it used to be CF_HAS_ROW_COUNT. */
 | |
| #define CF_STATUS_COMMAND         (1U << 2)
 | |
| #define CF_SHOW_TABLE_COMMAND     (1U << 3)
 | |
| #define CF_WRITE_LOGS_COMMAND     (1U << 4)
 | |
| /**
 | |
|   Must be set for SQL statements that may contain
 | |
|   Item expressions and/or use joins and tables.
 | |
|   Indicates that the parse tree of such statement may
 | |
|   contain rule-based optimizations that depend on metadata
 | |
|   (i.e. number of columns in a table), and consequently
 | |
|   that the statement must be re-prepared whenever
 | |
|   referenced metadata changes. Must not be set for
 | |
|   statements that themselves change metadata, e.g. RENAME,
 | |
|   ALTER and other DDL, since otherwise will trigger constant
 | |
|   reprepare. Consequently, complex item expressions and
 | |
|   joins are currently prohibited in these statements.
 | |
| */
 | |
| #define CF_REEXECUTION_FRAGILE    (1U << 5)
 | |
| /**
 | |
|   Implicitly commit before the SQL statement is executed.
 | |
| 
 | |
|   Statements marked with this flag will cause any active
 | |
|   transaction to end (commit) before proceeding with the
 | |
|   command execution.
 | |
| 
 | |
|   This flag should be set for statements that probably can't
 | |
|   be rolled back or that do not expect any previously metadata
 | |
|   locked tables.
 | |
| */
 | |
| #define CF_IMPLICT_COMMIT_BEGIN   (1U << 6)
 | |
| /**
 | |
|   Implicitly commit after the SQL statement.
 | |
| 
 | |
|   Statements marked with this flag are automatically committed
 | |
|   at the end of the statement.
 | |
| 
 | |
|   This flag should be set for statements that will implicitly
 | |
|   open and take metadata locks on system tables that should not
 | |
|   be carried for the whole duration of a active transaction.
 | |
| */
 | |
| #define CF_IMPLICIT_COMMIT_END    (1U << 7)
 | |
| /**
 | |
|   CF_IMPLICT_COMMIT_BEGIN and CF_IMPLICIT_COMMIT_END are used
 | |
|   to ensure that the active transaction is implicitly committed
 | |
|   before and after every DDL statement and any statement that
 | |
|   modifies our currently non-transactional system tables.
 | |
| */
 | |
| #define CF_AUTO_COMMIT_TRANS  (CF_IMPLICT_COMMIT_BEGIN | CF_IMPLICIT_COMMIT_END)
 | |
| 
 | |
| /**
 | |
|   Diagnostic statement.
 | |
|   Diagnostic statements:
 | |
|   - SHOW WARNING
 | |
|   - SHOW ERROR
 | |
|   - GET DIAGNOSTICS (WL#2111)
 | |
|   do not modify the diagnostics area during execution.
 | |
| */
 | |
| #define CF_DIAGNOSTIC_STMT        (1U << 8)
 | |
| 
 | |
| /**
 | |
|   Identifies statements that may generate row events
 | |
|   and that may end up in the binary log.
 | |
| */
 | |
| #define CF_CAN_GENERATE_ROW_EVENTS (1U << 9)
 | |
| 
 | |
| /* Bits in server_command_flags */
 | |
| 
 | |
| /**
 | |
|   Skip the increase of the global query id counter. Commonly set for
 | |
|   commands that are stateless (won't cause any change on the server
 | |
|   internal states).
 | |
| */
 | |
| #define CF_SKIP_QUERY_ID        (1U << 0)
 | |
| 
 | |
| /**
 | |
|   Skip the increase of the number of statements that clients have
 | |
|   sent to the server. Commonly used for commands that will cause
 | |
|   a statement to be executed but the statement might have not been
 | |
|   sent by the user (ie: stored procedure).
 | |
| */
 | |
| #define CF_SKIP_QUESTIONS       (1U << 1)
 | |
| 
 | |
| 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);
 | |
| void mark_transaction_to_rollback(THD *thd, bool all);
 | |
| 
 | |
| /* Inline functions */
 | |
| 
 | |
| inline bool add_item_to_list(THD *thd, Item *item)
 | |
| {
 | |
|   return thd->lex->current_select->add_item_to_list(thd, item);
 | |
| }
 | |
| 
 | |
| inline bool add_value_to_list(THD *thd, Item *value)
 | |
| {
 | |
|   return thd->lex->value_list.push_back(value);
 | |
| }
 | |
| 
 | |
| inline bool add_order_to_list(THD *thd, Item *item, bool asc)
 | |
| {
 | |
|   return thd->lex->current_select->add_order_to_list(thd, item, asc);
 | |
| }
 | |
| 
 | |
| inline bool add_group_to_list(THD *thd, Item *item, bool asc)
 | |
| {
 | |
|   return thd->lex->current_select->add_group_to_list(thd, item, asc);
 | |
| }
 | |
| 
 | |
| #endif /* MYSQL_SERVER */
 | |
| 
 | |
| /**
 | |
|   The meat of thd_proc_info(THD*, char*), a macro that packs the last
 | |
|   three calling-info parameters.
 | |
| */
 | |
| extern "C"
 | |
| const char *set_thd_proc_info(void *thd_arg, const char *info,
 | |
|                               const char *calling_func,
 | |
|                               const char *calling_file,
 | |
|                               const unsigned int calling_line);
 | |
| 
 | |
| #define thd_proc_info(thd, msg) \
 | |
|   set_thd_proc_info(thd, msg, __func__, __FILE__, __LINE__)
 | |
| 
 | |
| #endif /* SQL_CLASS_INCLUDED */
 |