Skip to content

Commit

Permalink
executor: fix the issue that SELECT ... INTO OUTFILE returns runtim…
Browse files Browse the repository at this point in the history
…e error (#19438)

* executor: fix the issue that `SELECT ... INTO OUTFILE` returns runtime error

* add more tests

Co-authored-by: ti-srebot <66930949+ti-srebot@users.noreply.github.com>
  • Loading branch information
qw4990 and ti-srebot authored Sep 1, 2020
1 parent 7690e29 commit a5839ab
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 10 deletions.
25 changes: 15 additions & 10 deletions executor/select_into.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,26 +121,31 @@ func (s *SelectIntoExec) dumpToOutfile() error {
(encloseFlag && encloseOpt && s.considerEncloseOpt(et)) {
s.lineBuf = append(s.lineBuf, encloseByte)
}
switch col.GetType().EvalType() {
case types.ETInt:
switch col.GetType().Tp {
case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong:
s.lineBuf = strconv.AppendInt(s.lineBuf, row.GetInt64(j), 10)
case mysql.TypeLonglong:
if mysql.HasUnsignedFlag(col.GetType().Flag) {
s.lineBuf = strconv.AppendUint(s.lineBuf, row.GetUint64(j), 10)
} else {
s.lineBuf = strconv.AppendInt(s.lineBuf, row.GetInt64(j), 10)
}
case types.ETReal:
case mysql.TypeFloat, mysql.TypeDouble:
s.realBuf, s.lineBuf = DumpRealOutfile(s.realBuf, s.lineBuf, row.GetFloat64(j), col.RetType)
case types.ETDecimal:
case mysql.TypeNewDecimal:
s.lineBuf = append(s.lineBuf, row.GetMyDecimal(j).String()...)
case types.ETString:
case mysql.TypeString, mysql.TypeVarString, mysql.TypeVarchar, mysql.TypeBit,
mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob, mysql.TypeBlob:
s.lineBuf = append(s.lineBuf, row.GetBytes(j)...)
case types.ETDatetime:
case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp:
s.lineBuf = append(s.lineBuf, row.GetTime(j).String()...)
case types.ETTimestamp:
s.lineBuf = append(s.lineBuf, row.GetTime(j).String()...)
case types.ETDuration:
case mysql.TypeDuration:
s.lineBuf = append(s.lineBuf, row.GetDuration(j, col.GetType().Decimal).String()...)
case types.ETJson:
case mysql.TypeEnum:
s.lineBuf = append(s.lineBuf, row.GetEnum(j).String()...)
case mysql.TypeSet:
s.lineBuf = append(s.lineBuf, row.GetSet(j).String()...)
case mysql.TypeJSON:
s.lineBuf = append(s.lineBuf, row.GetJSON(j).String()...)
}
if (encloseFlag && !encloseOpt) ||
Expand Down
35 changes: 35 additions & 0 deletions executor/select_into_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,41 @@ func (s *testSuite1) TestSelectIntoFileExists(c *C) {
c.Assert(strings.Contains(err.Error(), outfile), IsTrue)
}

func (s *testSuite1) TestSelectIntoOutfileTypes(c *C) {
tmpDir := os.TempDir()
outfile := filepath.Join(tmpDir, "select-into-outfile.data")
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")

tk.MustExec("drop table if exists t")
tk.MustExec("CREATE TABLE `t` ( `a` bit(10) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;")
tk.MustExec("INSERT INTO `t` VALUES (_binary '\\0'), (_binary '\\1'), (_binary '\\2'), (_binary '\\3');")
tk.MustExec(fmt.Sprintf("SELECT * FROM t INTO OUTFILE %q", outfile))
cmpAndRm("\x00\x00\n\x001\n\x002\n\x003\n", outfile, c)

tk.MustExec("drop table if exists t")
tk.MustExec("CREATE TABLE `t` (col ENUM ('value1','value2','value3'));")
tk.MustExec("INSERT INTO t values ('value1'), ('value2');")
tk.MustExec(fmt.Sprintf("SELECT * FROM t INTO OUTFILE %q", outfile))
cmpAndRm("value1\nvalue2\n", outfile, c)

tk.MustExec("drop table if exists t")
tk.MustExec("create table t ( v json);")
tk.MustExec(`insert into t values ('{"id": 1, "name": "aaa"}'), ('{"id": 2, "name": "xxx"}');`)
tk.MustExec(fmt.Sprintf("SELECT * FROM t INTO OUTFILE %q", outfile))
cmpAndRm(`{"id": 1, "name": "aaa"}
{"id": 2, "name": "xxx"}
`, outfile, c)

tk.MustExec("drop table if exists t")
tk.MustExec("create table t (v tinyint unsigned)")
tk.MustExec("insert into t values (0), (1)")
tk.MustExec(fmt.Sprintf("SELECT * FROM t INTO OUTFILE %q", outfile))
cmpAndRm(`0
1
`, outfile, c)
}

func (s *testSuite1) TestSelectIntoOutfileFromTable(c *C) {
tmpDir := os.TempDir()
outfile := filepath.Join(tmpDir, "TestSelectIntoOutfileFromTable.data")
Expand Down

0 comments on commit a5839ab

Please sign in to comment.