3863 Christopher Powers 2012-03-28
Bug#13809293 - PERFSCHEMA.DML_ESMS_BY_DIGEST FAILS ON DAILY-TRUNK SPORADICALLY
The error was triggered by mb character strings being stored as UTF8 without
conversion. PFS now converts digest identifier to UTF8 before storing in table.
modified:
include/mysql/psi/mysql_statement.h
include/mysql/psi/psi.h
sql/mysqld.cc
sql/sql_parse.cc
storage/perfschema/pfs.cc
storage/perfschema/pfs_digest.cc
storage/perfschema/pfs_digest.h
storage/perfschema/table_helper.cc
3862 Christopher Powers 2012-03-27 [merge]
local merge
added:
mysql-test/suite/rpl/r/rpl_gtid_sql_until_before_after.result
mysql-test/suite/rpl/t/rpl_gtid_sql_until_before_after.test
modified:
include/my_md5.h
mysql-test/collections/default.experimental
mysql-test/r/sp-bugs.result
mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result
mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test
mysql-test/suite/innodb/r/innodb-index-online.result
mysql-test/suite/innodb/t/innodb-index-online.test
mysql-test/t/sp-bugs.test
sql/log_event.cc
sql/rpl_gtid.h
sql/rpl_gtid_set.cc
sql/rpl_rli.cc
sql/rpl_rli.h
sql/rpl_slave.cc
sql/sql_lex.h
sql/sql_show.cc
sql/sql_yacc.yy
storage/innobase/api/api0api.cc
storage/innobase/api/api0misc.cc
storage/innobase/include/api0api.h
=== modified file 'include/mysql/psi/mysql_statement.h'
--- a/include/mysql/psi/mysql_statement.h 2012-02-10 23:14:57 +0000
+++ b/include/mysql/psi/mysql_statement.h 2012-03-29 03:22:29 +0000
@@ -63,10 +63,10 @@
#endif
#ifdef HAVE_PSI_STATEMENT_INTERFACE
- #define MYSQL_START_STATEMENT(STATE, K, DB, DB_LEN) \
- inline_mysql_start_statement(STATE, K, DB, DB_LEN, __FILE__, __LINE__)
+ #define MYSQL_START_STATEMENT(STATE, K, DB, DB_LEN, CS) \
+ inline_mysql_start_statement(STATE, K, DB, DB_LEN, CS, __FILE__, __LINE__)
#else
- #define MYSQL_START_STATEMENT(STATE, K, DB, DB_LEN) \
+ #define MYSQL_START_STATEMENT(STATE, K, DB, DB_LEN, CS) \
NULL
#endif
@@ -152,11 +152,11 @@ inline_mysql_add_token(PSI_digest_locker
static inline struct PSI_statement_locker *
inline_mysql_start_statement(PSI_statement_locker_state *state,
PSI_statement_key key,
- const char *db, uint db_len,
+ const char *db, uint db_len, uint csid,
const char *src_file, int src_line)
{
PSI_statement_locker *locker;
- locker= PSI_CALL(get_thread_statement_locker)(state, key);
+ locker= PSI_CALL(get_thread_statement_locker)(state, key, csid);
if (likely(locker != NULL))
PSI_CALL(start_statement)(locker, db, db_len, src_file, src_line);
return locker;
=== modified file 'include/mysql/psi/psi.h'
--- a/include/mysql/psi/psi.h 2012-03-05 10:57:53 +0000
+++ b/include/mysql/psi/psi.h 2012-03-29 03:22:29 +0000
@@ -958,6 +958,8 @@ struct PSI_digest_storage
{
my_bool m_full;
int m_byte_count;
+ /** Character set identifier. */
+ uint m_csid;
unsigned char m_token_array[PSI_MAX_DIGEST_STORAGE_SIZE];
};
typedef struct PSI_digest_storage PSI_digest_storage;
@@ -1632,11 +1634,12 @@ typedef void (*end_stage_v1_t) (void);
Get a statement instrumentation locker.
@param state data storage for the locker
@param key the statement instrumentation key
+ @param csid client character set id
@return a statement locker, or NULL
*/
typedef struct PSI_statement_locker* (*get_thread_statement_locker_v1_t)
(struct PSI_statement_locker_state_v1 *state,
- PSI_statement_key key);
+ PSI_statement_key key, uint csid);
/**
Refine a statement locker to a more specific key.
=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc 2012-03-22 06:25:38 +0000
+++ b/sql/mysqld.cc 2012-03-29 03:22:29 +0000
@@ -797,7 +797,8 @@ void net_after_header_psi(struct st_net
{
thd->m_statement_psi= MYSQL_START_STATEMENT(& thd->m_statement_state,
stmt_info_new_packet.m_key,
- thd->db, thd->db_length);
+ thd->db, thd->db_length,
+ thd->charset()->number);
THD_STAGE_INFO(thd, stage_init);
}
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2012-03-14 09:52:49 +0000
+++ b/sql/sql_parse.cc 2012-03-29 03:22:29 +0000
@@ -1316,9 +1316,10 @@ bool dispatch_command(enum enum_server_c
(char *) thd->security_ctx->host_or_ip);
/* PSI begin */
- thd->m_statement_psi= MYSQL_START_STATEMENT(& thd->m_statement_state,
+ thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state,
com_statement_info[command].m_key,
- thd->db, thd->db_length);
+ thd->db, thd->db_length,
+ thd->charset()->number);
THD_STAGE_INFO(thd, stage_init);
MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, beginning_of_next_stmt, length);
=== modified file 'storage/perfschema/pfs.cc'
--- a/storage/perfschema/pfs.cc 2012-03-19 19:29:28 +0000
+++ b/storage/perfschema/pfs.cc 2012-03-29 03:22:29 +0000
@@ -4169,7 +4169,8 @@ static void end_stage_v1()
static PSI_statement_locker*
get_thread_statement_locker_v1(PSI_statement_locker_state *state,
- PSI_statement_key key)
+ PSI_statement_key key,
+ uint csid)
{
DBUG_ASSERT(state != NULL);
if (! flag_global_instrumentation)
@@ -4269,6 +4270,7 @@ get_thread_statement_locker_v1(PSI_state
flags|= STATE_FLAG_DIGEST;
state->m_digest_state.m_last_id_index= 0;
digest_reset(& state->m_digest_state.m_digest_storage);
+ state->m_digest_state.m_digest_storage.m_csid= csid;
}
state->m_discarded= false;
@@ -4567,10 +4569,7 @@ static void end_statement_v1(PSI_stateme
if (flags & STATE_FLAG_DIGEST)
{
digest_storage= &state->m_digest_state.m_digest_storage;
-
- /*
- Populate PFS_statements_digest_stat with computed digest information.
- */
+ /* Populate PFS_statements_digest_stat with computed digest information.*/
digest_stat= find_or_create_digest(thread, digest_storage);
}
@@ -4637,10 +4636,7 @@ static void end_statement_v1(PSI_stateme
{
/* Set digest stat. */
digest_storage= &state->m_digest_state.m_digest_storage;
-
- /*
- Populate PFS_statements_digest_stat with computed digest information.
- */
+ /* Populate statements_digest_stat with computed digest information. */
digest_stat= find_or_create_digest(thread, digest_storage);
}
}
=== modified file 'storage/perfschema/pfs_digest.cc'
--- a/storage/perfschema/pfs_digest.cc 2012-02-28 15:57:52 +0000
+++ b/storage/perfschema/pfs_digest.cc 2012-03-29 03:22:29 +0000
@@ -31,6 +31,7 @@
#include "my_md5.h"
#include "sql_lex.h"
#include "sql_get_diagnostics.h"
+#include "sql_string.h"
#include <string.h>
/* Generated code */
@@ -168,8 +169,8 @@ static LF_PINS* get_digest_hash_pins(PFS
}
PFS_statement_stat*
-find_or_create_digest(PFS_thread* thread,
- PSI_digest_storage* digest_storage)
+find_or_create_digest(PFS_thread *thread,
+ PSI_digest_storage *digest_storage)
{
if (statements_digest_stat_array == NULL)
return NULL;
@@ -348,98 +349,145 @@ void reset_esms_by_digest()
*/
void get_digest_text(char* digest_text, PSI_digest_storage* digest_storage)
{
+ DBUG_ASSERT(digest_storage != NULL);
bool truncated= false;
int byte_count= digest_storage->m_byte_count;
- int need_bytes;
+ int bytes_needed= 0;
uint tok= 0;
- char *id_string;
- int id_length;
int current_byte= 0;
lex_token_string *tok_data;
/* -4 is to make sure extra space for '...' and a '\0' at the end. */
- int available_bytes_to_write= COL_DIGEST_TEXT_SIZE - 4;
+ int bytes_available= COL_DIGEST_TEXT_SIZE - 4;
+
+ /* Convert text to utf8 if necessary */
+ uint csid= digest_storage->m_csid;
+ const CHARSET_INFO *from_cs=get_charset(csid, 0);
+ const CHARSET_INFO *to_cs=get_charset_by_name("utf8_bin", 0);
+ /* Max number of characters * max mb len of target character set */
+ const uint max_converted_size= PSI_MAX_DIGEST_STORAGE_SIZE * 3;
+ char id_string[max_converted_size];
DBUG_ASSERT(byte_count <= PSI_MAX_DIGEST_STORAGE_SIZE);
- while ((current_byte < byte_count) &&
- (available_bytes_to_write > 0) &&
- (! truncated))
+ while (current_byte < byte_count &&
+ bytes_available > 0 &&
+ !truncated)
{
current_byte= read_token(digest_storage, current_byte, &tok);
- tok_data= & lex_token_array[tok];
+ tok_data= &lex_token_array[tok];
switch (tok)
{
/* All identifiers are printed with their name. */
case IDENT:
- current_byte= read_identifier(digest_storage, current_byte,
- & id_string, & id_length);
- need_bytes= id_length + 1; /* <id> space */
- if (need_bytes <= available_bytes_to_write)
{
- if (id_length > 0)
+ char *id_ptr;
+ int id_len;
+ uint err_cs;
+
+ /* Get the next identifier in the storage buffer. */
+ current_byte= read_identifier(digest_storage, current_byte,
+ &id_ptr, &id_len);
+ /* Verify that the converted text will fit. */
+ if (to_cs->mbmaxlen*id_len > max_converted_size)
{
- strncpy(digest_text, id_string, id_length);
- digest_text+= id_length;
+ truncated= true;
+ break;
+ }
+ /* Convert identifier string into the storage character set. */
+ int id_length= my_convert(id_string, max_converted_size, to_cs, id_ptr,
+ id_len, from_cs, &err_cs);
+
+ if (id_length == 0 || err_cs != 0)
+ {
+ truncated= true;
+ break;
+ }
+ /* Copy the converted identifier into the digest string. */
+ bytes_needed= id_length + 1; /* <id> space */
+ if (bytes_needed <= bytes_available)
+ {
+ if (id_length > 0)
+ {
+ memcpy(digest_text, id_string, id_length);
+ digest_text+= id_length;
+ }
+ *digest_text++= ' ';
+ bytes_available-= bytes_needed;
+ }
+ else
+ {
+ truncated= true;
}
- *digest_text= ' ';
- digest_text++;
- available_bytes_to_write-= need_bytes;
- }
- else
- {
- truncated= true;
}
break;
+
case IDENT_QUOTED:
- current_byte= read_identifier(digest_storage, current_byte,
- & id_string, & id_length);
- need_bytes= id_length + 3; /* quote <id> quote space */
- if (need_bytes <= available_bytes_to_write)
{
- *digest_text= '`';
- digest_text++;
- if (id_length > 0)
+ char *id_ptr;
+ int id_len;
+ uint err_cs;
+
+ /* Get the next identifier in the storage buffer. */
+ current_byte= read_identifier(digest_storage, current_byte,
+ &id_ptr, &id_len);
+ /* Verify that the converted text will fit. */
+ if (to_cs->mbmaxlen*id_len > max_converted_size)
{
- strncpy(digest_text, id_string, id_length);
- digest_text+= id_length;
+ truncated= true;
+ break;
+ }
+ /* Convert identifier string into the storage character set. */
+ int id_length= my_convert(id_string, max_converted_size, to_cs, id_ptr,
+ id_len, from_cs, &err_cs);
+
+ if (id_length == 0 || err_cs != 0)
+ {
+ truncated= true;
+ break;
+ }
+ /* Copy the converted identifier into the digest string. */
+ bytes_needed= id_length + 3; /* quote <id> quote space */
+ if (bytes_needed <= bytes_available)
+ {
+ *digest_text++= '`';
+ if (id_length > 0)
+ {
+ memcpy(digest_text, id_string, id_length);
+ digest_text+= id_length;
+ }
+ *digest_text++= '`';
+ *digest_text++= ' ';
+ bytes_available-= bytes_needed;
+ }
+ else
+ {
+ truncated= true;
}
- *digest_text= '`';
- digest_text++;
- *digest_text= ' ';
- digest_text++;
- available_bytes_to_write-= need_bytes;
- }
- else
- {
- truncated= true;
}
break;
/* Everything else is printed as is. */
default:
/*
- Make sure not to overflow digest_text buffer while writing
- this token string.
+ Make sure not to overflow digest_text buffer.
+1 is to make sure extra space for ' '.
*/
int tok_length= tok_data->m_token_length;
- need_bytes= tok_length + 1;
+ bytes_needed= tok_length + 1;
- if (need_bytes <= available_bytes_to_write)
+ if (bytes_needed <= bytes_available)
{
- strncpy(digest_text,
- tok_data->m_token_string,
- tok_length);
+ strncpy(digest_text, tok_data->m_token_string, tok_length);
digest_text+= tok_length;
- *digest_text= ' ';
- digest_text++;
- available_bytes_to_write-= need_bytes;
+ *digest_text++= ' ';
+ bytes_available-= bytes_needed;
}
else
{
truncated= true;
}
+ break;
}
}
=== modified file 'storage/perfschema/pfs_digest.h'
--- a/storage/perfschema/pfs_digest.h 2012-02-28 15:57:52 +0000
+++ b/storage/perfschema/pfs_digest.h 2012-03-29 03:22:29 +0000
@@ -46,24 +46,16 @@ struct PFS_digest_hash
/** A statement digest stat record. */
struct PFS_statements_digest_stat
{
- /**
- Digest MD5 Hash.
- */
+ /** Digest MD5 Hash. */
PFS_digest_hash m_digest_hash;
- /**
- Digest Storage.
- */
+ /** Digest Storage. */
PSI_digest_storage m_digest_storage;
- /**
- Statement stat.
- */
+ /** Statement stat. */
PFS_statement_stat m_stat;
- /**
- First Seen/last seen.
- */
+ /** First and last seen timestamps.*/
ulonglong m_first_seen;
ulonglong m_last_seen;
@@ -78,10 +70,10 @@ void cleanup_digest();
int init_digest_hash(void);
void cleanup_digest_hash(void);
-PFS_statement_stat* find_or_create_digest(PFS_thread*,
- PSI_digest_storage*);
+PFS_statement_stat* find_or_create_digest(PFS_thread *thread,
+ PSI_digest_storage *digest_storage);
-void get_digest_text(char* digest_text, PSI_digest_storage*);
+void get_digest_text(char *digest_text, PSI_digest_storage *digest_storage);
void reset_esms_by_digest();
@@ -90,8 +82,8 @@ extern PFS_statements_digest_stat *state
/* Instrumentation callbacks for pfs.cc */
-struct PSI_digest_locker* pfs_digest_start_v1(PSI_statement_locker *locker);
-PSI_digest_locker* pfs_digest_add_token_v1(PSI_digest_locker *locker,
+struct PSI_digest_locker *pfs_digest_start_v1(PSI_statement_locker *locker);
+PSI_digest_locker *pfs_digest_add_token_v1(PSI_digest_locker *locker,
uint token,
OPAQUE_LEX_YYSTYPE *yylval);
@@ -99,6 +91,7 @@ static inline void digest_reset(PSI_dige
{
digest->m_full= false;
digest->m_byte_count= 0;
+ digest->m_csid= 0; //TBD default character set
}
static inline void digest_copy(PSI_digest_storage *to, const PSI_digest_storage *from)
@@ -107,6 +100,7 @@ static inline void digest_copy(PSI_diges
{
to->m_full= from->m_full;
to->m_byte_count= from->m_byte_count;
+ to->m_csid= from->m_csid;
DBUG_ASSERT(to->m_byte_count <= PSI_MAX_DIGEST_STORAGE_SIZE);
memcpy(to->m_token_array, from->m_token_array, to->m_byte_count);
}
@@ -116,11 +110,12 @@ static inline void digest_copy(PSI_diges
DBUG_ASSERT(from->m_byte_count == 0);
to->m_full= false;
to->m_byte_count= 0;
+ to->m_csid= 0;
}
}
/**
- Function to read a single token from token array.
+ Read a single token from token array.
*/
inline int read_token(PSI_digest_storage *digest_storage,
int index, uint *tok)
@@ -141,7 +136,7 @@ inline int read_token(PSI_digest_storage
}
/**
- Function to store a single token in token array.
+ Store a single token in token array.
*/
inline void store_token(PSI_digest_storage* digest_storage, uint token)
{
@@ -162,7 +157,7 @@ inline void store_token(PSI_digest_stora
}
/**
- Function to read an identifier from token array.
+ Read an identifier from token array.
*/
inline int read_identifier(PSI_digest_storage* digest_storage,
int index, char ** id_string, int *id_length)
@@ -186,7 +181,7 @@ inline int read_identifier(PSI_digest_st
}
/**
- Function to store an identifier in token array.
+ Store an identifier in token array.
*/
inline void store_token_identifier(PSI_digest_storage* digest_storage,
uint token,
@@ -207,9 +202,7 @@ inline void store_token_identifier(PSI_d
dest[3]= (id_length >> 8) & 0xff;
/* Write the string data */
if (id_length > 0)
- {
- strncpy((char *)(dest + 4), id_name, id_length);
- }
+ memcpy((char *)(dest + 4), id_name, id_length);
digest_storage->m_byte_count+= bytes_needed;
}
else
=== modified file 'storage/perfschema/table_helper.cc'
--- a/storage/perfschema/table_helper.cc 2012-03-19 19:29:28 +0000
+++ b/storage/perfschema/table_helper.cc 2012-03-29 03:22:29 +0000
@@ -101,7 +101,7 @@ void PFS_account_row::set_field(uint ind
}
}
-int PFS_digest_row::make_row(PFS_statements_digest_stat* pfs)
+int PFS_digest_row::make_row(PFS_statements_digest_stat *pfs)
{
/*
"0" value for byte_count indicates special entry i.e. aggregated
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-trunk branch (chris.powers:3862 to 3863) Bug#13809293 | Christopher Powers | 29 Mar |