summaryrefslogtreecommitdiff
path: root/sql/sql_class.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_class.h')
-rw-r--r--sql/sql_class.h1400
1 files changed, 1106 insertions, 294 deletions
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 80aa5710b62..9adf6bf1d6a 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2016, Oracle and/or its affiliates.
- Copyright (c) 2009, 2017, MariaDB Corporation.
+ Copyright (c) 2009, 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,6 @@
/* Classes in mysql */
-#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
#include "dur_prop.h"
#include <waiting_threads.h>
#include "sql_const.h"
@@ -38,6 +37,7 @@
#include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA, THR_LOCK_INFO */
#include "thr_timer.h"
#include "thr_malloc.h"
+#include "log_slow.h" /* LOG_SLOW_DISABLE_... */
#include <my_tree.h>
#include "sql_digest_stream.h" // sql_digest_state
@@ -93,8 +93,25 @@ enum enum_slave_run_triggers_for_rbr { SLAVE_RUN_TRIGGERS_FOR_RBR_NO,
SLAVE_RUN_TRIGGERS_FOR_RBR_LOGGING};
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};
+
+/*
+ MARK_COLUMNS_READ: A column is goind to be read.
+ MARK_COLUMNS_WRITE: A column is going to be written to.
+ MARK_COLUMNS_READ: A column is goind to be read.
+ 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: A column is going to be written to.
+ 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_column_usage
+{ COLUMNS_READ, COLUMNS_WRITE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE};
+
+static inline bool should_mark_column(enum_column_usage column_usage)
+{ return column_usage >= MARK_COLUMNS_READ; }
+
enum enum_filetype { FILETYPE_CSV, FILETYPE_XML };
enum enum_binlog_row_image {
@@ -140,6 +157,8 @@ enum enum_binlog_row_image {
#define MODE_HIGH_NOT_PRECEDENCE (1ULL << 29)
#define MODE_NO_ENGINE_SUBSTITUTION (1ULL << 30)
#define MODE_PAD_CHAR_TO_FULL_LENGTH (1ULL << 31)
+#define MODE_EMPTY_STRING_IS_NULL (1ULL << 32)
+#define MODE_SIMULTANEOUS_ASSIGNMENT (1ULL << 33)
/* Bits for different old style modes */
#define OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE (1 << 0)
@@ -148,7 +167,6 @@ enum enum_binlog_row_image {
extern char internal_table_name[2];
extern char empty_c_string[1];
-extern LEX_STRING EMPTY_STR;
extern MYSQL_PLUGIN_IMPORT const char **errmesg;
extern bool volatile shutdown_in_progress;
@@ -195,7 +213,7 @@ typedef struct st_user_var_events
{
user_var_entry *user_var_event;
char *value;
- ulong length;
+ size_t length;
Item_result type;
uint charset_number;
bool unsigned_flag;
@@ -234,14 +252,11 @@ typedef struct st_copy_info {
class Key_part_spec :public Sql_alloc {
public:
- LEX_STRING field_name;
+ LEX_CSTRING field_name;
uint length;
- Key_part_spec(const LEX_STRING &name, uint len)
- : field_name(name), length(len)
+ Key_part_spec(const LEX_CSTRING *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
@@ -287,8 +302,9 @@ class Alter_column :public Sql_alloc {
public:
const char *name;
Virtual_column_info *default_value;
- Alter_column(const char *par_name, Virtual_column_info *expr)
- :name(par_name), default_value(expr) {}
+ bool alter_if_exists;
+ Alter_column(const char *par_name, Virtual_column_info *expr, bool par_exists)
+ :name(par_name), default_value(expr), alter_if_exists(par_exists) {}
/**
Used to make a clone of this object for ALTER/CREATE TABLE
@sa comment for Key_part_spec::clone
@@ -304,37 +320,29 @@ public:
enum Keytype type;
KEY_CREATE_INFO key_create_info;
List<Key_part_spec> columns;
- LEX_STRING name;
+ LEX_CSTRING name;
engine_option_value *option_list;
bool generated;
+ bool invisible;
- Key(enum Keytype type_par, const LEX_STRING &name_arg,
+ Key(enum Keytype type_par, const LEX_CSTRING *name_arg,
ha_key_alg algorithm_arg, bool generated_arg, DDL_options_st ddl_options)
:DDL_options(ddl_options),
type(type_par), key_create_info(default_key_create_info),
- name(name_arg), option_list(NULL), generated(generated_arg)
+ name(*name_arg), option_list(NULL), generated(generated_arg),
+ invisible(false)
{
key_create_info.algorithm= algorithm_arg;
- }
- Key(enum Keytype type_par, const LEX_STRING &name_arg,
+ }
+ Key(enum Keytype type_par, const LEX_CSTRING *name_arg,
KEY_CREATE_INFO *key_info_arg,
- bool generated_arg, List<Key_part_spec> &cols,
+ bool generated_arg, List<Key_part_spec> *cols,
engine_option_value *create_opt, DDL_options_st ddl_options)
:DDL_options(ddl_options),
- type(type_par), key_create_info(*key_info_arg), columns(cols),
- name(name_arg), option_list(create_opt), generated(generated_arg)
+ type(type_par), key_create_info(*key_info_arg), columns(*cols),
+ name(*name_arg), option_list(create_opt), generated(generated_arg),
+ invisible(false)
{}
- 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,
- engine_option_value *create_opt, DDL_options_st ddl_options)
- :DDL_options(ddl_options),
- type(type_par), key_create_info(*key_info_arg), columns(cols),
- option_list(create_opt), 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) */
@@ -352,19 +360,20 @@ class Foreign_key: public Key {
public:
enum fk_match_opt { FK_MATCH_UNDEF, FK_MATCH_FULL,
FK_MATCH_PARTIAL, FK_MATCH_SIMPLE};
-
- LEX_STRING ref_db;
- LEX_STRING ref_table;
+ LEX_CSTRING ref_db;
+ LEX_CSTRING 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,
- const LEX_STRING &ref_db_arg, const LEX_STRING &ref_table_arg,
- List<Key_part_spec> &ref_cols,
- uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg,
+ enum enum_fk_option delete_opt, update_opt;
+ enum fk_match_opt match_opt;
+ Foreign_key(const LEX_CSTRING *name_arg, List<Key_part_spec> *cols,
+ const LEX_CSTRING *ref_db_arg, const LEX_CSTRING *ref_table_arg,
+ List<Key_part_spec> *ref_cols,
+ enum_fk_option delete_opt_arg, enum_fk_option update_opt_arg,
+ fk_match_opt match_opt_arg,
DDL_options ddl_options)
:Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols, NULL,
ddl_options),
- ref_db(ref_db_arg), ref_table(ref_table_arg), ref_columns(ref_cols),
+ ref_db(*ref_db_arg), ref_table(*ref_table_arg), ref_columns(*ref_cols),
delete_opt(delete_opt_arg), update_opt(update_opt_arg),
match_opt(match_opt_arg)
{
@@ -385,8 +394,9 @@ public:
typedef struct st_mysql_lock
{
TABLE **table;
- uint table_count,lock_count;
THR_LOCK_DATA **locks;
+ uint table_count,lock_count;
+ uint flags;
} MYSQL_LOCK;
@@ -454,7 +464,7 @@ typedef enum enum_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[];
+extern const LEX_CSTRING Diag_condition_item_names[];
/**
These states are bit coded with HARD. For each state there must be a pair
@@ -552,6 +562,8 @@ typedef struct system_variables
ulonglong join_buff_space_limit;
ulonglong log_slow_filter;
ulonglong log_slow_verbosity;
+ ulonglong log_slow_disabled_statements;
+ ulonglong log_disabled_statements;
ulonglong bulk_insert_buff_size;
ulonglong join_buff_size;
ulonglong sortbuff_size;
@@ -581,6 +593,7 @@ typedef struct system_variables
ulong saved_auto_increment_increment, saved_auto_increment_offset;
#endif /* WITH_WSREP */
uint eq_range_index_dive_limit;
+ ulong column_compression_zlib_strategy;
ulong lock_wait_timeout;
ulong join_cache_level;
ulong max_allowed_packet;
@@ -631,6 +644,7 @@ typedef struct system_variables
ulong query_cache_type;
ulong tx_isolation;
ulong updatable_views_with_limit;
+ ulong alter_algorithm;
int max_user_connections;
ulong server_id;
/**
@@ -654,7 +668,6 @@ typedef struct system_variables
my_bool keep_files_on_create;
my_bool old_mode;
- my_bool old_alter_table;
my_bool old_passwords;
my_bool big_tables;
my_bool only_standard_compliant_cte;
@@ -668,6 +681,7 @@ typedef struct system_variables
my_bool sql_log_bin_off;
my_bool binlog_annotate_row_events;
my_bool binlog_direct_non_trans_update;
+ my_bool column_compression_zlib_wrap;
plugin_ref table_plugin;
plugin_ref tmp_table_plugin;
@@ -684,7 +698,7 @@ typedef struct system_variables
CHARSET_INFO *collation_connection;
/* Names. These will be allocated in buffers in thd */
- LEX_STRING default_master_connection;
+ LEX_CSTRING default_master_connection;
/* Error messages */
MY_LOCALE *lc_messages;
@@ -717,6 +731,16 @@ typedef struct system_variables
my_bool session_track_state_change;
ulong threadpool_priority;
+
+ uint idle_transaction_timeout;
+ uint idle_readonly_transaction_timeout;
+ uint idle_write_transaction_timeout;
+ uint column_compression_threshold;
+ uint column_compression_zlib_level;
+ uint in_subquery_conversion_threshold;
+
+ vers_asof_timestamp_t vers_asof_timestamp;
+ ulong vers_alter_history;
} SV;
/**
@@ -727,6 +751,8 @@ typedef struct system_variables
typedef struct system_status_var
{
+ ulong column_compressions;
+ ulong column_decompressions;
ulong com_stat[(uint) SQLCOM_END];
ulong com_create_tmp_table;
ulong com_drop_tmp_table;
@@ -771,6 +797,7 @@ typedef struct system_status_var
/* The following are for internal temporary tables */
ulong ha_tmp_update_count;
ulong ha_tmp_write_count;
+ ulong ha_tmp_delete_count;
ulong ha_prepare_count;
ulong ha_icp_attempts;
ulong ha_icp_match;
@@ -779,7 +806,6 @@ typedef struct system_status_var
ulong ha_savepoint_rollback_count;
ulong ha_external_lock_count;
- ulong net_big_packet_count;
ulong opened_tables;
ulong opened_shares;
ulong opened_views; /* +1 opening a view */
@@ -800,11 +826,16 @@ typedef struct system_status_var
ulong filesort_pq_sorts_;
/* Features used */
+ ulong feature_custom_aggregate_functions; /* +1 when custom aggregate
+ functions are used */
ulong feature_dynamic_columns; /* +1 when creating a dynamic column */
ulong feature_fulltext; /* +1 when MATCH is used */
ulong feature_gis; /* +1 opening a table with GIS features */
+ ulong feature_invisible_columns; /* +1 opening a table with invisible column */
+ ulong feature_json; /* +1 when JSON function appears in the statement */
ulong feature_locale; /* +1 when LOCALE is set */
ulong feature_subquery; /* +1 when subqueries are used */
+ ulong feature_system_versioning; /* +1 opening a table WITH SYSTEM VERSIONING */
ulong feature_timezone; /* +1 when XPATH is used */
ulong feature_trigger; /* +1 opening a table with triggers */
ulong feature_xml; /* +1 when XPATH is used */
@@ -835,10 +866,15 @@ typedef struct system_status_var
ulonglong rows_sent;
ulonglong rows_tmp_read;
ulonglong binlog_bytes_written;
+ ulonglong table_open_cache_hits;
+ ulonglong table_open_cache_misses;
+ ulonglong table_open_cache_overflows;
double last_query_cost;
double cpu_time, busy_time;
+ uint32 threads_running;
/* Don't initialize */
/* Memory used for thread local storage */
+ int64 max_local_memory_used;
volatile int64 local_memory_used;
/* Memory allocated for global usage */
volatile int64 global_memory_used;
@@ -916,7 +952,7 @@ void free_tmp_table(THD *thd, TABLE *entry);
/* The following macro is to make init of Query_arena simpler */
-#ifndef DBUG_OFF
+#ifdef DBUG_ASSERT_EXISTS
#define INIT_ARENA_DBUG_INFO is_backup_arena= 0; is_reprepared= FALSE;
#else
#define INIT_ARENA_DBUG_INFO
@@ -931,7 +967,7 @@ public:
*/
Item *free_list;
MEM_ROOT *mem_root; // Pointer to current memroot
-#ifndef DBUG_OFF
+#ifdef DBUG_ASSERT_EXISTS
bool is_backup_arena; /* True if this arena is used for backup. */
bool is_reprepared;
#endif
@@ -950,6 +986,7 @@ public:
enum_state state;
+public:
/* We build without RTTI, so dynamic_cast can't be used. */
enum Type
{
@@ -982,7 +1019,7 @@ public:
inline void* calloc(size_t size)
{
void *ptr;
- if ((ptr=alloc_root(mem_root,size)))
+ if (likely((ptr=alloc_root(mem_root,size))))
bzero(ptr, size);
return ptr;
}
@@ -992,10 +1029,10 @@ public:
{ 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)
+ inline void *memdup_w_gap(const void *str, size_t size, size_t gap)
{
void *ptr;
- if ((ptr= alloc_root(mem_root,size+gap)))
+ if (likely((ptr= alloc_root(mem_root,size+gap))))
memcpy(ptr,str,size);
return ptr;
}
@@ -1021,6 +1058,22 @@ public:
};
+class Query_arena_stmt
+{
+ THD *thd;
+ Query_arena backup;
+ Query_arena *arena;
+
+public:
+ Query_arena_stmt(THD *_thd);
+ ~Query_arena_stmt();
+ bool arena_replaced()
+ {
+ return arena != NULL;
+ }
+};
+
+
class Server_side_cursor;
/**
@@ -1050,20 +1103,9 @@ public:
*/
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 */
+ enum enum_column_usage column_usage;
+
+ LEX_CSTRING name; /* name for named prepared statements */
LEX *lex; // parse tree descriptor
/*
Points to the query associated with this statement. It's const, but
@@ -1094,6 +1136,10 @@ public:
{
return static_cast<uint32>(query_string.length());
}
+ inline char *query_end() const
+ {
+ return query_string.str() + query_string.length();
+ }
CHARSET_INFO *query_charset() const { return query_string.charset(); }
void set_query_inner(const CSET_STRING &string_arg)
{
@@ -1111,18 +1157,13 @@ public:
/**
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
+ If there is the current (default) database, "db.str" contains its name. If
+ there is no current (default) database, "db.str" is NULL and "db.length" is
+ 0. In other words, db 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;
+ LEX_CSTRING db;
/* This is set to 1 of last call to send_result_to_client() was ok */
my_bool query_cache_is_applicable;
@@ -1161,7 +1202,7 @@ public:
int insert(THD *thd, Statement *statement);
- Statement *find_by_name(LEX_STRING *name)
+ Statement *find_by_name(LEX_CSTRING *name)
{
Statement *stmt;
stmt= (Statement*)my_hash_search(&names_hash, (uchar*)name->str,
@@ -1267,7 +1308,7 @@ public:
ip - client IP
*/
const char *host;
- char *user, *ip;
+ const char *user, *ip;
char priv_user[USERNAME_LENGTH];
char proxy_user[USERNAME_LENGTH + MAX_HOSTNAME + 5];
/* The host privilege we are using */
@@ -1294,9 +1335,9 @@ public:
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bool
change_security_context(THD *thd,
- LEX_STRING *definer_user,
- LEX_STRING *definer_host,
- LEX_STRING *db,
+ LEX_CSTRING *definer_user,
+ LEX_CSTRING *definer_host,
+ LEX_CSTRING *db,
Security_context **backup);
void
@@ -1594,19 +1635,25 @@ public:
class Sub_statement_state
{
public:
+ Discrete_interval auto_inc_interval_for_cur_row;
+ Discrete_intervals_list auto_inc_intervals_forced;
+ SAVEPOINT *savepoints;
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;
+ ulonglong tmp_tables_size;
ulonglong client_capabilities;
+ ulonglong cuted_fields, sent_row_count, examined_row_count;
+ ulonglong affected_rows;
+ ulonglong bytes_sent_old;
+ ulong tmp_tables_used;
+ ulong tmp_tables_disk_used;
+ ulong query_plan_fsort_passes;
ulong query_plan_flags;
uint in_sub_stmt; /* 0, SUB_STMT_TRIGGER or SUB_STMT_FUNCTION */
bool enable_slow_log;
bool last_insert_id_used;
- SAVEPOINT *savepoints;
enum enum_check_fields count_cuted_fields;
};
@@ -1622,7 +1669,8 @@ enum enum_thread_type
SYSTEM_THREAD_EVENT_WORKER= 16,
SYSTEM_THREAD_BINLOG_BACKGROUND= 32,
SYSTEM_THREAD_SLAVE_BACKGROUND= 64,
- SYSTEM_THREAD_GENERIC= 128
+ SYSTEM_THREAD_GENERIC= 128,
+ SYSTEM_THREAD_SEMISYNC_MASTER_BACKGROUND= 256
};
inline char const *
@@ -1638,6 +1686,7 @@ show_system_thread(enum_thread_type thread)
RETURN_NAME_AS_STRING(SYSTEM_THREAD_EVENT_SCHEDULER);
RETURN_NAME_AS_STRING(SYSTEM_THREAD_EVENT_WORKER);
RETURN_NAME_AS_STRING(SYSTEM_THREAD_SLAVE_BACKGROUND);
+ RETURN_NAME_AS_STRING(SYSTEM_THREAD_SEMISYNC_MASTER_BACKGROUND);
default:
sprintf(buf, "<UNKNOWN SYSTEM THREAD: %d>", thread);
return buf;
@@ -1818,8 +1867,9 @@ private:
class Locked_tables_list
{
-private:
+public:
MEM_ROOT m_locked_tables_root;
+private:
TABLE_LIST *m_locked_tables;
TABLE_LIST **m_locked_tables_last;
/** An auxiliary array used only in reopen_tables(). */
@@ -1841,7 +1891,8 @@ public:
m_locked_tables_count(0),
some_table_marked_for_reopen(0)
{
- init_sql_alloc(&m_locked_tables_root, MEM_ROOT_BLOCK_SIZE, 0,
+ init_sql_alloc(&m_locked_tables_root, "Locked_tables_list",
+ MEM_ROOT_BLOCK_SIZE, 0,
MYF(MY_THREAD_SPECIFIC));
}
void unlock_locked_tables(THD *thd);
@@ -2101,14 +2152,8 @@ struct wait_for_commit
void reinit();
};
-
extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
-class THD;
-#ifndef DBUG_OFF
-void dbug_serve_apcs(THD *thd, int n_calls);
-#endif
-
/**
@class THD
For each client connection we create a separate thread with THD serving as
@@ -2218,12 +2263,16 @@ public:
Protects THD data accessed from other threads:
- thd->query and thd->query_length (used by SHOW ENGINE
INNODB STATUS and SHOW PROCESSLIST
- - thd->db and thd->db_length (used in SHOW PROCESSLIST)
- - thd->mysys_var (used by KILL statement and shutdown).
+ - thd->db (used in SHOW PROCESSLIST)
Is locked when THD is deleted.
*/
mysql_mutex_t LOCK_thd_data;
- /* Protect kill information */
+ /*
+ Protects:
+ - kill information
+ - mysys_var (used by KILL statement and shutdown).
+ - Also ensures that THD is not deleted while mutex is hold
+ */
mysql_mutex_t LOCK_thd_kill;
/* all prepared statements and cursors of this connection */
@@ -2285,12 +2334,13 @@ public:
const char *calling_file,
const unsigned int calling_line)
{
- DBUG_PRINT("THD::enter_stage", ("%s:%d", calling_file, calling_line));
+ DBUG_PRINT("THD::enter_stage", ("%s at %s:%d", stage->m_name,
+ calling_file, calling_line));
DBUG_ASSERT(stage);
m_current_stage_key= stage->m_key;
proc_info= stage->m_name;
#if defined(ENABLED_PROFILING)
- profiling.status_change(stage->m_name, calling_func, calling_file,
+ profiling.status_change(proc_info, calling_func, calling_file,
calling_line);
#endif
#ifdef HAVE_PSI_THREAD_INTERFACE
@@ -2316,7 +2366,8 @@ public:
/* Needed by MariaDB semi sync replication */
Trans_binlog_info *semisync_info;
-
+ /* If this is a semisync slave connection. */
+ bool semi_sync_slave;
ulonglong client_capabilities; /* What the client supports */
ulong max_client_packet_length;
@@ -2327,7 +2378,9 @@ public:
chapter 'Miscellaneous functions', for functions GET_LOCK, RELEASE_LOCK.
*/
HASH ull_hash;
-#ifndef DBUG_OFF
+ /* Hash of used seqeunces (for PREVIOUS value) */
+ HASH sequences;
+#ifdef DBUG_ASSERT_EXISTS
uint dbug_sentry; // watch out for memory corruption
#endif
struct st_my_thread_var *mysys_var;
@@ -2534,6 +2587,8 @@ private:
uint binlog_table_maps;
public:
void issue_unsafe_warnings();
+ void reset_unsafe_warnings()
+ { binlog_unsafe_warning_flags= 0; }
uint get_binlog_table_maps() const {
return binlog_table_maps;
@@ -2554,6 +2609,15 @@ public:
WT_THD wt; ///< for deadlock detection
Rows_log_event *m_pending_rows_event;
+ struct st_trans_time : public timeval
+ {
+ void reset(THD *thd)
+ {
+ tv_sec= thd->query_start();
+ tv_usec= (long) thd->query_start_sec_part();
+ }
+ } start_time;
+
/*
Tables changed in transaction (that must be invalidated in query cache).
List contain only transactional tables, that not invalidated in query
@@ -2585,7 +2649,8 @@ public:
{
bzero((char*)this, sizeof(*this));
xid_state.xid.null();
- init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0,
+ init_sql_alloc(&mem_root, "THD::transactions",
+ ALLOC_ROOT_MIN_BLOCK_SIZE, 0,
MYF(MY_THREAD_SPECIFIC));
}
} transaction;
@@ -2801,6 +2866,14 @@ public:
{
m_row_count_func= row_count_func;
}
+ inline void set_affected_rows(longlong row_count_func)
+ {
+ /*
+ We have to add to affected_rows (used by slow log), as otherwise
+ information for 'call' will be wrong
+ */
+ affected_rows+= (row_count_func >= 0 ? row_count_func : 0);
+ }
ha_rows cuted_fields;
@@ -2830,6 +2903,9 @@ public:
ha_rows get_examined_row_count() const
{ return m_examined_row_count; }
+ ulonglong get_affected_rows() const
+ { return affected_rows; }
+
void set_sent_row_count(ha_rows count);
void set_examined_row_count(ha_rows count);
@@ -2907,8 +2983,16 @@ public:
/* Statement id is thread-wide. This counter is used to generate ids */
ulong statement_id_counter;
ulong rand_saved_seed1, rand_saved_seed2;
+
+ /* The following variables are used when printing to slow log */
ulong query_plan_flags;
ulong query_plan_fsort_passes;
+ ulong tmp_tables_used;
+ ulong tmp_tables_disk_used;
+ ulonglong tmp_tables_size;
+ ulonglong bytes_sent_old;
+ ulonglong affected_rows; /* Number of changed rows */
+
pthread_t real_id; /* For debugging */
my_thread_id thread_id, thread_dbug_id;
uint32 os_thread_id;
@@ -2975,10 +3059,14 @@ public:
} *killed_err;
/* See also thd_killed() */
- inline bool check_killed()
+ inline bool check_killed(bool dont_send_error_message= 0)
{
- if (killed)
+ if (unlikely(killed))
+ {
+ if (!dont_send_error_message)
+ send_kill_message();
return TRUE;
+ }
if (apc_target.have_apc_requests())
apc_target.process_apc_requests();
return FALSE;
@@ -2991,13 +3079,12 @@ public:
If this is a slave, the name of the connection stored here.
This is used for taging error messages in the log files.
*/
- LEX_STRING connection_name;
+ LEX_CSTRING connection_name;
char default_master_connection_buff[MAX_CONNECTION_NAME+1];
uint8 password; /* 0, 1 or 2 */
uint8 failed_com_change_user;
bool slave_thread;
bool extra_port; /* If extra connection */
-
bool no_errors;
/**
@@ -3026,7 +3113,7 @@ public:
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;
+ bool rand_used, time_zone_used;
bool query_start_sec_part_used;
/* for IS NULL => = last_insert_id() fix in remove_eq_conds() */
bool substitute_null_with_insert_id;
@@ -3039,9 +3126,11 @@ public:
is set if a statement accesses a temporary table created through
CREATE TEMPORARY TABLE.
*/
- bool charset_is_system_charset, charset_is_collation_connection;
+private:
+ 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 */
+public:
+ 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 */
@@ -3073,10 +3162,13 @@ public:
the query. 0 if no error on the master.
*/
int slave_expected_error;
+ enum_sql_command last_sql_command; // Last sql_command exceuted in mysql_execute_command()
sp_rcontext *spcont; // SP runtime context
sp_cache *sp_proc_cache;
sp_cache *sp_func_cache;
+ sp_cache *sp_package_spec_cache;
+ sp_cache *sp_package_body_cache;
/** number of name_const() substitutions, see sp_head.cc:subst_spvars() */
uint query_name_consts;
@@ -3175,11 +3267,15 @@ public:
/* Debug Sync facility. See debug_sync.cc. */
struct st_debug_sync_control *debug_sync_control;
#endif /* defined(ENABLED_DEBUG_SYNC) */
+ /**
+ @param id thread identifier
+ @param is_wsrep_applier thread type
+ */
THD(my_thread_id id, bool is_wsrep_applier= false);
~THD();
- void init(void);
+ void init();
/*
Initialize memory roots necessary for query processing and (!)
pre-allocate memory for it. We can't do that in THD constructor because
@@ -3214,7 +3310,13 @@ public:
}
void close_active_vio();
#endif
- void awake(killed_state state_to_set);
+ void awake_no_mutex(killed_state state_to_set);
+ void awake(killed_state state_to_set)
+ {
+ mysql_mutex_lock(&LOCK_thd_kill);
+ awake_no_mutex(state_to_set);
+ mysql_mutex_unlock(&LOCK_thd_kill);
+ }
/** Disconnect the associated communication endpoint. */
void disconnect();
@@ -3320,45 +3422,109 @@ public:
{
return !MY_TEST(variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES);
}
- inline my_time_t query_start() { query_start_used=1; return start_time; }
+ const Type_handler *type_handler_for_date() const;
+ bool timestamp_to_TIME(MYSQL_TIME *ltime, my_time_t ts,
+ ulong sec_part, ulonglong fuzzydate);
+ inline my_time_t query_start() { return start_time; }
inline ulong query_start_sec_part()
{ query_start_sec_part_used=1; return start_time_sec_part; }
- inline void set_current_time()
+ MYSQL_TIME query_start_TIME();
+
+private:
+ struct {
+ my_hrtime_t start;
+ my_time_t sec;
+ ulong sec_part;
+ } system_time;
+
+ void set_system_time()
{
my_hrtime_t hrtime= my_hrtime();
- start_time= hrtime_to_my_time(hrtime);
- start_time_sec_part= hrtime_sec_part(hrtime);
-#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_THREAD_CALL(set_thread_start_time)(start_time);
-#endif
+ my_time_t sec= hrtime_to_my_time(hrtime);
+ ulong sec_part= hrtime_sec_part(hrtime);
+ if (sec > system_time.sec ||
+ (sec == system_time.sec && sec_part > system_time.sec_part) ||
+ hrtime.val < system_time.start.val)
+ {
+ system_time.sec= sec;
+ system_time.sec_part= sec_part;
+ system_time.start= hrtime;
+ }
+ else
+ {
+ if (system_time.sec_part < TIME_MAX_SECOND_PART)
+ system_time.sec_part++;
+ else
+ {
+ system_time.sec++;
+ system_time.sec_part= 0;
+ }
+ }
}
+
+public:
+ timeval transaction_time()
+ {
+ if (!in_multi_stmt_transaction_mode())
+ transaction.start_time.reset(this);
+ return transaction.start_time;
+ }
+
inline void set_start_time()
{
if (user_time.val)
{
start_time= hrtime_to_my_time(user_time);
start_time_sec_part= hrtime_sec_part(user_time);
-#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_THREAD_CALL(set_thread_start_time)(start_time);
-#endif
}
else
- set_current_time();
+ {
+ set_system_time();
+ start_time= system_time.sec;
+ start_time_sec_part= system_time.sec_part;
+ }
+ PSI_CALL_set_thread_start_time(start_time);
}
inline void set_time()
{
set_start_time();
start_utime= utime_after_lock= microsecond_interval_timer();
}
+ /* only used in SET @@timestamp=... */
inline void set_time(my_hrtime_t t)
{
user_time= t;
set_time();
}
+ /*
+ this is only used by replication and BINLOG command.
+ usecs > TIME_MAX_SECOND_PART means "was not in binlog"
+ */
inline void set_time(my_time_t t, ulong sec_part)
{
- my_hrtime_t hrtime= { hrtime_from_time(t) + sec_part };
- set_time(hrtime);
+ if (opt_secure_timestamp > (slave_thread ? SECTIME_REPL : SECTIME_SUPER))
+ set_time(); // note that BINLOG itself requires SUPER
+ else
+ {
+ if (sec_part <= TIME_MAX_SECOND_PART)
+ {
+ start_time= system_time.sec= t;
+ start_time_sec_part= system_time.sec_part= sec_part;
+ }
+ else if (t != system_time.sec)
+ {
+ start_time= system_time.sec= t;
+ start_time_sec_part= system_time.sec_part= 0;
+ }
+ else
+ {
+ start_time= t;
+ start_time_sec_part= ++system_time.sec_part;
+ }
+ user_time.val= hrtime_from_time(start_time) + start_time_sec_part;
+ PSI_CALL_set_thread_start_time(start_time);
+ start_utime= utime_after_lock= microsecond_interval_timer();
+ }
}
void set_time_after_lock()
{
@@ -3384,7 +3550,7 @@ public:
void update_server_status()
{
set_time_for_next_stage();
- if (utime_after_query > utime_after_lock + variables.long_query_time)
+ if (utime_after_query >= utime_after_lock + variables.long_query_time)
server_status|= SERVER_QUERY_WAS_SLOW;
}
inline ulonglong found_rows(void)
@@ -3463,45 +3629,109 @@ public:
{
return !stmt_arena->is_stmt_prepare();
}
- inline void* trans_alloc(unsigned int size)
+ inline void* trans_alloc(size_t size)
{
return alloc_root(&transaction.mem_root,size);
}
- LEX_STRING *make_lex_string(LEX_STRING *lex_str, const char* str, uint length)
+ LEX_STRING *make_lex_string(LEX_STRING *lex_str, const char* str, size_t length)
+ {
+ if (!(lex_str->str= strmake_root(mem_root, str, length)))
+ {
+ lex_str->length= 0;
+ return 0;
+ }
+ lex_str->length= length;
+ return lex_str;
+ }
+ LEX_CSTRING *make_lex_string(LEX_CSTRING *lex_str, const char* str, size_t length)
{
if (!(lex_str->str= strmake_root(mem_root, str, length)))
+ {
+ lex_str->length= 0;
return 0;
+ }
lex_str->length= length;
return lex_str;
}
+ // Remove double quotes: aaa""bbb -> aaa"bbb
+ bool quote_unescape(LEX_CSTRING *dst, const LEX_CSTRING *src, char quote)
+ {
+ const char *tmp= src->str;
+ const char *tmpend= src->str + src->length;
+ char *to;
+ if (!(dst->str= to= (char *) alloc(src->length + 1)))
+ {
+ dst->length= 0; // Safety
+ return true;
+ }
+ for ( ; tmp < tmpend; )
+ {
+ if ((*to++= *tmp++) == quote)
+ tmp++; // Skip double quotes
+ }
+ *to= 0; // End null for safety
+ dst->length= to - dst->str;
+ return false;
+ }
- LEX_STRING *make_lex_string(const char* str, uint length)
+ LEX_CSTRING *make_clex_string(const char* str, size_t length)
{
- LEX_STRING *lex_str;
- if (!(lex_str= (LEX_STRING *)alloc_root(mem_root, sizeof(LEX_STRING))))
+ LEX_CSTRING *lex_str;
+ char *tmp;
+ if (unlikely(!(lex_str= (LEX_CSTRING *)alloc_root(mem_root,
+ sizeof(LEX_CSTRING) +
+ length+1))))
return 0;
- return make_lex_string(lex_str, str, length);
+ tmp= (char*) (lex_str+1);
+ lex_str->str= tmp;
+ memcpy(tmp, str, length);
+ tmp[length]= 0;
+ lex_str->length= length;
+ return lex_str;
+ }
+ LEX_CSTRING *make_clex_string(const LEX_CSTRING from)
+ {
+ return make_clex_string(from.str, from.length);
}
// Allocate LEX_STRING for character set conversion
- bool alloc_lex_string(LEX_STRING *dst, uint length)
+ bool alloc_lex_string(LEX_STRING *dst, size_t length)
{
- if ((dst->str= (char*) alloc(length)))
+ if (likely((dst->str= (char*) alloc(length))))
return false;
dst->length= 0; // Safety
return true; // EOM
}
bool convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
- const char *from, uint from_length,
+ const char *from, size_t from_length,
CHARSET_INFO *from_cs);
+ bool convert_string(LEX_CSTRING *to, CHARSET_INFO *to_cs,
+ const char *from, size_t from_length,
+ CHARSET_INFO *from_cs)
+ {
+ LEX_STRING tmp;
+ bool rc= convert_string(&tmp, to_cs, from, from_length, from_cs);
+ to->str= tmp.str;
+ to->length= tmp.length;
+ return rc;
+ }
+ bool convert_string(LEX_CSTRING *to, CHARSET_INFO *tocs,
+ const LEX_CSTRING *from, CHARSET_INFO *fromcs,
+ bool simple_copy_is_possible)
+ {
+ if (!simple_copy_is_possible)
+ return unlikely(convert_string(to, tocs, from->str, from->length, fromcs));
+ *to= *from;
+ return false;
+ }
/*
Convert a strings between character sets.
Uses my_convert_fix(), which uses an mb_wc .. mc_mb loop internally.
dstcs and srccs cannot be &my_charset_bin.
*/
bool convert_fix(CHARSET_INFO *dstcs, LEX_STRING *dst,
- CHARSET_INFO *srccs, const char *src, uint src_length,
+ CHARSET_INFO *srccs, const char *src, size_t src_length,
String_copier *status);
/*
@@ -3510,15 +3740,14 @@ public:
*/
bool convert_with_error(CHARSET_INFO *dstcs, LEX_STRING *dst,
CHARSET_INFO *srccs,
- const char *src, uint src_length);
-
+ const char *src, size_t src_length);
/*
If either "dstcs" or "srccs" is &my_charset_bin,
then performs native copying using cs->cset->copy_fix().
Otherwise, performs Unicode conversion using convert_fix().
*/
bool copy_fix(CHARSET_INFO *dstcs, LEX_STRING *dst,
- CHARSET_INFO *srccs, const char *src, uint src_length,
+ CHARSET_INFO *srccs, const char *src, size_t src_length,
String_copier *status);
/*
@@ -3526,13 +3755,58 @@ public:
in case of bad byte sequences or Unicode conversion problems.
*/
bool copy_with_error(CHARSET_INFO *dstcs, LEX_STRING *dst,
- CHARSET_INFO *srccs, const char *src, uint src_length);
+ CHARSET_INFO *srccs, const char *src, size_t src_length);
bool convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs);
+ /*
+ Check if the string is wellformed, raise an error if not wellformed.
+ @param str - The string to check.
+ @param length - the string length.
+ */
+ bool check_string_for_wellformedness(const char *str,
+ size_t length,
+ CHARSET_INFO *cs) const;
+
+ bool to_ident_sys_alloc(Lex_ident_sys_st *to, const Lex_ident_cli_st *from);
+
+ /*
+ Create a string literal with optional client->connection conversion.
+ @param str - the string in the client character set
+ @param length - length of the string
+ @param repertoire - the repertoire of the string
+ */
+ Item_basic_constant *make_string_literal(const char *str, size_t length,
+ uint repertoire);
+ Item_basic_constant *make_string_literal(const Lex_string_with_metadata_st &str)
+ {
+ uint repertoire= str.repertoire(variables.character_set_client);
+ return make_string_literal(str.str, str.length, repertoire);
+ }
+ Item_basic_constant *make_string_literal_nchar(const Lex_string_with_metadata_st &str);
+ Item_basic_constant *make_string_literal_charset(const Lex_string_with_metadata_st &str,
+ CHARSET_INFO *cs);
+ bool make_text_string_sys(LEX_CSTRING *to,
+ const Lex_string_with_metadata_st *from)
+ {
+ return convert_string(to, system_charset_info,
+ from, charset(), charset_is_system_charset);
+ }
+ bool make_text_string_connection(LEX_CSTRING *to,
+ const Lex_string_with_metadata_st *from)
+ {
+ return convert_string(to, variables.collation_connection,
+ from, charset(), charset_is_collation_connection);
+ }
+ bool make_text_string_filesystem(LEX_CSTRING *to,
+ const Lex_string_with_metadata_st *from)
+ {
+ return convert_string(to, variables.character_set_filesystem,
+ from, charset(), charset_is_character_set_filesystem);
+ }
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);
+ void add_changed_table(const char *key, size_t key_length);
+ CHANGED_TABLE_LIST * changed_table_dup(const char *key, size_t key_length);
int prepare_explain_fields(select_result *result, List<Item> *field_list,
uint8 explain_flags, bool is_analyze);
int send_explain_fields(select_result *result, uint8 explain_flags,
@@ -3621,7 +3895,7 @@ public:
void set_stmt_da(Diagnostics_area *da)
{ m_stmt_da= da; }
- inline CHARSET_INFO *charset() { return variables.character_set_client; }
+ inline CHARSET_INFO *charset() const { return variables.character_set_client; }
void update_charset();
void update_charset(CHARSET_INFO *character_set_client,
CHARSET_INFO *collation_connection)
@@ -3729,7 +4003,7 @@ public:
The worst things that can happen is that we get
a suboptimal error message.
*/
- if ((killed_err= (err_info*) alloc(sizeof(*killed_err))))
+ if (likely((killed_err= (err_info*) alloc(sizeof(*killed_err)))))
{
killed_err->no= killed_errno_arg;
::strmake((char*) killed_err->msg, killed_err_msg_arg,
@@ -3739,20 +4013,7 @@ public:
}
}
int killed_errno();
- inline void reset_killed()
- {
- /*
- Resetting killed has to be done under a mutex to ensure
- its not done during an awake() call.
- */
- if (killed != NOT_KILLED)
- {
- mysql_mutex_lock(&LOCK_thd_kill);
- killed= NOT_KILLED;
- killed_err= 0;
- mysql_mutex_unlock(&LOCK_thd_kill);
- }
- }
+ void reset_killed();
inline void reset_kill_query()
{
if (killed < KILL_CONNECTION)
@@ -3782,6 +4043,9 @@ public:
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 store_slow_query_state(Sub_statement_state *backup);
+ void reset_slow_query_state();
+ void add_slow_query_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);
@@ -3840,6 +4104,11 @@ public:
DBUG_VOID_RETURN;
}
+ inline void set_current_stmt_binlog_format(enum_binlog_format format)
+ {
+ current_stmt_binlog_format= format;
+ }
+
inline void set_current_stmt_binlog_format_row()
{
DBUG_ENTER("set_current_stmt_binlog_format_row");
@@ -3914,67 +4183,21 @@ public:
@retval FALSE Success
@retval TRUE Out-of-memory error
*/
- bool set_db(const char *new_db, size_t new_db_len)
- {
- /*
- Acquiring mutex LOCK_thd_data as we either free the memory allocated
- for the database and reallocating the memory for the new db or memcpy
- the new_db to the db.
- */
- mysql_mutex_lock(&LOCK_thd_data);
- /* 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;
- bool result= new_db && !db;
- mysql_mutex_unlock(&LOCK_thd_data);
-#ifdef HAVE_PSI_THREAD_INTERFACE
- if (result)
- PSI_THREAD_CALL(set_thread_db)(new_db, (int) new_db_len);
-#endif
- return result;
- }
+ bool set_db(const LEX_CSTRING *new_db);
- /**
- Set the current database; use shallow copy of C-string.
+ /** Set the current database, without copying */
+ void reset_db(const LEX_CSTRING *new_db);
- @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)
- {
- if (new_db != db || new_db_len != db_length)
- {
- mysql_mutex_lock(&LOCK_thd_data);
- db= new_db;
- db_length= new_db_len;
- mysql_mutex_unlock(&LOCK_thd_data);
-#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_THREAD_CALL(set_thread_db)(new_db, (int) new_db_len);
-#endif
- }
- }
/*
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.
+
+ Can only be called by owner of thd (no mutex protection)
*/
- bool copy_db_to(char **p_db, size_t *p_db_length)
+ bool copy_db_to(LEX_CSTRING *to)
{
- if (db == NULL)
+ if (db.str == NULL)
{
/*
No default database is set. In this case if it's guaranteed that
@@ -3990,16 +4213,19 @@ public:
return TRUE;
}
/* This will allow to throw an error later for non-CTE references */
- *p_db= NULL;
- *p_db_length= 0;
+ to->str= NULL;
+ to->length= 0;
+ return FALSE;
}
- else
- {
- *p_db= strmake(db, db_length);
- *p_db_length= db_length;
- }
- return FALSE;
+
+ to->str= strmake(db.str, db.length);
+ to->length= db.length;
+ return to->str == NULL; /* True on error */
}
+ /* Get db name or "". Use for printing current db */
+ const char *get_db()
+ { return safe_str(db.str); }
+
thd_scheduler event_scheduler;
public:
@@ -4070,6 +4296,39 @@ public:
*/
void raise_note_printf(uint code, ...);
+ /**
+ @brief Push an error message into MySQL error stack with line
+ and position information.
+
+ This function provides semantic action implementers with a way
+ to push the famous "You have a syntax error near..." error
+ message into the error stack, which is normally produced only if
+ a parse error is discovered internally by the Bison generated
+ parser.
+ */
+ void parse_error(const char *err_text, const char *yytext)
+ {
+ Lex_input_stream *lip= &m_parser_state->m_lip;
+ if (!yytext && !(yytext= lip->get_tok_start()))
+ yytext= "";
+ /* Push an error into the error stack */
+ ErrConvString err(yytext, strlen(yytext), variables.character_set_client);
+ my_printf_error(ER_PARSE_ERROR, ER_THD(this, ER_PARSE_ERROR), MYF(0),
+ err_text, err.ptr(), lip->yylineno);
+ }
+ void parse_error(uint err_number, const char *yytext= 0)
+ {
+ parse_error(ER_THD(this, err_number), yytext);
+ }
+ void parse_error()
+ {
+ parse_error(ER_SYNTAX_ERROR);
+ }
+#ifdef mysqld_error_find_printf_error_used
+ void parse_error(const char *t)
+ {
+ }
+#endif
private:
/*
Only the implementation of the SIGNAL and RESIGNAL statements
@@ -4096,8 +4355,42 @@ private:
raise_condition(uint sql_errno,
const char* sqlstate,
Sql_condition::enum_warning_level level,
+ const char* msg)
+ {
+ return raise_condition(sql_errno, sqlstate, level,
+ Sql_user_condition_identity(), msg);
+ }
+
+ /**
+ Raise a generic or a user defined SQL condition.
+ @param ucid - the user condition identity
+ (or an empty identity if not a user 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
+ */
+ Sql_condition*
+ raise_condition(uint sql_errno,
+ const char* sqlstate,
+ Sql_condition::enum_warning_level level,
+ const Sql_user_condition_identity &ucid,
const char* msg);
+ Sql_condition*
+ raise_condition(const Sql_condition *cond)
+ {
+ Sql_condition *raised= raise_condition(cond->get_sql_errno(),
+ cond->get_sqlstate(),
+ cond->get_level(),
+ *cond/*Sql_user_condition_identity*/,
+ cond->get_message_text());
+ if (raised)
+ raised->copy_opt_attributes(cond);
+ return raised;
+ }
+
public:
/** Overloaded to guard query/query_length fields */
virtual void set_statement(Statement *stmt);
@@ -4115,12 +4408,12 @@ public:
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,
+ void set_query(char *query_arg, size_t 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*/
+ void set_query(char *query_arg, size_t query_length_arg) /*Mutex protected*/
{
set_query(CSET_STRING(query_arg, query_length_arg, charset()));
}
@@ -4130,9 +4423,7 @@ public:
set_query_inner(string_arg);
mysql_mutex_unlock(&LOCK_thd_data);
-#ifdef HAVE_PSI_THREAD_INTERFACE
- PSI_THREAD_CALL(set_thread_info)(query(), query_length());
-#endif
+ PSI_CALL_set_thread_info(query(), query_length());
}
void reset_query() /* Mutex protected */
{ set_query(CSET_STRING()); }
@@ -4187,14 +4478,14 @@ public:
void binlog_invoker(bool role) { m_binlog_invoker= role ? INVOKER_ROLE : INVOKER_USER; }
enum need_invoker need_binlog_invoker() { return m_binlog_invoker; }
void get_definer(LEX_USER *definer, bool role);
- void set_invoker(const LEX_STRING *user, const LEX_STRING *host)
+ void set_invoker(const LEX_CSTRING *user, const LEX_CSTRING *host)
{
- invoker_user= *user;
- invoker_host= *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; }
+ LEX_CSTRING get_invoker_user() { return invoker.user; }
+ LEX_CSTRING get_invoker_host() { return invoker.host; }
+ bool has_invoker() { return invoker.user.length > 0; }
void print_aborted_warning(uint threshold, const char *reason)
{
@@ -4202,7 +4493,7 @@ public:
{
Security_context *sctx= &main_security_ctx;
sql_print_warning(ER_THD(this, ER_NEW_ABORTING_CONNECTION),
- thread_id, (db ? db : "unconnected"),
+ thread_id, (db.str ? db.str : "unconnected"),
sctx->user ? sctx->user : "unauthenticated",
sctx->host_or_ip, reason);
}
@@ -4293,8 +4584,7 @@ private:
TRIGGER or VIEW statements or current user in account management
statements if it is not NULL.
*/
- LEX_STRING invoker_user;
- LEX_STRING invoker_host;
+ AUTHID invoker;
public:
#ifndef EMBEDDED_LIBRARY
@@ -4341,7 +4631,8 @@ public:
const char *path,
const char *db,
const char *table_name,
- bool open_in_engine);
+ bool open_in_engine,
+ bool open_internal_tables);
TABLE *find_temporary_table(const char *db, const char *table_name,
Temporary_table_state state= TMP_TABLE_IN_USE);
@@ -4353,14 +4644,14 @@ public:
TMP_TABLE_SHARE *find_tmp_table_share(const char *db,
const char *table_name);
TMP_TABLE_SHARE *find_tmp_table_share(const TABLE_LIST *tl);
- TMP_TABLE_SHARE *find_tmp_table_share(const char *key, uint key_length);
+ TMP_TABLE_SHARE *find_tmp_table_share(const char *key, size_t key_length);
bool open_temporary_table(TABLE_LIST *tl);
bool open_temporary_tables(TABLE_LIST *tl);
bool close_temporary_tables();
- bool rename_temporary_table(TABLE *table, const char *db,
- const char *table_name);
+ bool rename_temporary_table(TABLE *table, const LEX_CSTRING *db,
+ const LEX_CSTRING *table_name);
bool drop_temporary_table(TABLE *table, bool *is_trans, bool delete_table);
bool rm_temporary_table(handlerton *hton, const char *path);
void mark_tmp_tables_as_free_for_reuse();
@@ -4466,6 +4757,7 @@ public:
/* Handling of timeouts for commands */
thr_timer_t query_timer;
+
public:
void set_query_timer()
{
@@ -4519,6 +4811,57 @@ public:
current_linfo= 0;
mysql_mutex_unlock(&LOCK_thread_count);
}
+
+
+ uint get_net_wait_timeout()
+ {
+ if (in_active_multi_stmt_transaction())
+ {
+ if (transaction.all.is_trx_read_write())
+ {
+ if (variables.idle_write_transaction_timeout > 0)
+ return variables.idle_write_transaction_timeout;
+ }
+ else
+ {
+ if (variables.idle_readonly_transaction_timeout > 0)
+ return variables.idle_readonly_transaction_timeout;
+ }
+
+ if (variables.idle_transaction_timeout > 0)
+ return variables.idle_transaction_timeout;
+ }
+
+ return variables.net_wait_timeout;
+ }
+
+ /**
+ Switch to a sublex, to parse a substatement or an expression.
+ */
+ void set_local_lex(sp_lex_local *sublex)
+ {
+ DBUG_ASSERT(lex->sphead);
+ lex= sublex;
+ /* Reset part of parser state which needs this. */
+ m_parser_state->m_yacc.reset_before_substatement();
+ }
+
+ /**
+ Switch back from a sublex (currently pointed by this->lex) to the old lex.
+ Sublex is merged to "oldlex" and this->lex is set to "oldlex".
+
+ This method is called after parsing a substatement or an expression.
+ set_local_lex() must be previously called.
+ @param oldlex - The old lex which was active before set_local_lex().
+ @returns - false on success, true on error (failed to merge LEX's).
+
+ See also sp_head::merge_lex().
+ */
+ bool restore_from_local_lex_to_old_lex(LEX *oldlex);
+
+ Item *sp_fix_func_item(Item **it_addr);
+ Item *sp_prepare_func_item(Item **it_addr, uint cols= 1);
+ bool sp_eval_expr(Field *result_field, Item **expr_item_ptr);
};
inline void add_to_active_threads(THD *thd)
@@ -4545,11 +4888,12 @@ inline void unlink_not_visible_thd(THD *thd)
/** A short cut for thd->get_stmt_da()->set_ok_status(). */
inline void
-my_ok(THD *thd, ulonglong affected_rows= 0, ulonglong id= 0,
+my_ok(THD *thd, ulonglong affected_rows_arg= 0, ulonglong id= 0,
const char *message= NULL)
{
- thd->set_row_count_func(affected_rows);
- thd->get_stmt_da()->set_ok_status(affected_rows, id, message);
+ thd->set_row_count_func(affected_rows_arg);
+ thd->set_affected_rows(affected_rows_arg);
+ thd->get_stmt_da()->set_ok_status(affected_rows_arg, id, message);
}
@@ -4590,15 +4934,15 @@ class sql_exchange :public Sql_alloc
{
public:
enum enum_filetype filetype; /* load XML, Added by Arnold & Erik */
- char *file_name;
+ const 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,
+ sql_exchange(const char *name, bool dumpfile_flag,
enum_filetype filetype_arg= FILETYPE_CSV);
- bool escaped_given(void);
+ bool escaped_given(void) const;
};
/*
@@ -4619,6 +4963,7 @@ public:
*/
virtual int send_data(List<Item> &items)=0;
virtual ~select_result_sink() {};
+ void reset(THD *thd_arg) { thd= thd_arg; }
};
class select_result_interceptor;
@@ -4646,7 +4991,8 @@ protected:
SELECT_LEX_UNIT *unit;
/* Something used only by the parser: */
public:
- select_result(THD *thd_arg): select_result_sink(thd_arg) {}
+ ha_rows est_records; /* estimated number of records in the result */
+ select_result(THD *thd_arg): select_result_sink(thd_arg), est_records(0) {}
void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; }
virtual ~select_result() {};
/**
@@ -4671,7 +5017,7 @@ public:
unit= u;
return 0;
}
- virtual int prepare2(void) { return 0; }
+ virtual int prepare2(JOIN *join) { return 0; }
/*
Because of peculiarities of prepared statements protocol
we need to know number of columns in the result set (if
@@ -4680,7 +5026,7 @@ public:
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 initialize_tables (JOIN *join=0) { return 0; }
+ virtual bool initialize_tables (JOIN *join) { return 0; }
virtual bool send_eof()=0;
/**
Check if this query returns a result set and therefore is allowed in
@@ -4697,6 +5043,11 @@ public:
*/
virtual void cleanup();
void set_thd(THD *thd_arg) { thd= thd_arg; }
+ void reset(THD *thd_arg)
+ {
+ select_result_sink::reset(thd_arg);
+ unit= NULL;
+ }
#ifdef EMBEDDED_LIBRARY
virtual void begin_dataset() {}
#else
@@ -4718,6 +5069,14 @@ public:
- this if the output is set elsewhere (a file, @variable, or table).
*/
virtual select_result_interceptor *result_interceptor()=0;
+
+ /*
+ This method is used to distinguish an normal SELECT from the cursor
+ structure discovery for cursor%ROWTYPE routine variables.
+ If this method returns "true", then a SELECT execution performs only
+ all preparation stages, but does not fetch any rows.
+ */
+ virtual bool view_structure_only() const { return false; }
};
@@ -4792,11 +5151,117 @@ public:
elsewhere. (this is used by ANALYZE $stmt feature).
*/
void disable_my_ok_calls() { suppress_my_ok= true; }
+ void reset(THD *thd_arg)
+ {
+ select_result::reset(thd_arg);
+ suppress_my_ok= false;
+ }
protected:
bool suppress_my_ok;
};
+class sp_cursor_statistics
+{
+protected:
+ ulonglong m_fetch_count; // Number of FETCH commands since last OPEN
+ ulonglong m_row_count; // Number of successful FETCH since last OPEN
+ bool m_found; // If last FETCH fetched a row
+public:
+ sp_cursor_statistics()
+ :m_fetch_count(0),
+ m_row_count(0),
+ m_found(false)
+ { }
+ bool found() const
+ { return m_found; }
+
+ ulonglong row_count() const
+ { return m_row_count; }
+
+ ulonglong fetch_count() const
+ { return m_fetch_count; }
+ void reset() { *this= sp_cursor_statistics(); }
+};
+
+
+/* A mediator between stored procedures and server side cursors */
+class sp_lex_keeper;
+class sp_cursor: public sp_cursor_statistics
+{
+private:
+ /// An interceptor of cursor result set used to implement
+ /// FETCH <cname> INTO <varlist>.
+ class Select_fetch_into_spvars: public select_result_interceptor
+ {
+ List<sp_variable> *spvar_list;
+ uint field_count;
+ bool m_view_structure_only;
+ bool send_data_to_variable_list(List<sp_variable> &vars, List<Item> &items);
+ public:
+ Select_fetch_into_spvars(THD *thd_arg, bool view_structure_only)
+ :select_result_interceptor(thd_arg),
+ m_view_structure_only(view_structure_only)
+ {}
+ void reset(THD *thd_arg)
+ {
+ select_result_interceptor::reset(thd_arg);
+ spvar_list= NULL;
+ field_count= 0;
+ }
+ uint get_field_count() { return field_count; }
+ void set_spvar_list(List<sp_variable> *vars) { spvar_list= vars; }
+
+ virtual bool send_eof() { return FALSE; }
+ virtual int send_data(List<Item> &items);
+ virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
+ virtual bool view_structure_only() const { return m_view_structure_only; }
+};
+
+public:
+ sp_cursor()
+ :result(NULL, false),
+ m_lex_keeper(NULL),
+ server_side_cursor(NULL)
+ { }
+ sp_cursor(THD *thd_arg, sp_lex_keeper *lex_keeper, bool view_structure_only)
+ :result(thd_arg, view_structure_only),
+ m_lex_keeper(lex_keeper),
+ server_side_cursor(NULL)
+ {}
+
+ virtual ~sp_cursor()
+ { destroy(); }
+
+ sp_lex_keeper *get_lex_keeper() { return m_lex_keeper; }
+
+ int open(THD *thd);
+
+ int close(THD *thd);
+
+ my_bool is_open()
+ { return MY_TEST(server_side_cursor); }
+
+ int fetch(THD *, List<sp_variable> *vars, bool error_on_no_data);
+
+ bool export_structure(THD *thd, Row_definition_list *list);
+
+ void reset(THD *thd_arg, sp_lex_keeper *lex_keeper)
+ {
+ sp_cursor_statistics::reset();
+ result.reset(thd_arg);
+ m_lex_keeper= lex_keeper;
+ server_side_cursor= NULL;
+ }
+
+private:
+ Select_fetch_into_spvars result;
+ sp_lex_keeper *m_lex_keeper;
+ Server_side_cursor *server_side_cursor;
+ void destroy();
+};
+
+
class select_send :public select_result {
/**
True if we have sent result set metadata to the client.
@@ -4914,7 +5379,7 @@ class select_insert :public select_result_interceptor {
enum_duplicates duplic, bool ignore);
~select_insert();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- virtual int prepare2(void);
+ virtual int prepare2(JOIN *join);
virtual int send_data(List<Item> &items);
virtual void store_values(List<Item> &values);
virtual bool can_rollback_data() { return 0; }
@@ -4966,7 +5431,13 @@ public:
// 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; }
+ int prepare2(JOIN *join) { return 0; }
+
+private:
+ TABLE *create_table_from_items(THD *thd,
+ List<Item> *items,
+ MYSQL_LOCK **lock,
+ TABLEOP_HOOKS *hooks);
};
#include <myisam.h>
@@ -5094,18 +5565,23 @@ public:
};
-class select_union :public select_result_interceptor
+class select_unit :public select_result_interceptor
{
+ uint curr_step, prev_step, curr_sel;
+ enum sub_select_type step;
public:
+ Item_int *intersect_mark;
TMP_TABLE_PARAM tmp_table_param;
int write_err; /* Error code from the last send_data->ha_write_row call. */
-public:
TABLE *table;
- ha_rows records;
- select_union(THD *thd_arg):
- select_result_interceptor(thd_arg), write_err(0), table(0), records(0)
- { tmp_table_param.init(); }
+ select_unit(THD *thd_arg):
+ select_result_interceptor(thd_arg),
+ intersect_mark(0), table(0)
+ {
+ init();
+ tmp_table_param.init();
+ }
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
/**
Do prepare() and prepare2() if they have been postponed until
@@ -5123,15 +5599,23 @@ public:
void cleanup();
virtual bool create_result_table(THD *thd, List<Item> *column_types,
bool is_distinct, ulonglong options,
- const char *alias,
+ const LEX_CSTRING *alias,
bool bit_fields_as_long,
bool create_table,
- bool keep_row_order= FALSE);
+ bool keep_row_order,
+ uint hidden);
TMP_TABLE_PARAM *get_tmp_table_param() { return &tmp_table_param; }
+ void init()
+ {
+ curr_step= prev_step= 0;
+ curr_sel= UINT_MAX;
+ step= UNION_TYPE;
+ write_err= 0;
+ }
+ void change_select();
};
-
-class select_union_recursive :public select_union
+class select_union_recursive :public select_unit
{
public:
/* The temporary table with the new records generated by one iterative step */
@@ -5148,16 +5632,17 @@ class select_union_recursive :public select_union
uint cleanup_count;
select_union_recursive(THD *thd_arg):
- select_union(thd_arg),
+ select_unit(thd_arg),
incr_table(0), first_rec_table_to_update(0), cleanup_count(0) {};
int send_data(List<Item> &items);
bool create_result_table(THD *thd, List<Item> *column_types,
bool is_distinct, ulonglong options,
- const char *alias,
+ const LEX_CSTRING *alias,
bool bit_fields_as_long,
bool create_table,
- bool keep_row_order= FALSE);
+ bool keep_row_order,
+ uint hidden);
void cleanup();
};
@@ -5174,7 +5659,7 @@ class select_union_recursive :public select_union
have a global ORDER BY clause. @see st_select_lex_unit::prepare().
*/
-class select_union_direct :public select_union
+class select_union_direct :public select_unit
{
private:
/* Result object that receives all rows */
@@ -5200,7 +5685,7 @@ public:
ha_rows send_records;
select_union_direct(THD *thd_arg, select_result *result_arg,
SELECT_LEX *last_select_lex_arg):
- select_union(thd_arg), result(result_arg),
+ select_unit(thd_arg), result(result_arg),
last_select_lex(last_select_lex_arg),
done_send_result_set_metadata(false), done_initialize_tables(false),
limit_found_rows(0)
@@ -5215,7 +5700,7 @@ public:
bool postponed_prepare(List<Item> &types);
bool send_result_set_metadata(List<Item> &list, uint flags);
int send_data(List<Item> &items);
- bool initialize_tables (JOIN *join= NULL);
+ bool initialize_tables (JOIN *join);
bool send_eof();
bool flush() { return false; }
bool check_simple_select() const
@@ -5283,7 +5768,7 @@ public:
about NULLs.
*/
-class select_materialize_with_stats : public select_union
+class select_materialize_with_stats : public select_unit
{
protected:
class Column_statistics
@@ -5316,14 +5801,15 @@ protected:
void reset();
public:
- select_materialize_with_stats(THD *thd_arg): select_union(thd_arg)
+ select_materialize_with_stats(THD *thd_arg): select_unit(thd_arg)
{ tmp_table_param.init(); }
bool create_result_table(THD *thd, List<Item> *column_types,
bool is_distinct, ulonglong options,
- const char *alias,
+ const LEX_CSTRING *alias,
bool bit_fields_as_long,
bool create_table,
- bool keep_row_order= FALSE);
+ bool keep_row_order,
+ uint hidden);
bool init_result_table(ulonglong select_options);
int send_data(List<Item> &items);
void cleanup();
@@ -5376,8 +5862,6 @@ public:
};
-
-
/*
Optimizer and executor structure for the materialized semi-join info. This
structure contains
@@ -5392,7 +5876,10 @@ public:
uint tables; /* Number of tables in the sj-nest */
- /* Expected #rows in the materialized table */
+ /* Number of rows in the materialized table, before the de-duplication */
+ double rows_with_duplicates;
+
+ /* Expected #rows in the materialized table, after de-duplication */
double rows;
/*
@@ -5465,22 +5952,23 @@ typedef struct st_sort_buffer {
class Table_ident :public Sql_alloc
{
public:
- LEX_STRING db;
- LEX_STRING table;
+ LEX_CSTRING db;
+ LEX_CSTRING table;
SELECT_LEX_UNIT *sel;
- inline Table_ident(THD *thd, LEX_STRING db_arg, LEX_STRING table_arg,
+ inline Table_ident(THD *thd, const LEX_CSTRING *db_arg,
+ const LEX_CSTRING *table_arg,
bool force)
- :table(table_arg), sel((SELECT_LEX_UNIT *)0)
+ :table(*table_arg), sel((SELECT_LEX_UNIT *)0)
{
if (!force && (thd->client_capabilities & CLIENT_NO_SCHEMA))
- db.str=0;
+ db= null_clex_str;
else
- db= db_arg;
+ db= *db_arg;
}
- inline Table_ident(LEX_STRING table_arg)
- :table(table_arg), sel((SELECT_LEX_UNIT *)0)
+ inline Table_ident(const LEX_CSTRING *table_arg)
+ :table(*table_arg), sel((SELECT_LEX_UNIT *)0)
{
- db.str=0;
+ db= null_clex_str;
}
/*
This constructor is used only for the case when we create a derived
@@ -5497,21 +5985,49 @@ public:
table.length=1;
}
bool is_derived_table() const { return MY_TEST(sel); }
- inline void change_db(char *db_name)
+ inline void change_db(LEX_CSTRING *db_name)
{
- db.str= db_name; db.length= (uint) strlen(db_name);
+ db= *db_name;
}
+ bool resolve_table_rowtype_ref(THD *thd, Row_definition_list &defs);
+ bool append_to(THD *thd, String *to) const;
+};
+
+
+class Qualified_column_ident: public Table_ident
+{
+public:
+ LEX_CSTRING m_column;
+public:
+ Qualified_column_ident(const LEX_CSTRING *column)
+ :Table_ident(&null_clex_str),
+ m_column(*column)
+ { }
+ Qualified_column_ident(const LEX_CSTRING *table, const LEX_CSTRING *column)
+ :Table_ident(table),
+ m_column(*column)
+ { }
+ Qualified_column_ident(THD *thd,
+ const LEX_CSTRING *db,
+ const LEX_CSTRING *table,
+ const LEX_CSTRING *column)
+ :Table_ident(thd, db, table, false),
+ m_column(*column)
+ { }
+ bool resolve_type_ref(THD *thd, Column_definition *def);
+ bool append_to(THD *thd, String *to) const;
};
+
// this is needed for user_vars hash
class user_var_entry
{
CHARSET_INFO *m_charset;
public:
user_var_entry() {} /* Remove gcc warning */
- LEX_STRING name;
+ LEX_CSTRING name;
char *value;
- ulong length;
+ size_t length;
query_id_t update_query_id, used_query_id;
Item_result type;
bool unsigned_flag;
@@ -5524,7 +6040,7 @@ class user_var_entry
void set_charset(CHARSET_INFO *cs) { m_charset= cs; }
};
-user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
+user_var_entry *get_variable(HASH *hash, LEX_CSTRING *name,
bool create_if_not_exists);
class SORT_INFO;
@@ -5566,7 +6082,7 @@ class multi_update :public select_result_interceptor
{
TABLE_LIST *all_tables; /* query/update command tables */
List<TABLE_LIST> *leaves; /* list of leves of join table tree */
- TABLE_LIST *update_tables, *table_being_updated;
+ TABLE_LIST *update_tables;
TABLE **tmp_tables, *main_table, *table_to_update;
TMP_TABLE_PARAM *tmp_table_param;
ha_rows updated, found;
@@ -5592,6 +6108,12 @@ class multi_update :public select_result_interceptor
/* Need this to protect against multiple prepare() calls */
bool prepared;
+
+ // For System Versioning (may need to insert new fields to a table).
+ ha_rows updated_sys_ver;
+
+ bool has_vers_fields;
+
public:
multi_update(THD *thd_arg, TABLE_LIST *ut, List<TABLE_LIST> *leaves_list,
List<Item> *fields, List<Item> *values,
@@ -5600,6 +6122,7 @@ public:
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
int send_data(List<Item> &items);
bool initialize_tables (JOIN *join);
+ int prepare2(JOIN *join);
int do_updates();
bool send_eof();
inline ha_rows num_found() const { return found; }
@@ -5609,34 +6132,62 @@ public:
void prepare_to_read_rows();
};
+class my_var_sp;
class my_var : public Sql_alloc {
public:
- const LEX_STRING name;
+ const LEX_CSTRING name;
enum type { SESSION_VAR, LOCAL_VAR, PARAM_VAR };
type scope;
- my_var(const LEX_STRING& j, enum type s) : name(j), scope(s) { }
+ my_var(const LEX_CSTRING *j, enum type s) : name(*j), scope(s) { }
virtual ~my_var() {}
virtual bool set(THD *thd, Item *val) = 0;
+ virtual my_var_sp *get_my_var_sp() { return NULL; }
};
class my_var_sp: public my_var {
+ const Sp_rcontext_handler *m_rcontext_handler;
+ const Type_handler *m_type_handler;
public:
uint offset;
- enum_field_types type;
/*
Routine to which this Item_splocal belongs. Used for checking if correct
runtime context is used for variable handling.
*/
sp_head *sp;
- my_var_sp(const LEX_STRING& j, uint o, enum_field_types t, sp_head *s)
- : my_var(j, LOCAL_VAR), offset(o), type(t), sp(s) { }
+ my_var_sp(const Sp_rcontext_handler *rcontext_handler,
+ const LEX_CSTRING *j, uint o, const Type_handler *type_handler,
+ sp_head *s)
+ : my_var(j, LOCAL_VAR),
+ m_rcontext_handler(rcontext_handler),
+ m_type_handler(type_handler), offset(o), sp(s) { }
~my_var_sp() { }
bool set(THD *thd, Item *val);
+ my_var_sp *get_my_var_sp() { return this; }
+ const Type_handler *type_handler() const { return m_type_handler; }
+ sp_rcontext *get_rcontext(sp_rcontext *local_ctx) const;
+};
+
+/*
+ This class handles fields of a ROW SP variable when it's used as a OUT
+ parameter in a stored procedure.
+*/
+class my_var_sp_row_field: public my_var_sp
+{
+ uint m_field_offset;
+public:
+ my_var_sp_row_field(const Sp_rcontext_handler *rcontext_handler,
+ const LEX_CSTRING *varname, const LEX_CSTRING *fieldname,
+ uint var_idx, uint field_idx, sp_head *s)
+ :my_var_sp(rcontext_handler, varname, var_idx,
+ &type_handler_double/*Not really used*/, s),
+ m_field_offset(field_idx)
+ { }
+ bool set(THD *thd, Item *val);
};
class my_var_user: public my_var {
public:
- my_var_user(const LEX_STRING& j)
+ my_var_user(const LEX_CSTRING *j)
: my_var(j, SESSION_VAR) { }
~my_var_user() { }
bool set(THD *thd, Item *val);
@@ -5644,10 +6195,13 @@ public:
class select_dumpvar :public select_result_interceptor {
ha_rows row_count;
+ my_var_sp *m_var_sp_row; // Not NULL if SELECT INTO row_type_sp_variable
+ bool send_data_to_var_list(List<Item> &items);
public:
List<my_var> var_list;
- select_dumpvar(THD *thd_arg): select_result_interceptor(thd_arg)
- { var_list.empty(); row_count= 0; }
+ select_dumpvar(THD *thd_arg)
+ :select_result_interceptor(thd_arg), row_count(0), m_var_sp_row(NULL)
+ { var_list.empty(); }
~select_dumpvar() {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
int send_data(List<Item> &items);
@@ -5779,10 +6333,23 @@ public:
SP Bulk execution optimized
*/
#define CF_SP_BULK_OPTIMIZED (1U << 21)
+/**
+ If command creates or drops a table
+*/
+#define CF_SCHEMA_CHANGE (1U << 22)
+/**
+ If command creates or drops a database
+*/
+#define CF_DB_CHANGE (1U << 23)
/* Bits in server_command_flags */
/**
+ Statement that deletes existing rows (DELETE, DELETE_MULTI)
+*/
+#define CF_DELETES_DATA (1U << 24)
+
+/**
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).
@@ -5894,6 +6461,17 @@ inline int handler::ha_write_tmp_row(uchar *buf)
return error;
}
+inline int handler::ha_delete_tmp_row(uchar *buf)
+{
+ int error;
+ MYSQL_DELETE_ROW_START(table_share->db.str, table_share->table_name.str);
+ increment_statistics(&SSV::ha_tmp_delete_count);
+ TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_DELETE_ROW, MAX_KEY, 0,
+ { error= delete_row(buf); })
+ MYSQL_DELETE_ROW_DONE(error);
+ return error;
+}
+
inline int handler::ha_update_tmp_row(const uchar *old_data, uchar *new_data)
{
int error;
@@ -5953,7 +6531,7 @@ void thd_exit_cond(MYSQL_THD thd, const PSI_stage_info *stage,
#define THD_EXIT_COND(P1, P2) \
thd_exit_cond(P1, P2, __func__, __FILE__, __LINE__)
-inline bool binlog_should_compress(ulong len)
+inline bool binlog_should_compress(size_t len)
{
return opt_bin_log_compress &&
len >= opt_bin_log_compress_min_len;
@@ -5991,6 +6569,240 @@ class Switch_to_definer_security_ctx
Security_context *m_sctx;
};
-#endif /* MYSQL_SERVER */
+/**
+ This class resembles the SQL Standard schema qualified object name:
+ <schema qualified name> ::= [ <schema name> <period> ] <qualified identifier>
+*/
+class Database_qualified_name
+{
+public:
+ LEX_CSTRING m_db;
+ LEX_CSTRING m_name;
+ Database_qualified_name(const LEX_CSTRING *db, const LEX_CSTRING *name)
+ :m_db(*db), m_name(*name)
+ { }
+ Database_qualified_name(const LEX_CSTRING &db, const LEX_CSTRING &name)
+ :m_db(db), m_name(name)
+ { }
+ Database_qualified_name(const char *db, size_t db_length,
+ const char *name, size_t name_length)
+ {
+ m_db.str= db;
+ m_db.length= db_length;
+ m_name.str= name;
+ m_name.length= name_length;
+ }
+
+ bool eq(const Database_qualified_name *other) const
+ {
+ CHARSET_INFO *cs= lower_case_table_names ?
+ &my_charset_utf8_general_ci :
+ &my_charset_utf8_bin;
+ return
+ m_db.length == other->m_db.length &&
+ m_name.length == other->m_name.length &&
+ !my_strnncoll(cs,
+ (const uchar *) m_db.str, m_db.length,
+ (const uchar *) other->m_db.str, other->m_db.length) &&
+ !my_strnncoll(cs,
+ (const uchar *) m_name.str, m_name.length,
+ (const uchar *) other->m_name.str, other->m_name.length);
+ }
+ void copy(MEM_ROOT *mem_root, const LEX_CSTRING &db,
+ const LEX_CSTRING &name);
+ // Export db and name as a qualified name string: 'db.name'
+ size_t make_qname(char *dst, size_t dstlen) const
+ {
+ return my_snprintf(dst, dstlen, "%.*s.%.*s",
+ (int) m_db.length, m_db.str,
+ (int) m_name.length, m_name.str);
+ }
+ // Export db and name as a qualified name string, allocate on mem_root.
+ bool make_qname(MEM_ROOT *mem_root, LEX_CSTRING *dst) const
+ {
+ const uint dot= !!m_db.length;
+ char *tmp;
+ /* format: [database + dot] + name + '\0' */
+ dst->length= m_db.length + dot + m_name.length;
+ if (unlikely(!(dst->str= tmp= (char*) alloc_root(mem_root,
+ dst->length + 1))))
+ return true;
+ sprintf(tmp, "%.*s%.*s%.*s",
+ (int) m_db.length, (m_db.length ? m_db.str : ""),
+ dot, ".",
+ (int) m_name.length, m_name.str);
+ DBUG_SLOW_ASSERT(ok_for_lower_case_names(m_db.str));
+ return false;
+ }
+
+ bool make_package_routine_name(MEM_ROOT *mem_root,
+ const LEX_CSTRING &package,
+ const LEX_CSTRING &routine)
+ {
+ char *tmp;
+ size_t length= package.length + 1 + routine.length + 1;
+ if (unlikely(!(tmp= (char *) alloc_root(mem_root, length))))
+ return true;
+ m_name.length= my_snprintf(tmp, length, "%.*s.%.*s",
+ (int) package.length, package.str,
+ (int) routine.length, routine.str);
+ m_name.str= tmp;
+ return false;
+ }
+
+ bool make_package_routine_name(MEM_ROOT *mem_root,
+ const LEX_CSTRING &db,
+ const LEX_CSTRING &package,
+ const LEX_CSTRING &routine)
+ {
+ if (unlikely(make_package_routine_name(mem_root, package, routine)))
+ return true;
+ if (unlikely(!(m_db.str= strmake_root(mem_root, db.str, db.length))))
+ return true;
+ m_db.length= db.length;
+ return false;
+ }
+};
+
+
+class ErrConvDQName: public ErrConv
+{
+ const Database_qualified_name *m_name;
+public:
+ ErrConvDQName(const Database_qualified_name *name)
+ :m_name(name)
+ { }
+ const char *ptr() const
+ {
+ m_name->make_qname(err_buffer, sizeof(err_buffer));
+ return err_buffer;
+ }
+};
+
+class Type_holder: public Sql_alloc,
+ public Item_args,
+ public Type_handler_hybrid_field_type,
+ public Type_all_attributes,
+ public Type_geometry_attributes
+{
+ TYPELIB *m_typelib;
+ bool m_maybe_null;
+public:
+ Type_holder()
+ :m_typelib(NULL),
+ m_maybe_null(false)
+ { }
+
+ void set_maybe_null(bool maybe_null_arg) { m_maybe_null= maybe_null_arg; }
+ bool get_maybe_null() const { return m_maybe_null; }
+
+ uint decimal_precision() const
+ {
+ /*
+ Type_holder is not used directly to create fields, so
+ its virtual decimal_precision() is never called.
+ We should eventually extend create_result_table() to accept
+ an array of Type_holders directly, without having to allocate
+ Item_type_holder's and put them into List<Item>.
+ */
+ DBUG_ASSERT(0);
+ return 0;
+ }
+ void set_geometry_type(uint type)
+ {
+ Type_geometry_attributes::set_geometry_type(type);
+ }
+ uint uint_geometry_type() const
+ {
+ return Type_geometry_attributes::get_geometry_type();
+ }
+ void set_typelib(TYPELIB *typelib)
+ {
+ m_typelib= typelib;
+ }
+ TYPELIB *get_typelib() const
+ {
+ return m_typelib;
+ }
+
+ bool aggregate_attributes(THD *thd)
+ {
+ for (uint i= 0; i < arg_count; i++)
+ m_maybe_null|= args[i]->maybe_null;
+ return
+ type_handler()->Item_hybrid_func_fix_attributes(thd,
+ "UNION", this, this,
+ args, arg_count);
+ }
+};
+
+
+/*
+ A helper class to set THD flags to emit warnings/errors in case of
+ overflow/type errors during assigning values into the SP variable fields.
+ Saves original flags values in constructor.
+ Restores original flags in destructor.
+*/
+class Sp_eval_expr_state
+{
+ THD *m_thd;
+ enum_check_fields m_count_cuted_fields;
+ bool m_abort_on_warning;
+ bool m_stmt_modified_non_trans_table;
+ void start()
+ {
+ m_thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
+ m_thd->abort_on_warning= m_thd->is_strict_mode();
+ m_thd->transaction.stmt.modified_non_trans_table= false;
+ }
+ void stop()
+ {
+ m_thd->count_cuted_fields= m_count_cuted_fields;
+ m_thd->abort_on_warning= m_abort_on_warning;
+ m_thd->transaction.stmt.modified_non_trans_table=
+ m_stmt_modified_non_trans_table;
+ }
+public:
+ Sp_eval_expr_state(THD *thd)
+ :m_thd(thd),
+ m_count_cuted_fields(thd->count_cuted_fields),
+ m_abort_on_warning(thd->abort_on_warning),
+ m_stmt_modified_non_trans_table(thd->transaction.stmt.
+ modified_non_trans_table)
+ {
+ start();
+ }
+ ~Sp_eval_expr_state()
+ {
+ stop();
+ }
+};
+
+
+#ifndef DBUG_OFF
+void dbug_serve_apcs(THD *thd, int n_calls);
+#endif
+
+class ScopedStatementReplication
+{
+public:
+ ScopedStatementReplication(THD *thd) :
+ saved_binlog_format(thd
+ ? thd->set_current_stmt_binlog_format_stmt()
+ : BINLOG_FORMAT_MIXED),
+ thd(thd)
+ {}
+ ~ScopedStatementReplication()
+ {
+ if (thd)
+ thd->restore_stmt_binlog_format(saved_binlog_format);
+ }
+
+private:
+ const enum_binlog_format saved_binlog_format;
+ THD *const thd;
+};
+
+#endif /* MYSQL_SERVER */
#endif /* SQL_CLASS_INCLUDED */