NValue NValue::opDivideDecimals(const NValue lhs, const NValue rhs) const { if ((lhs.getValueType() != VALUE_TYPE_DECIMAL) || (rhs.getValueType() != VALUE_TYPE_DECIMAL)) { throw SQLException(SQLException::dynamic_sql_error, "No decimal NValue in decimal subtract"); } if (lhs.isNull() || rhs.isNull()) { TTInt retval; retval.SetMin(); return getDecimalValue( retval ); } TTLInt calc; calc.FromInt(lhs.getDecimal()); calc *= NValue::kMaxScaleFactor; if (calc.Div(rhs.getDecimal())) { char message[4096]; snprintf( message, 4096, "Attempted to divide %s by %s causing overflow/underflow (or divide by zero)", lhs.createStringFromDecimal().c_str(), rhs.createStringFromDecimal().c_str()); throw SQLException(SQLException::data_exception_numeric_value_out_of_range, message); } TTInt retval; if (retval.FromInt(calc) || retval > NValue::s_maxDecimal || retval < s_minDecimal) { char message[4096]; snprintf( message, 4096, "Attempted to divide %s by %s causing overflow. Unscaled result was %s", lhs.createStringFromDecimal().c_str(), rhs.createStringFromDecimal().c_str(), calc.ToString(10).c_str()); throw SQLException(SQLException::data_exception_numeric_value_out_of_range, message); } return getDecimalValue(retval); }
/** * Serialize sign and value using radix point (no exponent). */ std::string NValue::createStringFromDecimal() const { assert(!isNull()); std::ostringstream buffer; TTInt scaledValue = getDecimal(); if (scaledValue.IsSign()) { buffer << '-'; } TTInt whole(scaledValue); TTInt fractional(scaledValue); whole /= NValue::kMaxScaleFactor; fractional %= NValue::kMaxScaleFactor; if (whole.IsSign()) { whole.ChangeSign(); } buffer << whole.ToString(10); buffer << '.'; if (fractional.IsSign()) { fractional.ChangeSign(); } std::string fractionalString = fractional.ToString(10); for (int ii = static_cast<int>(fractionalString.size()); ii < NValue::kMaxDecScale; ii++) { buffer << '0'; } buffer << fractionalString; return buffer.str(); }
Decimal Decimal::op_subtract(const Decimal rhs) const { TTInt rett; rett = this->GetTTInt(); rett.Sub(rhs.GetTTInt()); Decimal ret; ret.SetTTInt(rett); return ret; }
Decimal Decimal::op_add(const Decimal rhs) const { TTInt rett; rett = this->GetTTInt(); rett.Add(rhs.GetTTInt()); Decimal ret; ret.SetTTInt(rett); return ret; }
string Decimal::toString(unsigned number_of_fractinal_digits) const { if (isNull()) return "NULL"; string ress = ""; TTInt rest = this->word[0]; rest.ToString(ress); int sign = 0; if (rest.IsSign()) sign = 1; while ((Decimal::kMaxDecScale + sign - (int) ress.length()) >= 0) ress.insert(sign, "0"); if(number_of_fractinal_digits > 0) ress.insert(ress.length() - Decimal::kMaxDecScale, "."); ress.erase(ress.size() - Decimal::kMaxDecScale + number_of_fractinal_digits, Decimal::kMaxDecScale - number_of_fractinal_digits); return ress; }
/* * Avoid scaling both sides if possible. E.g, don't turn dec * 2 into * (dec * 2*kMaxScale*E-12). Then the result of simple multiplication * is a*b*E-24 and have to further multiply to get back to the assumed * E-12, which can overflow unnecessarily at the middle step. */ NValue NValue::opMultiplyDecimals(const NValue &lhs, const NValue &rhs) const { if ((lhs.getValueType() != VALUE_TYPE_DECIMAL) && (rhs.getValueType() != VALUE_TYPE_DECIMAL)) { throw SQLException(SQLException::dynamic_sql_error, "Non-decimal NValue in decimal multiply"); } if (lhs.isNull() || rhs.isNull()) { TTInt retval; retval.SetMin(); return getDecimalValue( retval ); } if ((lhs.getValueType() == VALUE_TYPE_DECIMAL) && (rhs.getValueType() == VALUE_TYPE_DECIMAL)) { TTLInt calc; calc.FromInt(lhs.getDecimal()); calc *= rhs.getDecimal(); calc /= NValue::kMaxScaleFactor; TTInt retval; if (retval.FromInt(calc) || retval > NValue::s_maxDecimal || retval < s_minDecimal) { char message[4096]; snprintf(message, 4096, "Attempted to multiply %s by %s causing overflow/underflow. Unscaled result was %s", lhs.createStringFromDecimal().c_str(), rhs.createStringFromDecimal().c_str(), calc.ToString(10).c_str()); throw SQLException(SQLException::data_exception_numeric_value_out_of_range, message); } return getDecimalValue(retval); } else if (lhs.getValueType() != VALUE_TYPE_DECIMAL) { TTLInt calc; calc.FromInt(rhs.getDecimal()); calc *= lhs.castAsDecimalAndGetValue(); calc /= NValue::kMaxScaleFactor; TTInt retval; retval.FromInt(calc); if (retval.FromInt(calc) || retval > NValue::s_maxDecimal || retval < s_minDecimal) { char message[4096]; snprintf(message, 4096, "Attempted to multiply %s by %s causing overflow/underflow. Unscaled result was %s", lhs.createStringFromDecimal().c_str(), rhs.createStringFromDecimal().c_str(), calc.ToString(10).c_str()); throw SQLException(SQLException::data_exception_numeric_value_out_of_range, message); } return getDecimalValue(retval); } else { TTLInt calc; calc.FromInt(lhs.getDecimal()); calc *= rhs.castAsDecimalAndGetValue(); calc /= NValue::kMaxScaleFactor; TTInt retval; retval.FromInt(calc); if (retval.FromInt(calc) || retval > NValue::s_maxDecimal || retval < s_minDecimal) { char message[4096]; snprintf(message, 4096, "Attempted to multiply %s by %s causing overflow/underflow. Unscaled result was %s", lhs.createStringFromDecimal().c_str(), rhs.createStringFromDecimal().c_str(), calc.ToString(10).c_str()); throw SQLException(SQLException::data_exception_numeric_value_out_of_range, message); } return getDecimalValue(retval); } }