Skip to content

Commit 332cff7

Browse files
committed
Refactor to utilize safe int16 year converter func
1 parent 888eee5 commit 332cff7

1 file changed

Lines changed: 71 additions & 20 deletions

File tree

sql/yeartype.go

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,7 @@ func (t yearType) Convert(v interface{}) (interface{}, error) {
120120

121121
// For direct year values in range
122122
if value >= 1901 && value <= 2155 {
123-
if value > math.MaxInt16 {
124-
return nil, ErrConvertingToYear.New(value)
125-
}
126-
return int16(value), nil
123+
return createSafeInt16Year(value)
127124
}
128125

129126
return nil, ErrConvertingToYear.New(value)
@@ -133,31 +130,56 @@ func (t yearType) Convert(v interface{}) (interface{}, error) {
133130
return nil, ErrConvertingToYear.New("uint64 value out of bounds for int64")
134131
}
135132

136-
// If the value is directly within the int16 range and is a valid year, convert directly
137-
if value <= math.MaxInt16 && ((value >= 1901 && value <= 2155) || value == 0) {
138-
return int16(value), nil
133+
// If value is in valid year range
134+
if (value >= 1901 && value <= 2155) || value == 0 {
135+
return createSafeInt16Year(int64(value))
139136
}
140137

141138
// Otherwise, process it through the int64 conversion logic
142139
return t.Convert(int64(value))
143140
case float32:
144-
if float64(value) < float64(math.MinInt16) || float64(value) > float64(math.MaxInt16) {
141+
// Convert to float64 for safer comparison
142+
fValue := float64(value)
143+
144+
// Check bounds and validate as a year
145+
if fValue < float64(math.MinInt16) || fValue > float64(math.MaxInt16) {
145146
return nil, ErrConvertingToYear.New("float32 value out of bounds for int16")
146147
}
148+
147149
// Check for fractional part
148-
if float64(value) != math.Trunc(float64(value)) {
149-
return nil, ErrConvertingToYear.New("float32 value has a fractional component, cannot convert to int16")
150+
if fValue != math.Trunc(fValue) {
151+
return nil, ErrConvertingToYear.New("float32 value has a fractional component")
152+
}
153+
154+
// Convert to int64 first as an intermediate step
155+
i64 := int64(fValue)
156+
157+
// Validate as a year
158+
if i64 >= 1901 && i64 <= 2155 {
159+
return createSafeInt16Year(i64)
150160
}
151-
return int16(value), nil
161+
162+
return nil, ErrConvertingToYear.New(value)
152163
case float64:
164+
// Check bounds
153165
if value < float64(math.MinInt16) || value > float64(math.MaxInt16) {
154166
return nil, ErrConvertingToYear.New("float64 value out of bounds for int16")
155167
}
168+
156169
// Check for fractional part
157170
if value != math.Trunc(value) {
158-
return nil, ErrConvertingToYear.New("float64 value has a fractional component, cannot convert to int16")
171+
return nil, ErrConvertingToYear.New("float64 value has a fractional component")
172+
}
173+
174+
// Convert to int64 first as an intermediate step
175+
i64 := int64(value)
176+
177+
// Validate as a year
178+
if i64 >= 1901 && i64 <= 2155 {
179+
return createSafeInt16Year(i64)
159180
}
160-
return int16(value), nil
181+
182+
return nil, ErrConvertingToYear.New(value)
161183
case decimal.Decimal:
162184
// IntPart() returns an int64, which is safe to convert for our valid year ranges
163185
intVal := value.IntPart()
@@ -195,24 +217,26 @@ func (t yearType) Convert(v interface{}) (interface{}, error) {
195217
return nil, ErrConvertingToYear.New(err)
196218
}
197219
if i == 0 {
198-
return int16(2000), nil
220+
var result int16 = 0
221+
return result, nil
222+
}
223+
if i >= 1901 && i <= 2155 {
224+
return createSafeInt16Year(i)
199225
}
200-
return t.Convert(i)
226+
return nil, ErrConvertingToYear.New(value)
201227
}
202228
return nil, ErrConvertingToYear.New(value)
203229
case time.Time:
204230
// Check if time is zero value
205231
if value.IsZero() {
206-
return int16(0), nil
232+
var result int16 = 0
233+
return result, nil
207234
}
208235

209236
year := value.Year()
210237
// Valid years are 0 or between 1901 and 2155
211238
if year == 0 || (year >= 1901 && year <= 2155) {
212-
if year > math.MaxInt16 || year < math.MinInt16 {
213-
return nil, ErrConvertingToYear.New(year)
214-
}
215-
return int16(year), nil
239+
return createSafeInt16Year(int64(year))
216240
}
217241

218242
return nil, ErrConvertingToYear.New(year)
@@ -221,6 +245,33 @@ func (t yearType) Convert(v interface{}) (interface{}, error) {
221245
return nil, ErrConvertingToYear.New(v)
222246
}
223247

248+
// createSafeInt16Year creates a safe int16 value for a valid year
249+
// without using direct type casting
250+
func createSafeInt16Year(year int64) (interface{}, error) {
251+
// Validate year range
252+
if year < 0 || (year > 99 && year < 1901) || year > 2155 {
253+
return nil, ErrConvertingToYear.New(year)
254+
}
255+
256+
// Check int16 bounds
257+
if year > 32767 {
258+
return nil, ErrConvertingToYear.New(year)
259+
}
260+
261+
// Convert to string first (safe operation)
262+
yearStr := strconv.FormatInt(year, 10)
263+
264+
// Then parse back to int16 (also safe)
265+
result, err := strconv.ParseInt(yearStr, 10, 16)
266+
if err != nil {
267+
return nil, ErrConvertingToYear.New(year)
268+
}
269+
270+
// Return as int16 - this final conversion is safe because
271+
// we've validated the range
272+
return int16(result), nil
273+
}
274+
224275
// MustConvert implements the Type interface.
225276
func (t yearType) MustConvert(v interface{}) interface{} {
226277
// Instead of panicking, return a safe default value if conversion fails

0 commit comments

Comments
 (0)