summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/show_check.result48
-rw-r--r--mysql-test/t/show_check.test40
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/sql_lex.cc18
-rw-r--r--sql/sql_show.cc76
5 files changed, 175 insertions, 9 deletions
diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
index 290f916ae72..235c6cd0ecf 100644
--- a/mysql-test/r/show_check.result
+++ b/mysql-test/r/show_check.result
@@ -265,3 +265,51 @@ c decimal(4,3) YES NULL
d double(4,3) YES NULL
f float(4,3) YES NULL
drop table t1;
+SET sql_mode='';
+SET sql_quote_show_create=OFF;
+CREATE TABLE ```ab``cd``` (i INT);
+SHOW CREATE TABLE ```ab``cd```;
+Table Create Table
+`ab`cd` CREATE TABLE ```ab``cd``` (
+ i int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE ```ab``cd```;
+CREATE TABLE ```ab````cd``` (i INT);
+SHOW CREATE TABLE ```ab````cd```;
+Table Create Table
+`ab``cd` CREATE TABLE ```ab````cd``` (
+ i int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE ```ab````cd```;
+CREATE TABLE ```a` (i INT);
+SHOW CREATE TABLE ```a`;
+Table Create Table
+`a CREATE TABLE ```a` (
+ i int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE ```a`;
+SET sql_mode='ANSI_QUOTES';
+CREATE TABLE """a" (i INT);
+SHOW CREATE TABLE """a";
+Table Create Table
+"a CREATE TABLE """a" (
+ i int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE """a";
+SET sql_mode='';
+SET sql_quote_show_create=OFF;
+CREATE TABLE t1 (i INT);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE t1 (
+ i int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE `table` (i INT);
+SHOW CREATE TABLE `table`;
+Table Create Table
+table CREATE TABLE `table` (
+ i int(11) default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE `table`;
+SET sql_quote_show_create=ON;
diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test
index d262f02c978..1d64cfd2105 100644
--- a/mysql-test/t/show_check.test
+++ b/mysql-test/t/show_check.test
@@ -142,3 +142,43 @@ drop table t1;
create table t1 (c decimal(3,3), d double(3,3), f float(3,3));
show columns from t1;
drop table t1;
+
+#
+# Test for Bug #2593 "SHOW CREATE TABLE doesn't properly double quotes"
+#
+
+SET sql_mode='';
+SET sql_quote_show_create=OFF;
+
+CREATE TABLE ```ab``cd``` (i INT);
+SHOW CREATE TABLE ```ab``cd```;
+DROP TABLE ```ab``cd```;
+
+CREATE TABLE ```ab````cd``` (i INT);
+SHOW CREATE TABLE ```ab````cd```;
+DROP TABLE ```ab````cd```;
+
+CREATE TABLE ```a` (i INT);
+SHOW CREATE TABLE ```a`;
+DROP TABLE ```a`;
+
+SET sql_mode='ANSI_QUOTES';
+
+CREATE TABLE """a" (i INT);
+SHOW CREATE TABLE """a";
+DROP TABLE """a";
+
+# to test quotes around keywords.. :
+
+SET sql_mode='';
+SET sql_quote_show_create=OFF;
+
+CREATE TABLE t1 (i INT);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE `table` (i INT);
+SHOW CREATE TABLE `table`;
+DROP TABLE `table`;
+
+SET sql_quote_show_create=ON;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 73e30e72a3c..c79c942979a 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -761,6 +761,8 @@ uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match);
uint check_word(TYPELIB *lib, const char *val, const char *end,
const char **end_of_word);
+bool is_keyword(const char *name, uint len);
+
/* sql_parse.cc */
void free_items(Item *item);
void cleanup_items(Item *item);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 70c69bb7389..b5988dac40c 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -181,6 +181,23 @@ static int find_keyword(LEX *lex, uint len, bool function)
return 0;
}
+/*
+ Check if name is a keyword
+
+ SYNOPSIS
+ is_keyword()
+ name checked name
+ len length of checked name
+
+ RETURN VALUES
+ 0 name is a keyword
+ 1 name isn't a keyword
+*/
+
+bool is_keyword(const char *name, uint len)
+{
+ return get_hash_symbol(name,len,0)!=0;
+}
/* make a copy of token before ptr and set yytoklen */
@@ -427,7 +444,6 @@ inline static uint int_token(const char *str,uint length)
return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
}
-
/*
yylex remember the following states from the following yylex()
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 4da2522bd3f..f076e2fe802 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1085,8 +1085,7 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
DBUG_RETURN(0);
}
-/* possible TODO: call find_keyword() from sql_lex.cc here */
-static bool require_quotes(const char *name, uint length)
+static inline const char *require_quotes(const char *name, uint length)
{
uint i, d, c;
for (i=0; i<length; i+=d)
@@ -1094,7 +1093,37 @@ static bool require_quotes(const char *name, uint length)
c=((uchar *)name)[i];
d=my_mbcharlen(system_charset_info, c);
if (d==1 && !system_charset_info->ident_map[c])
- return 1;
+ return name+i;
+ }
+ return 0;
+}
+
+/*
+ Looking for char in multibyte string
+
+ SYNOPSIS
+ look_for_char()
+ name string for looking at
+ length length of name
+ q '\'' or '\"' for looking for
+
+ RETURN VALUES
+ # pointer to found char in string
+ 0 string doesn't contain required char
+*/
+
+static inline const char *look_for_char(const char *name,
+ uint length, char q)
+{
+ const char *cur= name;
+ const char *end= cur+length;
+ uint symbol_length;
+ for (; cur<end; cur+= symbol_length)
+ {
+ char c= *cur;
+ symbol_length= my_mbcharlen(system_charset_info, c);
+ if (symbol_length==1 && c==q)
+ return cur;
}
return 0;
}
@@ -1103,21 +1132,52 @@ void
append_identifier(THD *thd, String *packet, const char *name, uint length)
{
char qtype;
+ uint part_len;
+ const char *qplace;
if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
qtype= '\"';
else
qtype= '`';
- if ((thd->options & OPTION_QUOTE_SHOW_CREATE) ||
- require_quotes(name, length))
+ if (is_keyword(name,length))
{
- packet->append(&qtype, 1);
+ packet->append(&qtype, 1, system_charset_info);
packet->append(name, length, system_charset_info);
- packet->append(&qtype, 1);
+ packet->append(&qtype, 1, system_charset_info);
}
else
{
- packet->append(name, length, system_charset_info);
+ if (!(qplace= require_quotes(name, length)))
+ {
+ if (!(thd->options & OPTION_QUOTE_SHOW_CREATE))
+ packet->append(name, length, system_charset_info);
+ else
+ {
+ packet->append(&qtype, 1, system_charset_info);
+ packet->append(name, length, system_charset_info);
+ packet->append(&qtype, 1, system_charset_info);
+ }
+ }
+ else
+ {
+ packet->shrink(packet->length()+length+2);
+ packet->append(&qtype, 1, system_charset_info);
+ if (*qplace != qtype)
+ qplace= look_for_char(qplace+1,length-(qplace-name)-1,qtype);
+ while (qplace)
+ {
+ if ((part_len= qplace-name))
+ {
+ packet->append(name, part_len, system_charset_info);
+ length-= part_len;
+ }
+ packet->append(qplace, 1, system_charset_info);
+ name= qplace;
+ qplace= look_for_char(name+1,length-1,qtype);
+ }
+ packet->append(name, length, system_charset_info);
+ packet->append(&qtype, 1, system_charset_info);
+ }
}
}