I am new to Golang (but not on HANA), and I am trying to test out the go-hdb to pull out data from TCURR table (from HANA DB SPS6). From what I understand is in that table, UKURS, FFACT, and TFACT are all Decimals in HANA DB. However when retrieving from Go, which I tried fetch using row.Scan to Float64 like this:
var mandt, kurst, fcurr, tcurr, gdatu, datum string
var ukurs float64
var ffact, tfact float64
if err := rows.Scan(&mandt, &kurst, &fcurr, &tcurr, &gdatu, &ukurs, &ffact, &tfact, &datum); err != nil {
log.Fatal(err)
}
But alas, getting error like this
2016/08/18 10:18:31 sql: Scan error on column index 5: converting driver.Value type []uint8 ("@\xe2\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0060") to a float64: invalid syntax
I try to read and understand the error it looks like needs uint8 data type (or byte), however, I am stuck with how to convert those uint8/byte into string.
Is there anyone have this problem before and how to getting decimal data and displayed it properly (ie print them into console)?
After to look and understand the driver package a while, I found out there is a function that actually answered my question. The function is reside within decimal.go
with function name decodeDecimal()
. Due to it is used by internal only, I copy the source code and paste to my code.
The code is something like this:
var mandt, kurst, fcurr, tcurr, gdatu, datum string
var ukurs, ffact, tfact []byte
if err := rows.Scan(&mandt, &kurst, &fcurr, &tcurr, &gdatu, &ukurs, &ffact, &tfact, &datum); err != nil {
WriteMsg("SCAN")
log.Fatal(err)
}
var bi big.Int
var z float64
var neg bool
var i int
var record []string
record = append(record, mandt)
record = append(record, kurst)
record = append(record, fcurr)
record = append(record, tcurr)
record = append(record, gdatu)
// ukurs
neg, i = decodeDecimal(ukurs, &bi)
z = BigIntToFloat(neg, &bi, i)
record = append(record, fmt.Sprintf("%.4f", z))
// ffact
neg, i = decodeDecimal(ffact, &bi)
z = BigIntToFloat(neg, &bi, i)
record = append(record, fmt.Sprintf("%.4f", z))
// tfact
neg, i = decodeDecimal(tfact, &bi)
z = BigIntToFloat(neg, &bi, i)
record = append(record, fmt.Sprintf("%.4f", z))
record = append(record, datum)
Function of decodeDecimal()
func decodeDecimal(b []byte, m *big.Int) (bool, int) {
//bigint word size (*--> src/pkg/math/big/arith.go)
const (
dec128Bias = 6176
// Compute the size _S of a Word in bytes.
_m = ^big.Word(0)
_logS = _m>>8&1 + _m>>16&1 + _m>>32&1
_S = 1 << _logS
)
neg := (b[15] & 0x80) != 0
exp := int((((uint16(b[15])<<8)|uint16(b[14]))<<1)>>2) - dec128Bias
b14 := b[14] // save b[14]
b[14] &= 0x01 // keep the mantissa bit (rest: sign and exp)
//most significand byte
msb := 14
for msb > 0 {
if b[msb] != 0 {
break
}
msb--
}
//calc number of words
numWords := (msb / _S) + 1
w := make([]big.Word, numWords)
k := numWords - 1
d := big.Word(0)
for i := msb; i >= 0; i-- {
d |= big.Word(b[i])
if k*_S == i {
w[k] = d
k--
d = 0
}
d <<= 8
}
b[14] = b14 // restore b[14]
m.SetBits(w)
return neg, exp
}
Function BigIntToFloat()
func BigIntToFloat(sign bool, m *big.Int, exp int) float64 {
var neg int64
if sign {
neg = -1
} else {
neg = 1
}
return float64(neg*m.Int64()) * math.Pow10(exp)
}