Skip to content

Commit

Permalink
coprocessor, dag: add IfJson, IfNullJson signature and some flags.
Browse files Browse the repository at this point in the history
  • Loading branch information
hicqu committed Sep 8, 2017
1 parent fbf6e28 commit e40d007
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 13 deletions.
3 changes: 2 additions & 1 deletion src/coprocessor/codec/mysql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ pub mod json;

pub use self::duration::Duration;
pub use self::decimal::{dec_encoded_len, Decimal, DecimalDecoder, DecimalEncoder, Res};
pub use self::types::{has_not_null_flag, has_unsigned_flag};
pub use self::types::{has_is_boolean_flag, has_not_null_flag, has_parse_to_json_flag,
has_unsigned_flag};
pub use self::time::Time;
pub use self::json::{parse_json_path_expr, Json, JsonDecoder, JsonEncoder, ModifyType,
PathExpression};
Expand Down
16 changes: 16 additions & 0 deletions src/coprocessor/codec/mysql/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
const NOT_NULL_FLAG: u64 = 1;
/// The field is unsigned.
pub const UNSIGNED_FLAG: u64 = 32;
/// When cast to Json, should **PARSE** but not **COERCE**.
pub const PARSE_TO_JSON_FLAG: u64 = 262144;
/// Telling boolean literal from integers.
pub const IS_BOOLEAN_FLAG: u64 = 524288;

/// `has_unsigned_flag` checks if `UNSIGNED_FLAG` is set.
#[inline]
Expand All @@ -29,6 +33,18 @@ pub fn has_not_null_flag(flag: u64) -> bool {
flag & NOT_NULL_FLAG > 0
}

#[inline]
pub fn has_parse_to_json_flag<T: Into<u64>>(flag: T) -> bool {
let flag: u64 = flag.into();
flag & PARSE_TO_JSON_FLAG > 0
}

#[inline]
pub fn has_is_boolean_flag<T: Into<u64>>(flag: T) -> bool {
let flag: u64 = flag.into();
flag & IS_BOOLEAN_FLAG > 0
}

/// `MySQL` type informations.
pub const UNSPECIFIED: u8 = 0;
pub const TINY: u8 = 1;
Expand Down
32 changes: 25 additions & 7 deletions src/coprocessor/dag/expr/builtin_cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,10 @@ impl FnCall {
row: &'a [Datum],
) -> Result<Option<Cow<'a, Json>>> {
let val = try_opt!(self.children[0].eval_int(ctx, row));
let j = if mysql::has_unsigned_flag(self.children[0].get_tp().get_flag() as u64) {
let flag = self.children[0].get_tp().get_flag();
let j = if mysql::has_is_boolean_flag(flag) {
Json::Boolean(val != 0)
} else if mysql::has_unsigned_flag(flag) {
Json::U64(val as u64)
} else {
Json::I64(val)
Expand Down Expand Up @@ -541,7 +544,7 @@ impl FnCall {
) -> Result<Option<Cow<'a, Json>>> {
let val = try_opt!(self.children[0].eval_string(ctx, row));
let s = try!(String::from_utf8(val.into_owned()));
if self.tp.get_decimal() == 0 {
if mysql::has_parse_to_json_flag(self.tp.get_flag()) {
let j: Json = try!(s.parse());
Ok(Some(Cow::Owned(j)))
} else {
Expand Down Expand Up @@ -1609,6 +1612,16 @@ mod test {
vec![Datum::U64(32)],
Some(Json::U64(32)),
),
(
Some(types::UNSIGNED_FLAG | types::IS_BOOLEAN_FLAG),
vec![Datum::U64(1)],
Some(Json::Boolean(true)),
),
(
Some(types::UNSIGNED_FLAG | types::IS_BOOLEAN_FLAG),
vec![Datum::I64(0)],
Some(Json::Boolean(false)),
),
(None, vec![Datum::I64(-1)], Some(Json::I64(-1))),
(None, vec![Datum::Null], None),
];
Expand Down Expand Up @@ -1680,21 +1693,26 @@ mod test {
ctx.ignore_truncate = true;
let cases = vec![
(
1,
false,
vec![Datum::Bytes(b"[1,2,3]".to_vec())],
Some(Json::String(String::from("[1,2,3]"))),
),
(
0,
true,
vec![Datum::Bytes(b"[1,2,3]".to_vec())],
Some(Json::Array(vec![Json::I64(1), Json::I64(2), Json::I64(3)])),
),
(0, vec![Datum::Null], None),
(false, vec![Datum::Null], None),
(true, vec![Datum::Null], None),
];
for (decimal, cols, exp) in cases {
for (by_parse, cols, exp) in cases {
let col_expr = col_expr(0, types::STRING as i32);
let mut ex = fncall_expr(ScalarFuncSig::CastStringAsJson, &[col_expr]);
ex.mut_field_type().set_decimal(decimal);
if by_parse {
let mut flag = ex.get_field_type().get_flag();
flag |= types::PARSE_TO_JSON_FLAG as u32;
ex.mut_field_type().set_flag(flag);
}
let e = Expression::build(ex, &ctx).unwrap();
let res = e.eval_json(&ctx, &cols).unwrap();
if exp.is_none() {
Expand Down
44 changes: 42 additions & 2 deletions src/coprocessor/dag/expr/builtin_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@ impl FnCall {
if_null(|i| self.children[i].eval_duration(ctx, row))
}

pub fn if_null_json<'a, 'b: 'a>(
&'b self,
ctx: &StatementContext,
row: &'a [Datum],
) -> Result<Option<Cow<'a, Json>>> {
if_null(|i| self.children[i].eval_json(ctx, row))
}

pub fn if_int(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<i64>> {
if_condition(self, ctx, row, |i| self.children[i].eval_int(ctx, row))
}
Expand Down Expand Up @@ -150,6 +158,14 @@ impl FnCall {
if_condition(self, ctx, row, |i| self.children[i].eval_duration(ctx, row))
}

pub fn if_json<'a, 'b: 'a>(
&'b self,
ctx: &StatementContext,
row: &'a [Datum],
) -> Result<Option<Cow<'a, Json>>> {
if_condition(self, ctx, row, |i| self.children[i].eval_json(ctx, row))
}

pub fn case_when_int(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<i64>> {
case_when(self, ctx, row, |v| v.eval_int(ctx, row))
}
Expand Down Expand Up @@ -287,7 +303,18 @@ mod test {
Datum::Dur(Duration::from_nanos(345, 2).unwrap()),
Datum::Dur(Duration::from_nanos(345, 2).unwrap()),
),
// TODO: add Time related tests after Time is implementted in Expression::build
(
ScalarFuncSig::IfNullTime,
Datum::Null,
Datum::Time(Time::parse_utc_datetime("1970-01-01 12:00:00", 6).unwrap()),
Datum::Time(Time::parse_utc_datetime("1970-01-01 12:00:00", 6).unwrap()),
),
(
ScalarFuncSig::IfNullJson,
Datum::Null,
Datum::Json(Json::String("hello".to_owned())),
Datum::Json(Json::String("hello".to_owned())),
),
];
let ctx = StatementContext::default();
for (operator, branch1, branch2, exp) in tests {
Expand Down Expand Up @@ -407,7 +434,20 @@ mod test {
Datum::Dur(Duration::from_nanos(345, 2).unwrap()),
Datum::Dur(Duration::from_nanos(345, 2).unwrap()),
),
// TODO: add Time related tests after Time is implementted in Expression::build
(
ScalarFuncSig::IfTime,
Datum::I64(0),
Datum::Time(Time::parse_utc_datetime("1970-01-01 12:00:00", 6).unwrap()),
Datum::Time(Time::parse_utc_datetime("1971-01-01 12:00:00", 6).unwrap()),
Datum::Time(Time::parse_utc_datetime("1971-01-01 12:00:00", 6).unwrap()),
),
(
ScalarFuncSig::IfJson,
Datum::I64(0),
Datum::Json(Json::I64(300)),
Datum::Json(Json::String("hello".to_owned())),
Datum::Json(Json::String("hello".to_owned())),
),
];
let ctx = StatementContext::default();
for (operator, cond, branch1, branch2, exp) in tests {
Expand Down
5 changes: 5 additions & 0 deletions src/coprocessor/dag/expr/builtin_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ impl FnCall {
Ok(Some(arg.is_none() as i64))
}

pub fn json_is_null(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<i64>> {
let arg = try!(self.children[0].eval_json(ctx, row));
Ok(Some(arg.is_none() as i64))
}

pub fn bit_and(&self, ctx: &StatementContext, row: &[Datum]) -> Result<Option<i64>> {
let lhs = try_opt!(self.children[0].eval_int(ctx, row));
let rhs = try_opt!(self.children[1].eval_int(ctx, row));
Expand Down
10 changes: 7 additions & 3 deletions src/coprocessor/dag/expr/fncall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ impl FnCall {
ScalarFuncSig::IfNullDecimal |
ScalarFuncSig::IfNullTime |
ScalarFuncSig::IfNullDuration |
ScalarFuncSig::IfNullJson |
ScalarFuncSig::LogicalAnd |
ScalarFuncSig::LogicalOr |
ScalarFuncSig::LogicalXor |
Expand Down Expand Up @@ -162,6 +163,7 @@ impl FnCall {
ScalarFuncSig::StringIsNull |
ScalarFuncSig::TimeIsNull |
ScalarFuncSig::DurationIsNull |
ScalarFuncSig::JsonIsNull |
ScalarFuncSig::AbsInt |
ScalarFuncSig::AbsUInt |
ScalarFuncSig::AbsReal |
Expand All @@ -186,6 +188,7 @@ impl FnCall {
ScalarFuncSig::IfDecimal |
ScalarFuncSig::IfTime |
ScalarFuncSig::IfDuration |
ScalarFuncSig::IfJson |
ScalarFuncSig::LikeSig => (3, 3),

ScalarFuncSig::JsonArraySig | ScalarFuncSig::JsonObjectSig => (0, usize::MAX),
Expand All @@ -212,8 +215,6 @@ impl FnCall {
ScalarFuncSig::JsonSetSig |
ScalarFuncSig::JsonInsertSig |
ScalarFuncSig::JsonReplaceSig => (3, usize::MAX),

_ => return Err(Error::UnknownSignature(sig)),
};
if args < min_args || args > max_args {
return Err(box_err!("unexpected arguments"));
Expand Down Expand Up @@ -344,7 +345,6 @@ macro_rules! dispatch_call {
$(ScalarFuncSig::$j_sig => {
self.$j_func(ctx, row, $($j_arg)*).map(Datum::from)
})*
_=>Err(Error::UnknownSignature(self.sig)),
}
}
}
Expand Down Expand Up @@ -439,6 +439,7 @@ dispatch_call! {
StringIsNull => string_is_null,
TimeIsNull => time_is_null,
DurationIsNull => duration_is_null,
JsonIsNull => json_is_null,

AbsInt => abs_int,
AbsUInt => abs_uint,
Expand Down Expand Up @@ -571,6 +572,9 @@ dispatch_call! {
CoalesceJson => coalesce_json,
CaseWhenJson => case_when_json,

IfJson => if_json,
IfNullJson => if_null_json,

JsonExtractSig => json_extract,
JsonSetSig => json_set,
JsonInsertSig => json_insert,
Expand Down

0 comments on commit e40d007

Please sign in to comment.