Skip to content

Commit

Permalink
copr: introduce Binary Json (tikv#6388)
Browse files Browse the repository at this point in the history
Signed-off-by: Fullstop000 <fullstop1005@gmail.com>
  • Loading branch information
Fullstop000 committed Feb 14, 2020
1 parent 524870e commit c26ac60
Show file tree
Hide file tree
Showing 41 changed files with 2,011 additions and 1,203 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions components/tidb_query/Cargo.toml
Expand Up @@ -26,6 +26,7 @@ match_template = { path = "../match_template" }
nom = "5.1.0"
num = { version = "0.2", default-features = false }
num-traits = "0.2"
num-derive = "0.3"
openssl = { version = "0.10" }
ordered-float = "1.0"
protobuf = "2"
Expand Down
2 changes: 1 addition & 1 deletion components/tidb_query/src/codec/chunk/chunk.rs
Expand Up @@ -342,7 +342,7 @@ mod tests {
let s = format!("{}.123435", row_id);
let bs = Datum::Bytes(s.as_bytes().to_vec());
let dec = Datum::Dec(s.parse().unwrap());
let json = Datum::Json(Json::String(s));
let json = Datum::Json(Json::from_string(s).unwrap());
chunk.append_datum(0, &Datum::Null).unwrap();
chunk.append_datum(1, &Datum::I64(row_id as i64)).unwrap();
chunk.append_datum(2, &bs).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion components/tidb_query/src/codec/chunk/column.rs
Expand Up @@ -780,7 +780,7 @@ impl Column {
/// Append a json datum to the column.
#[inline]
pub fn append_json(&mut self, j: &Json) -> Result<()> {
self.data.write_json(j)?;
self.data.write_json(j.as_ref())?;
self.finished_append_var();
Ok(())
}
Expand Down
30 changes: 15 additions & 15 deletions components/tidb_query/src/codec/convert.rs
Expand Up @@ -443,31 +443,31 @@ impl ToInt for Json {
#[inline]
fn to_int(&self, ctx: &mut EvalContext, tp: FieldTypeTp) -> Result<i64> {
// Casts json to int has different behavior in TiDB/MySQL when the json
// value is a `Json::Double` and we will keep compatible with TiDB
// value is a `Json::from_f64` and we will keep compatible with TiDB
// **Note**: select cast(cast('4.5' as json) as signed)
// TiDB: 5
// MySQL: 4
let val = match *self {
Json::Object(_) | Json::Array(_) | Json::None | Json::Boolean(false) => Ok(0),
Json::Boolean(true) => Ok(1),
Json::I64(d) => Ok(d),
Json::U64(d) => Ok(d as i64),
Json::Double(d) => d.to_int(ctx, tp),
Json::String(ref s) => s.as_bytes().to_int(ctx, tp),
let val = match self.as_ref().get_type() {
JsonType::Object | JsonType::Array => Ok(0),
JsonType::Literal => Ok(self.as_ref().get_literal().map_or(0, |x| x as i64)),
JsonType::I64 => Ok(self.as_ref().get_i64()),
JsonType::U64 => Ok(self.as_ref().get_u64() as i64),
JsonType::Double => self.as_ref().get_double().to_int(ctx, tp),
JsonType::String => self.as_ref().get_str_bytes()?.to_int(ctx, tp),
}?;
val.to_int(ctx, tp)
}

// Port from TiDB's types.ConvertJSONToInt
#[inline]
fn to_uint(&self, ctx: &mut EvalContext, tp: FieldTypeTp) -> Result<u64> {
let val = match *self {
Json::Object(_) | Json::Array(_) | Json::None | Json::Boolean(false) => Ok(0u64),
Json::Boolean(true) => Ok(1u64),
Json::I64(d) => Ok(d as u64),
Json::U64(d) => Ok(d),
Json::Double(d) => d.to_uint(ctx, tp),
Json::String(ref s) => s.as_bytes().to_uint(ctx, tp),
let val = match self.as_ref().get_type() {
JsonType::Object | JsonType::Array => Ok(0),
JsonType::Literal => Ok(self.as_ref().get_literal().map_or(0, |x| x as u64)),
JsonType::I64 => Ok(self.as_ref().get_i64() as u64),
JsonType::U64 => Ok(self.as_ref().get_u64()),
JsonType::Double => self.as_ref().get_double().to_uint(ctx, tp),
JsonType::String => self.as_ref().get_str_bytes()?.to_uint(ctx, tp),
}?;
val.to_uint(ctx, tp)
}
Expand Down
2 changes: 1 addition & 1 deletion components/tidb_query/src/codec/data_type/mod.rs
Expand Up @@ -10,7 +10,7 @@ mod vector;
pub type Int = i64;
pub type Real = ordered_float::NotNan<f64>;
pub type Bytes = Vec<u8>;
pub use crate::codec::mysql::{Decimal, Duration, Json, Time as DateTime};
pub use crate::codec::mysql::{Decimal, Duration, Json, JsonType, Time as DateTime};

// Dynamic eval types.
pub use self::scalar::{ScalarValue, ScalarValueRef};
Expand Down
4 changes: 2 additions & 2 deletions components/tidb_query/src/codec/data_type/vector.rs
Expand Up @@ -206,7 +206,7 @@ impl VectorValue {
let el = &vec[*idx];
match el {
Some(v) => {
size += 1 /* FLAG */ + v.binary_len();
size += 1 /* FLAG */ + v.as_ref().binary_len();
}
None => {
size += 1;
Expand Down Expand Up @@ -247,7 +247,7 @@ impl VectorValue {
let el = &vec[*idx];
match el {
Some(v) => {
size += 8 /* Offset */ + v.binary_len();
size += 8 /* Offset */ + v.as_ref().binary_len();
}
None => {
size += 8 /* Offset */;
Expand Down
50 changes: 29 additions & 21 deletions components/tidb_query/src/codec/datum.rs
Expand Up @@ -245,21 +245,21 @@ impl Datum {
fn cmp_json(&self, ctx: &mut EvalContext, json: &Json) -> Result<Ordering> {
let order = match *self {
Datum::Json(ref j) => j.cmp(json),
Datum::I64(d) => Json::I64(d).cmp(json),
Datum::U64(d) => Json::U64(d).cmp(json),
Datum::F64(d) => Json::Double(d).cmp(json),
Datum::I64(d) => Json::from_i64(d)?.cmp(json),
Datum::U64(d) => Json::from_u64(d)?.cmp(json),
Datum::F64(d) => Json::from_f64(d)?.cmp(json),
Datum::Dec(ref d) => {
// FIXME: it this same as TiDB's?
let ff = d.convert(ctx)?;
Json::Double(ff).cmp(json)
Json::from_f64(ff)?.cmp(json)
}
Datum::Bytes(ref d) => {
let data = str::from_utf8(d)?;
Json::String(String::from(data)).cmp(json)
Json::from_string(String::from(data))?.cmp(json)
}
_ => {
let data = self.to_string().unwrap_or_default();
Json::String(data).cmp(json)
Json::from_string(data)?.cmp(json)
}
};
Ok(order)
Expand Down Expand Up @@ -431,31 +431,31 @@ impl Datum {
let json: Json = s.parse()?;
Ok(json)
}
Datum::I64(d) => Ok(Json::I64(d)),
Datum::U64(d) => Ok(Json::U64(d)),
Datum::F64(d) => Ok(Json::Double(d)),
Datum::I64(d) => Json::from_i64(d),
Datum::U64(d) => Json::from_u64(d),
Datum::F64(d) => Json::from_f64(d),
Datum::Dec(d) => {
// TODO: remove the `cast_as_json` method
let ff = d.convert(&mut EvalContext::default())?;
Ok(Json::Double(ff))
Json::from_f64(ff)
}
Datum::Json(d) => Ok(d),
_ => {
let s = self.into_string()?;
Ok(Json::String(s))
Json::from_string(s)
}
}
}

/// into_json would convert Datum::Bytes(bs) into Json::String(bs)
/// and convert Datum::Null into Json::None.
/// into_json would convert Datum::Bytes(bs) into Json::from_string(bs)
/// and convert Datum::Null into Json::none().
/// This func would be used in json_unquote and json_modify
pub fn into_json(self) -> Result<Json> {
match self {
Datum::Null => Ok(Json::None),
Datum::Null => Json::none(),
Datum::Bytes(bs) => {
let s = String::from_utf8(bs)?;
Ok(Json::String(s))
Json::from_string(s)
}
_ => self.cast_as_json(),
}
Expand Down Expand Up @@ -901,7 +901,7 @@ pub trait DatumEncoder:
}
Datum::Json(ref j) => {
self.write_u8(JSON_FLAG)?;
self.write_json(j)?;
self.write_json(j.as_ref())?;
}
}
}
Expand Down Expand Up @@ -944,7 +944,7 @@ pub fn approximate_size(values: &[Datum], comparable: bool) -> usize {
}
}
Datum::Dec(ref d) => d.approximate_encoded_size(),
Datum::Json(ref d) => d.binary_len(),
Datum::Json(ref d) => d.as_ref().binary_len(),
Datum::Null | Datum::Min | Datum::Max => 0,
}
})
Expand Down Expand Up @@ -1592,16 +1592,24 @@ mod tests {
Datum::Json(Json::from_str(r#"{"key":"value"}"#).unwrap()),
Ordering::Equal,
),
(Datum::I64(18), Datum::Json(Json::I64(18)), Ordering::Equal),
(Datum::U64(18), Datum::Json(Json::I64(20)), Ordering::Less),
(
Datum::I64(18),
Datum::Json(Json::from_i64(18).unwrap()),
Ordering::Equal,
),
(
Datum::U64(18),
Datum::Json(Json::from_i64(20).unwrap()),
Ordering::Less,
),
(
Datum::F64(1.2),
Datum::Json(Json::Double(1.0)),
Datum::Json(Json::from_f64(1.0).unwrap()),
Ordering::Greater,
),
(
Datum::Dec(i32::MIN.into()),
Datum::Json(Json::Double(f64::from(i32::MIN))),
Datum::Json(Json::from_f64(f64::from(i32::MIN)).unwrap()),
Ordering::Equal,
),
(
Expand Down
2 changes: 1 addition & 1 deletion components/tidb_query/src/codec/datum_codec.rs
Expand Up @@ -178,7 +178,7 @@ pub trait DatumPayloadEncoder:

#[inline]
fn write_datum_payload_json(&mut self, v: &Json) -> Result<()> {
self.write_json(v).map_err(|_| {
self.write_json(v.as_ref()).map_err(|_| {
Error::InvalidDataType("Failed to encode datum payload from json".to_owned())
})
}
Expand Down
6 changes: 3 additions & 3 deletions components/tidb_query/src/codec/mysql/decimal.rs
Expand Up @@ -1829,9 +1829,9 @@ impl ConvertTo<Decimal> for Json {
/// Port from TiDB's types.ConvertJSONToDecimal
#[inline]
fn convert(&self, ctx: &mut EvalContext) -> Result<Decimal> {
match self {
Json::String(s) => {
Decimal::from_str(s.as_str()).or_else(|e| {
match self.as_ref().get_type() {
JsonType::String => {
Decimal::from_str(self.as_ref().get_str()?).or_else(|e| {
ctx.handle_truncate_err(e)?;
// FIXME: if TiDB's MyDecimal::FromString return err,
// it may has res. However, if TiKV's Decimal::from_str
Expand Down

0 comments on commit c26ac60

Please sign in to comment.