Skip to content

Commit

Permalink
Add FLOOR function (#183)
Browse files Browse the repository at this point in the history
  • Loading branch information
cswinter authored Jul 24, 2024
1 parent 84d6a9f commit e9045c7
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 18 deletions.
8 changes: 8 additions & 0 deletions src/engine/operators/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::i64;

use chrono::{DateTime, Datelike};

use crate::engine::of64;

use super::map_operator::MapOp;


Expand All @@ -12,6 +14,12 @@ impl MapOp<i64, i64> for ToYear {
fn name() -> &'static str { "to_year" }
}

pub struct Floor;

impl MapOp<of64, i64> for Floor {
fn apply(&self, f: of64) -> i64 { f.floor() as i64 }
fn name() -> &'static str { "floor" }
}

pub struct BooleanNot;

Expand Down
9 changes: 9 additions & 0 deletions src/engine/operators/type_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ impl Cast<u64> for u32 { fn cast(self) -> u64 { u64::from(self) } }
impl Cast<u64> for i64 { fn cast(self) -> u64 { self as u64 } }


impl Cast<of64> for u8 { fn cast(self) -> OrderedFloat<f64> { OrderedFloat::from(self as f64) } }

impl Cast<of64> for u16 { fn cast(self) -> OrderedFloat<f64> { OrderedFloat::from(self as f64) } }

impl Cast<of64> for u32 { fn cast(self) -> OrderedFloat<f64> { OrderedFloat::from(self as f64) } }

impl Cast<of64> for i64 { fn cast(self) -> OrderedFloat<f64> { OrderedFloat::from(self as f64) } }


impl<'a> Cast<Val<'a>> for u8 { fn cast(self) -> Val<'a> { Val::Integer(self as i64) } }

impl<'a> Cast<Val<'a>> for u16 { fn cast(self) -> Val<'a> { Val::Integer(self as i64) } }
Expand Down
33 changes: 27 additions & 6 deletions src/engine/operators/vector_operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,14 @@ pub mod operator {
lhs: ScalarI64, rhs: Float;
Ok(Box::new(BinarySVOperator { lhs, rhs, output: output.into(), op: PhantomData::<Multiplication<_, _, OrderedFloat<f64>>> }));
lhs: Float, rhs: ScalarI64;
Ok(Box::new(BinaryVSOperator { lhs, rhs, output: output.into(), op: PhantomData::<Multiplication<_, _, OrderedFloat<f64>>> }));
lhs: ScalarF64, rhs: Integer;
Ok(Box::new(BinarySVOperator { lhs, rhs, output: output.into(), op: PhantomData::<Multiplication<_, _, OrderedFloat<f64>>> }));
lhs: Integer, rhs: ScalarF64;
Ok(Box::new(BinaryVSOperator { lhs, rhs, output: output.into(), op: PhantomData::<Multiplication<_, _, OrderedFloat<f64>>> }));
lhs: ScalarF64, rhs: Float;
Ok(Box::new(BinarySVOperator { lhs, rhs, output: output.into(), op: PhantomData::<Multiplication<_, _, OrderedFloat<f64>>> }));
lhs: Float, rhs: ScalarF64;
Ok(Box::new(BinaryVSOperator { lhs, rhs, output: output.into(), op: PhantomData::<Multiplication<_, _, OrderedFloat<f64>>> }))
}
}
Expand Down Expand Up @@ -1347,13 +1355,18 @@ pub mod operator {
input.tag, output.tag
);
}
} else {
if input.tag == EncodingType::Str && output.tag == EncodingType::OptStr {
return Ok(Box::new(TypeConversionOperator {
input: input.str()?,
output: output.opt_str()?,
}));
} else if input.tag == EncodingType::Str && output.tag == EncodingType::OptStr {
Ok(Box::new(TypeConversionOperator {
input: input.str()?,
output: output.opt_str()?,
}))
} else if output.tag == EncodingType::F64 {
reify_types! {
"type_conversion";
input: IntegerNoU64, output: Float;
Ok(Box::new(TypeConversionOperator { input, output }))
}
} else {
reify_types! {
"type_conversion";
input: Integer, output: Integer;
Expand All @@ -1379,6 +1392,14 @@ pub mod operator {
})
}

pub fn floor<'a>(input: BufferRef<of64>, output: BufferRef<i64>) -> BoxedOperator<'a> {
Box::new(MapOperator {
input,
output,
map: Floor,
})
}

pub fn regex<'a>(
input: BufferRef<&'a str>,
r: &str,
Expand Down
20 changes: 20 additions & 0 deletions src/engine/planning/query_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ pub enum QueryPlan {
#[output(t = "base=data;null=_always")]
nullable: TypedBufferRef,
},
Floor {
input: BufferRef<of64>,
#[output]
floor: BufferRef<i64>,
},
/// Converts NullableI64, NullableStr, or NullableF64 into a representation where nulls are encoded as part
/// of the data (i64 with i64::MAX representing null for NullableI64, Option<&str> for NullableStr, and special NaN value F64_NULL representing null for NullableF64).
FuseNulls {
Expand Down Expand Up @@ -1350,6 +1355,18 @@ impl QueryPlan {
}
(planner.to_year(decoded), Type::integer())
}
Func1Type::Floor => {
let decoded = t.codec.decode(plan, planner);
match t.decoded {
BasicType::Integer => (decoded, t),
BasicType::Float => (planner.floor(decoded.f64()?).into(), t),
_ => bail!(
QueryError::TypeError,
"Found floor({:?}), expected floor(float)",
&t
),
}
}
Func1Type::Length => {
let decoded = t.codec.decode(plan, planner);
if t.decoded != BasicType::String {
Expand Down Expand Up @@ -1520,7 +1537,9 @@ fn encoding_range(plan: &TypedBufferRef, qp: &QueryPlanner) -> Option<(i64, i64)
let max = p1.max(p2).max(p3).max(p4);
Some((min, max))
}
Floor { input, .. } => encoding_range(&input.into(), qp),
ScalarI64 { value, .. } => Some((value, value)),
ScalarF64 { value, .. } => Some((value.floor() as i64, value.ceil() as i64)),
ref plan => {
error!("encoding_range not implement for {:?}", plan);
None
Expand Down Expand Up @@ -1865,6 +1884,7 @@ pub(super) fn prepare<'a>(
QueryPlan::GetNullMap { nullable, present } => {
operator::get_null_map(nullable.nullable_any()?, present)
}
QueryPlan::Floor { input, floor } => operator::floor(input, floor),
QueryPlan::FuseNulls { nullable, fused } => operator::fuse_nulls(nullable, fused)?,
QueryPlan::FuseIntNulls {
offset,
Expand Down
1 change: 1 addition & 0 deletions src/syntax/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub enum Func1Type {
IsNull,
IsNotNull,
Length,
Floor,
}

impl Expr {
Expand Down
5 changes: 4 additions & 1 deletion src/syntax/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,10 @@ fn convert_to_native_expr(node: &ASTNode) -> Result<Box<Expr>, QueryError> {
convert_to_native_expr(pattern)?,
)
}
_ => return Err(QueryError::NotImplemented(format!("{:?}", node))),
ASTNode::Floor { expr, field: DateTimeField::NoDateTime } => {
Expr::Func1(Func1Type::Floor, convert_to_native_expr(expr)?)
}
_ => return Err(QueryError::NotImplemented(format!("Parsing for this ASTNode not implemented: {:?}", node))),
}))
}

Expand Down
22 changes: 11 additions & 11 deletions test_data/edge_cases.csv
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
u8_offset_encoded,non_dense_ints,enum,string_packed,constant0,constant0_2,negative,id,nullable_int,nullable_int2,country,largenum,float,nullable_float
256,0,aa,xyz,0,0,-199,0,-1,,Germany,-9223372036854775808,0.123412,
258,2,aa,abc,0,0,39,1,-40,-40,USA,9223372036854775806,3e-4,
259,3,aa,axz,0,0,-100,2,,,France,9223372036854775806,-124.0,0.4
257,1,bb,AXY,0,0,34,3,,0,,9223372036854775806,3.15159,
275,4,bb,azy,0,0,4031,4,10,9,France,-9223372036854775808,0.1234e30,
500,0,aa,$sss,0,0,32,5,,6,,9223372036854775806,1e-6,
343,2,cc,asd,0,0,-130,6,,,Turkey,-9223372036854775808,0.0,1e-32
432,1,aa,_f,0,0,-120,7,20,,,9223372036854775806,0.000001,
511,2,cc,t,0,0,4010,8,,1,,-9223372036854775808,-1.0,
500,3,bb,😈,0,0,-40,9,13,14,Germany,9223372036854775806,1234124.51325,1.123124e30
u8_offset_encoded,non_dense_ints,enum,string_packed,constant0,constant0_2,negative,id,nullable_int,nullable_int2,country,largenum,float,nullable_float,float01
256,0,aa,xyz,0,0,-199,0,-1,,Germany,-9223372036854775808,0.123412,,0.3
258,2,aa,abc,0,0,39,1,-40,-40,USA,9223372036854775806,3e-4,,-0.4
259,3,aa,axz,0,0,-100,2,,,France,9223372036854775806,-124.0,0.4,0.421231
257,1,bb,AXY,0,0,34,3,,0,,9223372036854775806,3.15159,,0.9482
275,4,bb,azy,0,0,4031,4,10,9,France,-9223372036854775808,0.1234e30,,0.1
500,0,aa,$sss,0,0,32,5,,6,,9223372036854775806,1e-6,,0.2
343,2,cc,asd,0,0,-130,6,,,Turkey,-9223372036854775808,0.0,1e-32,0.5
432,1,aa,_f,0,0,-120,7,20,,,9223372036854775806,0.000001,,0.23
511,2,cc,t,0,0,4010,8,,1,,-9223372036854775808,-1.0,,0.742
500,3,bb,😈,0,0,-40,9,13,14,Germany,9223372036854775806,1234124.51325,1.123124e30,-0.2
32 changes: 32 additions & 0 deletions tests/query_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1878,3 +1878,35 @@ fn test_float_greater_than_int() {
// &[vec![Int(0)]],
// );
// }


#[test]
fn test_floor1() {
test_query_ec(
"SELECT MAX(id), MIN(id), FLOOR(float01 * 10) FROM default",
&[
vec![Int(1), Int(1), Int(-4)],
vec![Int(9), Int(9), Int(-2)],
vec![Int(4), Int(4), Int(1)],
vec![Int(7), Int(5), Int(2)],
vec![Int(0), Int(0), Int(3)],
vec![Int(2), Int(2), Int(4)],
vec![Int(6), Int(6), Int(5)],
vec![Int(8), Int(8), Int(7)],
vec![Int(3), Int(3), Int(9)]
],
);
}


#[test]
fn test_floor2() {
test_query_ec(
"SELECT MIN(id), MAX(id), FLOOR(id * 0.23) FROM default",
&[
vec![Int(0), Int(4), Int(0)],
vec![Int(5), Int(8), Int(1)],
vec![Int(9), Int(9), Int(2)],
],
);
}

0 comments on commit e9045c7

Please sign in to comment.