You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-08 14:02:17 +03:00
Added support for connection attributes
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
||||
/************************************************************************************
|
||||
Copyright (C) 2000, 2012 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
|
||||
Monty Program AB
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
@@ -11,11 +13,13 @@
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA */
|
||||
License along with this library; if not see <http://www.gnu.org/licenses>
|
||||
or write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
|
||||
|
||||
/* Dynamic hashing of record with different key-length */
|
||||
Part of this code includes code from the PHP project which
|
||||
is freely available from http://www.php.net
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef _hash_h
|
||||
#define _hash_h
|
||||
@@ -23,7 +27,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef byte *(*hash_get_key)(const byte *,uint*,my_bool);
|
||||
typedef uchar *(*hash_get_key)(const uchar *,size_t*,my_bool);
|
||||
typedef void (*hash_free_key)(void *);
|
||||
|
||||
/* flags for hash_init */
|
||||
@@ -31,7 +35,7 @@ typedef void (*hash_free_key)(void *);
|
||||
|
||||
typedef struct st_hash_info {
|
||||
uint next; /* index to next key */
|
||||
byte *data; /* data for current entry */
|
||||
uchar *data; /* data for current entry */
|
||||
} HASH_LINK;
|
||||
|
||||
typedef struct st_hash {
|
||||
@@ -41,7 +45,7 @@ typedef struct st_hash {
|
||||
DYNAMIC_ARRAY array; /* Place for hash_keys */
|
||||
hash_get_key get_key;
|
||||
void (*free)(void *);
|
||||
uint (*calc_hashnr)(const byte *key,uint length);
|
||||
uint (*calc_hashnr)(const uchar *key,uint length);
|
||||
} HASH;
|
||||
|
||||
#define hash_init(A,B,C,D,E,F,G) _hash_init(A,B,C,D,E,F,G CALLER_INFO)
|
||||
@@ -49,12 +53,12 @@ my_bool _hash_init(HASH *hash,uint default_array_elements, uint key_offset,
|
||||
uint key_length, hash_get_key get_key,
|
||||
void (*free_element)(void*), uint flags CALLER_INFO_PROTO);
|
||||
void hash_free(HASH *tree);
|
||||
byte *hash_element(HASH *hash,uint idx);
|
||||
gptr hash_search(HASH *info,const byte *key,uint length);
|
||||
gptr hash_next(HASH *info,const byte *key,uint length);
|
||||
my_bool hash_insert(HASH *info,const byte *data);
|
||||
my_bool hash_delete(HASH *hash,byte *record);
|
||||
my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length);
|
||||
uchar *hash_element(HASH *hash,uint idx);
|
||||
gptr hash_search(HASH *info,const uchar *key,uint length);
|
||||
gptr hash_next(HASH *info,const uchar *key,uint length);
|
||||
my_bool hash_insert(HASH *info,const uchar *data);
|
||||
my_bool hash_delete(HASH *hash,uchar *record);
|
||||
my_bool hash_update(HASH *hash,uchar *record,uchar *old_key,uint old_key_length);
|
||||
my_bool hash_check(HASH *hash); /* Only in debug library */
|
||||
|
||||
#define hash_clear(H) bzero((char*) (H),sizeof(*(H)))
|
||||
|
@@ -275,3 +275,4 @@
|
||||
#cmakedefine SHAREDIR "@SHAREDIR@"
|
||||
#cmakedefine DEFAULT_CHARSET_HOME "@DEFAULT_CHARSET_HOME@"
|
||||
#cmakedefine PLUGINDIR "@PLUGINDIR@"
|
||||
|
||||
|
390
include/mysql.h
390
include/mysql.h
@@ -54,29 +54,31 @@ typedef int my_socket;
|
||||
#include "mysql_version.h"
|
||||
#include "my_list.h"
|
||||
#include "m_ctype.h"
|
||||
#include "my_sys.h"
|
||||
#include "hash.h"
|
||||
|
||||
#ifndef ST_USED_MEM_DEFINED
|
||||
#define ST_USED_MEM_DEFINED
|
||||
typedef struct st_used_mem { /* struct for once_alloc */
|
||||
struct st_used_mem *next; /* Next block in use */
|
||||
size_t left; /* memory left in block */
|
||||
size_t size; /* Size of block */
|
||||
} USED_MEM;
|
||||
typedef struct st_used_mem { /* struct for once_alloc */
|
||||
struct st_used_mem *next; /* Next block in use */
|
||||
size_t left; /* memory left in block */
|
||||
size_t size; /* Size of block */
|
||||
} USED_MEM;
|
||||
|
||||
typedef struct st_mem_root {
|
||||
USED_MEM *free;
|
||||
USED_MEM *used;
|
||||
USED_MEM *pre_alloc;
|
||||
size_t min_malloc;
|
||||
size_t block_size;
|
||||
unsigned int block_num;
|
||||
unsigned int first_block_usage;
|
||||
void (*error_handler)(void);
|
||||
} MEM_ROOT;
|
||||
typedef struct st_mem_root {
|
||||
USED_MEM *free;
|
||||
USED_MEM *used;
|
||||
USED_MEM *pre_alloc;
|
||||
size_t min_malloc;
|
||||
size_t block_size;
|
||||
unsigned int block_num;
|
||||
unsigned int first_block_usage;
|
||||
void (*error_handler)(void);
|
||||
} MEM_ROOT;
|
||||
#endif
|
||||
|
||||
extern unsigned int mysql_port;
|
||||
extern char *mysql_unix_port;
|
||||
extern unsigned int mysql_port;
|
||||
extern char *mysql_unix_port;
|
||||
|
||||
#define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG)
|
||||
#define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG)
|
||||
@@ -85,203 +87,207 @@ extern char *mysql_unix_port;
|
||||
#define IS_NUM_FIELD(f) ((f)->flags & NUM_FLAG)
|
||||
#define INTERNAL_NUM_FIELD(f) (((f)->type <= MYSQL_TYPE_INT24 && ((f)->type != MYSQL_TYPE_TIMESTAMP || (f)->length == 14 || (f)->length == 8)) || (f)->type == MYSQL_TYPE_YEAR)
|
||||
|
||||
typedef struct st_mysql_field {
|
||||
char *name; /* Name of column */
|
||||
char *org_name; /* Name of original column (added after 3.23.58) */
|
||||
char *table; /* Table of column if column was a field */
|
||||
char *org_table; /* Name of original table (added after 3.23.58 */
|
||||
char *db; /* table schema (added after 3.23.58) */
|
||||
char *catalog; /* table catalog (added after 3.23.58) */
|
||||
char *def; /* Default value (set by mysql_list_fields) */
|
||||
unsigned long length; /* Width of column */
|
||||
unsigned long max_length; /* Max width of selected set */
|
||||
/* added after 3.23.58 */
|
||||
unsigned int name_length;
|
||||
unsigned int org_name_length;
|
||||
unsigned int table_length;
|
||||
unsigned int org_table_length;
|
||||
unsigned int db_length;
|
||||
unsigned int catalog_length;
|
||||
unsigned int def_length;
|
||||
/***********************/
|
||||
unsigned int flags; /* Div flags */
|
||||
unsigned int decimals; /* Number of decimals in field */
|
||||
unsigned int charsetnr; /* char set number (added in 4.1) */
|
||||
enum enum_field_types type; /* Type of field. Se mysql_com.h for types */
|
||||
void *extension; /* added in 4.1 */
|
||||
} MYSQL_FIELD;
|
||||
typedef struct st_mysql_field {
|
||||
char *name; /* Name of column */
|
||||
char *org_name; /* Name of original column (added after 3.23.58) */
|
||||
char *table; /* Table of column if column was a field */
|
||||
char *org_table; /* Name of original table (added after 3.23.58 */
|
||||
char *db; /* table schema (added after 3.23.58) */
|
||||
char *catalog; /* table catalog (added after 3.23.58) */
|
||||
char *def; /* Default value (set by mysql_list_fields) */
|
||||
unsigned long length; /* Width of column */
|
||||
unsigned long max_length; /* Max width of selected set */
|
||||
/* added after 3.23.58 */
|
||||
unsigned int name_length;
|
||||
unsigned int org_name_length;
|
||||
unsigned int table_length;
|
||||
unsigned int org_table_length;
|
||||
unsigned int db_length;
|
||||
unsigned int catalog_length;
|
||||
unsigned int def_length;
|
||||
/***********************/
|
||||
unsigned int flags; /* Div flags */
|
||||
unsigned int decimals; /* Number of decimals in field */
|
||||
unsigned int charsetnr; /* char set number (added in 4.1) */
|
||||
enum enum_field_types type; /* Type of field. Se mysql_com.h for types */
|
||||
void *extension; /* added in 4.1 */
|
||||
} MYSQL_FIELD;
|
||||
|
||||
typedef char **MYSQL_ROW; /* return data as array of strings */
|
||||
typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */
|
||||
typedef char **MYSQL_ROW; /* return data as array of strings */
|
||||
typedef unsigned int MYSQL_FIELD_OFFSET; /* offset to current field */
|
||||
|
||||
#if defined(NO_CLIENT_LONG_LONG)
|
||||
typedef unsigned long my_ulonglong;
|
||||
typedef unsigned long my_ulonglong;
|
||||
#elif defined (_WIN32)
|
||||
typedef unsigned __int64 my_ulonglong;
|
||||
typedef unsigned __int64 my_ulonglong;
|
||||
#else
|
||||
typedef unsigned long long my_ulonglong;
|
||||
typedef unsigned long long my_ulonglong;
|
||||
#endif
|
||||
|
||||
|
||||
#define SET_CLIENT_ERROR(a, b, c, d) \
|
||||
{ \
|
||||
(a)->net.last_errno= (b);\
|
||||
strncpy((a)->net.sqlstate, (c), sizeof((a)->net.sqlstate));\
|
||||
strncpy((a)->net.last_error, (d) ? (d) : ER((b)), sizeof((a)->net.last_error));\
|
||||
}
|
||||
{ \
|
||||
(a)->net.last_errno= (b);\
|
||||
strncpy((a)->net.sqlstate, (c), sizeof((a)->net.sqlstate));\
|
||||
strncpy((a)->net.last_error, (d) ? (d) : ER((b)), sizeof((a)->net.last_error));\
|
||||
}
|
||||
|
||||
#define CLEAR_CLIENT_ERROR(a) \
|
||||
{ \
|
||||
(a)->net.last_errno= 0;\
|
||||
strcpy((a)->net.sqlstate, "00000");\
|
||||
(a)->net.last_error[0]= '\0';\
|
||||
}
|
||||
{ \
|
||||
(a)->net.last_errno= 0;\
|
||||
strcpy((a)->net.sqlstate, "00000");\
|
||||
(a)->net.last_error[0]= '\0';\
|
||||
}
|
||||
|
||||
#define MYSQL_COUNT_ERROR (~(my_ulonglong) 0)
|
||||
|
||||
|
||||
typedef struct st_mysql_rows {
|
||||
struct st_mysql_rows *next; /* list of rows */
|
||||
MYSQL_ROW data;
|
||||
unsigned long length;
|
||||
} MYSQL_ROWS;
|
||||
typedef struct st_mysql_rows {
|
||||
struct st_mysql_rows *next; /* list of rows */
|
||||
MYSQL_ROW data;
|
||||
unsigned long length;
|
||||
} MYSQL_ROWS;
|
||||
|
||||
typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */
|
||||
typedef MYSQL_ROWS *MYSQL_ROW_OFFSET; /* offset to current row */
|
||||
|
||||
typedef struct st_mysql_data {
|
||||
my_ulonglong rows;
|
||||
unsigned int fields;
|
||||
MYSQL_ROWS *data;
|
||||
MEM_ROOT alloc;
|
||||
} MYSQL_DATA;
|
||||
typedef struct st_mysql_data {
|
||||
my_ulonglong rows;
|
||||
unsigned int fields;
|
||||
MYSQL_ROWS *data;
|
||||
MEM_ROOT alloc;
|
||||
} MYSQL_DATA;
|
||||
|
||||
enum mysql_option
|
||||
{
|
||||
MYSQL_OPT_CONNECT_TIMEOUT,
|
||||
MYSQL_OPT_COMPRESS,
|
||||
MYSQL_OPT_NAMED_PIPE,
|
||||
MYSQL_INIT_COMMAND,
|
||||
MYSQL_READ_DEFAULT_FILE,
|
||||
MYSQL_READ_DEFAULT_GROUP,
|
||||
MYSQL_SET_CHARSET_DIR,
|
||||
MYSQL_SET_CHARSET_NAME,
|
||||
MYSQL_OPT_LOCAL_INFILE,
|
||||
MYSQL_OPT_PROTOCOL,
|
||||
MYSQL_SHARED_MEMORY_BASE_NAME,
|
||||
MYSQL_OPT_READ_TIMEOUT,
|
||||
MYSQL_OPT_WRITE_TIMEOUT,
|
||||
MYSQL_OPT_USE_RESULT,
|
||||
MYSQL_OPT_USE_REMOTE_CONNECTION,
|
||||
MYSQL_OPT_USE_EMBEDDED_CONNECTION,
|
||||
MYSQL_OPT_GUESS_CONNECTION,
|
||||
MYSQL_SET_CLIENT_IP,
|
||||
MYSQL_SECURE_AUTH,
|
||||
MYSQL_REPORT_DATA_TRUNCATION,
|
||||
MYSQL_OPT_RECONNECT,
|
||||
MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
|
||||
MYSQL_PLUGIN_DIR,
|
||||
MYSQL_DEFAULT_AUTH,
|
||||
MYSQL_OPT_BIND,
|
||||
MYSQL_OPT_SSL_KEY,
|
||||
MYSQL_OPT_SSL_CERT,
|
||||
MYSQL_OPT_SSL_CA,
|
||||
MYSQL_OPT_SSL_CAPATH,
|
||||
MYSQL_OPT_SSL_CIPHER,
|
||||
MYSQL_OPT_SSL_CRL,
|
||||
MYSQL_OPT_SSL_CRLPATH,
|
||||
enum mysql_option
|
||||
{
|
||||
MYSQL_OPT_CONNECT_TIMEOUT,
|
||||
MYSQL_OPT_COMPRESS,
|
||||
MYSQL_OPT_NAMED_PIPE,
|
||||
MYSQL_INIT_COMMAND,
|
||||
MYSQL_READ_DEFAULT_FILE,
|
||||
MYSQL_READ_DEFAULT_GROUP,
|
||||
MYSQL_SET_CHARSET_DIR,
|
||||
MYSQL_SET_CHARSET_NAME,
|
||||
MYSQL_OPT_LOCAL_INFILE,
|
||||
MYSQL_OPT_PROTOCOL,
|
||||
MYSQL_SHARED_MEMORY_BASE_NAME,
|
||||
MYSQL_OPT_READ_TIMEOUT,
|
||||
MYSQL_OPT_WRITE_TIMEOUT,
|
||||
MYSQL_OPT_USE_RESULT,
|
||||
MYSQL_OPT_USE_REMOTE_CONNECTION,
|
||||
MYSQL_OPT_USE_EMBEDDED_CONNECTION,
|
||||
MYSQL_OPT_GUESS_CONNECTION,
|
||||
MYSQL_SET_CLIENT_IP,
|
||||
MYSQL_SECURE_AUTH,
|
||||
MYSQL_REPORT_DATA_TRUNCATION,
|
||||
MYSQL_OPT_RECONNECT,
|
||||
MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
|
||||
MYSQL_PLUGIN_DIR,
|
||||
MYSQL_DEFAULT_AUTH,
|
||||
MYSQL_OPT_BIND,
|
||||
MYSQL_OPT_SSL_KEY,
|
||||
MYSQL_OPT_SSL_CERT,
|
||||
MYSQL_OPT_SSL_CA,
|
||||
MYSQL_OPT_SSL_CAPATH,
|
||||
MYSQL_OPT_SSL_CIPHER,
|
||||
MYSQL_OPT_SSL_CRL,
|
||||
MYSQL_OPT_SSL_CRLPATH,
|
||||
/* Connection attribute options */
|
||||
MYSQL_OPT_CONNECT_ATTR_RESET,
|
||||
MYSQL_OPT_CONNECT_ATTR_ADD,
|
||||
MYSQL_OPT_CONNECT_ATTR_DELETE,
|
||||
|
||||
/* MariaDB specific */
|
||||
MYSQL_PROGRESS_CALLBACK=5999,
|
||||
MYSQL_DATABASE_DRIVER=7000
|
||||
};
|
||||
/* MariaDB specific */
|
||||
MYSQL_PROGRESS_CALLBACK=5999,
|
||||
MYSQL_DATABASE_DRIVER=7000
|
||||
};
|
||||
|
||||
enum mysql_status { MYSQL_STATUS_READY,
|
||||
MYSQL_STATUS_GET_RESULT,
|
||||
MYSQL_STATUS_USE_RESULT,
|
||||
MYSQL_STATUS_QUERY_SENT,
|
||||
MYSQL_STATUS_SENDING_LOAD_DATA,
|
||||
MYSQL_STATUS_FETCHING_DATA,
|
||||
MYSQL_STATUS_NEXT_RESULT_PENDING,
|
||||
MYSQL_STATUS_QUIT_SENT, /* object is "destroyed" at this stage */
|
||||
};
|
||||
enum mysql_status { MYSQL_STATUS_READY,
|
||||
MYSQL_STATUS_GET_RESULT,
|
||||
MYSQL_STATUS_USE_RESULT,
|
||||
MYSQL_STATUS_QUERY_SENT,
|
||||
MYSQL_STATUS_SENDING_LOAD_DATA,
|
||||
MYSQL_STATUS_FETCHING_DATA,
|
||||
MYSQL_STATUS_NEXT_RESULT_PENDING,
|
||||
MYSQL_STATUS_QUIT_SENT, /* object is "destroyed" at this stage */
|
||||
};
|
||||
|
||||
enum mysql_protocol_type
|
||||
{
|
||||
MYSQL_PROTOCOL_DEFAULT, MYSQL_PROTOCOL_TCP, MYSQL_PROTOCOL_SOCKET,
|
||||
MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY
|
||||
};
|
||||
enum mysql_protocol_type
|
||||
{
|
||||
MYSQL_PROTOCOL_DEFAULT, MYSQL_PROTOCOL_TCP, MYSQL_PROTOCOL_SOCKET,
|
||||
MYSQL_PROTOCOL_PIPE, MYSQL_PROTOCOL_MEMORY
|
||||
};
|
||||
|
||||
struct st_mysql_options {
|
||||
unsigned int connect_timeout, read_timeout, write_timeout;
|
||||
unsigned int port, protocol;
|
||||
unsigned long client_flag;
|
||||
char *host,*user,*password,*unix_socket,*db;
|
||||
struct st_dynamic_array *init_command;
|
||||
char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name;
|
||||
char *ssl_key; /* PEM key file */
|
||||
char *ssl_cert; /* PEM cert file */
|
||||
char *ssl_ca; /* PEM CA file */
|
||||
char *ssl_capath; /* PEM directory of CA-s? */
|
||||
char *ssl_cipher;
|
||||
char *shared_memory_base_name;
|
||||
unsigned long max_allowed_packet;
|
||||
my_bool use_ssl; /* if to use SSL or not */
|
||||
my_bool compress,named_pipe;
|
||||
my_bool unused_1, unused_2, unused_3, unused_4;
|
||||
enum mysql_option methods_to_use;
|
||||
char *client_ip;
|
||||
my_bool secure_auth;
|
||||
my_bool report_data_truncation;
|
||||
/* function pointers for local infile support */
|
||||
int (*local_infile_init)(void **, const char *, void *);
|
||||
int (*local_infile_read)(void *, char *, unsigned int);
|
||||
void (*local_infile_end)(void *);
|
||||
int (*local_infile_error)(void *, char *, unsigned int);
|
||||
void *local_infile_userdata;
|
||||
struct st_mysql_options_extention *extension;
|
||||
};
|
||||
struct st_mysql_options {
|
||||
unsigned int connect_timeout, read_timeout, write_timeout;
|
||||
unsigned int port, protocol;
|
||||
unsigned long client_flag;
|
||||
char *host,*user,*password,*unix_socket,*db;
|
||||
struct st_dynamic_array *init_command;
|
||||
char *my_cnf_file,*my_cnf_group, *charset_dir, *charset_name;
|
||||
char *ssl_key; /* PEM key file */
|
||||
char *ssl_cert; /* PEM cert file */
|
||||
char *ssl_ca; /* PEM CA file */
|
||||
char *ssl_capath; /* PEM directory of CA-s? */
|
||||
char *ssl_cipher;
|
||||
char *shared_memory_base_name;
|
||||
unsigned long max_allowed_packet;
|
||||
my_bool use_ssl; /* if to use SSL or not */
|
||||
my_bool compress,named_pipe;
|
||||
my_bool unused_1, unused_2, unused_3, unused_4;
|
||||
enum mysql_option methods_to_use;
|
||||
char *client_ip;
|
||||
my_bool secure_auth;
|
||||
my_bool report_data_truncation;
|
||||
/* function pointers for local infile support */
|
||||
int (*local_infile_init)(void **, const char *, void *);
|
||||
int (*local_infile_read)(void *, char *, unsigned int);
|
||||
void (*local_infile_end)(void *);
|
||||
int (*local_infile_error)(void *, char *, unsigned int);
|
||||
void *local_infile_userdata;
|
||||
struct st_mysql_options_extention *extension;
|
||||
};
|
||||
|
||||
typedef struct st_mariadb_db_driver
|
||||
{
|
||||
struct st_mariadb_client_plugin_DB *plugin;
|
||||
char *name;
|
||||
void *buffer;
|
||||
} MARIADB_DB_DRIVER;
|
||||
typedef struct st_mariadb_db_driver
|
||||
{
|
||||
struct st_mariadb_client_plugin_DB *plugin;
|
||||
char *name;
|
||||
void *buffer;
|
||||
} MARIADB_DB_DRIVER;
|
||||
|
||||
typedef struct st_mysql {
|
||||
NET net; /* Communication parameters */
|
||||
void *unused_0;
|
||||
char *host,*user,*passwd,*unix_socket,*server_version,*host_info;
|
||||
char *info,*db;
|
||||
const struct charset_info_st *charset; /* character set */
|
||||
MYSQL_FIELD *fields;
|
||||
MEM_ROOT field_alloc;
|
||||
my_ulonglong affected_rows;
|
||||
my_ulonglong insert_id; /* id if insert on table with NEXTNR */
|
||||
my_ulonglong extra_info; /* Used by mysqlshow */
|
||||
unsigned long thread_id; /* Id for connection in server */
|
||||
unsigned long packet_length;
|
||||
unsigned int port;
|
||||
unsigned long client_flag,server_capabilities; /* changed from int to long in 4.1 protocol */
|
||||
unsigned int protocol_version;
|
||||
unsigned int field_count;
|
||||
unsigned int server_status;
|
||||
unsigned int server_language;
|
||||
unsigned int warning_count; /* warning count, added in 4.1 protocol */
|
||||
struct st_mysql_options options;
|
||||
enum mysql_status status;
|
||||
my_bool free_me; /* If free in mysql_close */
|
||||
my_bool reconnect; /* set to 1 if automatic reconnect */
|
||||
char scramble_buff[20+ 1];
|
||||
/* madded after 3.23.58 */
|
||||
my_bool unused_1;
|
||||
void *unused_2, *unused_3, *unused_4, *unused_5;
|
||||
LIST *stmts;
|
||||
const struct st_mysql_methods *methods;
|
||||
void *thd;
|
||||
my_bool *unbuffered_fetch_owner;
|
||||
char *info_buffer;
|
||||
void *extension;
|
||||
typedef struct st_mysql {
|
||||
NET net; /* Communication parameters */
|
||||
void *unused_0;
|
||||
char *host,*user,*passwd,*unix_socket,*server_version,*host_info;
|
||||
char *info,*db;
|
||||
const struct charset_info_st *charset; /* character set */
|
||||
MYSQL_FIELD *fields;
|
||||
MEM_ROOT field_alloc;
|
||||
my_ulonglong affected_rows;
|
||||
my_ulonglong insert_id; /* id if insert on table with NEXTNR */
|
||||
my_ulonglong extra_info; /* Used by mysqlshow */
|
||||
unsigned long thread_id; /* Id for connection in server */
|
||||
unsigned long packet_length;
|
||||
unsigned int port;
|
||||
unsigned long client_flag,server_capabilities; /* changed from int to long in 4.1 protocol */
|
||||
unsigned int protocol_version;
|
||||
unsigned int field_count;
|
||||
unsigned int server_status;
|
||||
unsigned int server_language;
|
||||
unsigned int warning_count; /* warning count, added in 4.1 protocol */
|
||||
struct st_mysql_options options;
|
||||
enum mysql_status status;
|
||||
my_bool free_me; /* If free in mysql_close */
|
||||
my_bool reconnect; /* set to 1 if automatic reconnect */
|
||||
char scramble_buff[20+ 1];
|
||||
/* madded after 3.23.58 */
|
||||
my_bool unused_1;
|
||||
void *unused_2, *unused_3, *unused_4, *unused_5;
|
||||
LIST *stmts;
|
||||
const struct st_mysql_methods *methods;
|
||||
void *thd;
|
||||
my_bool *unbuffered_fetch_owner;
|
||||
char *info_buffer;
|
||||
void *extension;
|
||||
} MYSQL;
|
||||
|
||||
struct st_mysql_options_extention {
|
||||
@@ -290,6 +296,8 @@ struct st_mysql_options_extention {
|
||||
char *ssl_crl;
|
||||
char *ssl_crlpath;
|
||||
char *server_public_key_path;
|
||||
HASH connect_attrs;
|
||||
size_t connect_attrs_len;
|
||||
void (*report_progress)(const MYSQL *mysql,
|
||||
unsigned int stage,
|
||||
unsigned int max_stage,
|
||||
@@ -468,6 +476,8 @@ CHARSET_INFO * STDCALL mysql_get_charset_by_name(const char *csname);
|
||||
CHARSET_INFO * STDCALL mysql_get_charset_by_nr(uint csnr);
|
||||
size_t STDCALL mariadb_convert_string(const char *from, size_t *from_len, CHARSET_INFO *from_cs,
|
||||
char *to, size_t *to_len, CHARSET_INFO *to_cs, int *errorcode);
|
||||
int STDCALL mysql_options4(MYSQL *mysql,enum mysql_option option,
|
||||
const void *arg1, const void *arg2);
|
||||
|
||||
#include <my_stmt.h>
|
||||
|
||||
|
@@ -149,6 +149,7 @@ enum enum_server_command
|
||||
#define CLIENT_MULTI_RESULTS (1UL << 17)
|
||||
#define CLIENT_PS_MULTI_RESULTS (1UL << 18)
|
||||
#define CLIENT_PLUGIN_AUTH (1UL << 19)
|
||||
#define CLIENT_CONNECT_ATTRS (1UL << 20)
|
||||
#define CLIENT_PROGRESS (1UL << 29) /* client supports progress indicator */
|
||||
#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30)
|
||||
#define CLIENT_REMEMBER_OPTIONS (1UL << 31)
|
||||
@@ -173,7 +174,8 @@ enum enum_server_command
|
||||
CLIENT_MULTI_RESULTS |\
|
||||
CLIENT_PROGRESS |\
|
||||
CLIENT_SSL_VERIFY_SERVER_CERT |\
|
||||
CLIENT_REMEMBER_OPTIONS)
|
||||
CLIENT_REMEMBER_OPTIONS |\
|
||||
CLIENT_CONNECT_ATTRS)
|
||||
|
||||
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD |\
|
||||
CLIENT_LONG_FLAG |\
|
||||
@@ -182,7 +184,8 @@ enum enum_server_command
|
||||
CLIENT_MULTI_RESULTS | \
|
||||
CLIENT_PS_MULTI_RESULTS |\
|
||||
CLIENT_PROTOCOL_41 |\
|
||||
CLIENT_PLUGIN_AUTH)
|
||||
CLIENT_PLUGIN_AUTH |\
|
||||
CLIENT_CONNECT_ATTRS)
|
||||
|
||||
#define CLIENT_DEFAULT_FLAGS ((CLIENT_SUPPORTED_FLAGS & ~CLIENT_COMPRESS)\
|
||||
& ~CLIENT_SSL)
|
||||
|
@@ -16,6 +16,10 @@
|
||||
#define MYSQL_UNIX_ADDR "@MYSQL_UNIX_ADDR@"
|
||||
#define MYSQL_CONFIG_NAME "my"
|
||||
|
||||
#define MARIADB_PACKAGE_VERSION "@CPACK_PACKAGE_VERSION@"
|
||||
#define MARIADB_SYSTEM_TYPE "@CMAKE_SYSTEM_NAME@"
|
||||
#define MARIADB_MACHINE_TYPE "@CMAKE_SYSTEM_PROCESSOR@"
|
||||
|
||||
/* mysqld compile time options */
|
||||
#ifndef MYSQL_CHARSET
|
||||
#define MYSQL_CHARSET "@default_charset@"
|
||||
|
@@ -22,7 +22,8 @@ ma_dyncol.c
|
||||
bchange.c
|
||||
bmove.c
|
||||
bmove_upp.c
|
||||
my_charset.c
|
||||
my_charset.c
|
||||
hash.c
|
||||
violite.c
|
||||
net.c
|
||||
charset.c
|
||||
|
644
libmariadb/hash.c
Normal file
644
libmariadb/hash.c
Normal file
@@ -0,0 +1,644 @@
|
||||
/************************************************************************************
|
||||
Copyright (C) 2000, 2012 MySQL AB & MySQL Finland AB & TCX DataKonsult AB,
|
||||
Monty Program AB
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not see <http://www.gnu.org/licenses>
|
||||
or write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
|
||||
|
||||
Part of this code includes code from the PHP project which
|
||||
is freely available from http://www.php.net
|
||||
*************************************************************************************/
|
||||
|
||||
/* The hash functions used for saveing keys */
|
||||
/* One of key_length or key_length_offset must be given */
|
||||
/* Key length of 0 isn't allowed */
|
||||
|
||||
#include "mysys_priv.h"
|
||||
#include <m_string.h>
|
||||
#include <m_ctype.h>
|
||||
#include "hash.h"
|
||||
|
||||
#define NO_RECORD ((uint) -1)
|
||||
#define LOWFIND 1
|
||||
#define LOWUSED 2
|
||||
#define HIGHFIND 4
|
||||
#define HIGHUSED 8
|
||||
|
||||
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength);
|
||||
static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
|
||||
static uint calc_hashnr(const uchar *key,uint length);
|
||||
static uint calc_hashnr_caseup(const uchar *key,uint length);
|
||||
static int hashcmp(HASH *hash,HASH_LINK *pos,const uchar *key,uint length);
|
||||
|
||||
|
||||
my_bool _hash_init(HASH *hash,uint size,uint key_offset,uint key_length,
|
||||
hash_get_key get_key,
|
||||
void (*free_element)(void*),uint flags CALLER_INFO_PROTO)
|
||||
{
|
||||
DBUG_ENTER("hash_init");
|
||||
DBUG_PRINT("enter",("hash: %lx size: %d",hash,size));
|
||||
|
||||
hash->records=0;
|
||||
if (my_init_dynamic_array_ci(&hash->array,sizeof(HASH_LINK),size,0))
|
||||
{
|
||||
hash->free=0; /* Allow call to hash_free */
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
hash->key_offset=key_offset;
|
||||
hash->key_length=key_length;
|
||||
hash->blength=1;
|
||||
hash->current_record= NO_RECORD; /* For the future */
|
||||
hash->get_key=get_key;
|
||||
hash->free=free_element;
|
||||
hash->flags=flags;
|
||||
if (flags & HASH_CASE_INSENSITIVE)
|
||||
hash->calc_hashnr=calc_hashnr_caseup;
|
||||
else
|
||||
hash->calc_hashnr=calc_hashnr;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
void hash_free(HASH *hash)
|
||||
{
|
||||
DBUG_ENTER("hash_free");
|
||||
if (hash->free)
|
||||
{
|
||||
uint i,records;
|
||||
HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
|
||||
for (i=0,records=hash->records ; i < records ; i++)
|
||||
(*hash->free)(data[i].data);
|
||||
hash->free=0;
|
||||
}
|
||||
delete_dynamic(&hash->array);
|
||||
hash->records=0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/* some helper functions */
|
||||
|
||||
/*
|
||||
This function is char* instead of uchar* as HPUX11 compiler can't
|
||||
handle inline functions that are not defined as native types
|
||||
*/
|
||||
|
||||
inline char*
|
||||
hash_key(HASH *hash,const uchar *record,uint *length,my_bool first)
|
||||
{
|
||||
if (hash->get_key)
|
||||
return (*hash->get_key)(record,length,first);
|
||||
*length=hash->key_length;
|
||||
return (uchar*) record+hash->key_offset;
|
||||
}
|
||||
|
||||
/* Calculate pos according to keys */
|
||||
|
||||
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength)
|
||||
{
|
||||
if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
|
||||
return (hashnr & ((buffmax >> 1) -1));
|
||||
}
|
||||
|
||||
static uint hash_rec_mask(HASH *hash,HASH_LINK *pos,uint buffmax,
|
||||
uint maxlength)
|
||||
{
|
||||
uint length;
|
||||
uchar *key= (uchar*) hash_key(hash,pos->data,&length,0);
|
||||
return hash_mask((*hash->calc_hashnr)(key,length),buffmax,maxlength);
|
||||
}
|
||||
|
||||
#ifndef NEW_HASH_FUNCTION
|
||||
|
||||
/* Calc hashvalue for a key */
|
||||
|
||||
static uint calc_hashnr(const uchar *key,uint length)
|
||||
{
|
||||
register uint nr=1, nr2=4;
|
||||
while (length--)
|
||||
{
|
||||
nr^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8);
|
||||
nr2+=3;
|
||||
}
|
||||
return((uint) nr);
|
||||
}
|
||||
|
||||
/* Calc hashvalue for a key, case indepenently */
|
||||
|
||||
static uint calc_hashnr_caseup(const uchar *key,uint length)
|
||||
{
|
||||
register uint nr=1, nr2=4;
|
||||
while (length--)
|
||||
{
|
||||
nr^= (((nr & 63)+nr2)*((uint) (uchar) toupper(*key++)))+ (nr << 8);
|
||||
nr2+=3;
|
||||
}
|
||||
return((uint) nr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Fowler/Noll/Vo hash
|
||||
*
|
||||
* The basis of the hash algorithm was taken from an idea sent by email to the
|
||||
* IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and
|
||||
* Glenn Fowler (gsf@research.att.com). Landon Curt Noll (chongo@toad.com)
|
||||
* later improved on their algorithm.
|
||||
*
|
||||
* The magic is in the interesting relationship between the special prime
|
||||
* 16777619 (2^24 + 403) and 2^32 and 2^8.
|
||||
*
|
||||
* This hash produces the fewest collisions of any function that we've seen so
|
||||
* far, and works well on both numbers and strings.
|
||||
*/
|
||||
|
||||
uint calc_hashnr(const uchar *key, uint len)
|
||||
{
|
||||
const uchar *end=key+len;
|
||||
uint hash;
|
||||
for (hash = 0; key < end; key++)
|
||||
{
|
||||
hash *= 16777619;
|
||||
hash ^= (uint) *(uchar*) key;
|
||||
}
|
||||
return (hash);
|
||||
}
|
||||
|
||||
uint calc_hashnr_caseup(const uchar *key, uint len)
|
||||
{
|
||||
const uchar *end=key+len;
|
||||
uint hash;
|
||||
for (hash = 0; key < end; key++)
|
||||
{
|
||||
hash *= 16777619;
|
||||
hash ^= (uint) (uchar) toupper(*key);
|
||||
}
|
||||
return (hash);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __SUNPRO_C /* SUNPRO can't handle this */
|
||||
inline
|
||||
#endif
|
||||
unsigned int rec_hashnr(HASH *hash,const uchar *record)
|
||||
{
|
||||
uint length;
|
||||
uchar *key= (uchar*) hash_key(hash,record,&length,0);
|
||||
return (*hash->calc_hashnr)(key,length);
|
||||
}
|
||||
|
||||
|
||||
/* Search after a record based on a key */
|
||||
/* Sets info->current_ptr to found record */
|
||||
|
||||
gptr hash_search(HASH *hash,const uchar *key,uint length)
|
||||
{
|
||||
HASH_LINK *pos;
|
||||
uint flag,idx;
|
||||
DBUG_ENTER("hash_search");
|
||||
|
||||
flag=1;
|
||||
if (hash->records)
|
||||
{
|
||||
idx=hash_mask((*hash->calc_hashnr)(key,length ? length :
|
||||
hash->key_length),
|
||||
hash->blength,hash->records);
|
||||
do
|
||||
{
|
||||
pos= dynamic_element(&hash->array,idx,HASH_LINK*);
|
||||
if (!hashcmp(hash,pos,key,length))
|
||||
{
|
||||
DBUG_PRINT("exit",("found key at %d",idx));
|
||||
hash->current_record= idx;
|
||||
DBUG_RETURN (pos->data);
|
||||
}
|
||||
if (flag)
|
||||
{
|
||||
flag=0; /* Reset flag */
|
||||
if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
|
||||
break; /* Wrong link */
|
||||
}
|
||||
}
|
||||
while ((idx=pos->next) != NO_RECORD);
|
||||
}
|
||||
hash->current_record= NO_RECORD;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/* Get next record with identical key */
|
||||
/* Can only be called if previous calls was hash_search */
|
||||
|
||||
gptr hash_next(HASH *hash,const uchar *key,uint length)
|
||||
{
|
||||
HASH_LINK *pos;
|
||||
uint idx;
|
||||
|
||||
if (hash->current_record != NO_RECORD)
|
||||
{
|
||||
HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
|
||||
for (idx=data[hash->current_record].next; idx != NO_RECORD ; idx=pos->next)
|
||||
{
|
||||
pos=data+idx;
|
||||
if (!hashcmp(hash,pos,key,length))
|
||||
{
|
||||
hash->current_record= idx;
|
||||
return pos->data;
|
||||
}
|
||||
}
|
||||
hash->current_record=NO_RECORD;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Change link from pos to new_link */
|
||||
|
||||
static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink)
|
||||
{
|
||||
HASH_LINK *old_link;
|
||||
do
|
||||
{
|
||||
old_link=array+next_link;
|
||||
}
|
||||
while ((next_link=old_link->next) != find);
|
||||
old_link->next= newlink;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Compare a key in a record to a whole key. Return 0 if identical */
|
||||
|
||||
static int hashcmp(HASH *hash,HASH_LINK *pos,const uchar *key,uint length)
|
||||
{
|
||||
uint rec_keylength;
|
||||
uchar *rec_key= (uchar*) hash_key(hash,pos->data,&rec_keylength,1);
|
||||
return (length && length != rec_keylength) ||
|
||||
memcmp(rec_key,key,rec_keylength);
|
||||
}
|
||||
|
||||
|
||||
/* Write a hash-key to the hash-index */
|
||||
|
||||
my_bool hash_insert(HASH *info,const uchar *record)
|
||||
{
|
||||
int flag;
|
||||
uint halfbuff,hash_nr,first_index,idx;
|
||||
uchar *ptr_to_rec,*ptr_to_rec2;
|
||||
HASH_LINK *data,*empty,*gpos,*gpos2,*pos;
|
||||
|
||||
LINT_INIT(gpos); LINT_INIT(gpos2);
|
||||
LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2);
|
||||
|
||||
flag=0;
|
||||
if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
|
||||
return(TRUE); /* No more memory */
|
||||
|
||||
info->current_record= NO_RECORD;
|
||||
data=dynamic_element(&info->array,0,HASH_LINK*);
|
||||
halfbuff= info->blength >> 1;
|
||||
|
||||
idx=first_index=info->records-halfbuff;
|
||||
if (idx != info->records) /* If some records */
|
||||
{
|
||||
do
|
||||
{
|
||||
pos=data+idx;
|
||||
hash_nr=rec_hashnr(info,pos->data);
|
||||
if (flag == 0) /* First loop; Check if ok */
|
||||
if (hash_mask(hash_nr,info->blength,info->records) != first_index)
|
||||
break;
|
||||
if (!(hash_nr & halfbuff))
|
||||
{ /* Key will not move */
|
||||
if (!(flag & LOWFIND))
|
||||
{
|
||||
if (flag & HIGHFIND)
|
||||
{
|
||||
flag=LOWFIND | HIGHFIND;
|
||||
/* key shall be moved to the current empty position */
|
||||
gpos=empty;
|
||||
ptr_to_rec=pos->data;
|
||||
empty=pos; /* This place is now free */
|
||||
}
|
||||
else
|
||||
{
|
||||
flag=LOWFIND | LOWUSED; /* key isn't changed */
|
||||
gpos=pos;
|
||||
ptr_to_rec=pos->data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(flag & LOWUSED))
|
||||
{
|
||||
/* Change link of previous LOW-key */
|
||||
gpos->data=ptr_to_rec;
|
||||
gpos->next=(uint) (pos-data);
|
||||
flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
|
||||
}
|
||||
gpos=pos;
|
||||
ptr_to_rec=pos->data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* key will be moved */
|
||||
if (!(flag & HIGHFIND))
|
||||
{
|
||||
flag= (flag & LOWFIND) | HIGHFIND;
|
||||
/* key shall be moved to the last (empty) position */
|
||||
gpos2 = empty; empty=pos;
|
||||
ptr_to_rec2=pos->data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(flag & HIGHUSED))
|
||||
{
|
||||
/* Change link of previous hash-key and save */
|
||||
gpos2->data=ptr_to_rec2;
|
||||
gpos2->next=(uint) (pos-data);
|
||||
flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
|
||||
}
|
||||
gpos2=pos;
|
||||
ptr_to_rec2=pos->data;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((idx=pos->next) != NO_RECORD);
|
||||
|
||||
if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
|
||||
{
|
||||
gpos->data=ptr_to_rec;
|
||||
gpos->next=NO_RECORD;
|
||||
}
|
||||
if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
|
||||
{
|
||||
gpos2->data=ptr_to_rec2;
|
||||
gpos2->next=NO_RECORD;
|
||||
}
|
||||
}
|
||||
/* Check if we are at the empty position */
|
||||
|
||||
idx=hash_mask(rec_hashnr(info,record),info->blength,info->records+1);
|
||||
pos=data+idx;
|
||||
if (pos == empty)
|
||||
{
|
||||
pos->data=(uchar*) record;
|
||||
pos->next=NO_RECORD;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if more records in same hash-nr family */
|
||||
empty[0]=pos[0];
|
||||
gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
|
||||
if (pos == gpos)
|
||||
{
|
||||
pos->data=(uchar*) record;
|
||||
pos->next=(uint) (empty - data);
|
||||
}
|
||||
else
|
||||
{
|
||||
pos->data=(uchar*) record;
|
||||
pos->next=NO_RECORD;
|
||||
movelink(data,(uint) (pos-data),(uint) (gpos-data),(uint) (empty-data));
|
||||
}
|
||||
}
|
||||
if (++info->records == info->blength)
|
||||
info->blength+= info->blength;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
** Remove one record from hash-table. The record with the same record
|
||||
** ptr is removed.
|
||||
** if there is a free-function it's called for record if found
|
||||
******************************************************************************/
|
||||
|
||||
my_bool hash_delete(HASH *hash,uchar *record)
|
||||
{
|
||||
uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
|
||||
HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
|
||||
DBUG_ENTER("hash_delete");
|
||||
if (!hash->records)
|
||||
DBUG_RETURN(1);
|
||||
|
||||
blength=hash->blength;
|
||||
data=dynamic_element(&hash->array,0,HASH_LINK*);
|
||||
/* Search after record with key */
|
||||
pos=data+ hash_mask(rec_hashnr(hash,record),blength,hash->records);
|
||||
gpos = 0;
|
||||
|
||||
while (pos->data != record)
|
||||
{
|
||||
gpos=pos;
|
||||
if (pos->next == NO_RECORD)
|
||||
DBUG_RETURN(1); /* Key not found */
|
||||
pos=data+pos->next;
|
||||
}
|
||||
|
||||
if ( --(hash->records) < hash->blength >> 1) hash->blength>>=1;
|
||||
hash->current_record= NO_RECORD;
|
||||
lastpos=data+hash->records;
|
||||
|
||||
/* Remove link to record */
|
||||
empty=pos; empty_index=(uint) (empty-data);
|
||||
if (gpos)
|
||||
gpos->next=pos->next; /* unlink current ptr */
|
||||
else if (pos->next != NO_RECORD)
|
||||
{
|
||||
empty=data+(empty_index=pos->next);
|
||||
pos->data=empty->data;
|
||||
pos->next=empty->next;
|
||||
}
|
||||
|
||||
if (empty == lastpos) /* last key at wrong pos or no next link */
|
||||
goto exit;
|
||||
|
||||
/* Move the last key (lastpos) */
|
||||
lastpos_hashnr=rec_hashnr(hash,lastpos->data);
|
||||
/* pos is where lastpos should be */
|
||||
pos=data+hash_mask(lastpos_hashnr,hash->blength,hash->records);
|
||||
if (pos == empty) /* Move to empty position. */
|
||||
{
|
||||
empty[0]=lastpos[0];
|
||||
goto exit;
|
||||
}
|
||||
pos_hashnr=rec_hashnr(hash,pos->data);
|
||||
/* pos3 is where the pos should be */
|
||||
pos3= data+hash_mask(pos_hashnr,hash->blength,hash->records);
|
||||
if (pos != pos3)
|
||||
{ /* pos is on wrong posit */
|
||||
empty[0]=pos[0]; /* Save it here */
|
||||
pos[0]=lastpos[0]; /* This should be here */
|
||||
movelink(data,(uint) (pos-data),(uint) (pos3-data),empty_index);
|
||||
goto exit;
|
||||
}
|
||||
pos2= hash_mask(lastpos_hashnr,blength,hash->records+1);
|
||||
if (pos2 == hash_mask(pos_hashnr,blength,hash->records+1))
|
||||
{ /* Identical key-positions */
|
||||
if (pos2 != hash->records)
|
||||
{
|
||||
empty[0]=lastpos[0];
|
||||
movelink(data,(uint) (lastpos-data),(uint) (pos-data),empty_index);
|
||||
goto exit;
|
||||
}
|
||||
idx= (uint) (pos-data); /* Link pos->next after lastpos */
|
||||
}
|
||||
else idx= NO_RECORD; /* Different positions merge */
|
||||
|
||||
empty[0]=lastpos[0];
|
||||
movelink(data,idx,empty_index,pos->next);
|
||||
pos->next=empty_index;
|
||||
|
||||
exit:
|
||||
VOID(pop_dynamic(&hash->array));
|
||||
if (hash->free)
|
||||
(*hash->free)((uchar*) record);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
Update keys when record has changed.
|
||||
This is much more efficent than using a delete & insert.
|
||||
*/
|
||||
|
||||
my_bool hash_update(HASH *hash,uchar *record,uchar *old_key,uint old_key_length)
|
||||
{
|
||||
uint idx,new_index,new_pos_index,blength,records,empty;
|
||||
HASH_LINK org_link,*data,*previous,*pos;
|
||||
DBUG_ENTER("hash_update");
|
||||
|
||||
data=dynamic_element(&hash->array,0,HASH_LINK*);
|
||||
blength=hash->blength; records=hash->records;
|
||||
|
||||
/* Search after record with key */
|
||||
|
||||
idx=hash_mask((*hash->calc_hashnr)(old_key,(old_key_length ?
|
||||
old_key_length :
|
||||
hash->key_length)),
|
||||
blength,records);
|
||||
new_index=hash_mask(rec_hashnr(hash,record),blength,records);
|
||||
if (idx == new_index)
|
||||
DBUG_RETURN(0); /* Nothing to do (No record check) */
|
||||
previous=0;
|
||||
for (;;)
|
||||
{
|
||||
|
||||
if ((pos= data+idx)->data == record)
|
||||
break;
|
||||
previous=pos;
|
||||
if ((idx=pos->next) == NO_RECORD)
|
||||
DBUG_RETURN(1); /* Not found in links */
|
||||
}
|
||||
hash->current_record= NO_RECORD;
|
||||
org_link= *pos;
|
||||
empty=idx;
|
||||
|
||||
/* Relink record from current chain */
|
||||
|
||||
if (!previous)
|
||||
{
|
||||
if (pos->next != NO_RECORD)
|
||||
{
|
||||
empty=pos->next;
|
||||
*pos= data[pos->next];
|
||||
}
|
||||
}
|
||||
else
|
||||
previous->next=pos->next; /* unlink pos */
|
||||
|
||||
/* Move data to correct position */
|
||||
pos=data+new_index;
|
||||
new_pos_index=hash_rec_mask(hash,pos,blength,records);
|
||||
if (new_index != new_pos_index)
|
||||
{ /* Other record in wrong position */
|
||||
data[empty] = *pos;
|
||||
movelink(data,new_index,new_pos_index,empty);
|
||||
org_link.next=NO_RECORD;
|
||||
data[new_index]= org_link;
|
||||
}
|
||||
else
|
||||
{ /* Link in chain at right position */
|
||||
org_link.next=data[new_index].next;
|
||||
data[empty]=org_link;
|
||||
data[new_index].next=empty;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
uchar *hash_element(HASH *hash,uint idx)
|
||||
{
|
||||
if (idx < hash->records)
|
||||
return dynamic_element(&hash->array,idx,HASH_LINK*)->data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
|
||||
my_bool hash_check(HASH *hash)
|
||||
{
|
||||
int error;
|
||||
uint i,rec_link,found,max_links,seek,links,idx;
|
||||
uint records,blength;
|
||||
HASH_LINK *data,*hash_info;
|
||||
|
||||
records=hash->records; blength=hash->blength;
|
||||
data=dynamic_element(&hash->array,0,HASH_LINK*);
|
||||
error=0;
|
||||
|
||||
for (i=found=max_links=seek=0 ; i < records ; i++)
|
||||
{
|
||||
if (hash_rec_mask(hash,data+i,blength,records) == i)
|
||||
{
|
||||
found++; seek++; links=1;
|
||||
for (idx=data[i].next ;
|
||||
idx != NO_RECORD && found < records + 1;
|
||||
idx=hash_info->next)
|
||||
{
|
||||
if (idx >= records)
|
||||
{
|
||||
DBUG_PRINT("error",
|
||||
("Found pointer outside array to %d from link starting at %d",
|
||||
idx,i));
|
||||
error=1;
|
||||
}
|
||||
hash_info=data+idx;
|
||||
seek+= ++links;
|
||||
if ((rec_link=hash_rec_mask(hash,hash_info,blength,records)) != i)
|
||||
{
|
||||
DBUG_PRINT("error",
|
||||
("Record in wrong link at %d: Start %d Record: %lx Record-link %d", idx,i,hash_info->data,rec_link));
|
||||
error=1;
|
||||
}
|
||||
else
|
||||
found++;
|
||||
}
|
||||
if (links > max_links) max_links=links;
|
||||
}
|
||||
}
|
||||
if (found != records)
|
||||
{
|
||||
DBUG_PRINT("error",("Found %ld of %ld records"));
|
||||
error=1;
|
||||
}
|
||||
if (records)
|
||||
DBUG_PRINT("info",
|
||||
("records: %ld seeks: %d max links: %d hitrate: %.2f",
|
||||
records,seek,max_links,(float) seek / (float) records));
|
||||
return error;
|
||||
}
|
||||
#endif
|
@@ -66,6 +66,7 @@
|
||||
#ifndef _WIN32
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#include <ma_dyncol.h>
|
||||
|
||||
static my_bool mysql_client_init=0;
|
||||
static void mysql_close_options(MYSQL *mysql);
|
||||
@@ -86,6 +87,7 @@ extern int mthd_stmt_fetch_row(MYSQL_STMT *stmt, unsigned char **row);
|
||||
extern int mthd_stmt_fetch_to_bind(MYSQL_STMT *stmt, unsigned char *row);
|
||||
extern int mthd_stmt_read_all_rows(MYSQL_STMT *stmt);
|
||||
extern void mthd_stmt_flush_unbuffered(MYSQL_STMT *stmt);
|
||||
extern unsigned char *mysql_net_store_length(unsigned char *packet, size_t length);
|
||||
|
||||
uint mysql_port=0;
|
||||
my_string mysql_unix_port=0;
|
||||
@@ -829,11 +831,14 @@ enum option_val
|
||||
OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth, OPT_db_type
|
||||
};
|
||||
|
||||
#define OPT_SET_EXTENDED_VALUE(OPTS, KEY, VAL, IS_STRING) \
|
||||
#define CHECK_OPT_EXTENSION_SET(OPTS)\
|
||||
if (!(OPTS)->extension) \
|
||||
(OPTS)->extension= (struct st_mysql_options_extention *) \
|
||||
my_malloc(sizeof(struct st_mysql_options_extention), \
|
||||
MYF(MY_WME | MY_ZEROFILL)); \
|
||||
|
||||
#define OPT_SET_EXTENDED_VALUE(OPTS, KEY, VAL, IS_STRING) \
|
||||
CHECK_OPT_EXTENSION_SET(OPTS) \
|
||||
if (IS_STRING) { \
|
||||
my_free((char *)(OPTS)->extension->KEY, MYF(MY_ALLOW_ZERO_PTR)); \
|
||||
(OPTS)->extension->KEY= my_strdup((char *)(VAL), MYF(MY_WME)); \
|
||||
@@ -1382,6 +1387,70 @@ mysql_connect(MYSQL *mysql,const char *host,
|
||||
}
|
||||
}
|
||||
|
||||
uchar *ma_send_connect_attr(MYSQL *mysql, uchar *buffer)
|
||||
{
|
||||
if (mysql->server_capabilities & CLIENT_CONNECT_ATTRS)
|
||||
{
|
||||
buffer= mysql_net_store_length((unsigned char *)buffer, (mysql->options.extension) ?
|
||||
mysql->options.extension->connect_attrs_len : 0);
|
||||
if (mysql->options.extension &&
|
||||
hash_inited(&mysql->options.extension->connect_attrs))
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < mysql->options.extension->connect_attrs.records; i++)
|
||||
{
|
||||
size_t len;
|
||||
uchar *p= hash_element(&mysql->options.extension->connect_attrs, i);
|
||||
|
||||
len= *(size_t *)p;
|
||||
buffer= mysql_net_store_length(buffer, len);
|
||||
p+= sizeof(size_t);
|
||||
memcpy(buffer, p, len);
|
||||
buffer+= len;
|
||||
p+= len;
|
||||
len= *(size_t *)p;
|
||||
buffer= mysql_net_store_length(buffer, len);
|
||||
p+= sizeof(size_t);
|
||||
memcpy(buffer, p, len);
|
||||
buffer+= len;
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/** set some default attributes */
|
||||
static my_bool
|
||||
ma_set_connect_attrs(MYSQL *mysql)
|
||||
{
|
||||
char buffer[255];
|
||||
int rc= 0;
|
||||
|
||||
rc= mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_name") +
|
||||
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_client_version") +
|
||||
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_os") +
|
||||
#ifdef _WIN32
|
||||
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_thread") +
|
||||
#endif
|
||||
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_pid") +
|
||||
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "_platform");
|
||||
|
||||
rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_name", "libmariadb");
|
||||
+ mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_version", MARIADB_PACKAGE_VERSION);
|
||||
+ mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_os", MARIADB_SYSTEM_TYPE);
|
||||
|
||||
#ifdef _WIN32
|
||||
snprintf(buffer, 255, "%lu", (ulong) GetCurrentThreadId());
|
||||
rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_thread", buffer);
|
||||
snprintf(buffer, 255, "%lu", (ulong) GetCurrentProcessId());
|
||||
#else
|
||||
snprintf(buffer, 255, "%lu", (ulong) getpid());
|
||||
#endif
|
||||
rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_pid", buffer);
|
||||
|
||||
rc+= mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "_platform", MARIADB_MACHINE_TYPE);
|
||||
return(test(rc>0));
|
||||
}
|
||||
|
||||
/*
|
||||
** Note that the mysql argument must be initialized with mysql_init()
|
||||
@@ -1426,6 +1495,8 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
|
||||
db ? db : "(Null)",
|
||||
user ? user : "(Null)"));
|
||||
|
||||
ma_set_connect_attrs(mysql);
|
||||
|
||||
if (net->vio) /* check if we are already connected */
|
||||
{
|
||||
SET_CLIENT_ERROR(mysql, CR_ALREADY_CONNECTED, SQLSTATE_UNKNOWN, 0);
|
||||
@@ -2047,6 +2118,8 @@ static void mysql_close_options(MYSQL *mysql)
|
||||
my_free((gptr)mysql->options.extension->db_driver, MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(mysql->options.extension->ssl_crl, MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(mysql->options.extension->ssl_crlpath, MYF(MY_ALLOW_ZERO_PTR));
|
||||
if(hash_inited(&mysql->options.extension->connect_attrs))
|
||||
hash_free(&mysql->options.extension->connect_attrs);
|
||||
}
|
||||
my_free((gptr)mysql->options.extension, MYF(MY_ALLOW_ZERO_PTR));
|
||||
/* clear all pointer */
|
||||
@@ -2664,6 +2737,16 @@ mysql_get_client_info(void)
|
||||
return (char*) MYSQL_CLIENT_VERSION;
|
||||
}
|
||||
|
||||
static size_t get_store_length(size_t length)
|
||||
{
|
||||
if (length < (size_t) L64(251))
|
||||
return 1;
|
||||
if (length < (size_t) L64(65536))
|
||||
return 2;
|
||||
if (length < (size_t) L64(16777216))
|
||||
return 3;
|
||||
return 9;
|
||||
}
|
||||
|
||||
int STDCALL
|
||||
mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
|
||||
@@ -2796,13 +2879,128 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const void *arg)
|
||||
break;
|
||||
case MYSQL_OPT_SSL_CRLPATH:
|
||||
OPT_SET_EXTENDED_VALUE(&mysql->options, ssl_crlpath, (char *)arg, 1);
|
||||
break;
|
||||
break;
|
||||
case MYSQL_OPT_CONNECT_ATTR_DELETE:
|
||||
{
|
||||
uchar *p;
|
||||
CHECK_OPT_EXTENSION_SET(&mysql->options);
|
||||
if (hash_inited(&mysql->options.extension->connect_attrs) &&
|
||||
(p= hash_search(&mysql->options.extension->connect_attrs, arg,
|
||||
arg ? strlen(arg) : 0)))
|
||||
{
|
||||
size_t key_len= *(size_t *)p;
|
||||
mysql->options.extension->connect_attrs_len-= key_len;
|
||||
mysql->options.extension->connect_attrs_len-= get_store_length(key_len);
|
||||
key_len= *(size_t *)(p + sizeof(size_t) + key_len);
|
||||
mysql->options.extension->connect_attrs_len-= key_len;
|
||||
mysql->options.extension->connect_attrs_len-= get_store_length(key_len);
|
||||
hash_delete(&mysql->options.extension->connect_attrs, p);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case MYSQL_OPT_CONNECT_ATTR_RESET:
|
||||
CHECK_OPT_EXTENSION_SET(&mysql->options);
|
||||
if (hash_inited(&mysql->options.extension->connect_attrs))
|
||||
{
|
||||
hash_free(&mysql->options.extension->connect_attrs);
|
||||
mysql->options.extension->connect_attrs_len= 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
uchar *ma_get_hash_key(const uchar *hash_entry,
|
||||
size_t *length,
|
||||
my_bool not_used __attribute__((unused)))
|
||||
{
|
||||
/* Hash entry has the following format:
|
||||
Offset: 0 key length
|
||||
sizeof(size_t) key
|
||||
key_length +
|
||||
sizeof(size_t) value length
|
||||
value
|
||||
*/
|
||||
uchar *p= (uchar *)hash_entry;
|
||||
*length=*((size_t*)p);
|
||||
p+= sizeof(size_t);
|
||||
return p;
|
||||
}
|
||||
|
||||
void ma_hash_free(void *p)
|
||||
{
|
||||
my_free(p, MYF(MYF_ALLOW_ZERO_PTR));
|
||||
}
|
||||
|
||||
int STDCALL mysql_options4(MYSQL *mysql,enum mysql_option option,
|
||||
const void *arg1, const void *arg2)
|
||||
{
|
||||
DBUG_ENTER("mysql_option4");
|
||||
DBUG_PRINT("enter",("option: %d",(int) option));
|
||||
|
||||
switch (option) {
|
||||
case MYSQL_OPT_CONNECT_ATTR_ADD:
|
||||
{
|
||||
uchar *buffer;
|
||||
size_t key_len= arg1 ? strlen(arg1) : 0,
|
||||
value_len= arg2 ? strlen(arg2) : 0;
|
||||
size_t storage_len= key_len + value_len +
|
||||
get_store_length(key_len) +
|
||||
get_store_length(value_len);
|
||||
|
||||
CHECK_OPT_EXTENSION_SET(&mysql->options);
|
||||
if (!key_len ||
|
||||
storage_len + mysql->options.extension->connect_attrs_len > 0xFFFF)
|
||||
{
|
||||
SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate, 0);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
if (!hash_inited(&mysql->options.extension->connect_attrs))
|
||||
{
|
||||
if (_hash_init(&mysql->options.extension->connect_attrs,
|
||||
0, 0, 0, ma_get_hash_key, ma_hash_free, 0))
|
||||
{
|
||||
SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
if ((buffer= (uchar *)my_malloc(2 * sizeof(size_t) + key_len + value_len,
|
||||
MYF(MY_WME | MY_ZEROFILL))))
|
||||
{
|
||||
uchar *p= buffer;
|
||||
*((size_t *)p)= key_len;
|
||||
p+= sizeof(size_t);
|
||||
memcpy(p, arg1, key_len);
|
||||
p+= key_len;
|
||||
*((size_t *)p)= value_len;
|
||||
p+= sizeof(size_t);
|
||||
if (arg2)
|
||||
memcpy(p, arg2, value_len);
|
||||
|
||||
if (hash_insert(&mysql->options.extension->connect_attrs, buffer))
|
||||
{
|
||||
my_free(buffer, MYF(0));
|
||||
SET_CLIENT_ERROR(mysql, CR_INVALID_PARAMETER_NO, unknown_sqlstate, 0);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
mysql->options.extension->connect_attrs_len+= storage_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate, 0);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
/****************************************************************************
|
||||
** Functions to get information from the MySQL structure
|
||||
** These are functions to make shared libraries more usable.
|
||||
|
@@ -53,6 +53,7 @@ EXPORTS
|
||||
mysql_num_fields
|
||||
mysql_num_rows
|
||||
mysql_options
|
||||
mysql_options4
|
||||
mysql_stmt_param_count
|
||||
mysql_stmt_param_metadata
|
||||
mysql_ping
|
||||
|
@@ -14,6 +14,7 @@ static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, size_t
|
||||
static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
|
||||
static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
|
||||
extern void read_user_name(char *name);
|
||||
extern uchar *ma_send_connect_attr(MYSQL *mysql, uchar *buffer);
|
||||
|
||||
#define compile_time_assert(A) \
|
||||
do {\
|
||||
@@ -61,7 +62,6 @@ struct st_mysql_client_plugin *mysql_client_builtins[]=
|
||||
0
|
||||
};
|
||||
|
||||
/* this is a "superset" of MYSQL_PLUGIN_VIO, in C++ I use inheritance */
|
||||
typedef struct {
|
||||
int (*read_packet)(struct st_plugin_vio *vio, uchar **buf);
|
||||
int (*write_packet)(struct st_plugin_vio *vio, const uchar *pkt, size_t pkt_len);
|
||||
@@ -170,34 +170,16 @@ static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
sends a COM_CHANGE_USER command with a caller provided payload
|
||||
|
||||
Packet format:
|
||||
|
||||
Bytes Content
|
||||
----- ----
|
||||
n user name - \0-terminated string
|
||||
n password
|
||||
3.23 scramble - \0-terminated string (9 bytes)
|
||||
otherwise - length (1 byte) coded
|
||||
n database name - \0-terminated string
|
||||
2 character set number (if the server >= 4.1.x)
|
||||
n client auth plugin name - \0-terminated string,
|
||||
(if the server supports plugin auth)
|
||||
|
||||
@retval 0 ok
|
||||
@retval 1 error
|
||||
*/
|
||||
|
||||
static int send_change_user_packet(MCPVIO_EXT *mpvio,
|
||||
const uchar *data, int data_len)
|
||||
{
|
||||
MYSQL *mysql= mpvio->mysql;
|
||||
char *buff, *end;
|
||||
int res= 1;
|
||||
size_t conn_attr_len= (mysql->options.extension) ?
|
||||
mysql->options.extension->connect_attrs_len : 0;
|
||||
|
||||
buff= my_alloca(USERNAME_LENGTH+1 + data_len+1 + NAME_LEN+1 + 2 + NAME_LEN+1);
|
||||
buff= my_alloca(USERNAME_LENGTH+1 + data_len+1 + NAME_LEN+1 + 2 + NAME_LEN+1 + 9 + conn_attr_len);
|
||||
|
||||
end= strmake(buff, mysql->user, USERNAME_LENGTH) + 1;
|
||||
|
||||
@@ -234,6 +216,8 @@ static int send_change_user_packet(MCPVIO_EXT *mpvio,
|
||||
if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
|
||||
end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
|
||||
|
||||
end= ma_send_connect_attr(mysql, end);
|
||||
|
||||
res= simple_command(mysql, MYSQL_COM_CHANGE_USER,
|
||||
buff, (ulong)(end-buff), 1);
|
||||
|
||||
@@ -243,36 +227,6 @@ error:
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
sends a client authentication packet (second packet in the 3-way handshake)
|
||||
|
||||
Packet format (when the server is 4.0 or earlier):
|
||||
|
||||
Bytes Content
|
||||
----- ----
|
||||
2 client capabilities
|
||||
3 max packet size
|
||||
n user name, \0-terminated
|
||||
9 scramble_323, \0-terminated
|
||||
|
||||
Packet format (when the server is 4.1 or newer):
|
||||
|
||||
Bytes Content
|
||||
----- ----
|
||||
4 client capabilities
|
||||
4 max packet size
|
||||
1 charset number
|
||||
23 reserved (always 0)
|
||||
n user name, \0-terminated
|
||||
n plugin auth data (e.g. scramble), length (1 byte) coded
|
||||
n database name, \0-terminated
|
||||
(if CLIENT_CONNECT_WITH_DB is set in the capabilities)
|
||||
n client auth plugin name - \0-terminated string,
|
||||
(if CLIENT_PLUGIN_AUTH is set in the capabilities)
|
||||
|
||||
@retval 0 ok
|
||||
@retval 1 error
|
||||
*/
|
||||
|
||||
static int send_client_reply_packet(MCPVIO_EXT *mpvio,
|
||||
const uchar *data, int data_len)
|
||||
@@ -280,9 +234,11 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
|
||||
MYSQL *mysql= mpvio->mysql;
|
||||
NET *net= &mysql->net;
|
||||
char *buff, *end;
|
||||
size_t conn_attr_len= (mysql->options.extension) ?
|
||||
mysql->options.extension->connect_attrs_len : 0;
|
||||
|
||||
/* see end= buff+32 below, fixed size of the packet is 32 bytes */
|
||||
buff= my_alloca(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN);
|
||||
buff= my_alloca(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN + conn_attr_len + 9);
|
||||
|
||||
mysql->client_flag|= mysql->options.client_flag;
|
||||
mysql->client_flag|= CLIENT_CAPABILITIES;
|
||||
@@ -416,6 +372,8 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
|
||||
if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
|
||||
end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;
|
||||
|
||||
end= ma_send_connect_attr(mysql, end);
|
||||
|
||||
/* Write authentication package */
|
||||
if (my_net_write(net, buff, (size_t) (end-buff)) || net_flush(net))
|
||||
{
|
||||
|
@@ -356,7 +356,7 @@ MYSQL_RES *_mysql_stmt_use_result(MYSQL_STMT *stmt)
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
unsigned char *mysql_net_store_length(unsigned char *packet, my_ulonglong length)
|
||||
unsigned char *mysql_net_store_length(unsigned char *packet, size_t length)
|
||||
{
|
||||
if (length < (my_ulonglong) L64(251)) {
|
||||
*packet = (unsigned char) length;
|
||||
|
@@ -582,7 +582,7 @@ static int test_wl4166_3(MYSQL *mysql)
|
||||
rc= mysql_stmt_bind_param(stmt, my_bind);
|
||||
check_stmt_rc(rc, stmt);
|
||||
|
||||
tm[0].year= 10000;
|
||||
tm[0].year= 2014;
|
||||
tm[0].month= 1; tm[0].day= 1;
|
||||
tm[0].hour= 1; tm[0].minute= 1; tm[0].second= 1;
|
||||
tm[0].second_part= 0; tm[0].neg= 0;
|
||||
@@ -592,15 +592,10 @@ static int test_wl4166_3(MYSQL *mysql)
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
diag("rc=%d %s", rc, mysql_stmt_error(stmt));
|
||||
check_stmt_rc(rc, stmt);
|
||||
/*
|
||||
Sic: only one warning, instead of two. The warning
|
||||
about data truncation when assigning a parameter is lost.
|
||||
This is a bug.
|
||||
*/
|
||||
FAIL_IF(mysql_warning_count(mysql) != 1, "warning count != 1");
|
||||
|
||||
if (verify_col_data(mysql, "t1", "year", "0000-00-00 00:00:00")) {
|
||||
if (verify_col_data(mysql, "t1", "year", "2014-01-01 01:01:01")) {
|
||||
mysql_stmt_close(stmt);
|
||||
rc= mysql_query(mysql, "drop table t1");
|
||||
return FAIL;
|
||||
@@ -904,7 +899,55 @@ static int test_conc44(MYSQL *mysql)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int test_connect_attrs(MYSQL *my)
|
||||
{
|
||||
MYSQL *mysql;
|
||||
MYSQL_RES *result;
|
||||
int rc, len;
|
||||
|
||||
mysql= mysql_init(NULL);
|
||||
|
||||
mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "foo0", "bar0");
|
||||
mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "foo1", "bar1");
|
||||
mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "foo2", "bar2");
|
||||
|
||||
FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema,
|
||||
port, socketname, 0), mysql_error(my));
|
||||
|
||||
if (!(mysql->server_capabilities & CLIENT_CONNECT_ATTRS))
|
||||
{
|
||||
mysql_close(mysql);
|
||||
diag("Server doesn't support connection attributes");
|
||||
return SKIP;
|
||||
}
|
||||
|
||||
rc= mysql_query(mysql, "SELECT * FROM performance_schema.session_connect_attrs where attr_name like 'foo%'");
|
||||
check_mysql_rc(rc, mysql);
|
||||
result= mysql_store_result(mysql);
|
||||
rc= mysql_num_rows(result);
|
||||
mysql_free_result(result);
|
||||
|
||||
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, NULL);
|
||||
mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "foo0", "bar0");
|
||||
mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "foo1", "bar1");
|
||||
mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "foo2", "bar2");
|
||||
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "foo0");
|
||||
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "foo1");
|
||||
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_DELETE, "foo2");
|
||||
|
||||
len= mysql->options.extension->connect_attrs_len;
|
||||
|
||||
|
||||
mysql_close(mysql);
|
||||
|
||||
FAIL_IF(rc < 3, "Expected 3 or more rows");
|
||||
FAIL_IF(len != 0, "Expected connection_attr_len=0");
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
struct my_tests_st my_tests[] = {
|
||||
{"test_connect_attrs", test_connect_attrs, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"test_conc49", test_conc49, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"test_bug28075", test_bug28075, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"test_bug28505", test_bug28505, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
|
Reference in New Issue
Block a user