mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
Address the overflow issue with values outside the int64 range
This commit is contained in:
parent
d6caf34c02
commit
4bed1df101
2 changed files with 110 additions and 5 deletions
47
executor.go
47
executor.go
|
|
@ -4486,25 +4486,37 @@ func (s SignedRow) ToTable() (*pb.TableResponse, error) {
|
|||
|
||||
// ToRows implements the ToRowser interface.
|
||||
func (s SignedRow) ToRows(callback func(*pb.RowResponse) error) error {
|
||||
// TODO: address the overflow issue with values outside the int64 range
|
||||
|
||||
ci := []*pb.ColumnInfo{{Name: s.Field(), Datatype: "int64"}}
|
||||
negs := s.Neg.Columns()
|
||||
for i := len(negs) - 1; i >= 0; i-- {
|
||||
val, err := toNegInt64(negs[i])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "converting uint64 to int64 (negative)")
|
||||
}
|
||||
|
||||
if err := callback(&pb.RowResponse{
|
||||
Headers: ci,
|
||||
Columns: []*pb.ColumnResponse{
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: -1 * int64(negs[i])}},
|
||||
}}); err != nil {
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: val}},
|
||||
},
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "calling callback")
|
||||
}
|
||||
ci = nil
|
||||
}
|
||||
for _, id := range s.Pos.Columns() {
|
||||
val, err := toInt64(id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "converting uint64 to int64 (positive)")
|
||||
}
|
||||
|
||||
if err := callback(&pb.RowResponse{
|
||||
Headers: ci,
|
||||
Columns: []*pb.ColumnResponse{
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: int64(id)}},
|
||||
}}); err != nil {
|
||||
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Int64Val{Int64Val: val}},
|
||||
},
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "calling callback")
|
||||
}
|
||||
ci = nil
|
||||
|
|
@ -4512,6 +4524,31 @@ func (s SignedRow) ToRows(callback func(*pb.RowResponse) error) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func toNegInt64(n uint64) (int64, error) {
|
||||
const absMinInt64 = uint64(1 << 63)
|
||||
|
||||
if n > absMinInt64 {
|
||||
return 0, errors.Errorf("value %d overflows int64", n)
|
||||
}
|
||||
|
||||
if n == absMinInt64 {
|
||||
return int64(-1 << 63), nil
|
||||
}
|
||||
|
||||
// n < 1 << 63
|
||||
return -int64(n), nil
|
||||
}
|
||||
|
||||
func toInt64(n uint64) (int64, error) {
|
||||
const maxInt64 = uint64(1<<63) - 1
|
||||
|
||||
if n > maxInt64 {
|
||||
return 0, errors.Errorf("value %d overflows int64", n)
|
||||
}
|
||||
|
||||
return int64(n), nil
|
||||
}
|
||||
|
||||
func (sr *SignedRow) union(other SignedRow) SignedRow {
|
||||
ret := SignedRow{&Row{}, &Row{}, ""}
|
||||
|
||||
|
|
|
|||
|
|
@ -495,3 +495,71 @@ func TestValCountComparisons(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestToNegInt64(t *testing.T) {
|
||||
tests := []struct {
|
||||
u64 uint64
|
||||
i64 int64
|
||||
overflow bool
|
||||
}{
|
||||
{
|
||||
u64: uint64(1 << 63),
|
||||
i64: int64(-1 << 63),
|
||||
},
|
||||
{
|
||||
u64: uint64(1<<63) - 1,
|
||||
i64: int64(-1<<63) + 1,
|
||||
},
|
||||
{
|
||||
u64: uint64(1<<63) + 1,
|
||||
overflow: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
val, err := toNegInt64(tc.u64)
|
||||
if err != nil && !tc.overflow {
|
||||
t.Fatalf("error: %+v, expected: %+v", err, tc)
|
||||
}
|
||||
|
||||
if val != tc.i64 {
|
||||
t.Fatalf("Expected: %+v, Got: %+v", tc.i64, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestToInt64(t *testing.T) {
|
||||
tests := []struct {
|
||||
u64 uint64
|
||||
i64 int64
|
||||
overflow bool
|
||||
}{
|
||||
{
|
||||
u64: uint64(1<<63) - 1,
|
||||
i64: 1<<63 - 1,
|
||||
},
|
||||
{
|
||||
u64: uint64(0),
|
||||
i64: 0,
|
||||
},
|
||||
{
|
||||
u64: uint64(1 << 63),
|
||||
overflow: true,
|
||||
},
|
||||
{
|
||||
u64: 1<<64 - 1,
|
||||
overflow: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
val, err := toInt64(tc.u64)
|
||||
if err != nil && !tc.overflow {
|
||||
t.Fatalf("error: %+v, expected: %+v", err, tc)
|
||||
}
|
||||
|
||||
if val != tc.i64 {
|
||||
t.Fatalf("Expected: %+v, Got: %+v", tc.i64, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue