Skip to content

Commit 639f18c

Browse files
committed
fix nval empty string out of index err and negative floating points treated being handled as positive ints
1 parent c7c84e8 commit 639f18c

File tree

1 file changed

+32
-28
lines changed

1 file changed

+32
-28
lines changed

sql/expression/function/conv.go

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -136,62 +136,66 @@ func (c *Conv) WithChildren(children ...sql.Expression) (sql.Expression, error)
136136
// This conversion truncates nVal as its first subpart that is convertable.
137137
// nVal is treated as unsigned except nVal is negative.
138138
func convertFromBase(ctx *sql.Context, nVal string, fromBase interface{}) interface{} {
139-
fromBase, _, err := types.Int64.Convert(ctx, fromBase)
140-
if err != nil {
139+
if len(nVal) == 0 {
141140
return nil
142141
}
143142

144-
fromVal := int(math.Abs(float64(fromBase.(int64))))
143+
// Convert and validate fromBase
144+
baseVal, _, err := types.Int64.Convert(ctx, fromBase)
145+
if err != nil {
146+
return nil
147+
}
148+
fromVal := int(math.Abs(float64(baseVal.(int64))))
145149
if fromVal < 2 || fromVal > 36 {
146150
return nil
147151
}
148152

153+
// Handle sign
149154
negative := false
150-
var upper string
151-
var lower string
152-
if nVal[0] == '-' {
155+
switch {
156+
case nVal[0] == '-':
157+
if len(nVal) == 1 {
158+
return uint64(0)
159+
}
153160
negative = true
154161
nVal = nVal[1:]
155-
} else if nVal[0] == '+' {
162+
case nVal[0] == '+':
163+
if len(nVal) == 1 {
164+
return uint64(0)
165+
}
156166
nVal = nVal[1:]
157167
}
158168

159-
// check for upper and lower bound for given fromBase
169+
// Determine bounds based on sign
170+
var maxLen int
160171
if negative {
161-
upper = strconv.FormatInt(math.MaxInt64, fromVal)
162-
lower = strconv.FormatInt(math.MinInt64, fromVal)
163-
if len(nVal) > len(lower) {
164-
nVal = lower
165-
} else if len(nVal) > len(upper) {
166-
nVal = upper
172+
maxLen = len(strconv.FormatInt(math.MinInt64, fromVal))
173+
if len(nVal) > maxLen {
174+
// Use MinInt64 representation in the given base
175+
nVal = strconv.FormatInt(math.MinInt64, fromVal)[1:] // remove minus sign
167176
}
168177
} else {
169-
upper = strconv.FormatUint(math.MaxUint64, fromVal)
170-
lower = "0"
171-
if len(nVal) < len(lower) {
172-
nVal = lower
173-
} else if len(nVal) > len(upper) {
174-
nVal = upper
178+
maxLen = len(strconv.FormatUint(math.MaxUint64, fromVal))
179+
if len(nVal) > maxLen {
180+
// Use MaxUint64 representation in the given base
181+
nVal = strconv.FormatUint(math.MaxUint64, fromVal)
175182
}
176183
}
177184

178-
truncate := false
179-
result := uint64(0)
180-
i := 1
181-
for !truncate && i <= len(nVal) {
185+
// Find the longest valid prefix that can be converted
186+
var result uint64
187+
for i := 1; i <= len(nVal); i++ {
182188
val, err := strconv.ParseUint(nVal[:i], fromVal, 64)
183189
if err != nil {
184-
truncate = true
185-
return result
190+
break
186191
}
187192
result = val
188-
i++
189193
}
190194

191195
if negative {
196+
// MySQL returns signed value for negative inputs
192197
return int64(result) * -1
193198
}
194-
195199
return result
196200
}
197201

0 commit comments

Comments
 (0)