\brief Infer the precision and scale of a Python decimal.Decimal instance \param python_decimal[in] An instance of decimal.Decimal \param precision[out] The value of the inferred precision \param scale[out] The value of the inferred scale \return The status of the operation
| 47 | // \param scale[out] The value of the inferred scale |
| 48 | // \return The status of the operation |
| 49 | static Status InferDecimalPrecisionAndScale(PyObject* python_decimal, int32_t* precision, |
| 50 | int32_t* scale) { |
| 51 | ARROW_DCHECK_NE(python_decimal, NULLPTR); |
| 52 | ARROW_DCHECK_NE(precision, NULLPTR); |
| 53 | ARROW_DCHECK_NE(scale, NULLPTR); |
| 54 | |
| 55 | // TODO(phillipc): Make sure we perform PyDecimal_Check(python_decimal) as a |
| 56 | // ARROW_DCHECK |
| 57 | OwnedRef as_tuple(PyObject_CallMethod(python_decimal, const_cast<char*>("as_tuple"), |
| 58 | const_cast<char*>(""))); |
| 59 | RETURN_IF_PYERROR(); |
| 60 | ARROW_DCHECK(PyTuple_Check(as_tuple.obj())); |
| 61 | |
| 62 | OwnedRef digits(PyObject_GetAttrString(as_tuple.obj(), "digits")); |
| 63 | RETURN_IF_PYERROR(); |
| 64 | ARROW_DCHECK(PyTuple_Check(digits.obj())); |
| 65 | |
| 66 | const auto num_digits = static_cast<int32_t>(PyTuple_Size(digits.obj())); |
| 67 | RETURN_IF_PYERROR(); |
| 68 | |
| 69 | OwnedRef py_exponent(PyObject_GetAttrString(as_tuple.obj(), "exponent")); |
| 70 | RETURN_IF_PYERROR(); |
| 71 | ARROW_DCHECK(IsPyInteger(py_exponent.obj())); |
| 72 | |
| 73 | const auto exponent = static_cast<int32_t>(PyLong_AsLong(py_exponent.obj())); |
| 74 | RETURN_IF_PYERROR(); |
| 75 | |
| 76 | if (exponent < 0) { |
| 77 | // If exponent > num_digits, we have a number with leading zeros |
| 78 | // such as 0.01234. Ensure we have enough precision for leading zeros |
| 79 | // (which are not included in num_digits). |
| 80 | *precision = std::max(num_digits, -exponent); |
| 81 | *scale = -exponent; |
| 82 | } else { |
| 83 | // Trailing zeros are not included in num_digits, need to add to precision. |
| 84 | // Note we don't generate negative scales as they are poorly supported |
| 85 | // in non-Arrow systems. |
| 86 | *precision = num_digits + exponent; |
| 87 | *scale = 0; |
| 88 | } |
| 89 | return Status::OK(); |
| 90 | } |
| 91 | |
| 92 | PyObject* DecimalFromString(PyObject* decimal_constructor, |
| 93 | const std::string& decimal_string) { |
no test coverage detected