diff --git a/include/mysql/psi/psi.h b/include/mysql/psi/psi.h index 49202c4e88f..7fcff89c8b6 100644 --- a/include/mysql/psi/psi.h +++ b/include/mysql/psi/psi.h @@ -1009,6 +1009,8 @@ struct PSI_statement_locker_state_v1 char m_schema_name[PSI_SCHEMA_NAME_LEN]; /** Length in bytes of @c m_schema_name. */ uint m_schema_name_length; + /** Statement character set number. */ + uint m_cs_number; }; /** diff --git a/include/mysql/psi/psi_abi_v1.h.pp b/include/mysql/psi/psi_abi_v1.h.pp index 898b9871d2e..2e2d7a79fe1 100644 --- a/include/mysql/psi/psi_abi_v1.h.pp +++ b/include/mysql/psi/psi_abi_v1.h.pp @@ -269,6 +269,7 @@ struct PSI_statement_locker_state_v1 const struct sql_digest_storage *m_digest; char m_schema_name[(64 * 3)]; uint m_schema_name_length; + uint m_cs_number; }; struct PSI_socket_locker_state_v1 { diff --git a/mysql-test/suite/perfschema/r/misc.result b/mysql-test/suite/perfschema/r/misc.result index 24cf4cc749a..24ab21848b0 100644 --- a/mysql-test/suite/perfschema/r/misc.result +++ b/mysql-test/suite/perfschema/r/misc.result @@ -107,3 +107,14 @@ select mysql_errno, returned_sqlstate, message_text, errors, warnings from performance_schema.events_statements_history_long where errors > 0; mysql_errno returned_sqlstate message_text errors warnings 1146 42S02 Table 'test.t1' doesn't exist 1 0 +use performance_schema; +truncate performance_schema.events_statements_history; +select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' AS A; +A +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +select _utf8mb4 'васÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑ' as B; +B +васвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвасвас +select count(*) from events_statements_history where sql_text like "%..."; +count(*) +2 diff --git a/mysql-test/suite/perfschema/t/misc.test b/mysql-test/suite/perfschema/t/misc.test index d6c302c29bf..b5af044a1f6 100644 --- a/mysql-test/suite/perfschema/t/misc.test +++ b/mysql-test/suite/perfschema/t/misc.test @@ -3,6 +3,7 @@ --source include/not_embedded.inc --source include/have_perfschema.inc +--source include/no_protocol.inc # # Bug#12790483 OBJECTS_SUMMARY_GLOBAL_BY_TYPE AND RENAME TABLE @@ -188,3 +189,20 @@ select mysql_errno, returned_sqlstate, message_text, errors, warnings --echo select mysql_errno, returned_sqlstate, message_text, errors, warnings from performance_schema.events_statements_history_long where errors > 0; + +# +# Bug#20519832 - TRUNCATED SQL_TEXT values are not suffixed with '...' +# +# Verify that truncated SQL statements are suffixed with '...' + +use performance_schema; +truncate performance_schema.events_statements_history; + +# Should truncate at 1024 bytes (1024 characters) +select 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' AS A; + +# Should truncate at 1024 bytes (487 characters) + +select _utf8mb4 'васÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑвасÑ' as B; + +select count(*) from events_statements_history where sql_text like "%..."; diff --git a/storage/perfschema/pfs.cc b/storage/perfschema/pfs.cc index 6e6f8dcb1c4..cf0fa82ba3f 100644 --- a/storage/perfschema/pfs.cc +++ b/storage/perfschema/pfs.cc @@ -4388,6 +4388,8 @@ get_thread_statement_locker_v1(PSI_statement_locker_state *state, const void *charset) { DBUG_ASSERT(state != NULL); + DBUG_ASSERT(charset != NULL); + if (! flag_global_instrumentation) return NULL; PFS_statement_class *klass= find_statement_class(key); @@ -4432,6 +4434,8 @@ get_thread_statement_locker_v1(PSI_statement_locker_state *state, pfs->m_lock_time= 0; pfs->m_current_schema_name_length= 0; pfs->m_sqltext_length= 0; + pfs->m_sqltext_truncated= false; + pfs->m_sqltext_cs_number= system_charset_info->number; /* default */ pfs->m_message_text[0]= '\0'; pfs->m_sql_errno= 0; @@ -4511,6 +4515,7 @@ get_thread_statement_locker_v1(PSI_statement_locker_state *state, state->m_digest= NULL; state->m_schema_name_length= 0; + state->m_cs_number= ((CHARSET_INFO *)charset)->number; return reinterpret_cast (state); } @@ -4616,10 +4621,14 @@ static void set_statement_text_v1(PSI_statement_locker *locker, PFS_events_statements *pfs= reinterpret_cast (state->m_statement); DBUG_ASSERT(pfs != NULL); if (text_len > sizeof (pfs->m_sqltext)) + { text_len= sizeof(pfs->m_sqltext); + pfs->m_sqltext_truncated= true; + } if (text_len) memcpy(pfs->m_sqltext, text, text_len); pfs->m_sqltext_length= text_len; + pfs->m_sqltext_cs_number= state->m_cs_number; } return; diff --git a/storage/perfschema/pfs_events_statements.h b/storage/perfschema/pfs_events_statements.h index b1e303e7021..d3fd79ea195 100644 --- a/storage/perfschema/pfs_events_statements.h +++ b/storage/perfschema/pfs_events_statements.h @@ -88,6 +88,12 @@ struct PFS_events_statements : public PFS_events ulonglong m_no_index_used; /** Optimizer metric, number of 'no good index used'. */ ulonglong m_no_good_index_used; + + /** True if sqltext was truncated. */ + bool m_sqltext_truncated; + /** Statement character set number. */ + uint m_sqltext_cs_number; + /** Statement digest. This underlying token array storage pointer is immutable, diff --git a/storage/perfschema/table_events_statements.cc b/storage/perfschema/table_events_statements.cc index 84214c11b0f..6931584895f 100644 --- a/storage/perfschema/table_events_statements.cc +++ b/storage/perfschema/table_events_statements.cc @@ -337,9 +337,32 @@ void table_events_statements_common::make_row_part_1(PFS_events_statements *stat m_row.m_name= klass->m_name; m_row.m_name_length= klass->m_name_length; - m_row.m_sqltext_length= statement->m_sqltext_length; - if (m_row.m_sqltext_length > 0) - memcpy(m_row.m_sqltext, statement->m_sqltext, m_row.m_sqltext_length); + CHARSET_INFO *cs= get_charset(statement->m_sqltext_cs_number, MYF(0)); + size_t valid_length= statement->m_sqltext_length; + + if (cs->mbmaxlen > 1) + { + int well_formed_error; + valid_length= cs->cset->well_formed_len(cs, statement->m_sqltext, statement->m_sqltext + valid_length, + valid_length, &well_formed_error); + } + + m_row.m_sqltext.set_charset(cs); + m_row.m_sqltext.length(0); + m_row.m_sqltext.append(statement->m_sqltext, (uint32)valid_length, cs); + + /* Indicate that sqltext is truncated or not well-formed. */ + if (statement->m_sqltext_truncated || valid_length < statement->m_sqltext_length) + { + size_t chars= m_row.m_sqltext.numchars(); + if (chars > 3) + { + chars-= 3; + size_t bytes_offset= m_row.m_sqltext.charpos(chars, 0); + m_row.m_sqltext.length(bytes_offset); + m_row.m_sqltext.append("...", 3); + } + } m_row.m_current_schema_name_length= statement->m_current_schema_name_length; if (m_row.m_current_schema_name_length > 0) @@ -482,8 +505,8 @@ int table_events_statements_common::read_row_values(TABLE *table, f->set_null(); break; case 9: /* SQL_TEXT */ - if (m_row.m_sqltext_length) - set_field_longtext_utf8(f, m_row.m_sqltext, m_row.m_sqltext_length); + if (m_row.m_sqltext.length()) + set_field_longtext_utf8(f, m_row.m_sqltext.ptr(), m_row.m_sqltext.length()); else f->set_null(); break; diff --git a/storage/perfschema/table_events_statements.h b/storage/perfschema/table_events_statements.h index a42bbcb2e5a..6c8899e14c3 100644 --- a/storage/perfschema/table_events_statements.h +++ b/storage/perfschema/table_events_statements.h @@ -63,11 +63,9 @@ struct row_events_statements /** Length in bytes of @c m_source. */ uint m_source_length; /** Column SQL_TEXT. */ - char m_sqltext[COL_INFO_SIZE]; + String m_sqltext; /** Column DIGEST and DIGEST_TEXT. */ PFS_digest_row m_digest; - /** Length in bytes of @c m_info. */ - uint m_sqltext_length; /** Column CURRENT_SCHEMA. */ char m_current_schema_name[NAME_LEN]; /** Length in bytes of @c m_current_schema_name. */ diff --git a/storage/perfschema/unittest/pfs_server_stubs.cc b/storage/perfschema/unittest/pfs_server_stubs.cc index a8f417e390b..ec916865a7d 100644 --- a/storage/perfschema/unittest/pfs_server_stubs.cc +++ b/storage/perfschema/unittest/pfs_server_stubs.cc @@ -28,6 +28,7 @@ volatile bool ready_to_exit= false; uint lower_case_table_names= 0; CHARSET_INFO *files_charset_info= NULL; +CHARSET_INFO *system_charset_info= NULL; void compute_digest_md5(const sql_digest_storage *, unsigned char *) {