New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coprocessor, dag: support decode Time from tipb.Expr #2199

Merged
merged 43 commits into from Aug 28, 2017
Commits
Jump to file or symbol
Failed to load files and symbols.
+182 −16
Diff settings

Always

Just for now

Viewing a subset of changes. View all

toto: port tests.

  • Loading branch information...
hicqu committed Aug 18, 2017
commit c4357ffe42098428a877e87d4186ea2f16304195
@@ -10,34 +10,168 @@
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
//
use std::{i64, f64};
use std::{f64, i64, u64};
use std::borrow::Cow;
use coprocessor::codec::{datum, mysql, Datum};
use super::{FnCall, Result, StatementContext};
use coprocessor::codec::mysql::{Decimal, MAX_FSP};
use super::{Error, FnCall, Result, StatementContext};
impl FnCall {
pub fn plus_real(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<f64>> {
let lhs = try!(self.children[0].eval_real(ctx, row));
let rhs = try!(self.children[1].eval_real(ctx, row));
do_plus(lhs, rhs, |l, r| {
let res = l + r;
if !res.is_finite() {
return Err(Error::Other("overflow"));
}
res
do_arithmetic(lhs, rhs, |l, r| {
let res = l + r;
if !res.is_finite() {
return Err(Error::Overflow);
}
Ok(r)
})
}
pub fn plus_decimal<'a, 'b: 'a>(&'b self, ctx: &StatementContext, row: &'a [Datum]) -> Result<Option<Cow<'a, Decimal>>> {
pub fn plus_decimal<'a, 'b: 'a>(
&'b self,
ctx: &StatementContext,
row: &'a [Datum],
) -> Result<Option<Cow<'a, Decimal>>> {
let lhs = try!(self.children[0].eval_decimal(ctx, row));
let rhs = try!(self.children[1].eval_decimal(ctx, row));
do_arithmetic(lhs, rhs, |l, r| {
let result: Result<Decimal> = (l.as_ref() + r.as_ref()).into();
result.map(Cow::Owned)
})
}
pub fn plus_int(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<i64>> {
let lhs = try!(self.children[0].eval_int(ctx, row));
let rhs = try!(self.children[1].eval_int(ctx, row));
do_arithmetic(lhs, rhs, |l, r| {
if (l > 0 && r > i64::MAX - l) || (l < 0 && r < i64::MIN - l) {
return Err(Error::Overflow);
}
Ok(l + r)
})
}
pub fn plus_uint(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<i64>> {
let lhs = try!(self.children[0].eval_int(ctx, row));
let rhs = try!(self.children[1].eval_int(ctx, row));
do_arithmetic(lhs, rhs, |l, r| {
let (l, r) = (l as u64, r as u64);
if l > u64::MAX - r {
return Err(Error::Overflow);
}
Ok((l + r) as i64)
})
}
pub fn minus_real(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<f64>> {
let lhs = try!(self.children[0].eval_real(ctx, row));
let rhs = try!(self.children[1].eval_real(ctx, row));
do_arithmetic(lhs, rhs, |l, r| {
let res = l - r;
if !res.is_finite() {
return Err(Error::Overflow);
}
Ok(r)
})
}
pub fn minus_decimal<'a, 'b: 'a>(
&'b self,
ctx: &StatementContext,
row: &'a [Datum],
) -> Result<Option<Cow<'a, Decimal>>> {
let lhs = try!(self.children[0].eval_decimal(ctx, row));
let rhs = try!(self.children[1].eval_decimal(ctx, row));
do_arithmetic(lhs, rhs, |l, r| {
let result: Result<Decimal> = (l.as_ref() - r.as_ref()).into();
result.map(Cow::Owned)
})
}
pub fn minus_int(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<i64>> {
let lhs = try!(self.children[0].eval_int(ctx, row));
let rhs = try!(self.children[1].eval_int(ctx, row));
do_arithmetic(lhs, rhs, |l, r| {
if (l > 0 && -r > i64::MAX - l) || (l < 0 && -r < i64::MIN - l) {
return Err(Error::Overflow);
}
Ok(l + r)
})
}
pub fn minus_uint(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<i64>> {
let lhs = try!(self.children[0].eval_int(ctx, row));
let rhs = try!(self.children[1].eval_int(ctx, row));
do_arithmetic(lhs, rhs, |l, r| {
let (l, r) = (l as u64, r as u64);
if l < r {
return Err(Error::Overflow);
}
Ok((l - r) as i64)
})
}
pub fn multiply_real(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<f64>> {
let lhs = try!(self.children[0].eval_real(ctx, row));
let rhs = try!(self.children[1].eval_real(ctx, row));
do_arithmetic(lhs, rhs, |l, r| {
let res = l * r;
if !res.is_finite() {
return Err(Error::Overflow);
}
Ok(r)
})
}
pub fn multiply_decimal<'a, 'b: 'a>(
&'b self,
ctx: &StatementContext,
row: &'a [Datum],
) -> Result<Option<Cow<'a, Decimal>>> {
let lhs = try!(self.children[0].eval_decimal(ctx, row));
let rhs = try!(self.children[1].eval_decimal(ctx, row));
do_arithmetic(lhs, rhs, |l, r| {
let result: Result<Decimal> = (l.as_ref() * r.as_ref()).into();
result.map(Cow::Owned)
})
}
pub fn multiply_int(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<i64>> {
let lhs = try!(self.children[0].eval_int(ctx, row));
let rhs = try!(self.children[1].eval_int(ctx, row));
do_arithmetic(lhs, rhs, |l, r| {
let res = l * r;
if l != 0 && res / l != r {
return Err(Error::Overflow);
}
Ok(res)
})
}
pub fn multiply_uint(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<i64>> {
let lhs = try!(self.children[0].eval_int(ctx, row));
let rhs = try!(self.children[1].eval_int(ctx, row));
do_arithmetic(lhs, rhs, |l, r| {
let (l, r) = (l as u64, r as u64);
let res = l * r;
if l != 0 && res / l != r {
return Err(Error::Overflow);
}
Ok(res as i64)
})
}
}
fn do_plus<T, F>(lhs: Option<T>, rhs: Option<T>, plus: F) -> Result<Option<T>>
#[inline]
fn do_arithmetic<T, F>(lhs: Option<T>, rhs: Option<T>, op: F) -> Result<Option<T>>
where
F: Fn(T, T) -> Result<Option<T>>
F: Fn(T, T) -> Result<T>,
{
Ok(None)
match (lhs, rhs) {
(None, _) | (_, None) => Ok(None),
(Some(lhs), Some(rhs)) => op(lhs, rhs).map(|t| Some(t)),
}
}
@@ -18,6 +18,7 @@ mod constant;
mod fncall;
mod builtin_cast;
mod compare;
mod arithmetic;
use self::compare::CmpOp;
use std::io;
@@ -26,7 +27,7 @@ use std::string::FromUtf8Error;
use tipb::expression::{Expr, ExprType, FieldType, ScalarFuncSig};
use coprocessor::codec::mysql::{Decimal, Duration, Json, Time, MAX_FSP};
use coprocessor::codec::mysql::{Decimal, Duration, Json, Res, Time, MAX_FSP};
use coprocessor::codec::mysql::decimal::DecimalDecoder;
use coprocessor::codec::mysql::types;
use coprocessor::codec::Datum;
@@ -59,6 +60,14 @@ quick_error! {
description("column offset not found")
display("illegal column offset: {}", offset)
}
Truncated {
description("Truncated")
display("error Truncated")
}
Overflow {
description("Overflow")
display("error Overflow")
}
Other(desc: &'static str) {
description(desc)
display("error {}", desc)
@@ -74,6 +83,16 @@ impl From<FromUtf8Error> for Error {
pub type Result<T> = ::std::result::Result<T, Error>;
impl<T> Into<Result<T>> for Res<T> {
fn into(self) -> Result<T> {
match self {
Res::Ok(t) => Ok(t),
Res::Truncated(_) => Err(Error::Truncated),
Res::Overflow(_) => Err(Error::Overflow),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
Constant(Constant),
@@ -178,6 +197,11 @@ impl Expression {
ScalarFuncSig::NEJson => f.compare_json(ctx, row, CmpOp::NE),
ScalarFuncSig::NullEQJson => f.compare_json(ctx, row, CmpOp::NullEQ),
ScalarFuncSig::PlusInt => f.plus_int(ctx, row),
ScalarFuncSig::PlusIntUnsigned => f.plus_uint(ctx, row),
ScalarFuncSig::MinusInt => f.minus_int(ctx, row),
ScalarFuncSig::MinusIntUnsigned => f.minus_uint(ctx, row),
_ => Err(Error::Other("Unknown signature")),
},
}
@@ -187,7 +211,11 @@ impl Expression {
match *self {
Expression::Constant(ref constant) => constant.eval_real(),
Expression::ColumnRef(ref column) => column.eval_real(row),
_ => unimplemented!(),
Expression::ScalarFn(ref f) => match f.sig {
ScalarFuncSig::PlusReal => f.plus_real(ctx, row),
ScalarFuncSig::MinusReal => f.minus_real(ctx, row),
_ => unimplemented!(),
},
}
}
@@ -199,7 +227,11 @@ impl Expression {
match *self {
Expression::Constant(ref constant) => constant.eval_decimal(),
Expression::ColumnRef(ref column) => column.eval_decimal(row),
_ => unimplemented!(),
Expression::ScalarFn(ref f) => match f.sig {
ScalarFuncSig::PlusDecimal => f.plus_decimal(ctx, row),
ScalarFuncSig::MinusDecimal => f.minus_decimal(ctx, row),
_ => unimplemented!(),
},
}
}
ProTip! Use n and p to navigate between commits in a pull request.