From 354bb40e75d94466e91fe6960523612c9d17ccfb Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 2 Nov 2017 23:11:29 +0300 Subject: Add implementation --- mysql/sql/atomic_class.h | 117 +++++ mysql/sql/auth/password.c | 378 ++++++++++++++++ mysql/sql/my_decimal.h | 538 +++++++++++++++++++++++ mysql/sql/mysqld.h | 979 +++++++++++++++++++++++++++++++++++++++++ mysql/sql/net_serv.cpp | 1059 +++++++++++++++++++++++++++++++++++++++++++++ mysql/sql/sql_alloc.h | 51 +++ mysql/sql/sql_cmd.h | 96 ++++ mysql/sql/thr_malloc.h | 38 ++ 8 files changed, 3256 insertions(+) create mode 100644 mysql/sql/atomic_class.h create mode 100644 mysql/sql/auth/password.c create mode 100644 mysql/sql/my_decimal.h create mode 100644 mysql/sql/mysqld.h create mode 100644 mysql/sql/net_serv.cpp create mode 100644 mysql/sql/sql_alloc.h create mode 100644 mysql/sql/sql_cmd.h create mode 100644 mysql/sql/thr_malloc.h (limited to 'mysql/sql') diff --git a/mysql/sql/atomic_class.h b/mysql/sql/atomic_class.h new file mode 100644 index 0000000..04d3492 --- /dev/null +++ b/mysql/sql/atomic_class.h @@ -0,0 +1,117 @@ +/* Copyright (c) 2015, 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., 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA */ + + +#ifndef ATOMIC_CLASS_H_INCLUDED +#define ATOMIC_CLASS_H_INCLUDED + +#include "my_atomic.h" + +/** + Wrapper class to use C++ syntax to access atomic integers. +*/ +#define DEFINE_ATOMIC_CLASS(NAME, SUFFIX, TYPE) \ + class Atomic_##NAME \ + { \ +public: \ + /* Create a new Atomic_* object. */ \ + Atomic_##NAME(TYPE n= 0) \ + { \ + my_atomic_store##SUFFIX(&value, n); \ + } \ + /* Atomically read the value. */ \ + TYPE atomic_get() \ + { \ + return my_atomic_load##SUFFIX(&value); \ + } \ + /* Atomically set the value. */ \ + void atomic_set(TYPE n) \ + { \ + my_atomic_store##SUFFIX(&value, n); \ + } \ + /* Atomically add to the value, and return the old value. */ \ + TYPE atomic_add(TYPE n) \ + { \ + return my_atomic_add##SUFFIX(&value, n); \ + } \ + /* Atomically set the value and return the old value. */ \ + TYPE atomic_get_and_set(TYPE n) \ + { \ + return my_atomic_fas##SUFFIX(&value, n); \ + } \ + /* If the old value is equal to *old, set the value to new and */ \ + /* return true. Otherwise, store the old value in '*old' and */ \ + /* return false. */ \ + bool atomic_compare_and_swap(TYPE *old, TYPE n) \ + { \ + return my_atomic_cas##SUFFIX(&value, old, n); \ + } \ + /* Read the value *non-atomically*. */ \ + TYPE non_atomic_get() \ + { \ + return value; \ + } \ + /* Set the value *non-atomically*. */ \ + void non_atomic_set(TYPE n) \ + { \ + value= n; \ + } \ + /* Add to the value *non-atomically*. */ \ + TYPE non_atomic_add(TYPE n) \ + { \ + TYPE ret= value; \ + value+= n; \ + return ret; \ + } \ + /* Set the value to the greatest of (old, n). */ \ + \ + /* The function will internally requires multiple atomic */ \ + /* operations. If the old value is known (or guessed), and less */ \ + /* than n, it requires one atomic operation less. Therefore, */ \ + /* the caller should set *guess to whatever is the likely value */ \ + /* that the variable currently has, if such a guess is known. */ \ + \ + /* @return If the new value is changed to n, *guess is set to */ \ + /* the old value and the the function returns true. Otherwise, */ \ + /* *guess is set to the current value (which is greater than or */ \ + /* equal to n), and the function returns false. */ \ + bool atomic_set_to_max(TYPE n, TYPE *guess= NULL) \ + { \ + TYPE _guess; \ + if (guess == NULL) \ + { \ + _guess= n - 1; \ + guess= &_guess; \ + } \ + else \ + DBUG_ASSERT(*guess < n); \ + bool ret; \ + do { \ + ret= atomic_compare_and_swap(guess, n); \ + } while (!ret && *guess < n); \ + return ret; \ + } \ + \ +private: \ + TYPE value; \ + } + +DEFINE_ATOMIC_CLASS(int32, 32, int32); +DEFINE_ATOMIC_CLASS(int64, 64, int64); +//DEFINE_ATOMIC_CLASS(pointer, ptr, void *); + +#endif //ifndef ATOMIC_CLASS_H_INCLUDED diff --git a/mysql/sql/auth/password.c b/mysql/sql/auth/password.c new file mode 100644 index 0000000..1f93350 --- /dev/null +++ b/mysql/sql/auth/password.c @@ -0,0 +1,378 @@ +/* + Copyright (c) 2000, 2014, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/* password checking routines */ +/***************************************************************************** + The main idea is that no password are sent between client & server on + connection and that no password are saved in mysql in a decodable form. + + On connection a random string is generated and sent to the client. + The client generates a new string with a random generator inited with + the hash values from the password and the sent string. + This 'check' string is sent to the server where it is compared with + a string generated from the stored hash_value of the password and the + random string. + + The password is saved (in user.password) by using the PASSWORD() function in + mysql. + + This is .c file because it's used in libmysqlclient, which is entirely in C. + (we need it to be portable to a variety of systems). + Example: + update user set password=PASSWORD("hello") where user="test" + This saves a hashed number as a string in the password field. + + The new authentication is performed in following manner: + + SERVER: public_seed=generate_user_salt() + send(public_seed) + + CLIENT: recv(public_seed) + hash_stage1=sha1("password") + hash_stage2=sha1(hash_stage1) + reply=xor(hash_stage1, sha1(public_seed,hash_stage2) + + // this three steps are done in scramble() + + send(reply) + + + SERVER: recv(reply) + hash_stage1=xor(reply, sha1(public_seed,hash_stage2)) + candidate_hash2=sha1(hash_stage1) + check(candidate_hash2==hash_stage2) + + // this three steps are done in check_scramble() + +*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "mysql.h" +#include "crypt_genhash_impl.h" + +void randominit(struct rand_struct *rand_st, ulong seed1, ulong seed2) +{ /* For mysql 3.21.# */ + rand_st->max_value= 0x3FFFFFFFL; + rand_st->max_value_dbl=(double) rand_st->max_value; + rand_st->seed1=seed1%rand_st->max_value ; + rand_st->seed2=seed2%rand_st->max_value; +} + +/* + Generate binary hash from raw text string + Used for Pre-4.1 password handling + SYNOPSIS + hash_password() + result OUT store hash in this location + password IN plain text password to build hash + password_len IN password length (password may be not null-terminated) +*/ + +void hash_password(ulong *result, const char *password, uint password_len) +{ + ulong nr=1345345333L, add=7, nr2=0x12345671L; + ulong tmp; + const char *password_end= password + password_len; + for (; password < password_end; password++) + { + if (*password == ' ' || *password == '\t') + continue; /* skip space in password */ + tmp= (ulong) (uchar) *password; + nr^= (((nr & 63)+add)*tmp)+ (nr << 8); + nr2+=(nr2 << 8) ^ nr; + add+=tmp; + } + result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */; + result[1]=nr2 & (((ulong) 1L << 31) -1L); +} + +static inline uint8 char_val(uint8 X) +{ + return (uint) (X >= '0' && X <= '9' ? X - '0' : + X >= 'A' && X <= 'Z' ? X - 'A' + 10 : X - 'a' + 10); +} + +/* Character to use as version identifier for version 4.1 */ + +#define PVERSION41_CHAR '*' + + +/* + Convert given octet sequence to asciiz string of hex characters; + str..str+len and 'to' may not overlap. + SYNOPSIS + octet2hex() + buf OUT output buffer. Must be at least 2*len+1 bytes + str, len IN the beginning and the length of the input string + + RETURN + buf+len*2 +*/ + +char *octet2hex(char *to, const char *str, uint len) +{ + const char *str_end= str + len; + for (; str != str_end; ++str) + { + *to++= _dig_vec_upper[((uchar) *str) >> 4]; + *to++= _dig_vec_upper[((uchar) *str) & 0x0F]; + } + *to= '\0'; + return to; +} + + +/* + Convert given asciiz string of hex (0..9 a..f) characters to octet + sequence. + SYNOPSIS + hex2octet() + to OUT buffer to place result; must be at least len/2 bytes + str, len IN begin, length for character string; str and to may not + overlap; len % 2 == 0 +*/ + +static void +hex2octet(uint8 *to, const char *str, uint len) +{ + const char *str_end= str + len; + while (str < str_end) + { + char tmp= char_val(*str++); + *to++= (tmp << 4) | char_val(*str++); + } +} + + +/* + Encrypt/Decrypt function used for password encryption in authentication. + Simple XOR is used here but it is OK as we crypt random strings. Note, + that XOR(s1, XOR(s1, s2)) == s2, XOR(s1, s2) == XOR(s2, s1) + SYNOPSIS + my_crypt() + to OUT buffer to hold crypted string; must be at least len bytes + long; to and s1 (or s2) may be the same. + s1, s2 IN input strings (of equal length) + len IN length of s1 and s2 +*/ + +static void +my_crypt(char *to, const uchar *s1, const uchar *s2, uint len) +{ + const uint8 *s1_end= s1 + len; + while (s1 < s1_end) + *to++= *s1++ ^ *s2++; +} + +#if defined(HAVE_OPENSSL) +void my_make_scrambled_password(char *to, const char *password, + size_t pass_len) +{ + + char salt[CRYPT_SALT_LENGTH + 1]; + + generate_user_salt(salt, CRYPT_SALT_LENGTH + 1); + my_crypt_genhash(to, + CRYPT_MAX_PASSWORD_SIZE, + password, + pass_len, + salt, + 0); + +} +#endif +/** + Compute two stage SHA1 hash of the password : + + hash_stage1=sha1("password") + hash_stage2=sha1(hash_stage1) + + @param password [IN] Password string. + @param pass_len [IN] Length of the password. + @param hash_stage1 [OUT] sha1(password) + @param hash_stage2 [OUT] sha1(hash_stage1) +*/ + +inline static +void compute_two_stage_sha1_hash(const char *password, size_t pass_len, + uint8 *hash_stage1, uint8 *hash_stage2) +{ + /* Stage 1: hash password */ + compute_sha1_hash(hash_stage1, password, pass_len); + + /* Stage 2 : hash first stage's output. */ + compute_sha1_hash(hash_stage2, (const char *) hash_stage1, SHA1_HASH_SIZE); +} + + +/* + MySQL 4.1.1 password hashing: SHA conversion (see RFC 2289, 3174) twice + applied to the password string, and then produced octet sequence is + converted to hex string. + The result of this function is used as return value from PASSWORD() and + is stored in the database. + SYNOPSIS + my_make_scrambled_password_sha1() + buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string + password IN password string + pass_len IN length of password string +*/ + +void my_make_scrambled_password_sha1(char *to, const char *password, + size_t pass_len) +{ + uint8 hash_stage2[SHA1_HASH_SIZE]; + + /* Two stage SHA1 hash of the password. */ + compute_two_stage_sha1_hash(password, pass_len, (uint8 *) to, hash_stage2); + + /* convert hash_stage2 to hex string */ + *to++= PVERSION41_CHAR; + octet2hex(to, (const char*) hash_stage2, SHA1_HASH_SIZE); +} + + +/* + Wrapper around my_make_scrambled_password() to maintain client lib ABI + compatibility. + In server code usage of my_make_scrambled_password() is preferred to + avoid strlen(). + SYNOPSIS + make_scrambled_password() + buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string + password IN NULL-terminated password string +*/ + +void make_scrambled_password(char *to, const char *password) +{ + my_make_scrambled_password_sha1(to, password, strlen(password)); +} + + +/* + Produce an obscure octet sequence from password and random + string, received from the server. This sequence corresponds to the + password, but password can not be easily restored from it. The sequence + is then sent to the server for validation. Trailing zero is not stored + in the buf as it is not needed. + This function is used by client to create authenticated reply to the + server's greeting. + SYNOPSIS + scramble() + buf OUT store scrambled string here. The buf must be at least + SHA1_HASH_SIZE bytes long. + message IN random message, must be exactly SCRAMBLE_LENGTH long and + NULL-terminated. + password IN users' password +*/ + +void +scramble(char *to, const char *message, const char *password) +{ + uint8 hash_stage1[SHA1_HASH_SIZE]; + uint8 hash_stage2[SHA1_HASH_SIZE]; + + /* Two stage SHA1 hash of the password. */ + compute_two_stage_sha1_hash(password, strlen(password), hash_stage1, + hash_stage2); + + /* create crypt string as sha1(message, hash_stage2) */; + compute_sha1_hash_multi((uint8 *) to, message, SCRAMBLE_LENGTH, + (const char *) hash_stage2, SHA1_HASH_SIZE); + my_crypt(to, (const uchar *) to, hash_stage1, SCRAMBLE_LENGTH); +} + + +/* + Check that scrambled message corresponds to the password; the function + is used by server to check that received reply is authentic. + This function does not check lengths of given strings: message must be + null-terminated, reply and hash_stage2 must be at least SHA1_HASH_SIZE + long (if not, something fishy is going on). + SYNOPSIS + check_scramble_sha1() + scramble clients' reply, presumably produced by scramble() + message original random string, previously sent to client + (presumably second argument of scramble()), must be + exactly SCRAMBLE_LENGTH long and NULL-terminated. + hash_stage2 hex2octet-decoded database entry + All params are IN. + + RETURN VALUE + 0 password is correct + !0 password is invalid +*/ + +my_bool +check_scramble_sha1(const uchar *scramble_arg, const char *message, + const uint8 *hash_stage2) +{ + uint8 buf[SHA1_HASH_SIZE]; + uint8 hash_stage2_reassured[SHA1_HASH_SIZE]; + + /* create key to encrypt scramble */ + compute_sha1_hash_multi(buf, message, SCRAMBLE_LENGTH, + (const char *) hash_stage2, SHA1_HASH_SIZE); + /* encrypt scramble */ + my_crypt((char *) buf, buf, scramble_arg, SCRAMBLE_LENGTH); + + /* now buf supposedly contains hash_stage1: so we can get hash_stage2 */ + compute_sha1_hash(hash_stage2_reassured, (const char *) buf, SHA1_HASH_SIZE); + + return MY_TEST(memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE)); +} + +my_bool +check_scramble(const uchar *scramble_arg, const char *message, + const uint8 *hash_stage2) +{ + return check_scramble_sha1(scramble_arg, message, hash_stage2); +} + +/* + Convert scrambled password from asciiz hex string to binary form. + + SYNOPSIS + get_salt_from_password() + res OUT buf to hold password. Must be at least SHA1_HASH_SIZE + bytes long. + password IN 4.1.1 version value of user.password +*/ + +void get_salt_from_password(uint8 *hash_stage2, const char *password) +{ + hex2octet(hash_stage2, password+1 /* skip '*' */, SHA1_HASH_SIZE * 2); +} + +/* + Convert scrambled password from binary form to asciiz hex string. + SYNOPSIS + make_password_from_salt() + to OUT store resulting string here, 2*SHA1_HASH_SIZE+2 bytes + salt IN password in salt format +*/ + +void make_password_from_salt(char *to, const uint8 *hash_stage2) +{ + *to++= PVERSION41_CHAR; + octet2hex(to, (const char*) hash_stage2, SHA1_HASH_SIZE); +} + diff --git a/mysql/sql/my_decimal.h b/mysql/sql/my_decimal.h new file mode 100644 index 0000000..d964484 --- /dev/null +++ b/mysql/sql/my_decimal.h @@ -0,0 +1,538 @@ +/* Copyright (c) 2005, 2015, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef MY_DECIMAL_INCLUDED +#define MY_DECIMAL_INCLUDED + +/** + @file + + It is interface module to fixed precision decimals library. + + Most functions use 'uint mask' as parameter, if during operation error + which fit in this mask is detected then it will be processed automatically + here. (errors are E_DEC_* constants, see include/decimal.h) + + Most function are just inline wrappers around library calls +*/ + +#if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) +#include "sql_string.h" /* String */ +#endif + +C_MODE_START +#include +C_MODE_END + +class String; +typedef struct st_mysql_time MYSQL_TIME; + +#define DECIMAL_LONGLONG_DIGITS 22 +#define DECIMAL_LONG_DIGITS 10 +#define DECIMAL_LONG3_DIGITS 8 + +/** maximum length of buffer in our big digits (uint32). */ +#define DECIMAL_BUFF_LENGTH 9 + +/* the number of digits that my_decimal can possibly contain */ +#define DECIMAL_MAX_POSSIBLE_PRECISION (DECIMAL_BUFF_LENGTH * 9) + + +/** + maximum guaranteed precision of number in decimal digits (number of our + digits * number of decimal digits in one our big digit - number of decimal + digits in one our big digit decreased by 1 (because we always put decimal + point on the border of our big digits)) +*/ +#define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2) +#define DECIMAL_MAX_SCALE 30 +#define DECIMAL_NOT_SPECIFIED 31 + +/** + maximum length of string representation (number of maximum decimal + digits + 1 position for sign + 1 position for decimal point, no terminator) +*/ +#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2) + +/** + maximum size of packet length. +*/ +#define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_PRECISION + + +inline uint my_decimal_size(uint precision, uint scale) +{ + /* + Always allocate more space to allow library to put decimal point + where it want + */ + return decimal_size(precision, scale) + 1; +} + + +inline int my_decimal_int_part(uint precision, uint decimals) +{ + return precision - ((decimals == DECIMAL_NOT_SPECIFIED) ? 0 : decimals); +} + + +/** + my_decimal class limits 'decimal_t' type to what we need in MySQL. + + It contains internally all necessary space needed by the instance so + no extra memory is needed. Objects should be moved using copy CTOR + or assignment operator, rather than memcpy/memmove. +*/ + +class my_decimal :public decimal_t +{ + /* + Several of the routines in strings/decimal.c have had buffer + overrun/underrun problems. These are *not* caught by valgrind. + To catch them, we allocate dummy fields around the buffer, + and test that their values do not change. + */ +#if !defined(DBUG_OFF) + int foo1; +#endif + + decimal_digit_t buffer[DECIMAL_BUFF_LENGTH]; + +#if !defined(DBUG_OFF) + int foo2; + static const int test_value= 123; +#endif + +public: + + my_decimal(const my_decimal &rhs) : decimal_t(rhs) + { + rhs.sanity_check(); +#if !defined(DBUG_OFF) + foo1= test_value; + foo2= test_value; +#endif + for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++) + buffer[i]= rhs.buffer[i]; + buf= buffer; + } + + my_decimal& operator=(const my_decimal &rhs) + { + sanity_check(); + rhs.sanity_check(); + if (this == &rhs) + return *this; + decimal_t::operator=(rhs); + for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++) + buffer[i]= rhs.buffer[i]; + buf= buffer; + return *this; + } + + void init() + { +#if !defined(DBUG_OFF) + foo1= test_value; + foo2= test_value; +#endif + /* + Do not initialize more of the base class, + we want to catch uninitialized use. + */ + len= DECIMAL_BUFF_LENGTH; + buf= buffer; + } + + my_decimal() + { + init(); + } + ~my_decimal() + { + sanity_check(); + } + + void sanity_check() const + { + DBUG_ASSERT(foo1 == test_value); + DBUG_ASSERT(foo2 == test_value); + DBUG_ASSERT(buf == buffer); + } + + bool sign() const { return decimal_t::sign; } + void sign(bool s) { decimal_t::sign= s; } + uint precision() const { return intg + frac; } + + /** Swap two my_decimal values */ + void swap(my_decimal &rhs) + { + swap_variables(my_decimal, *this, rhs); + } + + // Error reporting in server code only. + int check_result(uint mask, int result) const +#ifdef MYSQL_CLIENT + { + return result; + } +#endif + ; +}; + + +#ifndef DBUG_OFF +void print_decimal(const my_decimal *dec); +void print_decimal_buff(const my_decimal *dec, const uchar* ptr, int length); +const char *dbug_decimal_as_string(char *buff, const my_decimal *val); +#else +#define dbug_decimal_as_string(A) NULL +#endif + +bool str_set_decimal(uint mask, const my_decimal *val, uint fixed_prec, + uint fixed_dec, char filler, String *str, + const CHARSET_INFO *cs); + +extern my_decimal decimal_zero; + + +inline +void max_my_decimal(my_decimal *to, int precision, int frac) +{ + DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION)&& + (frac <= DECIMAL_MAX_SCALE)); + max_decimal(precision, frac, to); +} + +inline void max_internal_decimal(my_decimal *to) +{ + max_my_decimal(to, DECIMAL_MAX_PRECISION, 0); +} + +inline int check_result_and_overflow(uint mask, int result, my_decimal *val) +{ + if (val->check_result(mask, result) & E_DEC_OVERFLOW) + { + bool sign= val->sign(); + val->sanity_check(); + max_internal_decimal(val); + val->sign(sign); + } + /* + Avoid returning negative zero, cfr. decimal_cmp() + For result == E_DEC_DIV_ZERO *val has not been assigned. + */ + if (result != E_DEC_DIV_ZERO && val->sign() && decimal_is_zero(val)) + val->sign(false); + return result; +} + +inline uint my_decimal_length_to_precision(uint length, uint scale, + bool unsigned_flag) +{ + /* Precision can't be negative thus ignore unsigned_flag when length is 0. */ + DBUG_ASSERT(length || !scale); + uint retval= (uint) (length - (scale>0 ? 1:0) - + (unsigned_flag || !length ? 0:1)); + return retval; +} + +inline uint32 my_decimal_precision_to_length_no_truncation(uint precision, + uint8 scale, + bool unsigned_flag) +{ + /* + When precision is 0 it means that original length was also 0. Thus + unsigned_flag is ignored in this case. + */ + DBUG_ASSERT(precision || !scale); + uint32 retval= (uint32)(precision + (scale > 0 ? 1 : 0) + + (unsigned_flag || !precision ? 0 : 1)); + return retval; +} + +inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale, + bool unsigned_flag) +{ + /* + When precision is 0 it means that original length was also 0. Thus + unsigned_flag is ignored in this case. + */ + DBUG_ASSERT(precision || !scale); + set_if_smaller(precision, DECIMAL_MAX_PRECISION); + return my_decimal_precision_to_length_no_truncation(precision, scale, + unsigned_flag); +} + +inline +int my_decimal_string_length(const my_decimal *d) +{ + /* length of string representation including terminating '\0' */ + return decimal_string_size(d); +} + + +inline +int my_decimal_max_length(const my_decimal *d) +{ + /* -1 because we do not count \0 */ + return decimal_string_size(d) - 1; +} + + +inline +int my_decimal_get_binary_size(uint precision, uint scale) +{ + return decimal_bin_size((int)precision, (int)scale); +} + + +inline +void my_decimal2decimal(const my_decimal *from, my_decimal *to) +{ + *to= *from; +} + + +int my_decimal2binary(uint mask, const my_decimal *d, uchar *bin, int prec, + int scale); + + +inline +int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec, + int scale) +{ + return d->check_result(mask, bin2decimal(bin, d, prec, scale)); +} + + +inline +int my_decimal_set_zero(my_decimal *d) +{ + /* + We need the up-cast here, since my_decimal has sign() member functions, + which conflicts with decimal_t::size + (and decimal_make_zero is a macro, rather than a funcion). + */ + decimal_make_zero(static_cast(d)); + return 0; +} + + +inline +bool my_decimal_is_zero(const my_decimal *decimal_value) +{ + return decimal_is_zero(decimal_value); +} + + +inline +int my_decimal_round(uint mask, const my_decimal *from, int scale, + bool truncate, my_decimal *to) +{ + return + from->check_result(mask, decimal_round(from, to, scale, + (truncate ? TRUNCATE : HALF_UP))); +} + + +inline +int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to) +{ + return from->check_result(mask, decimal_round(from, to, 0, FLOOR)); +} + + +inline +int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to) +{ + return from->check_result(mask, decimal_round(from, to, 0, CEILING)); +} + + +inline bool str_set_decimal(const my_decimal *val, String *str, + const CHARSET_INFO *cs) +{ + return str_set_decimal(E_DEC_FATAL_ERROR, val, 0, 0, 0, str, cs); +} + +#ifndef MYSQL_CLIENT +class String; +int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec, + uint fixed_dec, char filler, String *str); +#endif + +inline +int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag, + longlong *l) +{ + my_decimal rounded; + /* decimal_round can return only E_DEC_TRUNCATED */ + decimal_round(d, &rounded, 0, HALF_UP); + return d->check_result(mask, (unsigned_flag ? + decimal2ulonglong(&rounded, (ulonglong *)l) : + decimal2longlong(&rounded, l))); +} + + +inline +int my_decimal2double(uint, const my_decimal *d, double *result) +{ + /* No need to call check_result as this will always succeed */ + return decimal2double(d, result); +} + + +inline int my_decimal2lldiv_t(uint mask, const my_decimal *d, lldiv_t *to) +{ + return d->check_result(mask, decimal2lldiv_t(d, to)); +} + + +inline int str2my_decimal(uint mask, const char *str, + my_decimal *d, char **end) +{ + return check_result_and_overflow(mask, string2decimal(str, d, end), d); +} + + +int str2my_decimal(uint mask, const char *from, size_t length, + const CHARSET_INFO *charset, my_decimal *decimal_value); + +#if defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) +inline +int string2my_decimal(uint mask, const String *str, my_decimal *d) +{ + return str2my_decimal(mask, str->ptr(), (uint)str->length(), str->charset(), d); +} + + +my_decimal *date2my_decimal(const MYSQL_TIME *ltime, my_decimal *dec); +my_decimal *time2my_decimal(const MYSQL_TIME *ltime, my_decimal *dec); +my_decimal *timeval2my_decimal(const struct timeval *tm, my_decimal *dec); + +#endif /*defined(MYSQL_SERVER) || defined(EMBEDDED_LIBRARY) */ + +inline +int double2my_decimal(uint mask, double val, my_decimal *d) +{ + return check_result_and_overflow(mask, double2decimal(val, d), d); +} + + +inline +int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d) +{ + return d->check_result(mask, (unsigned_flag ? + ulonglong2decimal((ulonglong)i, d) : + longlong2decimal(i, d))); +} + + +inline +void my_decimal_neg(decimal_t *arg) +{ + // Avoid returning negative zero, cfr. decimal_cmp() + if (decimal_is_zero(arg)) + { + arg->sign= 0; + return; + } + arg->sign^= 1; +} + + +inline +int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b) +{ + return check_result_and_overflow(mask, + decimal_add(a, b, res), + res); +} + + +inline +int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b) +{ + return check_result_and_overflow(mask, + decimal_sub(a, b, res), + res); +} + + +inline +int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b) +{ + return check_result_and_overflow(mask, + decimal_mul(a, b, res), + res); +} + + +inline +int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b, int div_scale_inc) +{ + return check_result_and_overflow(mask, + decimal_div(a, b, res, div_scale_inc), + res); +} + + +inline +int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, + const my_decimal *b) +{ + return check_result_and_overflow(mask, + decimal_mod(a, b, res), + res); +} + + +/** + @return + -1 if ab and 0 if a==b +*/ +inline +int my_decimal_cmp(const my_decimal *a, const my_decimal *b) +{ + return decimal_cmp(a, b); +} + +inline +bool operator<(const my_decimal &lhs, const my_decimal &rhs) +{ + return my_decimal_cmp(&lhs, &rhs) < 0; +} + +inline +bool operator!=(const my_decimal &lhs, const my_decimal &rhs) +{ + return my_decimal_cmp(&lhs, &rhs) != 0; +} + +inline +int my_decimal_intg(const my_decimal *a) +{ + return decimal_intg(a); +} + + +void my_decimal_trim(ulong *precision, uint *scale); + +#endif // MY_DECIMAL_INCLUDED diff --git a/mysql/sql/mysqld.h b/mysql/sql/mysqld.h new file mode 100644 index 0000000..4639fd3 --- /dev/null +++ b/mysql/sql/mysqld.h @@ -0,0 +1,979 @@ +/* Copyright (c) 2010, 2017, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef MYSQLD_INCLUDED +#define MYSQLD_INCLUDED + +#include "my_global.h" /* MYSQL_PLUGIN_IMPORT, FN_REFLEN, FN_EXTLEN */ +#include "my_bitmap.h" /* MY_BITMAP */ +#include "my_decimal.h" /* my_decimal */ +#include "mysql_com.h" /* SERVER_VERSION_LENGTH */ +#include "my_atomic.h" /* my_atomic_add64 */ +#include "sql_cmd.h" /* SQLCOM_END */ +#include "my_thread_local.h" /* my_get_thread_local */ +#include "my_thread.h" /* my_thread_attr_t */ +#include "atomic_class.h" /* Atomic_int32 */ + +class THD; +struct handlerton; +class Time_zone; +template class Bitmap; + +typedef struct st_mysql_const_lex_string LEX_CSTRING; +typedef struct st_mysql_show_var SHOW_VAR; + +/* + This forward declaration is used from C files where the real + definition is included before. Since C does not allow repeated + typedef declarations, even when identical, the definition may not be + repeated. +*/ +#ifndef CHARSET_INFO_DEFINED +typedef struct charset_info_st CHARSET_INFO; +#endif /* CHARSET_INFO_DEFINED */ + +#if MAX_INDEXES <= 64 +typedef Bitmap<64> key_map; /* Used for finding keys */ +#elif MAX_INDEXES > 255 +#error "MAX_INDEXES values greater than 255 is not supported." +#else +typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */ +#endif + + /* Bits from testflag */ +#define TEST_PRINT_CACHED_TABLES 1 +#define TEST_NO_KEY_GROUP 2 +#define TEST_MIT_THREAD 4 +/* + TEST_BLOCKING is made obsolete and is not used any + where in the code base and is retained here so that + the other bit flag values are not changed. +*/ +#define OBSOLETE_TEST_BLOCKING 8 +#define TEST_KEEP_TMP_TABLES 16 +#define TEST_READCHECK 64 /**< Force use of readcheck */ +#define TEST_NO_EXTRA 128 +#define TEST_CORE_ON_SIGNAL 256 /**< Give core if signal */ +#define TEST_NO_STACKTRACE 512 +#define TEST_SIGINT 1024 /**< Allow sigint on threads */ +#define TEST_SYNCHRONIZATION 2048 /**< get server to do sleep in + some places */ +#define TEST_DO_QUICK_LEAK_CHECK 4096 /**< Do Valgrind leak check for + each command. */ + +#define SPECIAL_NO_NEW_FUNC 2 /* Skip new functions */ +#define SPECIAL_SKIP_SHOW_DB 4 /* Don't allow 'show db' */ +#define SPECIAL_NO_RESOLVE 64 /* Don't use gethostname */ +#define SPECIAL_NO_HOST_CACHE 512 /* Don't cache hosts */ +#define SPECIAL_SHORT_LOG_FORMAT 1024 + +/* Function prototypes */ +#ifndef EMBEDDED_LIBRARY +void kill_mysql(void); +#endif +void refresh_status(THD *thd); +bool is_secure_file_path(char *path); +int handle_early_options(); +void adjust_related_options(ulong *requested_open_files); +ulong sql_rnd_with_mutex(); + +// These are needed for unit testing. +void set_remaining_args(int argc, char **argv); +int init_common_variables(); +void my_init_signals(); +bool gtid_server_init(); +void gtid_server_cleanup(); +const char *fixup_enforce_gtid_consistency_command_line(char *value_arg); + +extern "C" MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info; +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info ; +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *national_charset_info; +extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *table_alias_charset; + +enum enum_server_operational_state +{ + SERVER_BOOTING, /* Server is not operational. It is starting */ + SERVER_OPERATING, /* Server is fully initialized and operating */ + SERVER_SHUTTING_DOWN /* erver is shutting down */ +}; +enum_server_operational_state get_server_state(); + +/** + Character set of the buildin error messages loaded from errmsg.sys. +*/ +extern CHARSET_INFO *error_message_charset_info; + +extern CHARSET_INFO *character_set_filesystem; + +extern MY_BITMAP temp_pool; +extern bool opt_large_files, server_id_supplied; +extern bool opt_update_log, opt_bin_log; +extern my_bool opt_log_slave_updates; +extern my_bool opt_log_unsafe_statements; +extern bool opt_general_log, opt_slow_log, opt_general_log_raw; +extern my_bool opt_backup_history_log; +extern my_bool opt_backup_progress_log; +extern ulonglong log_output_options; +extern ulong log_backup_output_options; +extern my_bool opt_log_queries_not_using_indexes; +extern ulong opt_log_throttle_queries_not_using_indexes; +extern bool opt_disable_networking, opt_skip_show_db; +extern bool opt_skip_name_resolve; +extern my_bool opt_help; +extern my_bool opt_verbose; +extern bool opt_ignore_builtin_innodb; +extern my_bool opt_character_set_client_handshake; +extern MYSQL_PLUGIN_IMPORT bool volatile abort_loop; +extern my_bool opt_bootstrap, opt_initialize; +extern my_bool opt_safe_user_create; +extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; +extern my_bool opt_slave_compressed_protocol, use_temp_pool; +extern ulong slave_exec_mode_options; +extern ulonglong slave_type_conversions_options; +extern my_bool read_only, opt_readonly; +extern my_bool super_read_only, opt_super_readonly; +extern my_bool lower_case_file_system; +extern ulonglong slave_rows_search_algorithms_options; +extern my_bool opt_require_secure_transport; + +#ifdef HAVE_REPLICATION +extern my_bool opt_slave_preserve_commit_order; +#endif + +#ifndef DBUG_OFF +extern uint slave_rows_last_search_algorithm_used; +#endif +extern ulong mts_parallel_option; +extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs; +extern my_bool opt_secure_auth; +extern char* opt_secure_file_priv; +extern char* opt_secure_backup_file_priv; +extern size_t opt_secure_backup_file_priv_len; +extern my_bool opt_log_slow_admin_statements, opt_log_slow_slave_statements; +extern my_bool sp_automatic_privileges, opt_noacl; +extern my_bool opt_old_style_user_limits, trust_function_creators; +extern my_bool check_proxy_users, mysql_native_password_proxy_users, sha256_password_proxy_users; +extern uint opt_crash_binlog_innodb; +extern char *shared_memory_base_name, *mysqld_unix_port; +extern my_bool opt_enable_shared_memory; +extern char *default_tz_name; +extern Time_zone *default_tz; +extern char *default_storage_engine; +extern char *default_tmp_storage_engine; +extern ulong internal_tmp_disk_storage_engine; +extern bool opt_endinfo, using_udf_functions; +extern my_bool locked_in_memory; +extern bool opt_using_transactions; +extern ulong max_long_data_size; +extern ulong current_pid; +extern ulong expire_logs_days; +extern my_bool relay_log_recovery; +extern uint sync_binlog_period, sync_relaylog_period, + sync_relayloginfo_period, sync_masterinfo_period, + opt_mts_checkpoint_period, opt_mts_checkpoint_group; +extern ulong opt_tc_log_size, tc_log_max_pages_used, tc_log_page_size; +extern ulong tc_log_page_waits; +extern my_bool relay_log_purge, opt_innodb_safe_binlog, opt_innodb; +extern my_bool relay_log_recovery; +extern my_bool offline_mode; +extern my_bool opt_log_builtin_as_identified_by_password; +extern uint test_flags,select_errors,ha_open_options; +extern uint protocol_version, mysqld_port, dropping_tables; +extern ulong delay_key_write_options; +extern ulong opt_log_timestamps; +extern const char *timestamp_type_names[]; +extern char *opt_general_logname, *opt_slow_logname, *opt_bin_logname, + *opt_relay_logname; +extern char *opt_backup_history_logname, *opt_backup_progress_logname, + *opt_backup_settings_name; +extern const char *log_output_str; +extern const char *log_backup_output_str; +extern char *mysql_home_ptr, *pidfile_name_ptr; +extern char *default_auth_plugin; +extern uint default_password_lifetime; +extern char *my_bind_addr_str; +extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN]; +extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file; +extern char default_logfile_name[FN_REFLEN]; +extern char *opt_tc_log_file; +/*Move UUID_LENGTH from item_strfunc.h*/ +#define UUID_LENGTH (8+1+4+1+4+1+4+1+12) +extern char server_uuid[UUID_LENGTH+1]; +extern const char *server_uuid_ptr; +extern const double log_10[309]; +extern ulonglong keybuff_size; +extern ulonglong thd_startup_options; +extern ulong binlog_cache_use, binlog_cache_disk_use; +extern ulong binlog_stmt_cache_use, binlog_stmt_cache_disk_use; +extern ulong aborted_threads; +extern ulong delayed_insert_timeout; +extern ulong delayed_insert_limit, delayed_queue_size; +extern ulong delayed_insert_threads, delayed_insert_writes; +extern ulong delayed_rows_in_use,delayed_insert_errors; +extern Atomic_int32 slave_open_temp_tables; +extern ulong query_cache_size, query_cache_min_res_unit; +extern ulong slow_launch_time; +extern ulong table_cache_size, table_def_size; +extern ulong table_cache_size_per_instance, table_cache_instances; +extern MYSQL_PLUGIN_IMPORT ulong max_connections; +extern ulong max_digest_length; +extern ulong max_connect_errors, connect_timeout; +extern my_bool opt_slave_allow_batching; +extern my_bool allow_slave_start; +extern LEX_CSTRING reason_slave_blocked; +extern ulong slave_trans_retries; +extern uint slave_net_timeout; +extern ulong opt_mts_slave_parallel_workers; +extern ulonglong opt_mts_pending_jobs_size_max; +extern uint max_user_connections; +extern ulong rpl_stop_slave_timeout; +extern my_bool log_bin_use_v1_row_events; +extern ulong what_to_log,flush_time; +extern ulong max_prepared_stmt_count, prepared_stmt_count; +extern ulong open_files_limit; +extern ulong binlog_cache_size, binlog_stmt_cache_size; +extern ulonglong max_binlog_cache_size, max_binlog_stmt_cache_size; +extern int32 opt_binlog_max_flush_queue_time; +extern ulong opt_binlog_group_commit_sync_delay; +extern ulong opt_binlog_group_commit_sync_no_delay_count; +extern ulong max_binlog_size, max_relay_log_size; +extern ulong slave_max_allowed_packet; +extern ulong opt_binlog_rows_event_max_size; +extern ulong binlog_checksum_options; +extern const char *binlog_checksum_type_names[]; +extern my_bool opt_master_verify_checksum; +extern my_bool opt_slave_sql_verify_checksum; +extern uint32 gtid_executed_compression_period; +extern my_bool binlog_gtid_simple_recovery; +extern ulong binlog_error_action; +extern ulong locked_account_connection_count; +enum enum_binlog_error_action +{ + /// Ignore the error and let server continue without binlogging + IGNORE_ERROR= 0, + /// Abort the server + ABORT_SERVER= 1 +}; +extern const char *binlog_error_action_list[]; + +extern ulong stored_program_cache_size; +extern ulong back_log; +extern char language[FN_REFLEN]; +extern "C" MYSQL_PLUGIN_IMPORT ulong server_id; +extern time_t server_start_time, flush_status_time; +extern char *opt_mysql_tmpdir, mysql_charsets_dir[]; +extern size_t mysql_unpacked_real_data_home_len; +extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list; +extern const char *show_comp_option_name[]; +extern const char *first_keyword, *binary_keyword; +extern MYSQL_PLUGIN_IMPORT const char *my_localhost; +extern const char *myisam_recover_options_str; +extern const char *in_left_expr_name, *in_additional_cond, *in_having_cond; +extern SHOW_VAR status_vars[]; +extern struct system_variables max_system_variables; +extern struct system_status_var global_status_var; +extern struct rand_struct sql_rand; +extern const char *opt_date_time_formats[]; +extern handlerton *myisam_hton; +extern handlerton *heap_hton; +extern handlerton *innodb_hton; +extern uint opt_server_id_bits; +extern ulong opt_server_id_mask; +#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE +/* engine specific hook, to be made generic */ +extern int(*ndb_wait_setup_func)(ulong); +extern ulong opt_ndb_wait_setup; +#endif +extern const char *load_default_groups[]; +extern struct my_option my_long_options[]; +extern struct my_option my_long_early_options[]; +extern bool mysqld_server_started; +extern "C" MYSQL_PLUGIN_IMPORT int orig_argc; +extern "C" MYSQL_PLUGIN_IMPORT char **orig_argv; +extern my_thread_attr_t connection_attrib; +extern my_bool old_mode; +extern my_bool avoid_temporal_upgrade; +extern LEX_STRING opt_init_connect, opt_init_slave; +extern char err_shared_dir[]; +extern my_decimal decimal_zero; +#ifndef EMBEDDED_LIBRARY +extern ulong connection_errors_internal; +extern ulong connection_errors_peer_addr; +#endif +extern ulong log_warnings; +extern bool opt_log_syslog_enable; +extern char *opt_log_syslog_tag; +#ifndef _WIN32 +extern bool opt_log_syslog_include_pid; +extern char *opt_log_syslog_facility; +#endif +/** The size of the host_cache. */ +extern uint host_cache_size; +extern ulong log_error_verbosity; + +/** System variable show_compatibility_56. */ +extern my_bool show_compatibility_56; + +#if defined(EMBEDDED_LIBRARY) +extern ulong max_allowed_packet; +extern ulong net_buffer_length; +#endif + +extern LEX_CSTRING sql_statement_names[(uint) SQLCOM_END + 1]; + +/* + THR_MALLOC is a key which will be used to set/get MEM_ROOT** for a thread, + using my_set_thread_local()/my_get_thread_local(). +*/ +extern thread_local_key_t THR_MALLOC; +extern bool THR_MALLOC_initialized; + +static inline MEM_ROOT ** my_thread_get_THR_MALLOC() +{ + DBUG_ASSERT(THR_MALLOC_initialized); + return (MEM_ROOT**) my_get_thread_local(THR_MALLOC); +} + +static inline int my_thread_set_THR_MALLOC(MEM_ROOT ** hdl) +{ + DBUG_ASSERT(THR_MALLOC_initialized); + return my_set_thread_local(THR_MALLOC, hdl); +} + +/* + THR_THD is a key which will be used to set/get THD* for a thread, + using my_set_thread_local()/my_get_thread_local(). +*/ +extern MYSQL_PLUGIN_IMPORT thread_local_key_t THR_THD; +extern bool THR_THD_initialized; + +static inline THD * my_thread_get_THR_THD() +{ + DBUG_ASSERT(THR_THD_initialized); + return (THD*)my_get_thread_local(THR_THD); +} + +static inline int my_thread_set_THR_THD(THD *thd) +{ + DBUG_ASSERT(THR_THD_initialized); + return my_set_thread_local(THR_THD, thd); +} + +#ifdef HAVE_PSI_INTERFACE + +C_MODE_START + +extern PSI_mutex_key key_LOCK_tc; + +#ifdef HAVE_OPENSSL +extern PSI_mutex_key key_LOCK_des_key_file; +#endif + +extern PSI_mutex_key key_BINLOG_LOCK_commit; +extern PSI_mutex_key key_BINLOG_LOCK_commit_queue; +extern PSI_mutex_key key_BINLOG_LOCK_done; +extern PSI_mutex_key key_BINLOG_LOCK_flush_queue; +extern PSI_mutex_key key_BINLOG_LOCK_index; +extern PSI_mutex_key key_BINLOG_LOCK_log; +extern PSI_mutex_key key_BINLOG_LOCK_binlog_end_pos; +extern PSI_mutex_key key_BINLOG_LOCK_sync; +extern PSI_mutex_key key_BINLOG_LOCK_sync_queue; +extern PSI_mutex_key key_BINLOG_LOCK_xids; +extern PSI_mutex_key + key_hash_filo_lock, + key_LOCK_crypt, key_LOCK_error_log, + key_LOCK_gdl, key_LOCK_global_system_variables, + key_LOCK_lock_db, key_LOCK_logger, key_LOCK_manager, + key_LOCK_prepared_stmt_count, + key_LOCK_server_started, key_LOCK_status, + key_LOCK_sql_slave_skip_counter, + key_LOCK_slave_net_timeout, + key_LOCK_table_share, key_LOCK_thd_data, key_LOCK_thd_sysvar, + key_LOCK_user_conn, key_LOCK_uuid_generator, key_LOG_LOCK_log, + key_master_info_data_lock, key_master_info_run_lock, + key_master_info_sleep_lock, key_master_info_thd_lock, + key_mutex_slave_reporting_capability_err_lock, key_relay_log_info_data_lock, + key_relay_log_info_sleep_lock, key_relay_log_info_thd_lock, + key_relay_log_info_log_space_lock, key_relay_log_info_run_lock, + key_mutex_slave_parallel_pend_jobs, key_mutex_mts_temp_tables_lock, + key_mutex_slave_parallel_worker, + key_mutex_slave_parallel_worker_count, + key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data, + key_LOCK_error_messages, + key_LOCK_log_throttle_qni, key_LOCK_query_plan, key_LOCK_thd_query, + key_LOCK_cost_const, key_LOCK_current_cond; +extern PSI_mutex_key key_RELAYLOG_LOCK_commit; +extern PSI_mutex_key key_RELAYLOG_LOCK_commit_queue; +extern PSI_mutex_key key_RELAYLOG_LOCK_done; +extern PSI_mutex_key key_RELAYLOG_LOCK_flush_queue; +extern PSI_mutex_key key_RELAYLOG_LOCK_index; +extern PSI_mutex_key key_RELAYLOG_LOCK_log; +extern PSI_mutex_key key_RELAYLOG_LOCK_sync; +extern PSI_mutex_key key_RELAYLOG_LOCK_sync_queue; +extern PSI_mutex_key key_RELAYLOG_LOCK_xids; +extern PSI_mutex_key key_LOCK_sql_rand; +extern PSI_mutex_key key_gtid_ensure_index_mutex; +extern PSI_mutex_key key_mts_temp_table_LOCK; +extern PSI_mutex_key key_LOCK_reset_gtid_table; +extern PSI_mutex_key key_LOCK_compress_gtid_table; +extern PSI_mutex_key key_mts_gaq_LOCK; +extern PSI_mutex_key key_thd_timer_mutex; +extern PSI_mutex_key key_LOCK_offline_mode; +extern PSI_mutex_key key_LOCK_default_password_lifetime; +extern PSI_mutex_key key_LOCK_group_replication_handler; + +#ifdef HAVE_REPLICATION +extern PSI_mutex_key key_commit_order_manager_mutex; +extern PSI_mutex_key key_mutex_slave_worker_hash; +#endif + +extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger, + key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave, + key_rwlock_LOCK_system_variables_hash, key_rwlock_query_cache_query_lock, + key_rwlock_global_sid_lock, key_rwlock_gtid_mode_lock, + key_rwlock_channel_map_lock, key_rwlock_channel_lock; + +extern PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool; +extern PSI_cond_key key_BINLOG_update_cond, + key_COND_cache_status_changed, key_COND_manager, + key_COND_server_started, + key_item_func_sleep_cond, key_master_info_data_cond, + key_master_info_start_cond, key_master_info_stop_cond, + key_master_info_sleep_cond, + key_relay_log_info_data_cond, key_relay_log_info_log_space_cond, + key_relay_log_info_start_cond, key_relay_log_info_stop_cond, + key_relay_log_info_sleep_cond, key_cond_slave_parallel_pend_jobs, + key_cond_slave_parallel_worker, key_cond_mts_gaq, + key_TABLE_SHARE_cond, key_user_level_lock_cond; +extern PSI_cond_key key_BINLOG_COND_done; +extern PSI_cond_key key_RELAYLOG_COND_done; +extern PSI_cond_key key_RELAYLOG_update_cond; +extern PSI_cond_key key_BINLOG_prep_xids_cond; +extern PSI_cond_key key_RELAYLOG_prep_xids_cond; +extern PSI_cond_key key_gtid_ensure_index_cond; +extern PSI_cond_key key_COND_compress_gtid_table; +extern PSI_cond_key key_COND_thr_lock; + +#ifdef HAVE_REPLICATION +extern PSI_cond_key key_cond_slave_worker_hash; +extern PSI_cond_key key_commit_order_manager_cond; +#endif +extern PSI_thread_key key_thread_bootstrap, + key_thread_handle_manager, key_thread_main, + key_thread_one_connection, key_thread_signal_hand, + key_thread_compress_gtid_table, key_thread_parser_service; +extern PSI_thread_key key_thread_timer_notifier; + +extern PSI_file_key key_file_map; +extern PSI_file_key key_file_binlog, key_file_binlog_cache, + key_file_binlog_index, key_file_binlog_index_cache, key_file_casetest, + key_file_dbopt, key_file_des_key_file, key_file_ERRMSG, key_select_to_file, + key_file_fileparser, key_file_frm, key_file_global_ddl_log, key_file_load, + key_file_loadfile, key_file_log_event_data, key_file_log_event_info, + key_file_master_info, key_file_misc, key_file_partition_ddl_log, + key_file_pid, key_file_relay_log_info, key_file_send_file, key_file_tclog, + key_file_trg, key_file_trn, key_file_init; +extern PSI_file_key key_file_general_log, key_file_slow_log; +extern PSI_file_key key_file_relaylog, key_file_relaylog_cache, key_file_relaylog_index, key_file_relaylog_index_cache; +extern PSI_socket_key key_socket_tcpip, key_socket_unix, key_socket_client_connection; + +void init_server_psi_keys(); + +C_MODE_END + +#endif /* HAVE_PSI_INTERFACE */ + +C_MODE_START + +extern PSI_memory_key key_memory_locked_table_list; +extern PSI_memory_key key_memory_locked_thread_list; +extern PSI_memory_key key_memory_thd_transactions; +extern PSI_memory_key key_memory_delegate; +extern PSI_memory_key key_memory_acl_mem; +extern PSI_memory_key key_memory_acl_memex; +extern PSI_memory_key key_memory_acl_cache; +extern PSI_memory_key key_memory_thd_main_mem_root; +extern PSI_memory_key key_memory_help; +extern PSI_memory_key key_memory_frm; +extern PSI_memory_key key_memory_table_share; +extern PSI_memory_key key_memory_gdl; +extern PSI_memory_key key_memory_table_triggers_list; +extern PSI_memory_key key_memory_prepared_statement_map; +extern PSI_memory_key key_memory_prepared_statement_main_mem_root; +extern PSI_memory_key key_memory_protocol_rset_root; +extern PSI_memory_key key_memory_warning_info_warn_root; +extern PSI_memory_key key_memory_sp_cache; +extern PSI_memory_key key_memory_sp_head_main_root; +extern PSI_memory_key key_memory_sp_head_execute_root; +extern PSI_memory_key key_memory_sp_head_call_root; +extern PSI_memory_key key_memory_table_mapping_root; +extern PSI_memory_key key_memory_quick_range_select_root; +extern PSI_memory_key key_memory_quick_index_merge_root; +extern PSI_memory_key key_memory_quick_ror_intersect_select_root; +extern PSI_memory_key key_memory_quick_ror_union_select_root; +extern PSI_memory_key key_memory_quick_group_min_max_select_root; +extern PSI_memory_key key_memory_test_quick_select_exec; +extern PSI_memory_key key_memory_prune_partitions_exec; +extern PSI_memory_key key_memory_binlog_recover_exec; +extern PSI_memory_key key_memory_blob_mem_storage; + +extern PSI_memory_key key_memory_Sys_var_charptr_value; +extern PSI_memory_key key_memory_THD_db; +extern PSI_memory_key key_memory_user_var_entry; +extern PSI_memory_key key_memory_user_var_entry_value; +extern PSI_memory_key key_memory_Slave_job_group_group_relay_log_name; +extern PSI_memory_key key_memory_Relay_log_info_group_relay_log_name; +extern PSI_memory_key key_memory_binlog_cache_mngr; +extern PSI_memory_key key_memory_Row_data_memory_memory; +extern PSI_memory_key key_memory_errmsgs; +extern PSI_memory_key key_memory_Event_queue_element_for_exec_names; +extern PSI_memory_key key_memory_Event_scheduler_scheduler_param; +extern PSI_memory_key key_memory_Gis_read_stream_err_msg; +extern PSI_memory_key key_memory_Geometry_objects_data; +extern PSI_memory_key key_memory_host_cache_hostname; +extern PSI_memory_key key_memory_User_level_lock; +extern PSI_memory_key key_memory_Filesort_info_record_pointers; +extern PSI_memory_key key_memory_Sort_param_tmp_buffer; +extern PSI_memory_key key_memory_Filesort_info_merge; +extern PSI_memory_key key_memory_Filesort_buffer_sort_keys; +extern PSI_memory_key key_memory_handler_errmsgs; +extern PSI_memory_key key_memory_handlerton; +extern PSI_memory_key key_memory_XID; +extern PSI_memory_key key_memory_MYSQL_LOCK; +extern PSI_memory_key key_memory_MYSQL_LOG_name; +extern PSI_memory_key key_memory_TC_LOG_MMAP_pages; +extern PSI_memory_key key_memory_my_str_malloc; +extern PSI_memory_key key_memory_MYSQL_BIN_LOG_basename; +extern PSI_memory_key key_memory_MYSQL_BIN_LOG_index; +extern PSI_memory_key key_memory_MYSQL_RELAY_LOG_basename; +extern PSI_memory_key key_memory_MYSQL_RELAY_LOG_index; +extern PSI_memory_key key_memory_rpl_filter; +extern PSI_memory_key key_memory_Security_context; +extern PSI_memory_key key_memory_NET_buff; +extern PSI_memory_key key_memory_NET_compress_packet; +extern PSI_memory_key key_memory_my_bitmap_map; +extern PSI_memory_key key_memory_QUICK_RANGE_SELECT_mrr_buf_desc; +extern PSI_memory_key key_memory_TABLE_RULE_ENT; +extern PSI_memory_key key_memory_Mutex_cond_array_Mutex_cond; +extern PSI_memory_key key_memory_Owned_gtids_sidno_to_hash; +extern PSI_memory_key key_memory_Sid_map_Node; +extern PSI_memory_key key_memory_bison_stack; +extern PSI_memory_key key_memory_TABLE_sort_io_cache; +extern PSI_memory_key key_memory_DATE_TIME_FORMAT; +extern PSI_memory_key key_memory_DDL_LOG_MEMORY_ENTRY; +extern PSI_memory_key key_memory_ST_SCHEMA_TABLE; +extern PSI_memory_key key_memory_ignored_db; +extern PSI_memory_key key_memory_SLAVE_INFO; +extern PSI_memory_key key_memory_log_event_old; +extern PSI_memory_key key_memory_HASH_ROW_ENTRY; +extern PSI_memory_key key_memory_table_def_memory; +extern PSI_memory_key key_memory_MPVIO_EXT_auth_info; +extern PSI_memory_key key_memory_LOG_POS_COORD; +extern PSI_memory_key key_memory_XID_STATE; +extern PSI_memory_key key_memory_Rpl_info_file_buffer; +extern PSI_memory_key key_memory_Rpl_info_table; +extern PSI_memory_key key_memory_binlog_pos; +extern PSI_memory_key key_memory_db_worker_hash_entry; +extern PSI_memory_key key_memory_rpl_slave_command_buffer; +extern PSI_memory_key key_memory_binlog_ver_1_event; +extern PSI_memory_key key_memory_rpl_slave_check_temp_dir; +extern PSI_memory_key key_memory_TABLE; +extern PSI_memory_key key_memory_binlog_statement_buffer; +extern PSI_memory_key key_memory_user_conn; +extern PSI_memory_key key_memory_dboptions_hash; +extern PSI_memory_key key_memory_hash_index_key_buffer; +extern PSI_memory_key key_memory_THD_handler_tables_hash; +extern PSI_memory_key key_memory_JOIN_CACHE; +extern PSI_memory_key key_memory_READ_INFO; +extern PSI_memory_key key_memory_partition_syntax_buffer; +extern PSI_memory_key key_memory_global_system_variables; +extern PSI_memory_key key_memory_THD_variables; +extern PSI_memory_key key_memory_PROFILE; +extern PSI_memory_key key_memory_LOG_name; +extern PSI_memory_key key_memory_string_iterator; +extern PSI_memory_key key_memory_frm_extra_segment_buff; +extern PSI_memory_key key_memory_frm_form_pos; +extern PSI_memory_key key_memory_frm_string; +extern PSI_memory_key key_memory_Unique_sort_buffer; +extern PSI_memory_key key_memory_Unique_merge_buffer; +extern PSI_memory_key key_memory_shared_memory_name; +extern PSI_memory_key key_memory_opt_bin_logname; +extern PSI_memory_key key_memory_Query_cache; +extern PSI_memory_key key_memory_READ_RECORD_cache; +extern PSI_memory_key key_memory_Quick_ranges; +extern PSI_memory_key key_memory_File_query_log_name; +extern PSI_memory_key key_memory_Table_trigger_dispatcher; +extern PSI_memory_key key_memory_show_slave_status_io_gtid_set; +extern PSI_memory_key key_memory_write_set_extraction; +extern PSI_memory_key key_memory_thd_timer; +extern PSI_memory_key key_memory_THD_Session_tracker; +extern PSI_memory_key key_memory_THD_Session_sysvar_resource_manager; +extern PSI_memory_key key_memory_get_all_tables; +extern PSI_memory_key key_memory_fill_schema_schemata; +extern PSI_memory_key key_memory_native_functions; +extern PSI_memory_key key_memory_JSON; + +C_MODE_END + +/* + MAINTAINER: Please keep this list in order, to limit merge collisions. + Hint: grep PSI_stage_info | sort -u +*/ +extern PSI_stage_info stage_after_create; +extern PSI_stage_info stage_allocating_local_table; +extern PSI_stage_info stage_alter_inplace_prepare; +extern PSI_stage_info stage_alter_inplace; +extern PSI_stage_info stage_alter_inplace_commit; +extern PSI_stage_info stage_changing_master; +extern PSI_stage_info stage_checking_master_version; +extern PSI_stage_info stage_checking_permissions; +extern PSI_stage_info stage_checking_privileges_on_cached_query; +extern PSI_stage_info stage_checking_query_cache_for_query; +extern PSI_stage_info stage_cleaning_up; +extern PSI_stage_info stage_closing_tables; +extern PSI_stage_info stage_compressing_gtid_table; +extern PSI_stage_info stage_connecting_to_master; +extern PSI_stage_info stage_converting_heap_to_ondisk; +extern PSI_stage_info stage_copying_to_group_table; +extern PSI_stage_info stage_copying_to_tmp_table; +extern PSI_stage_info stage_copy_to_tmp_table; +extern PSI_stage_info stage_creating_sort_index; +extern PSI_stage_info stage_creating_table; +extern PSI_stage_info stage_creating_tmp_table; +extern PSI_stage_info stage_deleting_from_main_table; +extern PSI_stage_info stage_deleting_from_reference_tables; +extern PSI_stage_info stage_discard_or_import_tablespace; +extern PSI_stage_info stage_end; +extern PSI_stage_info stage_executing; +extern PSI_stage_info stage_execution_of_init_command; +extern PSI_stage_info stage_explaining; +extern PSI_stage_info stage_finished_reading_one_binlog_switching_to_next_binlog; +extern PSI_stage_info stage_flushing_relay_log_and_master_info_repository; +extern PSI_stage_info stage_flushing_relay_log_info_file; +extern PSI_stage_info stage_freeing_items; +extern PSI_stage_info stage_fulltext_initialization; +extern PSI_stage_info stage_got_handler_lock; +extern PSI_stage_info stage_got_old_table; +extern PSI_stage_info stage_init; +extern PSI_stage_info stage_insert; +extern PSI_stage_info stage_invalidating_query_cache_entries_table; +extern PSI_stage_info stage_invalidating_query_cache_entries_table_list; +extern PSI_stage_info stage_killing_slave; +extern PSI_stage_info stage_logging_slow_query; +extern PSI_stage_info stage_making_temp_file_append_before_load_data; +extern PSI_stage_info stage_making_temp_file_create_before_load_data; +extern PSI_stage_info stage_manage_keys; +extern PSI_stage_info stage_master_has_sent_all_binlog_to_slave; +extern PSI_stage_info stage_opening_tables; +extern PSI_stage_info stage_optimizing; +extern PSI_stage_info stage_preparing; +extern PSI_stage_info stage_purging_old_relay_logs; +extern PSI_stage_info stage_query_end; +extern PSI_stage_info stage_queueing_master_event_to_the_relay_log; +extern PSI_stage_info stage_reading_event_from_the_relay_log; +extern PSI_stage_info stage_registering_slave_on_master; +extern PSI_stage_info stage_removing_duplicates; +extern PSI_stage_info stage_removing_tmp_table; +extern PSI_stage_info stage_rename; +extern PSI_stage_info stage_rename_result_table; +extern PSI_stage_info stage_requesting_binlog_dump; +extern PSI_stage_info stage_reschedule; +extern PSI_stage_info stage_searching_rows_for_update; +extern PSI_stage_info stage_sending_binlog_event_to_slave; +extern PSI_stage_info stage_sending_cached_result_to_client; +extern PSI_stage_info stage_sending_data; +extern PSI_stage_info stage_setup; +extern PSI_stage_info stage_slave_has_read_all_relay_log; +extern PSI_stage_info stage_slave_waiting_event_from_coordinator; +extern PSI_stage_info stage_slave_waiting_for_workers_to_process_queue; +extern PSI_stage_info stage_slave_waiting_worker_queue; +extern PSI_stage_info stage_slave_waiting_worker_to_free_events; +extern PSI_stage_info stage_slave_waiting_worker_to_release_partition; +extern PSI_stage_info stage_slave_waiting_workers_to_exit; +extern PSI_stage_info stage_sorting_for_group; +extern PSI_stage_info stage_sorting_for_order; +extern PSI_stage_info stage_sorting_result; +extern PSI_stage_info stage_sql_thd_waiting_until_delay; +extern PSI_stage_info stage_statistics; +extern PSI_stage_info stage_storing_result_in_query_cache; +extern PSI_stage_info stage_storing_row_into_queue; +extern PSI_stage_info stage_system_lock; +extern PSI_stage_info stage_update; +extern PSI_stage_info stage_updating; +extern PSI_stage_info stage_updating_main_table; +extern PSI_stage_info stage_updating_reference_tables; +extern PSI_stage_info stage_upgrading_lock; +extern PSI_stage_info stage_user_sleep; +extern PSI_stage_info stage_verifying_table; +extern PSI_stage_info stage_waiting_for_gtid_to_be_committed; +extern PSI_stage_info stage_waiting_for_handler_insert; +extern PSI_stage_info stage_waiting_for_handler_lock; +extern PSI_stage_info stage_waiting_for_handler_open; +extern PSI_stage_info stage_waiting_for_insert; +extern PSI_stage_info stage_waiting_for_master_to_send_event; +extern PSI_stage_info stage_waiting_for_master_update; +extern PSI_stage_info stage_waiting_for_relay_log_space; +extern PSI_stage_info stage_waiting_for_slave_mutex_on_exit; +extern PSI_stage_info stage_waiting_for_slave_thread_to_start; +extern PSI_stage_info stage_waiting_for_query_cache_lock; +extern PSI_stage_info stage_waiting_for_table_flush; +extern PSI_stage_info stage_waiting_for_the_next_event_in_relay_log; +extern PSI_stage_info stage_waiting_for_the_slave_thread_to_advance_position; +extern PSI_stage_info stage_waiting_to_finalize_termination; +extern PSI_stage_info stage_worker_waiting_for_its_turn_to_commit; +extern PSI_stage_info stage_worker_waiting_for_commit_parent; +extern PSI_stage_info stage_suspending; +extern PSI_stage_info stage_starting; +extern PSI_stage_info stage_waiting_for_no_channel_reference; +#ifdef HAVE_PSI_STATEMENT_INTERFACE +/** + Statement instrumentation keys (sql). + The last entry, at [SQLCOM_END], is for parsing errors. +*/ +extern PSI_statement_info sql_statement_info[(uint) SQLCOM_END + 1]; + +/** + Statement instrumentation keys (com). + The last entry, at [COM_END], is for packet errors. +*/ +extern PSI_statement_info com_statement_info[(uint) COM_END + 1]; + +/** + Statement instrumentation key for replication. +*/ +extern PSI_statement_info stmt_info_rpl; + +void init_sql_statement_info(); +void init_com_statement_info(); +#endif /* HAVE_PSI_STATEMENT_INTERFACE */ + +#ifndef _WIN32 +extern my_thread_t signal_thread; +#endif + +#ifdef HAVE_OPENSSL +extern struct st_VioSSLFd * ssl_acceptor_fd; +#endif /* HAVE_OPENSSL */ + +/* + The following variables were under INNODB_COMPABILITY_HOOKS + */ +extern my_bool opt_large_pages; +extern uint opt_large_page_size; +extern char lc_messages_dir[FN_REFLEN]; +extern char *lc_messages_dir_ptr; +extern const char *log_error_dest; +extern MYSQL_PLUGIN_IMPORT char reg_ext[FN_EXTLEN]; +extern MYSQL_PLUGIN_IMPORT uint reg_ext_length; +extern MYSQL_PLUGIN_IMPORT uint lower_case_table_names; +extern MYSQL_PLUGIN_IMPORT bool mysqld_embedded; + +extern long tc_heuristic_recover; + +extern ulong specialflag; +extern size_t mysql_data_home_len; +extern size_t mysql_real_data_home_len; +extern const char *mysql_real_data_home_ptr; +extern MYSQL_PLUGIN_IMPORT char *mysql_data_home; +extern "C" MYSQL_PLUGIN_IMPORT char server_version[SERVER_VERSION_LENGTH]; +extern MYSQL_PLUGIN_IMPORT char mysql_real_data_home[]; +extern char mysql_unpacked_real_data_home[]; +extern MYSQL_PLUGIN_IMPORT struct system_variables global_system_variables; +extern char default_logfile_name[FN_REFLEN]; + +#define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list)) + +extern MYSQL_PLUGIN_IMPORT const key_map key_map_empty; +extern MYSQL_PLUGIN_IMPORT key_map key_map_full; /* Should be threaded as const */ + +/* + Server mutex locks and condition variables. + */ +extern mysql_mutex_t + LOCK_item_func_sleep, LOCK_status, + LOCK_uuid_generator, + LOCK_crypt, LOCK_timezone, + LOCK_slave_list, LOCK_manager, + LOCK_global_system_variables, LOCK_user_conn, LOCK_log_throttle_qni, + LOCK_prepared_stmt_count, LOCK_error_messages, + LOCK_sql_slave_skip_counter, LOCK_slave_net_timeout, + LOCK_offline_mode, LOCK_default_password_lifetime; +#ifdef HAVE_OPENSSL +extern char* des_key_file; +extern mysql_mutex_t LOCK_des_key_file; +#endif +extern mysql_mutex_t LOCK_server_started; +extern mysql_cond_t COND_server_started; +extern mysql_mutex_t LOCK_reset_gtid_table; +extern mysql_mutex_t LOCK_compress_gtid_table; +extern mysql_cond_t COND_compress_gtid_table; +extern mysql_rwlock_t LOCK_sys_init_connect, LOCK_sys_init_slave; +extern mysql_rwlock_t LOCK_system_variables_hash; +extern mysql_cond_t COND_manager; +extern int32 thread_running; +extern mysql_mutex_t LOCK_group_replication_handler; + +extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher, + *opt_ssl_key, *opt_ssl_crl, *opt_ssl_crlpath, *opt_tls_version; + + +extern char *opt_disabled_storage_engines; +/** + only options that need special treatment in get_one_option() deserve + to be listed below +*/ +enum options_mysqld +{ + OPT_to_set_the_start_number=256, + OPT_BIND_ADDRESS, + OPT_BINLOG_CHECKSUM, + OPT_BINLOG_DO_DB, + OPT_BINLOG_FORMAT, + OPT_BINLOG_MAX_FLUSH_QUEUE_TIME, + OPT_BINLOG_IGNORE_DB, + OPT_BIN_LOG, + OPT_BOOTSTRAP, + OPT_CONSOLE, + OPT_DEBUG_SYNC_TIMEOUT, + OPT_DELAY_KEY_WRITE_ALL, + OPT_ISAM_LOG, + OPT_IGNORE_DB_DIRECTORY, + OPT_KEY_BUFFER_SIZE, + OPT_KEY_CACHE_AGE_THRESHOLD, + OPT_KEY_CACHE_BLOCK_SIZE, + OPT_KEY_CACHE_DIVISION_LIMIT, + OPT_LC_MESSAGES_DIRECTORY, + OPT_LOWER_CASE_TABLE_NAMES, + OPT_MASTER_RETRY_COUNT, + OPT_MASTER_VERIFY_CHECKSUM, + OPT_POOL_OF_THREADS, + OPT_REPLICATE_DO_DB, + OPT_REPLICATE_DO_TABLE, + OPT_REPLICATE_IGNORE_DB, + OPT_REPLICATE_IGNORE_TABLE, + OPT_REPLICATE_REWRITE_DB, + OPT_REPLICATE_WILD_DO_TABLE, + OPT_REPLICATE_WILD_IGNORE_TABLE, + OPT_SERVER_ID, + OPT_SKIP_HOST_CACHE, + OPT_SKIP_LOCK, + OPT_SKIP_NEW, + OPT_SKIP_RESOLVE, + OPT_SKIP_STACK_TRACE, + OPT_SKIP_SYMLINKS, + OPT_SLAVE_SQL_VERIFY_CHECKSUM, + OPT_SSL_CA, + OPT_SSL_CAPATH, + OPT_SSL_CERT, + OPT_SSL_CIPHER, + OPT_TLS_VERSION, + OPT_SSL_KEY, + OPT_UPDATE_LOG, + OPT_WANT_CORE, + OPT_LOG_ERROR, + OPT_MAX_LONG_DATA_SIZE, + OPT_EARLY_PLUGIN_LOAD, + OPT_PLUGIN_LOAD, + OPT_PLUGIN_LOAD_ADD, + OPT_SSL_CRL, + OPT_SSL_CRLPATH, + OPT_PFS_INSTRUMENT, + OPT_DEFAULT_AUTH, + OPT_SECURE_AUTH, + OPT_THREAD_CACHE_SIZE, + OPT_HOST_CACHE_SIZE, + OPT_TABLE_DEFINITION_CACHE, + OPT_MDL_CACHE_SIZE, + OPT_MDL_HASH_INSTANCES, + OPT_SKIP_INNODB, + OPT_AVOID_TEMPORAL_UPGRADE, + OPT_SHOW_OLD_TEMPORALS, + OPT_ENFORCE_GTID_CONSISTENCY, + OPT_TRANSACTION_READ_ONLY, + OPT_TRANSACTION_ISOLATION +}; + + +/** + Query type constants (usable as bitmap flags). +*/ +enum enum_query_type +{ + /// Nothing specific, ordinary SQL query. + QT_ORDINARY= 0, + /// In utf8. + QT_TO_SYSTEM_CHARSET= (1 << 0), + /// Without character set introducers. + QT_WITHOUT_INTRODUCERS= (1 << 1), + /// When printing a SELECT, add its number (select_lex->number) + QT_SHOW_SELECT_NUMBER= (1 << 2), + /// Don't print a database if it's equal to the connection's database + QT_NO_DEFAULT_DB= (1 << 3), + /// When printing a derived table, don't print its expression, only alias + QT_DERIVED_TABLE_ONLY_ALIAS= (1 << 4), + /// Print in charset of Item::print() argument (typically thd->charset()). + QT_TO_ARGUMENT_CHARSET= (1 << 5), + /// Print identifiers without database's name + QT_NO_DB= (1 << 6), + /// Print identifiers without table's name + QT_NO_TABLE= (1 << 7), + /** + Change all Item_basic_constant to ? (used by query rewrite to compute + digest.) Un-resolved hints will also be printed in this format. + */ + QT_NORMALIZED_FORMAT= (1 << 8), + /** + If an expression is constant, print the expression, not the value + it evaluates to. Should be used for error messages, so that they + don't reveal values. + */ + QT_NO_DATA_EXPANSION= (1 << 9), +}; + +/* query_id */ +typedef int64 query_id_t; +extern query_id_t global_query_id; + +/* increment query_id and return it. */ +inline MY_ATTRIBUTE((warn_unused_result)) query_id_t next_query_id() +{ + query_id_t id= my_atomic_add64(&global_query_id, 1); + return (id+1); +} + +/* + TODO: Replace this with an inline function. + */ +#ifndef EMBEDDED_LIBRARY +extern "C" void unireg_abort(int exit_code) MY_ATTRIBUTE((noreturn)); +#else +extern "C" void unireg_clear(int exit_code); +#define unireg_abort(exit_code) do { unireg_clear(exit_code); DBUG_RETURN(exit_code); } while(0) +#endif + +#if defined(MYSQL_DYNAMIC_PLUGIN) && defined(_WIN32) +extern "C" THD *_current_thd_noinline(); +#define _current_thd() _current_thd_noinline() +#else +static inline THD *_current_thd(void) +{ + return my_thread_get_THR_THD(); +} +#endif +#define current_thd _current_thd() + +#define ER(X) ER_THD(current_thd,X) + +#endif /* MYSQLD_INCLUDED */ diff --git a/mysql/sql/net_serv.cpp b/mysql/sql/net_serv.cpp new file mode 100644 index 0000000..a6bc857 --- /dev/null +++ b/mysql/sql/net_serv.cpp @@ -0,0 +1,1059 @@ +/* Copyright (c) 2000, 2016, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file + + This file is the net layer API for the MySQL client/server protocol. + + Write and read of logical packets to/from socket. + + Writes are cached into net_buffer_length big packets. + Read packets are reallocated dynamicly when reading big packets. + Each logical packet has the following pre-info: + 3 byte length & 1 byte package-number. + + This file needs to be written in C as it's used by the libmysql client as a + C file. +*/ + +/* + HFTODO this must be hidden if we don't want client capabilities in + embedded library + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "probes_mysql.h" +/* key_memory_NET_buff */ +#include "mysqld.h" + +#include + +using std::min; +using std::max; + +PSI_memory_key key_memory_NET_buff; +PSI_memory_key key_memory_NET_compress_packet; + +#ifdef EMBEDDED_LIBRARY +#undef MYSQL_SERVER +#undef MYSQL_CLIENT +#define MYSQL_CLIENT +#endif /*EMBEDDED_LIBRARY */ + + +/* + The following handles the differences when this is linked between the + client and the server. + + This gives an error if a too big packet is found. + The server can change this, but because the client can't normally do this + the client should have a bigger max_allowed_packet. +*/ + +#ifdef MYSQL_SERVER +/* + The following variables/functions should really not be declared + extern, but as it's hard to include sql_class.h here, we have to + live with this for a while. +*/ +extern void query_cache_insert(const char *packet, ulong length, + unsigned pkt_nr); +extern void thd_increment_bytes_sent(size_t length); +extern void thd_increment_bytes_received(size_t length); + +/* Additional instrumentation hooks for the server */ +#include "mysql_com_server.h" +#endif + +#define VIO_SOCKET_ERROR ((size_t) -1) + +static my_bool net_write_buff(NET *, const uchar *, size_t); + +/** Init with packet info. */ + +my_bool my_net_init(NET *net, Vio* vio) +{ + DBUG_ENTER("my_net_init"); + net->vio = vio; + my_net_local_init(net); /* Set some limits */ + if (!(net->buff=(uchar*) my_malloc(key_memory_NET_buff, + (size_t) net->max_packet+ + NET_HEADER_SIZE + COMP_HEADER_SIZE, + MYF(MY_WME)))) + DBUG_RETURN(1); + net->buff_end=net->buff+net->max_packet; + net->error=0; net->return_status=0; + net->pkt_nr=net->compress_pkt_nr=0; + net->write_pos=net->read_pos = net->buff; + net->last_error[0]=0; + net->compress=0; net->reading_or_writing=0; + net->where_b = net->remain_in_buf=0; + net->last_errno=0; + net->unused= 0; +#ifdef MYSQL_SERVER + net->extension= NULL; +#endif + + if (vio) + { + /* For perl DBI/DBD. */ + net->fd= vio_fd(vio); + vio_fastsend(vio); + } + DBUG_RETURN(0); +} + + +void net_end(NET *net) +{ + DBUG_ENTER("net_end"); + my_free(net->buff); + net->buff=0; + DBUG_VOID_RETURN; +} + +void net_claim_memory_ownership(NET *net) +{ + my_claim(net->buff); +} + +/** Realloc the packet buffer. */ + +my_bool net_realloc(NET *net, size_t length) +{ + uchar *buff; + size_t pkt_length; + DBUG_ENTER("net_realloc"); + DBUG_PRINT("enter",("length: %lu", (ulong) length)); + + if (length >= net->max_packet_size) + { + DBUG_PRINT("error", ("Packet too large. Max size: %lu", + net->max_packet_size)); + /* @todo: 1 and 2 codes are identical. */ + net->error= 1; + net->last_errno= ER_NET_PACKET_TOO_LARGE; +#ifdef MYSQL_SERVER + my_error(ER_NET_PACKET_TOO_LARGE, MYF(0)); +#endif + DBUG_RETURN(1); + } + pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1); + /* + We must allocate some extra bytes for the end 0 and to be able to + read big compressed blocks in + net_read_packet() may actually read 4 bytes depending on build flags and + platform. + */ + if (!(buff= (uchar*) my_realloc(key_memory_NET_buff, + (char*) net->buff, pkt_length + + NET_HEADER_SIZE + COMP_HEADER_SIZE, + MYF(MY_WME)))) + { + /* @todo: 1 and 2 codes are identical. */ + net->error= 1; + net->last_errno= ER_OUT_OF_RESOURCES; + /* In the server the error is reported by MY_WME flag. */ + DBUG_RETURN(1); + } + net->buff=net->write_pos=buff; + net->buff_end=buff+(net->max_packet= (ulong) pkt_length); + DBUG_RETURN(0); +} + + +/** + Clear (reinitialize) the NET structure for a new command. + + @remark Performs debug checking of the socket buffer to + ensure that the protocol sequence is correct. + + @param net NET handler + @param check_buffer Whether to check the socket buffer. +*/ + +void net_clear(NET *net, + my_bool check_buffer MY_ATTRIBUTE((unused))) +{ + DBUG_ENTER("net_clear"); + +#if !defined(EMBEDDED_LIBRARY) + /* Ensure the socket buffer is empty, except for an EOF (at least 1). */ + DBUG_ASSERT(!check_buffer || (vio_pending(net->vio) <= 1)); +#endif + + /* Ready for new command */ + net->pkt_nr= net->compress_pkt_nr= 0; + net->write_pos= net->buff; + + DBUG_VOID_RETURN; +} + + +/** Flush write_buffer if not empty. */ + +my_bool net_flush(NET *net) +{ + my_bool error= 0; + DBUG_ENTER("net_flush"); + if (net->buff != net->write_pos) + { + error= net_write_packet(net, net->buff, + (size_t) (net->write_pos - net->buff)); + net->write_pos= net->buff; + } + /* Sync packet number if using compression */ + if (net->compress) + net->pkt_nr=net->compress_pkt_nr; + DBUG_RETURN(error); +} + + +/** + Whether a I/O operation should be retried later. + + @param net NET handler. + @param retry_count Maximum number of interrupted operations. + + @retval TRUE Operation should be retried. + @retval FALSE Operation should not be retried. Fatal error. +*/ + +static my_bool +net_should_retry(NET *net, uint *retry_count MY_ATTRIBUTE((unused))) +{ + my_bool retry; + +#ifndef MYSQL_SERVER + /* + In the client library, interrupted I/O operations are always retried. + Otherwise, it's either a timeout or an unrecoverable error. + */ + retry= vio_should_retry(net->vio); +#else + /* + In the server, interrupted I/O operations are retried up to a limit. + In this scenario, pthread_kill can be used to wake up + (interrupt) threads waiting for I/O. + */ + retry= vio_should_retry(net->vio) && ((*retry_count)++ < net->retry_count); +#endif + + return retry; +} + + +/***************************************************************************** +** Write something to server/client buffer +*****************************************************************************/ + +/** + Write a logical packet with packet header. + + Format: Packet length (3 bytes), packet number (1 byte) + When compression is used, a 3 byte compression length is added. + + @note If compression is used, the original packet is modified! +*/ + +my_bool my_net_write(NET *net, const uchar *packet, size_t len) +{ + uchar buff[NET_HEADER_SIZE]; + int rc; + + if (unlikely(!net->vio)) /* nowhere to write */ + return 0; + + MYSQL_NET_WRITE_START(len); + + DBUG_EXECUTE_IF("simulate_net_write_failure", { + my_error(ER_NET_ERROR_ON_WRITE, MYF(0)); + return 1; + }; + ); + + /* + Big packets are handled by splitting them in packets of MAX_PACKET_LENGTH + length. The last packet is always a packet that is < MAX_PACKET_LENGTH. + (The last packet may even have a length of 0) + */ + while (len >= MAX_PACKET_LENGTH) + { + const ulong z_size = MAX_PACKET_LENGTH; + int3store(buff, z_size); + buff[3]= (uchar) net->pkt_nr++; + if (net_write_buff(net, buff, NET_HEADER_SIZE) || + net_write_buff(net, packet, z_size)) + { + MYSQL_NET_WRITE_DONE(1); + return 1; + } + packet += z_size; + len-= z_size; + } + /* Write last packet */ + int3store(buff, static_cast(len)); + buff[3]= (uchar) net->pkt_nr++; + if (net_write_buff(net, buff, NET_HEADER_SIZE)) + { + MYSQL_NET_WRITE_DONE(1); + return 1; + } +#ifndef DEBUG_DATA_PACKETS + DBUG_DUMP("packet_header", buff, NET_HEADER_SIZE); +#endif + rc= MY_TEST(net_write_buff(net,packet,len)); + MYSQL_NET_WRITE_DONE(rc); + return rc; +} + + +/** + Send a command to the server. + + The reason for having both header and packet is so that libmysql + can easy add a header to a special command (like prepared statements) + without having to re-alloc the string. + + As the command is part of the first data packet, we have to do some data + juggling to put the command in there, without having to create a new + packet. + + This function will split big packets into sub-packets if needed. + (Each sub packet can only be 2^24 bytes) + + @param net NET handler + @param command Command in MySQL server (enum enum_server_command) + @param header Header to write after command + @param head_len Length of header + @param packet Query or parameter to query + @param len Length of packet + + @retval + 0 ok + @retval + 1 error +*/ + +my_bool +net_write_command(NET *net,uchar command, + const uchar *header, size_t head_len, + const uchar *packet, size_t len) +{ + size_t length=len+1+head_len; /* 1 extra byte for command */ + uchar buff[NET_HEADER_SIZE+1]; + uint header_size=NET_HEADER_SIZE+1; + int rc; + DBUG_ENTER("net_write_command"); + DBUG_PRINT("enter",("length: %lu", (ulong) len)); + + MYSQL_NET_WRITE_START(length); + + buff[4]=command; /* For first packet */ + + if (length >= MAX_PACKET_LENGTH) + { + /* Take into account that we have the command in the first header */ + len= MAX_PACKET_LENGTH - 1 - head_len; + do + { + int3store(buff, MAX_PACKET_LENGTH); + buff[3]= (uchar) net->pkt_nr++; + if (net_write_buff(net, buff, header_size) || + net_write_buff(net, header, head_len) || + net_write_buff(net, packet, len)) + { + MYSQL_NET_WRITE_DONE(1); + DBUG_RETURN(1); + } + packet+= len; + length-= MAX_PACKET_LENGTH; + len= MAX_PACKET_LENGTH; + head_len= 0; + header_size= NET_HEADER_SIZE; + } while (length >= MAX_PACKET_LENGTH); + len=length; /* Data left to be written */ + } + int3store(buff, static_cast(length)); + buff[3]= (uchar) net->pkt_nr++; + rc= MY_TEST(net_write_buff(net, buff, header_size) || + (head_len && net_write_buff(net, header, head_len)) || + net_write_buff(net, packet, len) || net_flush(net)); + MYSQL_NET_WRITE_DONE(rc); + DBUG_RETURN(rc); +} + + +/** + Caching the data in a local buffer before sending it. + + Fill up net->buffer and send it to the client when full. + + If the rest of the to-be-sent-packet is bigger than buffer, + send it in one big block (to avoid copying to internal buffer). + If not, copy the rest of the data to the buffer and return without + sending data. + + @param net Network handler + @param packet Packet to send + @param len Length of packet + + @note + The cached buffer can be sent as it is with 'net_flush()'. + In this code we have to be careful to not send a packet longer than + MAX_PACKET_LENGTH to net_write_packet() if we are using the compressed + protocol as we store the length of the compressed packet in 3 bytes. + + @retval + 0 ok + @retval + 1 +*/ + +static my_bool +net_write_buff(NET *net, const uchar *packet, size_t len) +{ + ulong left_length; + if (net->compress && net->max_packet > MAX_PACKET_LENGTH) + left_length= (ulong) (MAX_PACKET_LENGTH - (net->write_pos - net->buff)); + else + left_length= (ulong) (net->buff_end - net->write_pos); + +#ifdef DEBUG_DATA_PACKETS + DBUG_DUMP("data", packet, len); +#endif + if (len > left_length) + { + if (net->write_pos != net->buff) + { + /* Fill up already used packet and write it */ + memcpy(net->write_pos, packet, left_length); + if (net_write_packet(net, net->buff, + (size_t) (net->write_pos - net->buff) + left_length)) + return 1; + net->write_pos= net->buff; + packet+= left_length; + len-= left_length; + } + if (net->compress) + { + /* + We can't have bigger packets than 16M with compression + Because the uncompressed length is stored in 3 bytes + */ + left_length= MAX_PACKET_LENGTH; + while (len > left_length) + { + if (net_write_packet(net, packet, left_length)) + return 1; + packet+= left_length; + len-= left_length; + } + } + if (len > net->max_packet) + return net_write_packet(net, packet, len); + /* Send out rest of the blocks as full sized blocks */ + } + memcpy(net->write_pos, packet, len); + net->write_pos+= len; + return 0; +} + + +/** + Write a determined number of bytes to a network handler. + + @param net NET handler. + @param buf Buffer containing the data to be written. + @param count The length, in bytes, of the buffer. + + @return TRUE on error, FALSE on success. +*/ + +static my_bool +net_write_raw_loop(NET *net, const uchar *buf, size_t count) +{ + unsigned int retry_count= 0; + + while (count) + { + size_t sentcnt= vio_write(net->vio, buf, count); + + /* VIO_SOCKET_ERROR (-1) indicates an error. */ + if (sentcnt == VIO_SOCKET_ERROR) + { + /* A recoverable I/O error occurred? */ + if (net_should_retry(net, &retry_count)) + continue; + else + break; + } + + count-= sentcnt; + buf+= sentcnt; +#ifdef MYSQL_SERVER + thd_increment_bytes_sent(sentcnt); +#endif + } + + /* On failure, propagate the error code. */ + if (count) + { + /* Socket should be closed. */ + net->error= 2; + + /* Interrupted by a timeout? */ + if (vio_was_timeout(net->vio)) + net->last_errno= ER_NET_WRITE_INTERRUPTED; + else + net->last_errno= ER_NET_ERROR_ON_WRITE; + +#ifdef MYSQL_SERVER + my_error(net->last_errno, MYF(0)); +#endif + } + + return MY_TEST(count); +} + + +/** + Compress and encapsulate a packet into a compressed packet. + + @param net NET handler. + @param packet The packet to compress. + @param[in,out] length Length of the packet. + + A compressed packet header is compromised of the packet + length (3 bytes), packet number (1 byte) and the length + of the original (uncompressed) packet. + + @return Pointer to the (new) compressed packet. +*/ + +static uchar * +compress_packet(NET *net, const uchar *packet, size_t *length) +{ + uchar *compr_packet; + size_t compr_length; + const uint header_length= NET_HEADER_SIZE + COMP_HEADER_SIZE; + + compr_packet= (uchar *) my_malloc(key_memory_NET_compress_packet, + *length + header_length, MYF(MY_WME)); + + if (compr_packet == NULL) + return NULL; + + memcpy(compr_packet + header_length, packet, *length); + + /* Compress the encapsulated packet. */ + if (my_compress(compr_packet + header_length, length, &compr_length)) + { + /* + If the length of the compressed packet is larger than the + original packet, the original packet is sent uncompressed. + */ + compr_length= 0; + } + + /* Length of the compressed (original) packet. */ + int3store(&compr_packet[NET_HEADER_SIZE], static_cast(compr_length)); + /* Length of this packet. */ + int3store(compr_packet, static_cast(*length)); + /* Packet number. */ + compr_packet[3]= (uchar) (net->compress_pkt_nr++); + + *length+= header_length; + + return compr_packet; +} + + +/** + Write a MySQL protocol packet to the network handler. + + @param net NET handler. + @param packet The packet to write. + @param length Length of the packet. + + @remark The packet might be encapsulated into a compressed packet. + + @return TRUE on error, FALSE on success. +*/ + +my_bool +net_write_packet(NET *net, const uchar *packet, size_t length) +{ + my_bool res; + DBUG_ENTER("net_write_packet"); + +#if defined(MYSQL_SERVER) + query_cache_insert((char*) packet, length, net->pkt_nr); +#endif + + /* Socket can't be used */ + if (net->error == 2) + DBUG_RETURN(TRUE); + + net->reading_or_writing= 2; + +#ifdef HAVE_COMPRESS + const bool do_compress= net->compress; + if (do_compress) + { + if ((packet= compress_packet(net, packet, &length)) == NULL) + { + net->error= 2; + net->last_errno= ER_OUT_OF_RESOURCES; + /* In the server, allocation failure raises a error. */ + net->reading_or_writing= 0; + DBUG_RETURN(TRUE); + } + } +#endif /* HAVE_COMPRESS */ + +#ifdef DEBUG_DATA_PACKETS + DBUG_DUMP("data", packet, length); +#endif + + res= net_write_raw_loop(net, packet, length); + +#ifdef HAVE_COMPRESS + if (do_compress) + my_free((void *) packet); +#endif + + net->reading_or_writing= 0; + + DBUG_RETURN(res); +} + +/***************************************************************************** +** Read something from server/clinet +*****************************************************************************/ + +/** + Read a determined number of bytes from a network handler. + + @param net NET handler. + @param count The number of bytes to read. + + @return TRUE on error, FALSE on success. +*/ + +static my_bool net_read_raw_loop(NET *net, size_t count) +{ + bool eof= false; + unsigned int retry_count= 0; + uchar *buf= net->buff + net->where_b; + + while (count) + { + size_t recvcnt= vio_read(net->vio, buf, count); + + /* VIO_SOCKET_ERROR (-1) indicates an error. */ + if (recvcnt == VIO_SOCKET_ERROR) + { + /* A recoverable I/O error occurred? */ + if (net_should_retry(net, &retry_count)) + continue; + else + break; + } + /* Zero indicates end of file. */ + else if (!recvcnt) + { + eof= true; + break; + } + + count-= recvcnt; + buf+= recvcnt; +#ifdef MYSQL_SERVER + thd_increment_bytes_received(recvcnt); +#endif + } + + /* On failure, propagate the error code. */ + if (count) + { + /* Socket should be closed. */ + net->error= 2; + + /* Interrupted by a timeout? */ + if (!eof && vio_was_timeout(net->vio)) + net->last_errno= ER_NET_READ_INTERRUPTED; + else + net->last_errno= ER_NET_READ_ERROR; + +#ifdef MYSQL_SERVER + my_error(net->last_errno, MYF(0)); +#endif + } + + return MY_TEST(count); +} + + +/** + Read the header of a packet. The MySQL protocol packet header + consists of the length, in bytes, of the payload (packet data) + and a serial number. + + @remark The encoded length is the length of the packet payload, + which does not include the packet header. + + @remark The serial number is used to ensure that the packets are + received in order. If the packet serial number does not + match the expected value, a error is returned. + + @param net NET handler. + + @return TRUE on error, FALSE on success. +*/ + +static my_bool net_read_packet_header(NET *net) +{ + uchar pkt_nr; + size_t count= NET_HEADER_SIZE; + my_bool rc; + + if (net->compress) + count+= COMP_HEADER_SIZE; + +#ifdef MYSQL_SERVER + struct st_net_server *server_extension; + + server_extension= static_cast (net->extension); + + if (server_extension != NULL) + { + void *user_data= server_extension->m_user_data; + DBUG_ASSERT(server_extension->m_before_header != NULL); + DBUG_ASSERT(server_extension->m_after_header != NULL); + + server_extension->m_before_header(net, user_data, count); + rc= net_read_raw_loop(net, count); + server_extension->m_after_header(net, user_data, count, rc); + } + else +#endif + { + rc= net_read_raw_loop(net, count); + } + + if (rc) + return TRUE; + + DBUG_DUMP("packet_header", net->buff + net->where_b, NET_HEADER_SIZE); + + pkt_nr= net->buff[net->where_b + 3]; + + /* + Verify packet serial number against the truncated packet counter. + The local packet counter must be truncated since its not reset. + */ + if (pkt_nr != (uchar) net->pkt_nr) + { + /* Not a NET error on the client. XXX: why? */ +#if defined(MYSQL_SERVER) + my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0)); +#elif defined(EXTRA_DEBUG) + /* + We don't make noise server side, since the client is expected + to break the protocol for e.g. --send LOAD DATA .. LOCAL where + the server expects the client to send a file, but the client + may reply with a new command instead. + */ + my_message_local(ERROR_LEVEL, + "packets out of order (found %u, expected %u)", + (uint) pkt_nr, net->pkt_nr); + DBUG_ASSERT(pkt_nr == net->pkt_nr); +#endif + return TRUE; + } + + net->pkt_nr++; + + return FALSE; +} + + +/** + Read one (variable-length) MySQL protocol packet. + A MySQL packet consists of a header and a payload. + + @remark Reads one packet to net->buff + net->where_b. + @remark Long packets are handled by my_net_read(). + @remark The network buffer is expanded if necessary. + + @return The length of the packet, or @packet_error on error. +*/ + +static size_t net_read_packet(NET *net, size_t *complen) +{ + size_t pkt_len, pkt_data_len; + + *complen= 0; + + net->reading_or_writing= 1; + + /* Retrieve packet length and number. */ + if (net_read_packet_header(net)) + goto error; + + net->compress_pkt_nr= net->pkt_nr; + +#ifdef HAVE_COMPRESS + if (net->compress) + { + /* + The right-hand expression + must match the size of the buffer allocated in net_realloc(). + */ + DBUG_ASSERT(net->where_b + NET_HEADER_SIZE + sizeof(uint32) <= + net->max_packet + NET_HEADER_SIZE + COMP_HEADER_SIZE); + + /* + If the packet is compressed then complen > 0 and contains the + number of bytes in the uncompressed packet. + */ + *complen= uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE])); + } +#endif + + /* The length of the packet that follows. */ + pkt_len= uint3korr(net->buff+net->where_b); + + /* End of big multi-packet. */ + if (!pkt_len) + goto end; + + pkt_data_len = max(pkt_len, *complen) + net->where_b; + + /* Expand packet buffer if necessary. */ + if ((pkt_data_len >= net->max_packet) && net_realloc(net, pkt_data_len)) + goto error; + + /* Read the packet data (payload). */ + if (net_read_raw_loop(net, pkt_len)) + goto error; + +end: + net->reading_or_writing= 0; + return pkt_len; + +error: + net->reading_or_writing= 0; + return packet_error; +} + + +/** + Read a packet from the client/server and return it without the internal + package header. + + If the packet is the first packet of a multi-packet packet + (which is indicated by the length of the packet = 0xffffff) then + all sub packets are read and concatenated. + + If the packet was compressed, its uncompressed and the length of the + uncompressed packet is returned. + + @return + The function returns the length of the found packet or packet_error. + net->read_pos points to the read data. +*/ + +ulong +my_net_read(NET *net) +{ + size_t len, complen; + + MYSQL_NET_READ_START(); + +#ifdef HAVE_COMPRESS + if (!net->compress) + { +#endif + len= net_read_packet(net, &complen); + if (len == MAX_PACKET_LENGTH) + { + /* First packet of a multi-packet. Concatenate the packets */ + ulong save_pos = net->where_b; + size_t total_length= 0; + do + { + net->where_b += len; + total_length += len; + len= net_read_packet(net, &complen); + } while (len == MAX_PACKET_LENGTH); + if (len != packet_error) + len+= total_length; + net->where_b = save_pos; + } + net->read_pos = net->buff + net->where_b; + if (len != packet_error) + net->read_pos[len]=0; /* Safeguard for mysql_use_result */ + MYSQL_NET_READ_DONE(0, len); + return static_cast(len); +#ifdef HAVE_COMPRESS + } + else + { + /* We are using the compressed protocol */ + + size_t buf_length; + ulong start_of_packet; + ulong first_packet_offset; + uint read_length, multi_byte_packet=0; + + if (net->remain_in_buf) + { + buf_length= net->buf_length; /* Data left in old packet */ + first_packet_offset= start_of_packet= (net->buf_length - + net->remain_in_buf); + /* Restore the character that was overwritten by the end 0 */ + net->buff[start_of_packet]= net->save_char; + } + else + { + /* reuse buffer, as there is nothing in it that we need */ + buf_length= start_of_packet= first_packet_offset= 0; + } + for (;;) + { + size_t packet_len; + + if (buf_length - start_of_packet >= NET_HEADER_SIZE) + { + read_length = uint3korr(net->buff+start_of_packet); + if (!read_length) + { + /* End of multi-byte packet */ + start_of_packet += NET_HEADER_SIZE; + break; + } + if (read_length + NET_HEADER_SIZE <= buf_length - start_of_packet) + { + if (multi_byte_packet) + { + /* + It's never the buffer on the first loop iteration that will have + multi_byte_packet on. + Thus there shall never be a non-zero first_packet_offset here. + */ + DBUG_ASSERT(first_packet_offset == 0); + /* Remove packet header for second packet */ + memmove(net->buff + start_of_packet, + net->buff + start_of_packet + NET_HEADER_SIZE, + buf_length - start_of_packet - NET_HEADER_SIZE); + start_of_packet += read_length; + buf_length -= NET_HEADER_SIZE; + } + else + start_of_packet+= read_length + NET_HEADER_SIZE; + + if (read_length != MAX_PACKET_LENGTH) /* last package */ + { + multi_byte_packet= 0; /* No last zero len packet */ + break; + } + multi_byte_packet= NET_HEADER_SIZE; + /* Move data down to read next data packet after current one */ + if (first_packet_offset) + { + memmove(net->buff,net->buff+first_packet_offset, + buf_length-first_packet_offset); + buf_length-=first_packet_offset; + start_of_packet -= first_packet_offset; + first_packet_offset=0; + } + continue; + } + } + /* Move data down to read next data packet after current one */ + if (first_packet_offset) + { + memmove(net->buff,net->buff+first_packet_offset, + buf_length-first_packet_offset); + buf_length-=first_packet_offset; + start_of_packet -= first_packet_offset; + first_packet_offset=0; + } + + net->where_b=buf_length; + if ((packet_len= net_read_packet(net, &complen)) == packet_error) + { + MYSQL_NET_READ_DONE(1, 0); + return packet_error; + } + if (my_uncompress(net->buff + net->where_b, packet_len, + &complen)) + { + net->error= 2; /* caller will close socket */ + net->last_errno= ER_NET_UNCOMPRESS_ERROR; +#ifdef MYSQL_SERVER + my_error(ER_NET_UNCOMPRESS_ERROR, MYF(0)); +#endif + MYSQL_NET_READ_DONE(1, 0); + return packet_error; + } + buf_length+= complen; + } + + net->read_pos= net->buff+ first_packet_offset + NET_HEADER_SIZE; + net->buf_length= buf_length; + net->remain_in_buf= (ulong) (buf_length - start_of_packet); + len = ((ulong) (start_of_packet - first_packet_offset) - NET_HEADER_SIZE - + multi_byte_packet); + net->save_char= net->read_pos[len]; /* Must be saved */ + net->read_pos[len]=0; /* Safeguard for mysql_use_result */ + } +#endif /* HAVE_COMPRESS */ + MYSQL_NET_READ_DONE(0, len); + return static_cast(len); +} + + +void my_net_set_read_timeout(NET *net, uint timeout) +{ + DBUG_ENTER("my_net_set_read_timeout"); + DBUG_PRINT("enter", ("timeout: %d", timeout)); + net->read_timeout= timeout; + if (net->vio) + vio_timeout(net->vio, 0, timeout); + DBUG_VOID_RETURN; +} + + +void my_net_set_write_timeout(NET *net, uint timeout) +{ + DBUG_ENTER("my_net_set_write_timeout"); + DBUG_PRINT("enter", ("timeout: %d", timeout)); + net->write_timeout= timeout; + if (net->vio) + vio_timeout(net->vio, 1, timeout); + DBUG_VOID_RETURN; +} + diff --git a/mysql/sql/sql_alloc.h b/mysql/sql/sql_alloc.h new file mode 100644 index 0000000..629dfe1 --- /dev/null +++ b/mysql/sql/sql_alloc.h @@ -0,0 +1,51 @@ +#ifndef SQL_ALLOC_INCLUDED +#define SQL_ALLOC_INCLUDED +/* Copyright (c) 2012, 2015, 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include "my_sys.h" // TRASH +#include "thr_malloc.h" // alloc_root + +/** + MySQL standard memory allocator class. You have to inherit the class + in order to use it. +*/ +class Sql_alloc +{ +public: + static void *operator new(size_t size) throw () + { + return sql_alloc(size); + } + static void *operator new[](size_t size) throw () + { + return sql_alloc(size); + } + static void *operator new[](size_t size, MEM_ROOT *mem_root) throw () + { return alloc_root(mem_root, size); } + static void *operator new(size_t size, MEM_ROOT *mem_root) throw () + { return alloc_root(mem_root, size); } + static void operator delete(void *ptr, size_t size) { TRASH(ptr, size); } + static void operator delete(void *ptr, MEM_ROOT *mem_root) + { /* never called */ } + static void operator delete[](void *ptr, MEM_ROOT *mem_root) + { /* never called */ } + static void operator delete[](void *ptr, size_t size) { TRASH(ptr, size); } + + inline Sql_alloc() {} + inline ~Sql_alloc() {} +}; + +#endif // SQL_ALLOC_INCLUDED diff --git a/mysql/sql/sql_cmd.h b/mysql/sql/sql_cmd.h new file mode 100644 index 0000000..8656f83 --- /dev/null +++ b/mysql/sql/sql_cmd.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2009, 2015, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file Representation of an SQL command. +*/ + +#ifndef SQL_CMD_INCLUDED +#define SQL_CMD_INCLUDED + +#include "my_sqlcommand.h" +#include "sql_alloc.h" +class THD; + +/** + @class Sql_cmd - Representation of an SQL command. + + This class is an interface between the parser and the runtime. + The parser builds the appropriate derived classes of Sql_cmd + to represent a SQL statement in the parsed tree. + The execute() method in the derived classes of Sql_cmd contain the runtime + implementation. + Note that this interface is used for SQL statements recently implemented, + the code for older statements tend to load the LEX structure with more + attributes instead. + Implement new statements by sub-classing Sql_cmd, as this improves + code modularity (see the 'big switch' in dispatch_command()), and decreases + the total size of the LEX structure (therefore saving memory in stored + programs). + The recommended name of a derived class of Sql_cmd is Sql_cmd_. + + Notice that the Sql_cmd class should not be confused with the Statement class. + Statement is a class that is used to manage an SQL command or a set + of SQL commands. When the SQL statement text is analyzed, the parser will + create one or more Sql_cmd objects to represent the actual SQL commands. +*/ +class Sql_cmd : public Sql_alloc +{ +private: + Sql_cmd(const Sql_cmd &); // No copy constructor wanted + void operator=(Sql_cmd &); // No assignment operator wanted + +public: + /** + @brief Return the command code for this statement + */ + virtual enum_sql_command sql_command_code() const = 0; + + /** + Execute this SQL statement. + @param thd the current thread. + @retval false on success. + @retval true on error + */ + virtual bool execute(THD *thd) = 0; + + /** + Command-specific reinitialization before execution of prepared statement + + @see reinit_stmt_before_use() + + @note Currently this function is overloaded for INSERT/REPLACE stmts only. + + @param thd Current THD. + */ + virtual void cleanup(THD *thd) {} + +protected: + Sql_cmd() + {} + + virtual ~Sql_cmd() + { + /* + Sql_cmd objects are allocated in thd->mem_root. + In MySQL, the C++ destructor is never called, the underlying MEM_ROOT is + simply destroyed instead. + Do not rely on the destructor for any cleanup. + */ + DBUG_ASSERT(FALSE); + } +}; + +#endif // SQL_CMD_INCLUDED diff --git a/mysql/sql/thr_malloc.h b/mysql/sql/thr_malloc.h new file mode 100644 index 0000000..6af9488 --- /dev/null +++ b/mysql/sql/thr_malloc.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2006, 2015, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef THR_MALLOC_INCLUDED +#define THR_MALLOC_INCLUDED + +#include "my_global.h" + +typedef struct charset_info_st CHARSET_INFO; +typedef struct st_mem_root MEM_ROOT; +typedef unsigned int PSI_memory_key; + +void init_sql_alloc(PSI_memory_key key, + MEM_ROOT *root, size_t block_size, size_t pre_alloc_size); + +void *sql_alloc(size_t); +void *sql_calloc(size_t); +char *sql_strdup(const char *str); +char *sql_strmake(const char *str, size_t len); +void *sql_memdup(const void * ptr, size_t size); +char *sql_strmake_with_convert(const char *str, size_t arg_length, + const CHARSET_INFO *from_cs, + size_t max_res_length, + const CHARSET_INFO *to_cs, size_t *result_length); + +#endif /* THR_MALLOC_INCLUDED */ -- cgit v1.1