mirror of
https://github.com/MariaDB/server.git
synced 2025-12-24 11:21:21 +03:00
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().
This commit is contained in:
@@ -1249,69 +1249,145 @@ innobase_invalidate_query_cache(
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Display an SQL identifier. */
|
||||
extern "C"
|
||||
void
|
||||
innobase_print_identifier(
|
||||
/*======================*/
|
||||
FILE* f, /* in: output stream */
|
||||
trx_t* trx, /* in: transaction */
|
||||
ibool table_id,/* in: TRUE=print a table name,
|
||||
FALSE=print other identifier */
|
||||
const char* name, /* in: name to print */
|
||||
ulint namelen)/* in: length of name */
|
||||
Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
|
||||
and quote it if needed. */
|
||||
static
|
||||
char*
|
||||
innobase_convert_identifier(
|
||||
/*========================*/
|
||||
/* 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 file_id)/* in: TRUE=id is a table or database name;
|
||||
FALSE=id is an UTF-8 string */
|
||||
{
|
||||
const char* s = name;
|
||||
char* qname = NULL;
|
||||
char nz[NAME_LEN + 1];
|
||||
char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix];
|
||||
|
||||
const char* s = id;
|
||||
int q;
|
||||
|
||||
if (table_id) {
|
||||
if (file_id) {
|
||||
/* Decode the table name. The filename_to_tablename()
|
||||
function expects a NUL-terminated string. The input and
|
||||
output strings buffers must not be shared. The function
|
||||
only produces more output when the name contains other
|
||||
characters than [0-9A-Z_a-z]. */
|
||||
char* temp_name = (char*) my_malloc((uint) namelen + 1, MYF(MY_WME));
|
||||
uint qnamelen = (uint) (namelen
|
||||
+ (1 + sizeof srv_mysql50_table_name_prefix));
|
||||
output strings buffers must not be shared. */
|
||||
|
||||
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 (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
|
||||
idlen = (sizeof nz) - 1;
|
||||
}
|
||||
|
||||
memcpy(nz, id, idlen);
|
||||
nz[idlen] = 0;
|
||||
|
||||
s = nz2;
|
||||
idlen = filename_to_tablename(nz, nz2, sizeof nz2);
|
||||
}
|
||||
|
||||
if (!trx || !trx->mysql_thd) {
|
||||
|
||||
/* See if the identifier needs to be quoted. */
|
||||
if (UNIV_UNLIKELY(!thd)) {
|
||||
q = '"';
|
||||
} else {
|
||||
q = get_quote_char_for_identifier((THD*) trx->mysql_thd,
|
||||
s, (int) namelen);
|
||||
q = get_quote_char_for_identifier((THD*) thd, s, (int) idlen);
|
||||
}
|
||||
|
||||
if (q == EOF) {
|
||||
fwrite(s, 1, namelen, f);
|
||||
} else {
|
||||
const char* e = s + namelen;
|
||||
putc(q, f);
|
||||
while (s < e) {
|
||||
int c = *s++;
|
||||
if (c == q) {
|
||||
putc(c, f);
|
||||
}
|
||||
putc(c, f);
|
||||
if (UNIV_UNLIKELY(idlen > buflen)) {
|
||||
idlen = buflen;
|
||||
}
|
||||
putc(q, f);
|
||||
memcpy(buf, s, idlen);
|
||||
return(buf + idlen);
|
||||
}
|
||||
|
||||
my_free(qname, MYF(MY_ALLOW_ZERO_PTR));
|
||||
/* 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;
|
||||
}
|
||||
|
||||
*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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
return(s);
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
||||
@@ -23,6 +23,7 @@ extern "C" {
|
||||
#include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
|
||||
#include "buf0buddy.h" /* for i_s_zip */
|
||||
#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";
|
||||
@@ -513,8 +514,7 @@ fill_innodb_locks_from_cache(
|
||||
/*=========================*/
|
||||
/* out: 0 on success */
|
||||
trx_i_s_cache_t* cache, /* in: cache to read from */
|
||||
THD* thd, /* in: used to call
|
||||
schema_table_store_record() */
|
||||
THD* thd, /* in: MySQL client connection */
|
||||
TABLE* table) /* in/out: fill this table */
|
||||
{
|
||||
Field** fields;
|
||||
@@ -532,6 +532,10 @@ fill_innodb_locks_from_cache(
|
||||
for (i = 0; i < rows_num; i++) {
|
||||
|
||||
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*)
|
||||
trx_i_s_cache_get_nth_row(
|
||||
@@ -554,12 +558,20 @@ fill_innodb_locks_from_cache(
|
||||
row->lock_type));
|
||||
|
||||
/* lock_table */
|
||||
OK(field_store_string(fields[IDX_LOCK_TABLE],
|
||||
row->lock_table));
|
||||
bufend = innobase_convert_name(buf, sizeof buf,
|
||||
row->lock_table,
|
||||
strlen(row->lock_table),
|
||||
thd, TRUE);
|
||||
OK(fields[IDX_LOCK_TABLE]->store(buf, bufend - buf,
|
||||
system_charset_info));
|
||||
|
||||
/* lock_index */
|
||||
OK(field_store_string(fields[IDX_LOCK_INDEX],
|
||||
row->lock_index));
|
||||
bufend = innobase_convert_name(buf, sizeof buf,
|
||||
row->lock_index,
|
||||
strlen(row->lock_index),
|
||||
thd, FALSE);
|
||||
OK(fields[IDX_LOCK_INDEX]->store(buf, bufend - buf,
|
||||
system_charset_info));
|
||||
|
||||
/* lock_space */
|
||||
OK(field_store_ulint(fields[IDX_LOCK_SPACE],
|
||||
|
||||
@@ -25,17 +25,20 @@ innobase_convert_string(
|
||||
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(
|
||||
/*======================*/
|
||||
FILE* f, /* in: output stream */
|
||||
trx_t* trx, /* in: transaction */
|
||||
ibool table_id,/* in: TRUE=print a table name,
|
||||
FALSE=print other identifier */
|
||||
const char* name, /* in: name to print */
|
||||
ulint namelen);/* in: length of name */
|
||||
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 */
|
||||
|
||||
/**********************************************************************
|
||||
Returns true if the thread is the replication thread on the slave
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
lock_data
|
||||
'1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc'''''
|
||||
'1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc'''''
|
||||
'2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""'
|
||||
'2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""'
|
||||
'3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\'
|
||||
'3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\'
|
||||
'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'
|
||||
-128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0
|
||||
-128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0
|
||||
127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615
|
||||
127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615
|
||||
supremum pseudo-record
|
||||
supremum pseudo-record
|
||||
lock_mode lock_type lock_table lock_index lock_rec lock_data
|
||||
X RECORD `test`.```t'\"_str` NULL 2 '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'''''
|
||||
X RECORD `test`.```t'\"_str` NULL 3 '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""'
|
||||
X RECORD `test`.```t'\"_str` NULL 4 '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\\\\'
|
||||
X RECORD `test`.```t'\"_str` NULL 5 '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'
|
||||
X RECORD `test`.`t_min` NULL 2 -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
|
||||
X RECORD `test`.`t_max` NULL 2 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
|
||||
X RECORD `test`.```t'\"_str` NULL 1 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
|
||||
2147483647, 4294967295,
|
||||
9223372036854775807, 18446744073709551615);
|
||||
|
||||
CREATE TABLE t_str (
|
||||
CREATE TABLE ```t'\"_str` (
|
||||
c1 VARCHAR(32),
|
||||
c2 VARCHAR(32),
|
||||
c3 VARCHAR(32),
|
||||
@@ -55,13 +55,13 @@ CREATE TABLE t_str (
|
||||
c7 VARCHAR(32),
|
||||
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''''');
|
||||
INSERT INTO t_str VALUES
|
||||
INSERT INTO ```t'\"_str` VALUES
|
||||
('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\\\\');
|
||||
INSERT INTO t_str VALUES
|
||||
INSERT INTO ```t'\"_str` VALUES
|
||||
('4', 'abc', 0x00616263, 0x61626300, 0x61006263, 0x6100626300, 0x610062630000);
|
||||
|
||||
-- connect (con_lock,localhost,root,,)
|
||||
@@ -78,7 +78,7 @@ INSERT INTO t_str VALUES
|
||||
SET autocommit=0;
|
||||
SELECT * FROM t_min FOR UPDATE;
|
||||
SELECT * FROM t_max FOR UPDATE;
|
||||
SELECT * FROM t_str FOR UPDATE;
|
||||
SELECT * FROM ```t'\"_str` FOR UPDATE;
|
||||
|
||||
-- connection con_min_trylock
|
||||
-- send
|
||||
@@ -90,24 +90,24 @@ SELECT * FROM t_max FOR UPDATE;
|
||||
|
||||
-- connection con_str_insert_supremum
|
||||
-- send
|
||||
INSERT INTO t_str VALUES
|
||||
INSERT INTO ```t'\"_str` VALUES
|
||||
('z', 'z', 'z', 'z', 'z', 'z', 'z');
|
||||
|
||||
-- connection con_str_lock_row1
|
||||
-- send
|
||||
SELECT * FROM t_str WHERE c1 = '1' FOR UPDATE;
|
||||
SELECT * FROM ```t'\"_str` WHERE c1 = '1' FOR UPDATE;
|
||||
|
||||
-- connection con_str_lock_row2
|
||||
-- send
|
||||
SELECT * FROM t_str WHERE c1 = '2' FOR UPDATE;
|
||||
SELECT * FROM ```t'\"_str` WHERE c1 = '2' FOR UPDATE;
|
||||
|
||||
-- connection con_str_lock_row3
|
||||
-- send
|
||||
SELECT * FROM t_str WHERE c1 = '3' FOR UPDATE;
|
||||
SELECT * FROM ```t'\"_str` WHERE c1 = '3' FOR UPDATE;
|
||||
|
||||
-- connection con_str_lock_row4
|
||||
-- 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.
|
||||
# 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;
|
||||
|
||||
-- enable_result_log
|
||||
-- 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
|
||||
|
||||
-- connection default
|
||||
@@ -132,4 +142,4 @@ SELECT lock_data FROM INFORMATION_SCHEMA.innodb_locks ORDER BY lock_data;
|
||||
-- disconnect con_str_lock_row4
|
||||
-- disconnect con_verify_innodb_locks
|
||||
|
||||
DROP TABLE t_min, t_max, t_str;
|
||||
DROP TABLE t_min, t_max, ```t'\"_str`;
|
||||
|
||||
31
ut/ut0ut.c
31
ut/ut0ut.c
@@ -18,6 +18,9 @@ Created 5/11/1994 Heikki Tuuri
|
||||
|
||||
#include "trx0trx.h"
|
||||
#include "ha_prototypes.h"
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
# include "mysql_com.h" /* NAME_LEN */
|
||||
#endif /* UNIV_HOTBACKUP */
|
||||
|
||||
ibool ut_always_false = FALSE;
|
||||
|
||||
@@ -465,27 +468,17 @@ ut_print_namel(
|
||||
#ifdef UNIV_HOTBACKUP
|
||||
fwrite(name, 1, namelen, f);
|
||||
#else
|
||||
if (table_id) {
|
||||
char* slash = memchr(name, '/', namelen);
|
||||
if (!slash) {
|
||||
/* 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;
|
||||
|
||||
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. */
|
||||
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);
|
||||
}
|
||||
fwrite(buf, 1, bufend - buf, f);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user