Use BigDecimal for large number handling
This commit is contained in:
parent
5d554d07d3
commit
73df91a438
5 changed files with 72 additions and 85 deletions
49
Cargo.lock
generated
49
Cargo.lock
generated
|
@ -64,12 +64,6 @@ dependencies = [
|
|||
"password-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "as-slice"
|
||||
version = "0.1.5"
|
||||
|
@ -147,6 +141,18 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b"
|
||||
|
||||
[[package]]
|
||||
name = "bigdecimal"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6aaf33151a6429fe9211d1b276eafdf70cdff28b071e76c0b0e1503221ea3744"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.57.0"
|
||||
|
@ -1218,9 +1224,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ba42135c6a5917b9db9cd7b293e5409e1c6b041e6f9825e92e55a894c63b6f8"
|
||||
checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
|
@ -1319,6 +1325,17 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
|
@ -1927,16 +1944,6 @@ dependencies = [
|
|||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_decimal"
|
||||
version = "1.22.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
|
@ -2225,6 +2232,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"argon2",
|
||||
"async-recursion",
|
||||
"bigdecimal",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"dmp",
|
||||
|
@ -2242,7 +2250,6 @@ dependencies = [
|
|||
"rand 0.8.5",
|
||||
"regex",
|
||||
"rmp-serde",
|
||||
"rust_decimal",
|
||||
"scrypt",
|
||||
"serde",
|
||||
"sha-1 0.10.0",
|
||||
|
@ -2271,9 +2278,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.88"
|
||||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebd69e719f31e88618baa1eaa6ee2de5c9a1c004f1e9ecdb58e8352a13f20a01"
|
||||
checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -16,9 +16,9 @@ kv-yokudb = []
|
|||
[dependencies]
|
||||
argon2 = "0.3.4"
|
||||
async-recursion = "1.0.0"
|
||||
bigdecimal = { version = "0.3.0", features = ["serde", "string-only"] }
|
||||
byteorder = "1.4.3"
|
||||
chrono = { version = "0.4.19", features = ["serde"] }
|
||||
dec = { version = "1.21.0", package = "rust_decimal", features = ["maths", "serde-float"] }
|
||||
derive = { version = "0.1.2", package = "surrealdb-derive" }
|
||||
dmp = "0.1.1"
|
||||
echodb = { version = "0.2.1", optional = true }
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
use crate::sql::comment::comment;
|
||||
use crate::sql::error::Error::ParserError;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::operator::{assigner, operator};
|
||||
use dec::prelude::FromPrimitive;
|
||||
use dec::prelude::ToPrimitive;
|
||||
use dec::Decimal;
|
||||
use dec::MathematicalOps;
|
||||
use bigdecimal::BigDecimal;
|
||||
use bigdecimal::FromPrimitive;
|
||||
use bigdecimal::ToPrimitive;
|
||||
use nom::branch::alt;
|
||||
use nom::character::complete::char;
|
||||
use nom::character::complete::digit1;
|
||||
use nom::character::complete::i64;
|
||||
use nom::character::complete::multispace1;
|
||||
use nom::combinator::eof;
|
||||
use nom::combinator::map;
|
||||
use nom::combinator::peek;
|
||||
use nom::number::complete::recognize_float;
|
||||
use nom::Err::Error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
|
@ -27,7 +24,7 @@ use std::str::FromStr;
|
|||
pub enum Number {
|
||||
Int(i64),
|
||||
Float(f64),
|
||||
Decimal(Decimal),
|
||||
Decimal(BigDecimal),
|
||||
}
|
||||
|
||||
impl Default for Number {
|
||||
|
@ -110,24 +107,18 @@ impl From<f64> for Number {
|
|||
|
||||
impl<'a> From<&'a str> for Number {
|
||||
fn from(s: &str) -> Self {
|
||||
match s.contains(&['e', 'E'][..]) {
|
||||
true => Number::Decimal(Decimal::from_scientific(s).unwrap_or_default()),
|
||||
false => Number::Decimal(Decimal::from_str(s).unwrap_or_default()),
|
||||
}
|
||||
Number::Decimal(BigDecimal::from_str(s).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Number {
|
||||
fn from(s: String) -> Self {
|
||||
match s.contains(&['e', 'E'][..]) {
|
||||
true => Number::Decimal(Decimal::from_scientific(&s).unwrap_or_default()),
|
||||
false => Number::Decimal(Decimal::from_str(&s).unwrap_or_default()),
|
||||
}
|
||||
Number::Decimal(BigDecimal::from_str(&s).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Decimal> for Number {
|
||||
fn from(v: Decimal) -> Self {
|
||||
impl From<BigDecimal> for Number {
|
||||
fn from(v: BigDecimal) -> Self {
|
||||
Number::Decimal(v)
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +163,7 @@ impl Number {
|
|||
match self {
|
||||
Number::Int(v) => v != &0,
|
||||
Number::Float(v) => v != &0.0,
|
||||
Number::Decimal(v) => v != &Decimal::default(),
|
||||
Number::Decimal(v) => v != &BigDecimal::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,7 +175,7 @@ impl Number {
|
|||
match self {
|
||||
Number::Int(v) => v,
|
||||
Number::Float(v) => v as i64,
|
||||
Number::Decimal(v) => v.to_i64().unwrap_or(0),
|
||||
Number::Decimal(v) => v.to_i64().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,27 +183,27 @@ impl Number {
|
|||
match self {
|
||||
Number::Int(v) => v as f64,
|
||||
Number::Float(v) => v,
|
||||
Number::Decimal(v) => v.to_f64().unwrap_or(0.0),
|
||||
Number::Decimal(v) => v.to_f64().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_decimal(self) -> Decimal {
|
||||
pub fn as_decimal(self) -> BigDecimal {
|
||||
match self {
|
||||
Number::Int(v) => Decimal::from(v),
|
||||
Number::Float(v) => Decimal::from_f64(v).unwrap_or_default(),
|
||||
Number::Int(v) => BigDecimal::from_i64(v).unwrap_or_default(),
|
||||
Number::Float(v) => BigDecimal::from_f64(v).unwrap_or_default(),
|
||||
Number::Decimal(v) => v,
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
// Complex conversion of number
|
||||
// -----------------------------------
|
||||
|
||||
pub fn to_usize(&self) -> usize {
|
||||
match self {
|
||||
Number::Int(v) => *v as usize,
|
||||
Number::Float(v) => *v as usize,
|
||||
Number::Decimal(v) => v.to_usize().unwrap_or(0),
|
||||
Number::Decimal(v) => v.to_usize().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,7 +211,7 @@ impl Number {
|
|||
match self {
|
||||
Number::Int(v) => *v,
|
||||
Number::Float(v) => *v as i64,
|
||||
Number::Decimal(v) => v.to_i64().unwrap_or(0),
|
||||
Number::Decimal(v) => v.to_i64().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -228,15 +219,15 @@ impl Number {
|
|||
match self {
|
||||
Number::Int(v) => *v as f64,
|
||||
Number::Float(v) => *v,
|
||||
Number::Decimal(v) => v.to_f64().unwrap_or(0.0),
|
||||
Number::Decimal(v) => v.to_f64().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_decimal(&self) -> Decimal {
|
||||
pub fn to_decimal(&self) -> BigDecimal {
|
||||
match self {
|
||||
Number::Int(v) => Decimal::from(*v),
|
||||
Number::Float(v) => Decimal::from_f64(*v).unwrap_or_default(),
|
||||
Number::Decimal(v) => *v,
|
||||
Number::Int(v) => BigDecimal::from_i64(*v).unwrap_or_default(),
|
||||
Number::Float(v) => BigDecimal::from_f64(*v).unwrap_or_default(),
|
||||
Number::Decimal(v) => v.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,7 +247,7 @@ impl Number {
|
|||
match self {
|
||||
Number::Int(v) => v.into(),
|
||||
Number::Float(v) => v.ceil().into(),
|
||||
Number::Decimal(v) => v.ceil().into(),
|
||||
Number::Decimal(v) => (v + BigDecimal::from_f32(0.5).unwrap()).round(0).into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,7 +255,7 @@ impl Number {
|
|||
match self {
|
||||
Number::Int(v) => v.into(),
|
||||
Number::Float(v) => v.floor().into(),
|
||||
Number::Decimal(v) => v.floor().into(),
|
||||
Number::Decimal(v) => (v - BigDecimal::from_f32(0.5).unwrap()).round(0).into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -272,7 +263,7 @@ impl Number {
|
|||
match self {
|
||||
Number::Int(v) => v.into(),
|
||||
Number::Float(v) => v.round().into(),
|
||||
Number::Decimal(v) => v.round().into(),
|
||||
Number::Decimal(v) => v.round(0).into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,7 +283,7 @@ impl Number {
|
|||
match self {
|
||||
Number::Int(v) => format!("{:.1$}", v, precision).into(),
|
||||
Number::Float(v) => format!("{:.1$}", v, precision).into(),
|
||||
Number::Decimal(v) => v.round_dp(precision as u32).into(),
|
||||
Number::Decimal(v) => v.round(precision as i64).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -315,14 +306,14 @@ impl PartialEq for Number {
|
|||
(Number::Int(v), Number::Float(w)) => (*v as f64).eq(w),
|
||||
(Number::Float(v), Number::Int(w)) => v.eq(&(*w as f64)),
|
||||
// ------------------------------
|
||||
(Number::Int(v), Number::Decimal(w)) => Decimal::from(*v).eq(w),
|
||||
(Number::Decimal(v), Number::Int(w)) => v.eq(&Decimal::from(*w)),
|
||||
(Number::Int(v), Number::Decimal(w)) => BigDecimal::from(*v).eq(w),
|
||||
(Number::Decimal(v), Number::Int(w)) => v.eq(&BigDecimal::from(*w)),
|
||||
// ------------------------------
|
||||
(Number::Float(v), Number::Decimal(w)) => {
|
||||
Decimal::from_f64(*v).unwrap_or_default().eq(w)
|
||||
BigDecimal::from_f64(*v).unwrap_or_default().eq(w)
|
||||
}
|
||||
(Number::Decimal(v), Number::Float(w)) => {
|
||||
v.eq(&Decimal::from_f64(*w).unwrap_or_default())
|
||||
v.eq(&BigDecimal::from_f64(*w).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -338,14 +329,14 @@ impl PartialOrd for Number {
|
|||
(Number::Int(v), Number::Float(w)) => (*v as f64).partial_cmp(w),
|
||||
(Number::Float(v), Number::Int(w)) => v.partial_cmp(&(*w as f64)),
|
||||
// ------------------------------
|
||||
(Number::Int(v), Number::Decimal(w)) => Decimal::from(*v).partial_cmp(w),
|
||||
(Number::Decimal(v), Number::Int(w)) => v.partial_cmp(&Decimal::from(*w)),
|
||||
(Number::Int(v), Number::Decimal(w)) => BigDecimal::from(*v).partial_cmp(w),
|
||||
(Number::Decimal(v), Number::Int(w)) => v.partial_cmp(&BigDecimal::from(*w)),
|
||||
// ------------------------------
|
||||
(Number::Float(v), Number::Decimal(w)) => {
|
||||
Decimal::from_f64(*v).unwrap_or_default().partial_cmp(w)
|
||||
BigDecimal::from_f64(*v).unwrap_or_default().partial_cmp(w)
|
||||
}
|
||||
(Number::Decimal(v), Number::Float(w)) => {
|
||||
v.partial_cmp(&Decimal::from_f64(*w).unwrap_or_default())
|
||||
v.partial_cmp(&BigDecimal::from_f64(*w).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -439,7 +430,6 @@ impl ops::Div for Number {
|
|||
type Output = Self;
|
||||
fn div(self, other: Self) -> Self {
|
||||
match (self, other) {
|
||||
(Number::Int(v), Number::Int(w)) => Number::Int(v / w),
|
||||
(Number::Float(v), Number::Float(w)) => Number::Float(v / w),
|
||||
(Number::Decimal(v), Number::Decimal(w)) => Number::Decimal(v / w),
|
||||
(Number::Int(v), Number::Float(w)) => Number::Float(v as f64 / w),
|
||||
|
@ -453,7 +443,6 @@ impl<'a, 'b> ops::Div<&'b Number> for &'a Number {
|
|||
type Output = Number;
|
||||
fn div(self, other: &'b Number) -> Number {
|
||||
match (self, other) {
|
||||
(Number::Int(v), Number::Int(w)) => Number::Int(v / w),
|
||||
(Number::Float(v), Number::Float(w)) => Number::Float(v / w),
|
||||
(Number::Decimal(v), Number::Decimal(w)) => Number::Decimal(v / w),
|
||||
(Number::Int(v), Number::Float(w)) => Number::Float(*v as f64 / w),
|
||||
|
@ -506,7 +495,7 @@ pub fn number(i: &str) -> IResult<&str, Number> {
|
|||
}
|
||||
|
||||
fn integer(i: &str) -> IResult<&str, Number> {
|
||||
let (i, v) = digit1(i)?;
|
||||
let (i, v) = i64(i)?;
|
||||
let (i, _) = peek(alt((
|
||||
map(multispace1, |_| ()),
|
||||
map(operator, |_| ()),
|
||||
|
@ -519,10 +508,7 @@ fn integer(i: &str) -> IResult<&str, Number> {
|
|||
map(char(','), |_| ()),
|
||||
map(eof, |_| ()),
|
||||
)))(i)?;
|
||||
match v.parse::<i64>() {
|
||||
Ok(v) => Ok((i, Number::from(v))),
|
||||
_ => Err(Error(ParserError(i))),
|
||||
}
|
||||
Ok((i, Number::from(v)))
|
||||
}
|
||||
|
||||
fn decimal(i: &str) -> IResult<&str, Number> {
|
||||
|
|
|
@ -49,8 +49,8 @@ impl Serialize for Thing {
|
|||
|
||||
pub fn thing(i: &str) -> IResult<&str, Thing> {
|
||||
let (i, t) = ident_raw(i)?;
|
||||
let (i, v) = ident_raw(i)?;
|
||||
let (i, _) = char(':')(i)?;
|
||||
let (i, v) = ident_raw(i)?;
|
||||
Ok((
|
||||
i,
|
||||
Thing {
|
||||
|
|
|
@ -23,8 +23,8 @@ use crate::sql::subquery::{subquery, Subquery};
|
|||
use crate::sql::table::{table, Table};
|
||||
use crate::sql::thing::{thing, Thing};
|
||||
use async_recursion::async_recursion;
|
||||
use bigdecimal::BigDecimal;
|
||||
use chrono::{DateTime, Utc};
|
||||
use dec::Decimal;
|
||||
use derive::Store;
|
||||
use fuzzy_matcher::skim::SkimMatcherV2;
|
||||
use fuzzy_matcher::FuzzyMatcher;
|
||||
|
@ -279,12 +279,6 @@ impl From<f64> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Decimal> for Value {
|
||||
fn from(v: Decimal) -> Self {
|
||||
Value::Number(Number::from(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Value {
|
||||
fn from(v: String) -> Self {
|
||||
Value::Strand(Strand::from(v))
|
||||
|
@ -496,14 +490,14 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn as_decimal(self) -> Decimal {
|
||||
pub fn as_decimal(self) -> BigDecimal {
|
||||
match self {
|
||||
Value::True => Decimal::from(1),
|
||||
Value::True => BigDecimal::from(1),
|
||||
Value::Number(v) => v.as_decimal(),
|
||||
Value::Strand(v) => Decimal::from_str(v.as_str()).unwrap_or_default(),
|
||||
Value::Strand(v) => BigDecimal::from_str(v.as_str()).unwrap_or_default(),
|
||||
Value::Duration(v) => v.value.as_secs().into(),
|
||||
Value::Datetime(v) => v.value.timestamp().into(),
|
||||
_ => Decimal::default(),
|
||||
_ => BigDecimal::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue