diff --git a/executor/show.go b/executor/show.go index e0679d0b82197..0893d8213d82f 100644 --- a/executor/show.go +++ b/executor/show.go @@ -507,19 +507,35 @@ func getDefaultCollate(charsetName string) string { return "" } +// escape the identifier for pretty-printing. +// For instance, the identifier "foo `bar`" will become "`foo ``bar```". +// The sqlMode controls whether to escape with backquotes (`) or double quotes +// (`"`) depending on whether mysql.ModeANSIQuotes is enabled. +func escape(cis model.CIStr, sqlMode mysql.SQLMode) string { + var quote string + if sqlMode&mysql.ModeANSIQuotes != 0 { + quote = `"` + } else { + quote = "`" + } + return quote + strings.Replace(cis.O, quote, quote+quote, -1) + quote +} + func (e *ShowExec) fetchShowCreateTable() error { tb, err := e.getTable() if err != nil { return errors.Trace(err) } + sqlMode := e.ctx.GetSessionVars().SQLMode + // TODO: let the result more like MySQL. var buf bytes.Buffer - buf.WriteString(fmt.Sprintf("CREATE TABLE `%s` (\n", tb.Meta().Name.O)) + buf.WriteString(fmt.Sprintf("CREATE TABLE %s (\n", escape(tb.Meta().Name, sqlMode))) var pkCol *table.Column var hasAutoIncID bool for i, col := range tb.Cols() { - buf.WriteString(fmt.Sprintf(" `%s` %s", col.Name.O, col.GetTypeDesc())) + buf.WriteString(fmt.Sprintf(" %s %s", escape(col.Name, sqlMode), col.GetTypeDesc())) if col.IsGenerated() { // It's a generated column. buf.WriteString(fmt.Sprintf(" GENERATED ALWAYS AS (%s)", col.GeneratedExprString)) @@ -576,7 +592,7 @@ func (e *ShowExec) fetchShowCreateTable() error { if pkCol != nil { // If PKIsHanle, pk info is not in tb.Indices(). We should handle it here. buf.WriteString(",\n") - buf.WriteString(fmt.Sprintf(" PRIMARY KEY (`%s`)", pkCol.Name.O)) + buf.WriteString(fmt.Sprintf(" PRIMARY KEY (%s)", escape(pkCol.Name, sqlMode))) } if len(tb.Indices()) > 0 { @@ -594,14 +610,14 @@ func (e *ShowExec) fetchShowCreateTable() error { if idxInfo.Primary { buf.WriteString(" PRIMARY KEY ") } else if idxInfo.Unique { - buf.WriteString(fmt.Sprintf(" UNIQUE KEY `%s` ", idxInfo.Name.O)) + buf.WriteString(fmt.Sprintf(" UNIQUE KEY %s ", escape(idxInfo.Name, sqlMode))) } else { - buf.WriteString(fmt.Sprintf(" KEY `%s` ", idxInfo.Name.O)) + buf.WriteString(fmt.Sprintf(" KEY %s ", escape(idxInfo.Name, sqlMode))) } cols := make([]string, 0, len(idxInfo.Columns)) for _, c := range idxInfo.Columns { - colInfo := fmt.Sprintf("`%s`", c.Name.String()) + colInfo := escape(c.Name, sqlMode) if c.Length != types.UnspecifiedLength { colInfo = fmt.Sprintf("%s(%s)", colInfo, strconv.Itoa(c.Length)) } @@ -703,8 +719,10 @@ func (e *ShowExec) fetchShowCreateDatabase() error { return infoschema.ErrDatabaseNotExists.GenWithStackByArgs(e.DBName.O) } + sqlMode := e.ctx.GetSessionVars().SQLMode + var buf bytes.Buffer - fmt.Fprintf(&buf, "CREATE DATABASE `%s`", db.Name.O) + fmt.Fprintf(&buf, "CREATE DATABASE %s", escape(db.Name, sqlMode)) if s := db.Charset; len(s) > 0 { fmt.Fprintf(&buf, " /* !40100 DEFAULT CHARACTER SET %s */", s) } diff --git a/executor/show_test.go b/executor/show_test.go index ee9ef7f9bb81d..0a8761d12e273 100644 --- a/executor/show_test.go +++ b/executor/show_test.go @@ -694,3 +694,32 @@ func (s *testSuite) TestShowSlow(c *C) { tk.MustQuery(`admin show slow top internal 3`) tk.MustQuery(`admin show slow top all 3`) } + +func (s *testSuite) TestShowEscape(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists `t``abl\"e`") + tk.MustExec("create table `t``abl\"e`(`c``olum\"n` int(11) primary key)") + tk.MustQuery("show create table `t``abl\"e`").Check(testutil.RowsWithSep("|", + ""+ + "t`abl\"e CREATE TABLE `t``abl\"e` (\n"+ + " `c``olum\"n` int(11) NOT NULL,\n"+ + " PRIMARY KEY (`c``olum\"n`)\n"+ + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin", + )) + + // ANSI_QUOTES will change the SHOW output + tk.MustExec("set @old_sql_mode=@@sql_mode") + tk.MustExec("set sql_mode=ansi_quotes") + tk.MustQuery("show create table \"t`abl\"\"e\"").Check(testutil.RowsWithSep("|", + ""+ + "t`abl\"e CREATE TABLE \"t`abl\"\"e\" (\n"+ + " \"c`olum\"\"n\" int(11) NOT NULL,\n"+ + " PRIMARY KEY (\"c`olum\"\"n\")\n"+ + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin", + )) + + tk.MustExec("rename table \"t`abl\"\"e\" to t") + tk.MustExec("set sql_mode=@old_sql_mode") +}