From c3b3b63f8a816f7d7ac54db4063561d704df4300 Mon Sep 17 00:00:00 2001 From: Johann Forster Date: Wed, 26 Jun 2019 14:59:24 +0200 Subject: [PATCH 1/3] added scan string type --- fields.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/fields.go b/fields.go index e1e2ece4b..14fb73f7e 100644 --- a/fields.go +++ b/fields.go @@ -111,6 +111,7 @@ var ( scanTypeUint16 = reflect.TypeOf(uint16(0)) scanTypeUint32 = reflect.TypeOf(uint32(0)) scanTypeUint64 = reflect.TypeOf(uint64(0)) + scanTypeString = reflect.TypeOf(string("")) scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{}) scanTypeUnknown = reflect.TypeOf(new(interface{})) ) @@ -175,11 +176,18 @@ func (mf *mysqlField) scanType() reflect.Type { } return scanTypeNullFloat - case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, - fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB, - fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, - fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON, - fieldTypeTime: + case fieldTypeVarChar, fieldTypeString, fieldTypeVarString: + return scanTypeString + + case fieldTypeTinyBLOB, fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB: + if mf.charSet == collations[defaultCollation] { + return scanTypeString + } + fallthrough + + case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeBit, + fieldTypeEnum, fieldTypeSet, + fieldTypeGeometry, fieldTypeJSON, fieldTypeTime: return scanTypeRawBytes case fieldTypeDate, fieldTypeNewDate, From e209d78007ae6e70ebfebcf2da8a5109ee59f131 Mon Sep 17 00:00:00 2001 From: j-forster Date: Thu, 27 Jun 2019 17:24:08 +0200 Subject: [PATCH 2/3] added scantype string Added scanTypeString and scanTypeNullString. --- driver_test.go | 15 +++++++++------ fields.go | 48 ++++++++++++++++++++++++++---------------------- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/driver_test.go b/driver_test.go index 3dee1bab2..e6c7f83a0 100644 --- a/driver_test.go +++ b/driver_test.go @@ -2733,6 +2733,9 @@ func TestRowsColumnTypes(t *testing.T) { rb0pad4 := sql.RawBytes("0\x00\x00\x00") // BINARY right-pads values with 0x00 rbx0 := sql.RawBytes("\x00") rbx42 := sql.RawBytes("\x42") + s0 := sql.NullString{String: "0", Valid: true} + sNULL := sql.NullString{String: "", Valid: false} + sTest := sql.NullString{String: "Test", Valid: true} var columns = []struct { name string @@ -2771,18 +2774,18 @@ func TestRowsColumnTypes(t *testing.T) { {"decimal2null", "DECIMAL(8,4)", "DECIMAL", scanTypeRawBytes, true, 8, 4, [3]string{"0", "NULL", "1234.123456"}, [3]interface{}{sql.RawBytes("0.0000"), rbNULL, sql.RawBytes("1234.1235")}}, {"decimal3", "DECIMAL(5,0) NOT NULL", "DECIMAL", scanTypeRawBytes, false, 5, 0, [3]string{"0", "13.37", "-12345.123456"}, [3]interface{}{rb0, sql.RawBytes("13"), sql.RawBytes("-12345")}}, {"decimal3null", "DECIMAL(5,0)", "DECIMAL", scanTypeRawBytes, true, 5, 0, [3]string{"0", "NULL", "-12345.123456"}, [3]interface{}{rb0, rbNULL, sql.RawBytes("-12345")}}, - {"char25null", "CHAR(25)", "CHAR", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, - {"varchar42", "VARCHAR(42) NOT NULL", "VARCHAR", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, + {"char25null", "CHAR(25)", "CHAR", scanTypeNullString, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{s0, sNULL, sTest}}, + {"varchar42", "VARCHAR(42) NOT NULL", "VARCHAR", scanTypeString, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{"0", "Test", "42"}}, {"binary4null", "BINARY(4)", "BINARY", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0pad4, rbNULL, rbTest}}, {"varbinary42", "VARBINARY(42) NOT NULL", "VARBINARY", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, {"tinyblobnull", "TINYBLOB", "BLOB", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, - {"tinytextnull", "TINYTEXT", "TEXT", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, + {"tinytextnull", "TINYTEXT", "TEXT", scanTypeNullString, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{s0, sNULL, sTest}}, {"blobnull", "BLOB", "BLOB", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, - {"textnull", "TEXT", "TEXT", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, + {"textnull", "TEXT", "TEXT", scanTypeNullString, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{s0, sNULL, sTest}}, {"mediumblob", "MEDIUMBLOB NOT NULL", "BLOB", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, - {"mediumtext", "MEDIUMTEXT NOT NULL", "TEXT", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, + {"mediumtext", "MEDIUMTEXT NOT NULL", "TEXT", scanTypeString, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{"0", "Test", "42"}}, {"longblob", "LONGBLOB NOT NULL", "BLOB", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, - {"longtext", "LONGTEXT NOT NULL", "TEXT", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, + {"longtext", "LONGTEXT NOT NULL", "TEXT", scanTypeString, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{"0", "Test", "42"}}, {"datetime", "DATETIME", "DATETIME", scanTypeNullTime, true, 0, 0, [3]string{"'2006-01-02 15:04:05'", "'2006-01-02 15:04:05.1'", "'2006-01-02 15:04:05.111111'"}, [3]interface{}{nt0, nt0, nt0}}, {"datetime2", "DATETIME(2)", "DATETIME", scanTypeNullTime, true, 2, 2, [3]string{"'2006-01-02 15:04:05'", "'2006-01-02 15:04:05.1'", "'2006-01-02 15:04:05.111111'"}, [3]interface{}{nt0, nt1, nt2}}, {"datetime6", "DATETIME(6)", "DATETIME", scanTypeNullTime, true, 6, 6, [3]string{"'2006-01-02 15:04:05'", "'2006-01-02 15:04:05.1'", "'2006-01-02 15:04:05.111111'"}, [3]interface{}{nt0, nt1, nt6}}, diff --git a/fields.go b/fields.go index 14fb73f7e..ad2207cb3 100644 --- a/fields.go +++ b/fields.go @@ -98,22 +98,23 @@ func (mf *mysqlField) typeDatabaseName() string { } var ( - scanTypeFloat32 = reflect.TypeOf(float32(0)) - scanTypeFloat64 = reflect.TypeOf(float64(0)) - scanTypeInt8 = reflect.TypeOf(int8(0)) - scanTypeInt16 = reflect.TypeOf(int16(0)) - scanTypeInt32 = reflect.TypeOf(int32(0)) - scanTypeInt64 = reflect.TypeOf(int64(0)) - scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{}) - scanTypeNullInt = reflect.TypeOf(sql.NullInt64{}) - scanTypeNullTime = reflect.TypeOf(NullTime{}) - scanTypeUint8 = reflect.TypeOf(uint8(0)) - scanTypeUint16 = reflect.TypeOf(uint16(0)) - scanTypeUint32 = reflect.TypeOf(uint32(0)) - scanTypeUint64 = reflect.TypeOf(uint64(0)) - scanTypeString = reflect.TypeOf(string("")) - scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{}) - scanTypeUnknown = reflect.TypeOf(new(interface{})) + scanTypeFloat32 = reflect.TypeOf(float32(0)) + scanTypeFloat64 = reflect.TypeOf(float64(0)) + scanTypeInt8 = reflect.TypeOf(int8(0)) + scanTypeInt16 = reflect.TypeOf(int16(0)) + scanTypeInt32 = reflect.TypeOf(int32(0)) + scanTypeInt64 = reflect.TypeOf(int64(0)) + scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{}) + scanTypeNullInt = reflect.TypeOf(sql.NullInt64{}) + scanTypeNullTime = reflect.TypeOf(NullTime{}) + scanTypeUint8 = reflect.TypeOf(uint8(0)) + scanTypeUint16 = reflect.TypeOf(uint16(0)) + scanTypeUint32 = reflect.TypeOf(uint32(0)) + scanTypeUint64 = reflect.TypeOf(uint64(0)) + scanTypeString = reflect.TypeOf(string("")) + scanTypeNullString = reflect.TypeOf(sql.NullString{}) + scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{}) + scanTypeUnknown = reflect.TypeOf(new(interface{})) ) type mysqlField struct { @@ -176,14 +177,17 @@ func (mf *mysqlField) scanType() reflect.Type { } return scanTypeNullFloat - case fieldTypeVarChar, fieldTypeString, fieldTypeVarString: - return scanTypeString - - case fieldTypeTinyBLOB, fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB: - if mf.charSet == collations[defaultCollation] { + case fieldTypeVarChar, fieldTypeString, fieldTypeVarString, fieldTypeTinyBLOB, + fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB: + // charsetnr == 63 means this column is binary. + // https://dev.mysql.com/doc/refman/8.0/en/c-api-data-structures.html + if mf.charSet == 63 { + return scanTypeRawBytes + } + if mf.flags&flagNotNULL != 0 { return scanTypeString } - fallthrough + return scanTypeNullString case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeBit, fieldTypeEnum, fieldTypeSet, From 52dcf21bd48649da199d0d1689b8a7b686eb5de8 Mon Sep 17 00:00:00 2001 From: Johann Forster Date: Fri, 28 Jun 2019 09:01:19 +0200 Subject: [PATCH 3/3] update authors --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index bfe74c4e1..4db002d97 100644 --- a/AUTHORS +++ b/AUTHORS @@ -45,6 +45,7 @@ Jeff Hodges Jeffrey Charles Jerome Meyer Jian Zhen +Johann Forster Joshua Prunier Julien Lefevre Julien Schmidt