Skip to content

Commit 1ca1a85

Browse files
xelavopelkKlepov AlexCopilotkprokopenko
authored
fix fill decimal (#1875)
Co-authored-by: Klepov Alex <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: Konstantin Prokopenko <[email protected]>
1 parent 0539319 commit 1ca1a85

File tree

4 files changed

+167
-1
lines changed

4 files changed

+167
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
* Fixed scan a column of type `Decimal(precision,scale)` into a struct field of type `types.Decimal{}` using `ScanStruct()`
2+
* Fixed race in integration test `TestTopicWriterLogMessagesWithoutData`
13
* Fixed traces handling in `topic.Reader`
2-
* Fixed race in integration test `TestTopicWriterLogMessagesWithoutData`
34

45
## v3.117.0
56
* Fixed `conn/pool.Get()` behaviour for YDB databases with public IPs. Bug was introduced in v3.116.2

internal/query/scanner/struct_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package scanner
22

33
import (
4+
"math/big"
45
"reflect"
56
"testing"
67
"time"
78

89
"github.com/stretchr/testify/require"
910
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
1011

12+
"github.com/ydb-platform/ydb-go-sdk/v3/internal/decimal"
1113
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
1214
"github.com/ydb-platform/ydb-go-sdk/v3/pkg/xtest"
15+
ttypes "github.com/ydb-platform/ydb-go-sdk/v3/table/types"
1316
)
1417

1518
func TestFieldName(t *testing.T) {
@@ -909,3 +912,96 @@ func TestScannerStructOrdering(t *testing.T) {
909912
require.Equal(t, "B", row.B)
910913
require.Equal(t, "C", row.C)
911914
}
915+
916+
func TestScannerDecimal(t *testing.T) {
917+
scanner := Struct(NewData(
918+
[]*Ydb.Column{
919+
{
920+
Name: "A",
921+
Type: &Ydb.Type{
922+
Type: &Ydb.Type_DecimalType{
923+
DecimalType: &Ydb.DecimalType{Scale: 9, Precision: 22},
924+
},
925+
},
926+
},
927+
},
928+
[]*Ydb.Value{
929+
{
930+
Value: &Ydb.Value_Low_128{
931+
Low_128: 10200000000,
932+
},
933+
},
934+
},
935+
))
936+
var row struct {
937+
A ttypes.Decimal
938+
}
939+
expected := ttypes.Decimal{Bytes: decimal.BigIntToByte(big.NewInt(10200000000), 22, 9), Precision: 22, Scale: 9}
940+
err := scanner.ScanStruct(&row)
941+
require.NoError(t, err)
942+
require.Equal(t, expected, row.A)
943+
}
944+
945+
func TestScannerDecimalNegative(t *testing.T) {
946+
scanner := Struct(NewData(
947+
[]*Ydb.Column{
948+
{
949+
Name: "A",
950+
Type: &Ydb.Type{
951+
Type: &Ydb.Type_DecimalType{
952+
DecimalType: &Ydb.DecimalType{Scale: 9, Precision: 22},
953+
},
954+
},
955+
},
956+
},
957+
[]*Ydb.Value{
958+
{
959+
Value: &Ydb.Value_Low_128{
960+
Low_128: 18446744071704551616,
961+
},
962+
High_128: 0xffffffffffffffff,
963+
},
964+
},
965+
))
966+
var row struct {
967+
A ttypes.Decimal
968+
}
969+
expected := ttypes.Decimal{Bytes: decimal.BigIntToByte(big.NewInt(-2005000000), 22, 9), Precision: 22, Scale: 9}
970+
err := scanner.ScanStruct(&row)
971+
require.NoError(t, err)
972+
require.Equal(t, expected, row.A)
973+
}
974+
975+
func TestScannerDecimalBigDecimal(t *testing.T) {
976+
scanner := Struct(NewData(
977+
[]*Ydb.Column{
978+
{
979+
Name: "A",
980+
Type: &Ydb.Type{
981+
Type: &Ydb.Type_DecimalType{
982+
DecimalType: &Ydb.DecimalType{Scale: 9, Precision: 22},
983+
},
984+
},
985+
},
986+
},
987+
[]*Ydb.Value{
988+
{
989+
// val: 1844674407370955.1615
990+
Value: &Ydb.Value_Low_128{
991+
Low_128: 3136633892082024448,
992+
},
993+
High_128: 5421010862427522,
994+
},
995+
},
996+
))
997+
var row struct {
998+
A ttypes.Decimal
999+
}
1000+
expectedVal := decimal.Decimal{
1001+
Bytes: [16]byte{0, 19, 66, 97, 114, 199, 77, 130, 43, 135, 143, 232, 0, 0, 0, 0},
1002+
Precision: 22, Scale: 9,
1003+
}
1004+
err := scanner.ScanStruct(&row)
1005+
require.NoError(t, err)
1006+
require.Equal(t, expectedVal, row.A)
1007+
}

internal/value/value.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,11 @@ func (v *decimalValue) castTo(dst any) error {
611611
case *driver.Value:
612612
*dstValue = v
613613

614+
return nil
615+
case *decimal.Decimal:
616+
decVal := decimal.Decimal{Bytes: v.value, Precision: v.Precision(), Scale: v.Scale()}
617+
*dstValue = decVal
618+
614619
return nil
615620
default:
616621
return xerrors.WithStackTrace(fmt.Errorf(

tests/integration/query_execute_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"errors"
1010
"fmt"
1111
"io"
12+
"math/big"
1213
"math/rand"
1314
"os"
1415
"path"
@@ -20,6 +21,7 @@ import (
2021
"github.com/stretchr/testify/require"
2122

2223
"github.com/ydb-platform/ydb-go-sdk/v3"
24+
"github.com/ydb-platform/ydb-go-sdk/v3/internal/decimal"
2325
"github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
2426
"github.com/ydb-platform/ydb-go-sdk/v3/internal/version"
2527
"github.com/ydb-platform/ydb-go-sdk/v3/log"
@@ -707,3 +709,65 @@ func TestQueryWideIntervalTypes(t *testing.T) {
707709
})
708710
}
709711
}
712+
713+
// https://github.com/ydb-platform/ydb-go-sdk/issues/1785
714+
func TestIssue1785FillDecimalFields(t *testing.T) {
715+
ctx, cancel := context.WithCancel(xtest.Context(t))
716+
defer cancel()
717+
db, err := ydb.Open(ctx,
718+
os.Getenv("YDB_CONNECTION_STRING"),
719+
ydb.WithAccessTokenCredentials(os.Getenv("YDB_ACCESS_TOKEN_CREDENTIALS")),
720+
ydb.WithTraceQuery(
721+
log.Query(
722+
log.Default(os.Stdout,
723+
log.WithLogQuery(),
724+
log.WithColoring(),
725+
log.WithMinLevel(log.INFO),
726+
),
727+
trace.QueryEvents,
728+
),
729+
),
730+
)
731+
require.NoError(t, err)
732+
t.Run("Query", func(t *testing.T) {
733+
type RowData struct {
734+
Id uint64 `sql:"id"`
735+
DecimalVal types.Decimal `sql:"dc"`
736+
}
737+
result, err := db.Query().Query(ctx, `
738+
SELECT id, dc
739+
FROM AS_TABLE(
740+
AsList(
741+
AsStruct(1u AS id, decimal("10.01",22,9) AS dc),
742+
AsStruct(2u AS id, decimal("-5.33",22,9) AS dc),
743+
AsStruct(3u AS id, decimal("1844674407370955.1615",22,9) AS dc)
744+
)
745+
);
746+
`,
747+
query.WithSyntax(query.SyntaxYQL),
748+
query.WithIdempotent(),
749+
)
750+
require.NoError(t, err)
751+
resultSet, err := result.NextResultSet(ctx)
752+
require.NoError(t, err)
753+
row, err := resultSet.NextRow(ctx)
754+
require.NoError(t, err)
755+
var rd RowData
756+
err = row.ScanStruct(&rd)
757+
require.NoError(t, err)
758+
require.EqualValues(t, uint64(1), rd.Id)
759+
require.EqualValues(t, types.Decimal{Bytes: decimal.BigIntToByte(big.NewInt(10010000000), 22, 9), Precision: 22, Scale: 9}, rd.DecimalVal)
760+
row, err = resultSet.NextRow(ctx)
761+
require.NoError(t, err)
762+
err = row.ScanStruct(&rd)
763+
require.NoError(t, err)
764+
require.EqualValues(t, uint64(2), rd.Id)
765+
require.EqualValues(t, types.Decimal{Bytes: decimal.BigIntToByte(big.NewInt(-5330000000), 22, 9), Precision: 22, Scale: 9}, rd.DecimalVal)
766+
row, err = resultSet.NextRow(ctx)
767+
require.NoError(t, err)
768+
err = row.ScanStruct(&rd)
769+
require.NoError(t, err)
770+
expectedVal := types.Decimal{Bytes: [16]byte{0, 19, 66, 97, 114, 199, 77, 130, 43, 135, 143, 232, 0, 0, 0, 0}, Precision: 22, Scale: 9}
771+
require.EqualValues(t, expectedVal, rd.DecimalVal)
772+
})
773+
}

0 commit comments

Comments
 (0)