Commit afccd4af authored by marko's avatar marko

branches/zip: INFORMATION_SCHEMA.INNODB_LOCKS: Quote lock_table, lock_index.

innodb_information_schema.test. Add tests that display most columns from
INFORMATION_SCHEMA.INNODB_LOCKS.  Test that quoting of table names works
and respects SQL_MODE='ANSI_QUOTES'.

innobase_print_identifier(): Remove.

innobase_convert_identifier(): New function,
based on innobase_print_identifier().

innobase_convert_name(): New function, similar to ut_print_namel(), but
using a memory buffer.

ut_print_namel(): Use innobase_convert_name().

fill_innodb_locks_from_cache(): Convert lock_table and lock_index by
calling innobase_convert_name().
parent 3e2b5b65
...@@ -1249,69 +1249,145 @@ innobase_invalidate_query_cache( ...@@ -1249,69 +1249,145 @@ innobase_invalidate_query_cache(
} }
/********************************************************************* /*********************************************************************
Display an SQL identifier. */ Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
extern "C" and quote it if needed. */
void static
innobase_print_identifier( char*
/*======================*/ innobase_convert_identifier(
FILE* f, /* in: output stream */ /*========================*/
trx_t* trx, /* in: transaction */ /* out: pointer to the end of buf */
ibool table_id,/* in: TRUE=print a table name, char* buf, /* out: buffer for converted identifier */
FALSE=print other identifier */ ulint buflen, /* in: length of buf, in bytes */
const char* name, /* in: name to print */ const char* id, /* in: identifier to convert */
ulint namelen)/* in: length of name */ ulint idlen, /* in: length of id, in bytes */
{ void* thd, /* in: MySQL connection thread, or NULL */
const char* s = name; ibool file_id)/* in: TRUE=id is a table or database name;
char* qname = NULL; FALSE=id is an UTF-8 string */
{
char nz[NAME_LEN + 1];
char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix];
const char* s = id;
int q; int q;
if (table_id) { if (file_id) {
/* Decode the table name. The filename_to_tablename() /* Decode the table name. The filename_to_tablename()
function expects a NUL-terminated string. The input and function expects a NUL-terminated string. The input and
output strings buffers must not be shared. The function output strings buffers must not be shared. */
only produces more output when the name contains other
characters than [0-9A-Z_a-z]. */ if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
char* temp_name = (char*) my_malloc((uint) namelen + 1, MYF(MY_WME)); idlen = (sizeof nz) - 1;
uint qnamelen = (uint) (namelen
+ (1 + sizeof srv_mysql50_table_name_prefix));
if (temp_name) {
qname = (char*) my_malloc(qnamelen, MYF(MY_WME));
if (qname) {
memcpy(temp_name, name, namelen);
temp_name[namelen] = 0;
s = qname;
namelen = filename_to_tablename(temp_name,
qname, qnamelen);
}
my_free(temp_name, MYF(0));
} }
}
if (!trx || !trx->mysql_thd) { memcpy(nz, id, idlen);
nz[idlen] = 0;
s = nz2;
idlen = filename_to_tablename(nz, nz2, sizeof nz2);
}
/* See if the identifier needs to be quoted. */
if (UNIV_UNLIKELY(!thd)) {
q = '"'; q = '"';
} else { } else {
q = get_quote_char_for_identifier((THD*) trx->mysql_thd, q = get_quote_char_for_identifier((THD*) thd, s, (int) idlen);
s, (int) namelen);
} }
if (q == EOF) { if (q == EOF) {
fwrite(s, 1, namelen, f); if (UNIV_UNLIKELY(idlen > buflen)) {
} else { idlen = buflen;
const char* e = s + namelen; }
putc(q, f); memcpy(buf, s, idlen);
while (s < e) { return(buf + idlen);
int c = *s++; }
if (c == q) {
putc(c, f); /* Quote the identifier. */
if (buflen < 2) {
return(buf);
}
*buf++ = q;
buflen--;
for (; idlen; idlen--) {
int c = *s++;
if (UNIV_UNLIKELY(c == q)) {
if (UNIV_UNLIKELY(buflen < 3)) {
break;
} }
putc(c, f);
*buf++ = c;
*buf++ = c;
buflen -= 2;
} else {
if (UNIV_UNLIKELY(buflen < 2)) {
break;
}
*buf++ = c;
buflen--;
}
}
*buf++ = q;
return(buf);
}
/*********************************************************************
Convert a table or index name to the MySQL system_charset_info (UTF-8)
and quote it if needed. */
extern "C"
char*
innobase_convert_name(
/*==================*/
/* out: pointer to the end of buf */
char* buf, /* out: buffer for converted identifier */
ulint buflen, /* in: length of buf, in bytes */
const char* id, /* in: identifier to convert */
ulint idlen, /* in: length of id, in bytes */
void* thd, /* in: MySQL connection thread, or NULL */
ibool table_id)/* in: TRUE=id is a table or database name;
FALSE=id is an index name */
{
char* s = buf;
const char* bufend = buf + buflen;
if (table_id) {
const char* slash = (const char*) memchr(id, '/', idlen);
if (!slash) {
goto no_db_name;
} }
putc(q, f);
/* Print the database name and table name separately. */
s = innobase_convert_identifier(s, bufend - s, id, slash - id,
thd, TRUE);
if (UNIV_LIKELY(s < bufend)) {
*s++ = '.';
s = innobase_convert_identifier(s, bufend - s,
slash + 1, idlen
- (slash - id) - 1,
thd, TRUE);
}
} else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
/* Temporary index name (smart ALTER TABLE) */
const char temp_index_suffix[]= "--temporary--";
s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
thd, FALSE);
if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
memcpy(s, temp_index_suffix,
sizeof temp_index_suffix - 1);
s += sizeof temp_index_suffix - 1;
}
} else {
no_db_name:
s = innobase_convert_identifier(buf, buflen, id, idlen,
thd, table_id);
} }
my_free(qname, MYF(MY_ALLOW_ZERO_PTR)); return(s);
} }
/************************************************************************** /**************************************************************************
......
...@@ -23,6 +23,7 @@ extern "C" { ...@@ -23,6 +23,7 @@ extern "C" {
#include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */ #include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
#include "buf0buddy.h" /* for i_s_zip */ #include "buf0buddy.h" /* for i_s_zip */
#include "buf0buf.h" /* for buf_pool and PAGE_ZIP_MIN_SIZE */ #include "buf0buf.h" /* for buf_pool and PAGE_ZIP_MIN_SIZE */
#include "ha_prototypes.h" /* for innobase_convert_name() */
} }
static const char plugin_author[] = "Innobase Oy"; static const char plugin_author[] = "Innobase Oy";
...@@ -513,8 +514,7 @@ fill_innodb_locks_from_cache( ...@@ -513,8 +514,7 @@ fill_innodb_locks_from_cache(
/*=========================*/ /*=========================*/
/* out: 0 on success */ /* out: 0 on success */
trx_i_s_cache_t* cache, /* in: cache to read from */ trx_i_s_cache_t* cache, /* in: cache to read from */
THD* thd, /* in: used to call THD* thd, /* in: MySQL client connection */
schema_table_store_record() */
TABLE* table) /* in/out: fill this table */ TABLE* table) /* in/out: fill this table */
{ {
Field** fields; Field** fields;
...@@ -532,6 +532,10 @@ fill_innodb_locks_from_cache( ...@@ -532,6 +532,10 @@ fill_innodb_locks_from_cache(
for (i = 0; i < rows_num; i++) { for (i = 0; i < rows_num; i++) {
i_s_locks_row_t* row; i_s_locks_row_t* row;
/* 2 * NAME_LEN for database and table name,
and some slack for the #mysql50# prefix and quotes */
char buf[3 * NAME_LEN];
const char* bufend;
row = (i_s_locks_row_t*) row = (i_s_locks_row_t*)
trx_i_s_cache_get_nth_row( trx_i_s_cache_get_nth_row(
...@@ -554,12 +558,20 @@ fill_innodb_locks_from_cache( ...@@ -554,12 +558,20 @@ fill_innodb_locks_from_cache(
row->lock_type)); row->lock_type));
/* lock_table */ /* lock_table */
OK(field_store_string(fields[IDX_LOCK_TABLE], bufend = innobase_convert_name(buf, sizeof buf,
row->lock_table)); row->lock_table,
strlen(row->lock_table),
thd, TRUE);
OK(fields[IDX_LOCK_TABLE]->store(buf, bufend - buf,
system_charset_info));
/* lock_index */ /* lock_index */
OK(field_store_string(fields[IDX_LOCK_INDEX], bufend = innobase_convert_name(buf, sizeof buf,
row->lock_index)); row->lock_index,
strlen(row->lock_index),
thd, FALSE);
OK(fields[IDX_LOCK_INDEX]->store(buf, bufend - buf,
system_charset_info));
/* lock_space */ /* lock_space */
OK(field_store_ulint(fields[IDX_LOCK_SPACE], OK(field_store_ulint(fields[IDX_LOCK_SPACE],
......
...@@ -25,17 +25,20 @@ innobase_convert_string( ...@@ -25,17 +25,20 @@ innobase_convert_string(
uint* errors); uint* errors);
/********************************************************************* /*********************************************************************
Display an SQL identifier. */ Convert a table or index name to the MySQL system_charset_info (UTF-8)
and quote it if needed. */
void
innobase_print_identifier( char*
/*======================*/ innobase_convert_name(
FILE* f, /* in: output stream */ /*==================*/
trx_t* trx, /* in: transaction */ /* out: pointer to the end of buf */
ibool table_id,/* in: TRUE=print a table name, char* buf, /* out: buffer for converted identifier */
FALSE=print other identifier */ ulint buflen, /* in: length of buf, in bytes */
const char* name, /* in: name to print */ const char* id, /* in: identifier to convert */
ulint namelen);/* in: length of name */ ulint idlen, /* in: length of id, in bytes */
void* thd, /* in: MySQL connection thread, or NULL */
ibool table_id);/* in: TRUE=id is a table or database name;
FALSE=id is an index name */
/********************************************************************** /**********************************************************************
Returns true if the thread is the replication thread on the slave Returns true if the thread is the replication thread on the slave
......
lock_data lock_mode lock_type lock_table lock_index lock_rec lock_data
'1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc''''' X RECORD `test`.```t'\"_str` NULL 2 '1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc'''''
'1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc''''' X RECORD `test`.```t'\"_str` NULL 2 '1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc'''''
'2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""' X RECORD `test`.```t'\"_str` NULL 3 '2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""'
'2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""' X RECORD `test`.```t'\"_str` NULL 3 '2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""'
'3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\' X RECORD `test`.```t'\"_str` NULL 4 '3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\'
'3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\' X RECORD `test`.```t'\"_str` NULL 4 '3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\'
'4', 'abc', '\0abc', 'abc\0', 'a\0bc', 'a\0bc\0', 'a\0bc\0\0' X RECORD `test`.```t'\"_str` NULL 5 '4', 'abc', '\0abc', 'abc\0', 'a\0bc', 'a\0bc\0', 'a\0bc\0\0'
'4', 'abc', '\0abc', 'abc\0', 'a\0bc', 'a\0bc\0', 'a\0bc\0\0' X RECORD `test`.```t'\"_str` NULL 5 '4', 'abc', '\0abc', 'abc\0', 'a\0bc', 'a\0bc\0', 'a\0bc\0\0'
-128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0 X RECORD `test`.`t_min` NULL 2 -128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0
-128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0 X RECORD `test`.`t_min` NULL 2 -128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0
127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615 X RECORD `test`.`t_max` NULL 2 127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615
127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615 X RECORD `test`.`t_max` NULL 2 127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615
supremum pseudo-record X RECORD `test`.```t'\"_str` NULL 1 supremum pseudo-record
supremum pseudo-record X RECORD `test`.```t'\"_str` NULL 1 supremum pseudo-record
lock_table COUNT(*)
`test`.`t_max` 2
`test`.`t_min` 2
`test`.```t'\"_str` 10
lock_table COUNT(*)
"test"."t_max" 2
"test"."t_min" 2
"test"."`t'\""_str" 10
...@@ -45,7 +45,7 @@ INSERT INTO t_max VALUES ...@@ -45,7 +45,7 @@ INSERT INTO t_max VALUES
2147483647, 4294967295, 2147483647, 4294967295,
9223372036854775807, 18446744073709551615); 9223372036854775807, 18446744073709551615);
CREATE TABLE t_str ( CREATE TABLE ```t'\"_str` (
c1 VARCHAR(32), c1 VARCHAR(32),
c2 VARCHAR(32), c2 VARCHAR(32),
c3 VARCHAR(32), c3 VARCHAR(32),
...@@ -55,13 +55,13 @@ CREATE TABLE t_str ( ...@@ -55,13 +55,13 @@ CREATE TABLE t_str (
c7 VARCHAR(32), c7 VARCHAR(32),
PRIMARY KEY(c1, c2, c3, c4, c5, c6, c7) PRIMARY KEY(c1, c2, c3, c4, c5, c6, c7)
); );
INSERT INTO t_str VALUES INSERT INTO ```t'\"_str` VALUES
('1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc'''''); ('1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc''''');
INSERT INTO t_str VALUES INSERT INTO ```t'\"_str` VALUES
('2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""'); ('2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""');
INSERT INTO t_str VALUES INSERT INTO ```t'\"_str` VALUES
('3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\'); ('3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\');
INSERT INTO t_str VALUES INSERT INTO ```t'\"_str` VALUES
('4', 'abc', 0x00616263, 0x61626300, 0x61006263, 0x6100626300, 0x610062630000); ('4', 'abc', 0x00616263, 0x61626300, 0x61006263, 0x6100626300, 0x610062630000);
-- connect (con_lock,localhost,root,,) -- connect (con_lock,localhost,root,,)
...@@ -78,7 +78,7 @@ INSERT INTO t_str VALUES ...@@ -78,7 +78,7 @@ INSERT INTO t_str VALUES
SET autocommit=0; SET autocommit=0;
SELECT * FROM t_min FOR UPDATE; SELECT * FROM t_min FOR UPDATE;
SELECT * FROM t_max FOR UPDATE; SELECT * FROM t_max FOR UPDATE;
SELECT * FROM t_str FOR UPDATE; SELECT * FROM ```t'\"_str` FOR UPDATE;
-- connection con_min_trylock -- connection con_min_trylock
-- send -- send
...@@ -90,24 +90,24 @@ SELECT * FROM t_max FOR UPDATE; ...@@ -90,24 +90,24 @@ SELECT * FROM t_max FOR UPDATE;
-- connection con_str_insert_supremum -- connection con_str_insert_supremum
-- send -- send
INSERT INTO t_str VALUES INSERT INTO ```t'\"_str` VALUES
('z', 'z', 'z', 'z', 'z', 'z', 'z'); ('z', 'z', 'z', 'z', 'z', 'z', 'z');
-- connection con_str_lock_row1 -- connection con_str_lock_row1
-- send -- send
SELECT * FROM t_str WHERE c1 = '1' FOR UPDATE; SELECT * FROM ```t'\"_str` WHERE c1 = '1' FOR UPDATE;
-- connection con_str_lock_row2 -- connection con_str_lock_row2
-- send -- send
SELECT * FROM t_str WHERE c1 = '2' FOR UPDATE; SELECT * FROM ```t'\"_str` WHERE c1 = '2' FOR UPDATE;
-- connection con_str_lock_row3 -- connection con_str_lock_row3
-- send -- send
SELECT * FROM t_str WHERE c1 = '3' FOR UPDATE; SELECT * FROM ```t'\"_str` WHERE c1 = '3' FOR UPDATE;
-- connection con_str_lock_row4 -- connection con_str_lock_row4
-- send -- send
SELECT * FROM t_str WHERE c1 = '4' FOR UPDATE; SELECT * FROM ```t'\"_str` WHERE c1 = '4' FOR UPDATE;
# Give time to the above 2 queries to execute before continuing. # Give time to the above 2 queries to execute before continuing.
# Without this sleep it sometimes happens that the SELECT from innodb_locks # Without this sleep it sometimes happens that the SELECT from innodb_locks
...@@ -117,7 +117,17 @@ SELECT * FROM t_str WHERE c1 = '4' FOR UPDATE; ...@@ -117,7 +117,17 @@ SELECT * FROM t_str WHERE c1 = '4' FOR UPDATE;
-- enable_result_log -- enable_result_log
-- connection con_verify_innodb_locks -- connection con_verify_innodb_locks
SELECT lock_data FROM INFORMATION_SCHEMA.innodb_locks ORDER BY lock_data; SELECT lock_mode, lock_type, lock_table, lock_index, lock_rec, lock_data
FROM INFORMATION_SCHEMA.INNODB_LOCKS ORDER BY lock_data;
SELECT lock_table,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS
GROUP BY lock_table;
set @save_sql_mode = @@sql_mode;
SET SQL_MODE='ANSI_QUOTES';
SELECT lock_table,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS
GROUP BY lock_table;
SET @@sql_mode=@save_sql_mode;
-- disable_result_log -- disable_result_log
-- connection default -- connection default
...@@ -132,4 +142,4 @@ SELECT lock_data FROM INFORMATION_SCHEMA.innodb_locks ORDER BY lock_data; ...@@ -132,4 +142,4 @@ SELECT lock_data FROM INFORMATION_SCHEMA.innodb_locks ORDER BY lock_data;
-- disconnect con_str_lock_row4 -- disconnect con_str_lock_row4
-- disconnect con_verify_innodb_locks -- disconnect con_verify_innodb_locks
DROP TABLE t_min, t_max, t_str; DROP TABLE t_min, t_max, ```t'\"_str`;
...@@ -18,6 +18,9 @@ Created 5/11/1994 Heikki Tuuri ...@@ -18,6 +18,9 @@ Created 5/11/1994 Heikki Tuuri
#include "trx0trx.h" #include "trx0trx.h"
#include "ha_prototypes.h" #include "ha_prototypes.h"
#ifndef UNIV_HOTBACKUP
# include "mysql_com.h" /* NAME_LEN */
#endif /* UNIV_HOTBACKUP */
ibool ut_always_false = FALSE; ibool ut_always_false = FALSE;
...@@ -465,27 +468,17 @@ ut_print_namel( ...@@ -465,27 +468,17 @@ ut_print_namel(
#ifdef UNIV_HOTBACKUP #ifdef UNIV_HOTBACKUP
fwrite(name, 1, namelen, f); fwrite(name, 1, namelen, f);
#else #else
if (table_id) { /* 2 * NAME_LEN for database and table name,
char* slash = memchr(name, '/', namelen); and some slack for the #mysql50# prefix and quotes */
if (!slash) { char buf[3 * NAME_LEN];
const char* bufend;
goto no_db_name; bufend = innobase_convert_name(buf, sizeof buf,
} name, namelen,
trx ? trx->mysql_thd : NULL,
table_id);
/* Print the database name and table name separately. */ fwrite(buf, 1, bufend - buf, f);
innobase_print_identifier(f, trx, TRUE, name, slash - name);
putc('.', f);
innobase_print_identifier(f, trx, TRUE, slash + 1,
namelen - (slash - name) - 1);
} else if (UNIV_UNLIKELY(*name == TEMP_INDEX_PREFIX)) {
/* Temporary index */
innobase_print_identifier(f, trx, table_id, name + 1,
namelen - 1);
fputs("--temporary--", f);
} else {
no_db_name:
innobase_print_identifier(f, trx, table_id, name, namelen);
}
#endif #endif
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment