Open
Description
string stm query only support float 10^-16...not support full decimal value..
// ok
select (0.2676120186162537123456789+0.267612018616253712345678912312312312312312312312312123) as field22
// fail
// select (0.2676120186162537123456789+'0.267612018616253712345678912312312312312312312312312123') as field22
// tip: quote the number to string number, will lose accracy
// fail
select (0.2676120186162537123456789+?) as field22
arg1:="0.267612018616253712345678912312312312312312312312312123"
//
Same with update,insert and more sql command...
Because field type is string , not NewDecimal type or good type when send packet stm binary
so... maybe add a draft proposal golang/go#30870 DecimalDecompose type to write custom field type value to mysql stm.
sample:
type Decimal struct {
str string
}
func NewDecimal(str string) Decimal {
return Decimal{str: str}
}
const fieldTypeNewDecimal = 246
func (x Decimal) Value() (driver.Value, error) {
return sqlValueDecompose{Type: fieldTypeNewDecimal, Data: []byte(x.str)}, nil
}
///
type sqlValueDecompose struct {
Type byte
Data []byte
}
// implement database/sql convertAssignRows=>decimalDecompose
// var _ sql.decimal = (*sqlValueDecompose)(nil)
// var _ sql.decimalDecompose = (*sqlValueDecompose)(nil)
func (x sqlValueDecompose) Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) {
return x.Type, false, x.Data, 0
}
///
func main() {
db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/test1")
require.NoError(t, err)
verifyTest := func(want1, sqlCmd string, args ...any) {
rows, err := db.Query(sqlCmd, args...)
require.NoError(t, err)
defer rows.Close()
require.True(t, rows.Next())
cb := sql.RawBytes{}
err = rows.Scan(&cb)
require.NoError(t, err)
str := string(cb)
require.Equal(t, str, want1)
}
//num1 := "0.11111222223333344444"
//num2 := "0.111112222233333444445555566666" // mysql max decimal(65,30)
//sum1 := "0.222224444466666888885555566666" // mysql max decimal(65,30)
num1 := "0.2676120186162537123456789"
num2 := "0.267612018616253712345678912312312312312312312312312123"
sum1 := "0.535224037232507424691357812312312312312312312312312123"
//verifyTest(sum1, "select ("+num1+"+?) as sum1", num2) // bad
//verifyTest(sum1, "select ("+num1+"+?) as sum1", string(num2)) // bad
//verifyTest(sum1, "select ("+num1+"+?) as sum1", []byte(num2)) // bad
//verifyTest(sum1, "select ("+num1+"+?) as sum1", sql.RawBytes(num2)) // bad
//verifyTest(sum1, "select ("+num1+"+"+num2+") as sum1") // good
verifyTest(sum1, "select ("+num1+"+?) as sum1", NewDecimal(num2)) // will good
}
/////////////
source : packets.go
func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error
//.....
for i, arg := range args {
//.....
switch v := arg.(type) {
case int64: // ...
case uint64: // ...
case DecimalDecompose:
tp, _, cb, _ := v.Decompose(nil)
err = func() error {
v := cb
paramTypes[i+i] = byte(tp)
paramTypes[i+i+1] = 0x00
if len(v) < longDataSize {
paramValues = appendLengthEncodedInteger(paramValues,
uint64(len(v)),
)
paramValues = append(paramValues, v...)
} else {
if err := stmt.writeCommandLongData(i, []byte(v)); err != nil {
return err
}
}
return nil
}()
if err != nil {
return err
}
// .......
//......
//
// type DecimalDecompose = sql.DecimalDecompose // sql.decimalDecompose
type DecimalDecompose interface {
// sql.decimalDecompose
Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32)
}
Or use some custom method?
Metadata
Metadata
Assignees
Labels
No labels