Skip to content

Commit

Permalink
ddl, util/types: make converter correctly convert string to hex or bi…
Browse files Browse the repository at this point in the history
…t. (#3115)
  • Loading branch information
bobotu authored and shenli committed Apr 25, 2017
1 parent 7699d3f commit 5c707ec
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 3 deletions.
7 changes: 7 additions & 0 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package ddl

import (
"fmt"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -353,9 +354,15 @@ func getDefaultValue(ctx context.Context, c *ast.ColumnOption, tp byte, fsp int)
if err != nil {
return nil, errors.Trace(err)
}

if v.IsNull() {
return nil, nil
}

if v.Kind() == types.KindMysqlHex {
return strconv.FormatInt(v.GetMysqlHex().Value, 10), nil
}

return v.ToString()
}

Expand Down
18 changes: 18 additions & 0 deletions ddl/ddl_db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1093,3 +1093,21 @@ out:
expected := fmt.Sprintf("%d %d", updateCnt, 3)
s.tk.MustQuery("select c2, c3 from tnn where c1 = 99").Check(testkit.Rows(expected))
}

func (s *testDBSuite) TestIssue2858And2717(c *C) {
defer testleak.AfterTest(c)()
s.tk = testkit.NewTestKit(c, s.store)
s.tk.MustExec("use " + s.schemaName)

s.tk.MustExec("create table t_issue_2858_bit (a bit(64) default b'0')")
s.tk.MustExec("insert into t_issue_2858_bit value ()")
s.tk.MustExec(`insert into t_issue_2858_bit values (100), ('10'), ('\0')`)
s.tk.MustQuery("select a+0 from t_issue_2858_bit").Check([][]interface{}{{0}, {100}, {0x3130}, {0}})
s.tk.MustExec(`alter table t_issue_2858_bit alter column a set default '\0'`)

s.tk.MustExec("create table t_issue_2858_hex (a int default 0x123)")
s.tk.MustExec("insert into t_issue_2858_hex value ()")
s.tk.MustExec("insert into t_issue_2858_hex values (123), (0x321)")
s.tk.MustQuery("select a from t_issue_2858_hex").Check([][]interface{}{{0x123}, {123}, {0x321}})
s.tk.MustExec(`alter table t_issue_2858_hex alter column a set default 0x321`)
}
31 changes: 31 additions & 0 deletions util/types/bit.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"strings"

"github.com/juju/errors"
"github.com/pingcap/tidb/util/hack"
)

// Bit is for mysql bit type.
Expand Down Expand Up @@ -104,3 +105,33 @@ func ParseBit(s string, width int) (Bit, error) {

return Bit{Value: n, Width: width}, nil
}

// ParseStringToBitValue parses the string for bit type into uint64.
func ParseStringToBitValue(s string, width int) (uint64, error) {
if len(s) == 0 {
return 0, errors.Errorf("invalid empty string for parsing bit value")
}

b := hack.Slice(s)
if width == UnspecifiedBitWidth {
width = len(b) * 8
}
if width == 0 {
width = MinBitWidth
}
if width < MinBitWidth || width > MaxBitWidth {
return 0, errors.Errorf("invalid display width for bit type, must in [1, 64], but %d", width)
}

var n uint64
l := len(b)
for i := range b {
n += uint64(b[l-i-1]) << uint(i*8)
}

if n > (uint64(1)<<uint64(width))-1 {
return 0, errors.Errorf("bit %s is too long for width %d", s, width)
}

return n, nil
}
4 changes: 4 additions & 0 deletions util/types/bit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ func (s *testBitSuite) TestBit(c *C) {
c.Assert(b.ToNumber(), Equals, float64(t.Number))
c.Assert(b.String(), Equals, t.String)
c.Assert(b.ToString(), Equals, t.BitString)

n, err := ParseStringToBitValue(t.BitString, t.Width)
c.Assert(err, IsNil)
c.Assert(n, Equals, uint64(t.Number))
}

tblErr := []struct {
Expand Down
5 changes: 3 additions & 2 deletions util/types/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,12 @@ func (s *testTypeConvertSuite) TestConvertType(c *C) {

// For TypeBit
ft = NewFieldType(mysql.TypeBit)
ft.Flen = 8
ft.Flen = 24
v, err = Convert("100", ft)
c.Assert(err, IsNil)
c.Assert(v, Equals, Bit{Value: 100, Width: 8})
c.Assert(v, Equals, Bit{Value: 3223600, Width: 24})

ft.Flen = 8
v, err = Convert(Hex{Value: 100}, ft)
c.Assert(err, IsNil)
c.Assert(v, Equals, Bit{Value: 100, Width: 8})
Expand Down
12 changes: 11 additions & 1 deletion util/types/datum.go
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,17 @@ func (d *Datum) convertToMysqlYear(sc *variable.StatementContext, target *FieldT
}

func (d *Datum) convertToMysqlBit(sc *variable.StatementContext, target *FieldType) (Datum, error) {
x, err := d.convertToUint(sc, target)
var (
x Datum
err error
)
if d.Kind() == KindString {
var n uint64
n, err = ParseStringToBitValue(d.GetString(), target.Flen)
x = NewUintDatum(n)
} else {
x, err = d.convertToUint(sc, target)
}
if err != nil {
return x, errors.Trace(err)
}
Expand Down

0 comments on commit 5c707ec

Please sign in to comment.