Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support decimal or custom value bind #1177

Open
RelicOfTesla opened this issue Dec 3, 2020 · 0 comments
Open

Support decimal or custom value bind #1177

RelicOfTesla opened this issue Dec 3, 2020 · 0 comments

Comments

@RelicOfTesla
Copy link

RelicOfTesla commented Dec 3, 2020

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?

@RelicOfTesla RelicOfTesla changed the title Support decimal value query Support decimal or custom value bind May 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant