Skip to content

Commit 6262e0b

Browse files
committed
Fallback to varchar if int is too large
1 parent 47a1728 commit 6262e0b

1 file changed

Lines changed: 25 additions & 14 deletions

File tree

src/duckdb_py/native/python_conversion.cpp

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -270,17 +270,17 @@ bool TryTransformPythonIntegerToDouble(Value &res, py::handle ele) {
270270
return true;
271271
}
272272

273-
// Converts a Python integer that overflows int64/uint64 into a HUGEINT or UHUGEINT Value by decomposing it into upper
274-
// and lower 64-bit components. Tries HUGEINT first; falls back to UHUGEINT for large positive values.
275-
static Value TransformPythonLongToHugeInt(py::handle ele, const LogicalType &target_type) {
273+
// Tries to convert a Python integer that overflows int64/uint64 into a HUGEINT or UHUGEINT Value
274+
// by decomposing it into upper and lower 64-bit components. Tries HUGEINT first; falls back to
275+
// UHUGEINT for large positive values. Returns false if the value doesn't fit in 128 bits.
276+
static bool TryTransformPythonLongToHugeInt(py::handle ele, const LogicalType &target_type, Value &result) {
276277
auto ptr = ele.ptr();
277278

278279
// Extract lower 64 bits (two's complement, works for negative values too)
279280
uint64_t lower = PyLong_AsUnsignedLongLongMask(ptr);
280281
if (lower == static_cast<uint64_t>(-1) && PyErr_Occurred()) {
281282
PyErr_Clear();
282-
throw InvalidInputException("Failed to convert Python integer to 128-bit integer: %s",
283-
std::string(py::str(ele)));
283+
return false;
284284
}
285285

286286
// Extract upper bits by right-shifting by 64
@@ -293,24 +293,37 @@ static Value TransformPythonLongToHugeInt(py::handle ele, const LogicalType &tar
293293
if (overflow == 0 && !(upper_signed == -1 && PyErr_Occurred())) {
294294
auto val = Value::HUGEINT(hugeint_t {upper_signed, lower});
295295
if (target_type.id() == LogicalTypeId::UNKNOWN || target_type.id() == LogicalTypeId::HUGEINT) {
296-
return val;
296+
result = val;
297+
} else {
298+
result = CastToTarget(std::move(val), target_type);
297299
}
298-
return CastToTarget(std::move(val), target_type);
300+
return true;
299301
}
300302
PyErr_Clear();
301303

302304
// Try unsigned 128-bit (uhugeint)
303305
uint64_t upper_unsigned = PyLong_AsUnsignedLongLong(upper_obj.ptr());
304306
if (PyErr_Occurred()) {
305307
PyErr_Clear();
306-
throw InvalidInputException("Python integer too large for 128-bit integer type: %s", std::string(py::str(ele)));
308+
return false;
307309
}
308310

309311
auto val = Value::UHUGEINT(uhugeint_t {upper_unsigned, lower});
310312
if (target_type.id() == LogicalTypeId::UNKNOWN || target_type.id() == LogicalTypeId::UHUGEINT) {
311-
return val;
313+
result = val;
314+
} else {
315+
result = CastToTarget(std::move(val), target_type);
316+
}
317+
return true;
318+
}
319+
320+
// Throwing wrapper for contexts that require a result (e.g. prepared statement parameters).
321+
static Value TransformPythonLongToHugeInt(py::handle ele, const LogicalType &target_type) {
322+
Value result;
323+
if (!TryTransformPythonLongToHugeInt(ele, target_type, result)) {
324+
throw InvalidInputException("Python integer too large for 128-bit integer type: %s", std::string(py::str(ele)));
312325
}
313-
return CastToTarget(std::move(val), target_type);
326+
return result;
314327
}
315328

316329
void TransformPythonUnsigned(uint64_t value, Value &res) {
@@ -347,8 +360,7 @@ bool TryTransformPythonNumeric(Value &res, py::handle ele, const LogicalType &ta
347360
throw InvalidInputException(StringUtil::Format("Failed to cast value: Python value '%s' to INT64",
348361
std::string(pybind11::str(ele))));
349362
}
350-
res = TransformPythonLongToHugeInt(ele, target_type);
351-
return true;
363+
return TryTransformPythonLongToHugeInt(ele, target_type, res);
352364
} else if (overflow == 1) {
353365
if (target_type.InternalType() == PhysicalType::INT64) {
354366
throw InvalidInputException(StringUtil::Format("Failed to cast value: Python value '%s' to INT64",
@@ -357,8 +369,7 @@ bool TryTransformPythonNumeric(Value &res, py::handle ele, const LogicalType &ta
357369
uint64_t unsigned_value = PyLong_AsUnsignedLongLong(ptr);
358370
if (PyErr_Occurred()) {
359371
PyErr_Clear();
360-
res = TransformPythonLongToHugeInt(ele, target_type);
361-
return true;
372+
return TryTransformPythonLongToHugeInt(ele, target_type, res);
362373
}
363374
TransformPythonUnsigned(unsigned_value, res);
364375
PyErr_Clear();

0 commit comments

Comments
 (0)