Skip to content

Commit

Permalink
executor: properly escape backquotes in identifiers in SHOW CREATE TA…
Browse files Browse the repository at this point in the history
…BLE (#8302)
  • Loading branch information
kennytm committed Nov 14, 2018
1 parent ff0c436 commit 9b0ab9d
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 7 deletions.
32 changes: 25 additions & 7 deletions executor/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,19 +462,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))
Expand Down Expand Up @@ -530,7 +546,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 {
Expand All @@ -548,14 +564,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))
}
Expand Down Expand Up @@ -623,8 +639,10 @@ func (e *ShowExec) fetchShowCreateDatabase() error {
return infoschema.ErrDatabaseNotExists.GenByArgs(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)
}
Expand Down
29 changes: 29 additions & 0 deletions executor/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,3 +525,32 @@ func (s *testSuite) TestShowTableStatus(c *C) {
c.Assert(row.GetString(3), Equals, "Compact")
}
}

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=utf8 COLLATE=utf8_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=utf8 COLLATE=utf8_bin",
))

tk.MustExec("rename table \"t`abl\"\"e\" to t")
tk.MustExec("set sql_mode=@old_sql_mode")
}

0 comments on commit 9b0ab9d

Please sign in to comment.