Copilot commented on code in PR #1501:
URL: https://github.com/apache/arrow-go/pull/1501#discussion_r4518986829


##########
arrow/scalar/decimal.go:
##########
@@ -0,0 +1,118 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package scalar
+
+import (
+       "fmt"
+       "unsafe"
+
+       "github.com/apache/arrow-go/v18/arrow"
+       "github.com/apache/arrow-go/v18/arrow/decimal"
+       "github.com/apache/arrow-go/v18/arrow/decimal128"
+       "github.com/apache/arrow-go/v18/arrow/decimal256"
+)
+
+type decimalScalar[T interface {
+       decimal.DecimalTypes
+       decimal.Num[T]
+}] struct {
+       scalar
+       Value T
+}
+
+type (
+       Decimal32 = decimalScalar[decimal.Decimal32]
+       Decimal64 = decimalScalar[decimal.Decimal64]
+)
+
+func NewDecimal32Scalar(val decimal.Decimal32, typ arrow.DataType) *Decimal32 {
+       return &Decimal32{scalar{typ, true}, val}
+}
+
+func NewDecimal64Scalar(val decimal.Decimal64, typ arrow.DataType) *Decimal64 {
+       return &Decimal64{scalar{typ, true}, val}
+}
+
+func (s *decimalScalar[T]) Data() []byte {
+       return unsafe.Slice((*byte)(unsafe.Pointer(&s.Value)), 
unsafe.Sizeof(s.Value))
+}
+
+func (s *decimalScalar[T]) value() interface{} { return s.Value }
+
+func (s *decimalScalar[T]) equals(rhs Scalar) bool {
+       return s.Value == rhs.(*decimalScalar[T]).Value
+}
+
+func (s *decimalScalar[T]) String() string {
+       if !s.Valid {
+               return "null"
+       }
+       val, err := s.CastTo(arrow.BinaryTypes.String)
+       if err != nil {
+               return "..."
+       }
+       return string(val.(*String).Value.Bytes())
+}
+
+// CastTo casts to string or to a decimal type at least as wide as the
+// scalar's own type.
+func (s *decimalScalar[T]) CastTo(to arrow.DataType) (Scalar, error) {
+       if !s.Valid {
+               return MakeNullScalar(to), nil
+       }
+
+       dt := s.Type.(arrow.DecimalType)
+       if to.ID() == arrow.STRING {
+               return 
NewStringScalar(s.Value.ToBigFloat(dt.GetScale()).Text('g', 
int(dt.GetPrecision()))), nil

Review Comment:
   This string cast can change the sign of a valid decimal: coefficient 1 with 
precision 1 and scale 19 formats as `-1e-19` instead of `1e-19` for both 
Decimal32 and Decimal64. Their `ToBigFloat` helpers compute powers of ten in 
`int64`, which also overflows for negative scales below -18. Use 
non-overflowing scaling or exact coefficient-and-scale formatting, and add 
regression cases for both `String()` and string casts.



##########
arrow/scalar/parse.go:
##########
@@ -868,6 +883,20 @@ func ParseScalar(dt arrow.DataType, val string) (Scalar, 
error) {
                return NewTime64Scalar(tm, dt), nil
        case arrow.DICTIONARY:
                return ParseScalar(dt.(*arrow.DictionaryType).ValueType, val)
+       case arrow.DECIMAL32:
+               typ := dt.(*arrow.Decimal32Type)
+               n, err := decimal.Decimal32FromString(val, typ.Precision, 
typ.Scale)

Review Comment:
   The new parsing paths accept out-of-range coefficients: `"4294967295"` 
becomes -1 for decimal32(9, 0), and `"9223372036854775808"` becomes MinInt64 
for decimal64(18, 0), without errors. The shared parser narrows before checking 
precision, and its `Abs()` check also incorrectly accepts MinInt32 and 
MinInt64. Validate the unscaled integer's signed range and requested precision 
before narrowing in `decimalFromString`; this fixes both `ParseScalar` branches 
(including line 895) and string inputs to `MakeScalarParam`.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to