Skip to content

Support decimal or custom value bind #1177

Open
@RelicOfTesla

Description

@RelicOfTesla

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.

#985 #986

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

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions