xeval/evaluator: implement json_extract
@@ -21,7 +21,7 @@ use tipb::select::SelectRequest;
use util::codec::number::NumberDecoder;
use util::codec::datum::{Datum, DatumDecoder};
-use util::codec::mysql::{DecimalDecoder, MAX_FSP, Duration, Json};
+use util::codec::mysql::{DecimalDecoder, MAX_FSP, Duration, Json, PathExpression};
use util::codec;
use util::collections::{HashMap, HashMapEntry};
@@ -137,6 +137,7 @@ impl Evaluator {
ExprType::IfNull => self.eval_if_null(ctx, expr),
ExprType::IsNull => self.eval_is_null(ctx, expr),
ExprType::NullIf => self.eval_null_if(ctx, expr),
+ ExprType::JsonExtract => self.eval_json_extract(ctx, expr),
ExprType::JsonType => self.eval_json_type(ctx, expr),
ExprType::JsonMerge => self.eval_json_merge(ctx, expr),
_ => Ok(Datum::Null),
@@ -415,6 +416,22 @@ impl Evaluator {
}
}
+ fn eval_json_extract(&mut self, ctx: &EvalContext, expr: &Expr) -> Result<Datum> {
+ let children = try!(self.eval_more_children(ctx, expr, 2));
+ if children.iter().any(|item| *item == Datum::Null) {
+ return Ok(Datum::Null);
+ }
+ let mut children = children.into_iter();
+ let json = try!(children.next().unwrap().cast_as_json());
+ let path_extrs: Vec<PathExpression> = try!(children.map(|item| item.to_json_path_expr())
+ .collect());
+ if let Some(data) = json.extract(&path_extrs) {
+ Ok(Datum::Json(data))
+ } else {
+ Ok(Datum::Null)
+ }
+ }
+
fn eval_json_type(&mut self, ctx: &EvalContext, expr: &Expr) -> Result<Datum> {
let child = try!(self.eval_one_child(ctx, expr));
if Datum::Null == child {
@@ -1073,6 +1090,15 @@ mod test {
build_expr(datums, tp)
}
+ test_eval!(test_eval_json_extract,
+ vec![(build_expr(vec![Datum::Null, Datum::Null], ExprType::JsonExtract),
+ Datum::Null),
+ (build_byte_datums_expr(&[br#"{"a": [{"aa": [{"aaa": 1}]}], "aaa": 2}"#,
+ b"$.a[0].aa[0].aaa",
+ b"$.aaa"],
+ ExprType::JsonExtract),
+ Datum::Json("[1,2]".parse().unwrap()))]);
+
test_eval!(test_eval_json_type,
vec![
(build_expr(vec![Datum::Null], ExprType::JsonType),
@@ -1103,6 +1129,11 @@ mod test {
test_eval_err!(test_eval_json_err,
vec![
+ build_expr(vec![], ExprType::JsonExtract),
+ build_byte_datums_expr(&[br#"{"a": [{"aa": [{"aaa": 1}]}], "aaa": 2}"#],
+ ExprType::JsonExtract),
+ build_byte_datums_expr(&[br#"{"a": [{"aa": [{"aaa": 1}]}], "aaa": 2}"#, b"aaa"],
+ ExprType::JsonExtract),
build_expr(vec![], ExprType::JsonType),
build_byte_datums_expr(&[br#"true"#, br#"444"#], ExprType::JsonType),
build_expr(vec![], ExprType::JsonMerge),
