use std::sync::Arc;
use chrono_tz::Tz;
use crate::binary::Encoder;
use crate::binary::ReadEx;
use crate::errors::Result;
use crate::types::column::column_data::BoxColumnData;
use crate::types::column::column_data::ColumnData;
use crate::types::column::list::List;
use crate::types::column::nullable::NullableColumnData;
use crate::types::column::BoxColumnWrapper;
use crate::types::column::ColumnFrom;
use crate::types::column::ColumnWrapper;
use crate::types::column::Either;
use crate::types::column::VectorColumnData;
use crate::types::decimal::Decimal;
use crate::types::decimal::NoBits;
use crate::types::from_sql::FromSql;
use crate::types::Column;
use crate::types::ColumnType;
use crate::types::SqlType;
use crate::types::Value;
use crate::types::ValueRef;
pub(crate) struct DecimalColumnData {
pub(crate) inner: Box<dyn ColumnData + Send + Sync>,
pub(crate) precision: u8,
pub(crate) scale: u8,
pub(crate) nobits: NoBits
}
pub(crate) struct DecimalAdapter<K: ColumnType> {
pub(crate) column: Column<K>,
pub(crate) precision: u8,
pub(crate) scale: u8,
pub(crate) nobits: NoBits
}
pub(crate) struct NullableDecimalAdapter<K: ColumnType> {
pub(crate) column: Column<K>,
pub(crate) precision: u8,
pub(crate) scale: u8,
pub(crate) nobits: NoBits
}
impl DecimalColumnData {
pub(crate) fn load<T: ReadEx>(
reader: &mut T,
precision: u8,
scale: u8,
nobits: NoBits,
size: usize,
tz: Tz
) -> Result<Self> {
let type_name = match nobits {
NoBits::N32 => "Int32",
NoBits::N64 => "Int64"
};
let inner =
<dyn ColumnData>::load_data::<BoxColumnWrapper, _>(reader, type_name, size, tz)?;
Ok(DecimalColumnData {
inner,
precision,
scale,
nobits
})
}
}
impl ColumnFrom for Vec<Decimal> {
fn column_from<W: ColumnWrapper>(source: Self) -> W::Wrapper {
let mut data = List::<i64>::with_capacity(source.len());
let mut precision = 18;
let mut opt_scale = None;
for s in source {
precision = std::cmp::max(precision, s.precision);
if let Some(old_scale) = opt_scale {
if old_scale != s.scale {
panic!("scale != scale")
}
} else {
opt_scale = Some(s.scale);
}
data.push(s.internal());
}
let scale = opt_scale.unwrap_or(4);
let inner = Box::new(VectorColumnData { data });
let column = DecimalColumnData {
inner,
precision,
scale,
nobits: NoBits::N64
};
W::wrap(column)
}
}
impl ColumnFrom for Vec<Option<Decimal>> {
fn column_from<W: ColumnWrapper>(source: Self) -> W::Wrapper {
let mut nulls: Vec<u8> = Vec::with_capacity(source.len());
let mut data = List::<i64>::with_capacity(source.len());
let mut precision = 18;
let mut opt_scale = None;
for os in source {
if let Some(s) = os {
precision = std::cmp::max(precision, s.precision);
if let Some(old_scale) = opt_scale {
if old_scale != s.scale {
panic!("scale != scale")
}
} else {
opt_scale = Some(s.scale);
}
data.push(s.internal());
nulls.push(0);
} else {
data.push(0);
nulls.push(1);
}
}
let scale = opt_scale.unwrap_or(4);
let inner = Box::new(VectorColumnData { data });
let inner = DecimalColumnData {
inner,
precision,
scale,
nobits: NoBits::N64
};
W::wrap(NullableColumnData {
nulls,
inner: Arc::new(inner)
})
}
}
impl ColumnData for DecimalColumnData {
fn sql_type(&self) -> SqlType {
SqlType::Decimal(self.precision, self.scale)
}
fn save(&self, encoder: &mut Encoder, start: usize, end: usize) {
self.inner.save(encoder, start, end)
}
fn len(&self) -> usize {
self.inner.len()
}
fn push(&mut self, value: Value) {
if let Value::Decimal(decimal) = value {
match self.nobits {
NoBits::N32 => {
let internal: i32 = decimal.internal();
self.inner.push(internal.into())
}
NoBits::N64 => {
let internal: i64 = decimal.internal();
self.inner.push(internal.into())
}
}
} else {
panic!("value should be decimal ({:?})", value);
}
}
fn at(&self, index: usize) -> ValueRef {
let underlying: i64 = match self.nobits {
NoBits::N32 => i64::from(i32::from(self.inner.at(index))),
NoBits::N64 => i64::from(self.inner.at(index))
};
ValueRef::Decimal(Decimal {
underlying,
precision: self.precision,
scale: self.scale,
nobits: self.nobits
})
}
fn clone_instance(&self) -> BoxColumnData {
Box::new(Self {
inner: self.inner.clone_instance(),
precision: self.precision,
scale: self.scale,
nobits: self.nobits
})
}
unsafe fn get_internal(&self, pointers: &[*mut *const u8], level: u8) -> Result<()> {
assert_eq!(level, 0);
self.inner.get_internal(pointers, 0)?;
*(pointers[2] as *mut NoBits) = self.nobits;
Ok(())
}
}
impl<K: ColumnType> ColumnData for DecimalAdapter<K> {
fn sql_type(&self) -> SqlType {
SqlType::Decimal(self.precision, self.scale)
}
fn save(&self, encoder: &mut Encoder, start: usize, end: usize) {
for i in start..end {
if let ValueRef::Decimal(decimal) = self.at(i) {
match self.nobits {
NoBits::N32 => {
let internal: i32 = decimal.internal();
encoder.write(internal);
}
NoBits::N64 => {
let internal: i64 = decimal.internal();
encoder.write(internal);
}
}
} else {
panic!("should be decimal");
}
}
}
fn len(&self) -> usize {
self.column.len()
}
fn push(&mut self, _: Value) {
unimplemented!()
}
fn at(&self, index: usize) -> ValueRef {
if let ValueRef::Decimal(decimal) = self.column.at(index) {
let mut d = decimal.set_scale(self.scale);
d.precision = self.precision;
d.nobits = self.nobits;
ValueRef::Decimal(d)
} else {
panic!("should be decimal");
}
}
fn clone_instance(&self) -> BoxColumnData {
unimplemented!()
}
}
impl<K: ColumnType> ColumnData for NullableDecimalAdapter<K> {
fn sql_type(&self) -> SqlType {
SqlType::Nullable(SqlType::Decimal(self.precision, self.scale).into())
}
fn save(&self, encoder: &mut Encoder, start: usize, end: usize) {
let size = end - start;
let mut nulls = vec![0; size];
let mut values: Vec<Option<Decimal>> = vec![None; size];
for (i, index) in (start..end).enumerate() {
values[i] = Option::from_sql(self.at(index)).unwrap();
if values[i].is_none() {
nulls[i] = 1;
}
}
encoder.write_bytes(nulls.as_ref());
for value in values {
let underlying = if let Some(v) = value { v.underlying } else { 0 };
match self.nobits {
NoBits::N32 => {
encoder.write(underlying as i32);
}
NoBits::N64 => {
encoder.write(underlying);
}
}
}
}
fn len(&self) -> usize {
self.column.len()
}
fn push(&mut self, _: Value) {
unimplemented!()
}
fn at(&self, index: usize) -> ValueRef {
let value: Option<Decimal> = Option::from_sql(self.column.at(index)).unwrap();
match value {
None => ValueRef::Nullable(Either::Left(self.sql_type().into())),
Some(mut v) => {
v = v.set_scale(self.scale);
v.precision = self.precision;
v.nobits = self.nobits;
let inner = ValueRef::Decimal(v);
ValueRef::Nullable(Either::Right(Box::new(inner)))
}
}
}
fn clone_instance(&self) -> BoxColumnData {
unimplemented!()
}
}