From a26cb6032ac3e1ba806ce239d2c221b1cf6afddb Mon Sep 17 00:00:00 2001 From: Stuart Carnie Date: Wed, 29 Mar 2023 07:22:27 +1100 Subject: [PATCH] feat: InfluxQL learns LOG function (arity 2) (#7333) --- .../query_tests2/cases/in/issue_6112.influxql | 9 +++-- .../cases/in/issue_6112.influxql.expected | 26 +++++++------ iox_query_influxql/src/plan/planner.rs | 37 +++++++++++++++++-- 3 files changed, 53 insertions(+), 19 deletions(-) diff --git a/influxdb_iox/tests/query_tests2/cases/in/issue_6112.influxql b/influxdb_iox/tests/query_tests2/cases/in/issue_6112.influxql index c3bc395ff3..23f78b8642 100644 --- a/influxdb_iox/tests/query_tests2/cases/in/issue_6112.influxql +++ b/influxdb_iox/tests/query_tests2/cases/in/issue_6112.influxql @@ -154,8 +154,7 @@ SELECT atan(f64), atan2(f64, 2), exp(f64), --- TODO(sgc): Dependent on https://github.com/apache/arrow-datafusion/issues/5206 --- log(f64, 8), + log(f64, 8), ln(f64), log2(f64), log10(f64), @@ -179,8 +178,7 @@ SELECT atan(i64), atan2(i64, 2), exp(i64), --- TODO(sgc): Dependent on https://github.com/apache/arrow-datafusion/issues/5206 --- log(i64, 8), + log(i64, 8), ln(i64), log2(i64), log10(i64), @@ -191,6 +189,9 @@ SELECT round(i64) FROM m0 LIMIT 1; +-- validate log requires two arguments +SELECT log(f64) FROM m0 LIMIT 1; + -- Deviation from InfluxQL is that NaNs are not coalesced to NULL -- The InfluxQL compatibility later will be responsible for this translation SELECT f64, asin(f64), acos(f64) FROM m0 LIMIT 1; diff --git a/influxdb_iox/tests/query_tests2/cases/in/issue_6112.influxql.expected b/influxdb_iox/tests/query_tests2/cases/in/issue_6112.influxql.expected index ee9c18344e..ff513df086 100644 --- a/influxdb_iox/tests/query_tests2/cases/in/issue_6112.influxql.expected +++ b/influxdb_iox/tests/query_tests2/cases/in/issue_6112.influxql.expected @@ -273,18 +273,20 @@ | m0 | 2022-10-31T02:00:00Z | 11.3 | 211 | lo | val01 | | | m0 | 2022-10-31T02:00:00Z | 10.4 | 101 | lo | val02 | | +------------------+----------------------+------+-----+-----+-------+-------+ --- InfluxQL: SELECT f64, abs(f64 * -1), sin(f64), cos(f64), tan(f64), asin(1/f64), acos(1/f64), atan(f64), atan2(f64, 2), exp(f64), ln(f64), log2(f64), log10(f64), sqrt(f64), pow(f64, 2), floor(f64), ceil(f64), round(f64) FROM m0 LIMIT 1; -+------------------+----------------------+------+------+---------------------+---------------------+--------------------+--------------------+-------------------+------------------+--------------------+-------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-------+------+-------+ -| iox::measurement | time | f64 | abs | sin | cos | tan | asin | acos | atan | atan2 | exp | ln | log2 | log10 | sqrt | pow | floor | ceil | round | -+------------------+----------------------+------+------+---------------------+---------------------+--------------------+--------------------+-------------------+------------------+--------------------+-------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-------+------+-------+ -| m0 | 2022-10-31T02:00:00Z | 10.1 | 10.1 | -0.6250706488928821 | -0.7805681801691837 | 0.8007893029375109 | 0.0991723838059207 | 1.471623942988976 | 1.47210806614649 | 1.3753055265462157 | 24343.00942440838 | 2.312535423847214 | 3.3362833878644325 | 1.0043213737826426 | 3.1780497164141406 | 102.00999999999999 | 10.0 | 11.0 | 10.0 | -+------------------+----------------------+------+------+---------------------+---------------------+--------------------+--------------------+-------------------+------------------+--------------------+-------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-------+------+-------+ --- InfluxQL: SELECT i64, abs(i64 * -1), sin(i64), cos(i64), tan(i64), acos(1/i64), atan(i64), atan2(i64, 2), exp(i64), ln(i64), log2(i64), log10(i64), sqrt(i64), pow(i64, 2), floor(i64), ceil(i64), round(i64) FROM m0 LIMIT 1; -+------------------+----------------------+-----+-------+---------------------+--------------------+--------------------+--------------------+-------------------+-----------+----------------------+------------------+-------------------+--------------------+-------------------+-------+-------+-------+-------+ -| iox::measurement | time | i64 | abs | sin | cos | tan | acos | atan | atan2 | exp | ln | log2 | log10 | sqrt | pow | floor | ceil | round | -+------------------+----------------------+-----+-------+---------------------+--------------------+--------------------+--------------------+-------------------+-----------+----------------------+------------------+-------------------+--------------------+-------------------+-------+-------+-------+-------+ -| m0 | 2022-10-31T02:00:00Z | 101 | 101.0 | 0.45202578717835057 | 0.8920048697881602 | 0.5067526002248183 | 1.5707963267948966 | 1.560895660206908 | 1.5509969 | 7.307059979368067e43 | 4.61512051684126 | 6.658211482751795 | 2.0043213737826426 | 10.04987562112089 | 10201 | 101.0 | 101.0 | 101.0 | -+------------------+----------------------+-----+-------+---------------------+--------------------+--------------------+--------------------+-------------------+-----------+----------------------+------------------+-------------------+--------------------+-------------------+-------+-------+-------+-------+ +-- InfluxQL: SELECT f64, abs(f64 * -1), sin(f64), cos(f64), tan(f64), asin(1/f64), acos(1/f64), atan(f64), atan2(f64, 2), exp(f64), log(f64, 8), ln(f64), log2(f64), log10(f64), sqrt(f64), pow(f64, 2), floor(f64), ceil(f64), round(f64) FROM m0 LIMIT 1; ++------------------+----------------------+------+------+---------------------+---------------------+--------------------+--------------------+-------------------+------------------+--------------------+-------------------+--------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-------+------+-------+ +| iox::measurement | time | f64 | abs | sin | cos | tan | asin | acos | atan | atan2 | exp | log | ln | log2 | log10 | sqrt | pow | floor | ceil | round | ++------------------+----------------------+------+------+---------------------+---------------------+--------------------+--------------------+-------------------+------------------+--------------------+-------------------+--------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-------+------+-------+ +| m0 | 2022-10-31T02:00:00Z | 10.1 | 10.1 | -0.6250706488928821 | -0.7805681801691837 | 0.8007893029375109 | 0.0991723838059207 | 1.471623942988976 | 1.47210806614649 | 1.3753055265462157 | 24343.00942440838 | 1.1120944626214775 | 2.312535423847214 | 3.3362833878644325 | 1.0043213737826426 | 3.1780497164141406 | 102.00999999999999 | 10.0 | 11.0 | 10.0 | ++------------------+----------------------+------+------+---------------------+---------------------+--------------------+--------------------+-------------------+------------------+--------------------+-------------------+--------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-------+------+-------+ +-- InfluxQL: SELECT i64, abs(i64 * -1), sin(i64), cos(i64), tan(i64), acos(1/i64), atan(i64), atan2(i64, 2), exp(i64), log(i64, 8), ln(i64), log2(i64), log10(i64), sqrt(i64), pow(i64, 2), floor(i64), ceil(i64), round(i64) FROM m0 LIMIT 1; ++------------------+----------------------+-----+-------+---------------------+--------------------+--------------------+--------------------+-------------------+-----------+----------------------+-----------+------------------+-------------------+--------------------+-------------------+-------+-------+-------+-------+ +| iox::measurement | time | i64 | abs | sin | cos | tan | acos | atan | atan2 | exp | log | ln | log2 | log10 | sqrt | pow | floor | ceil | round | ++------------------+----------------------+-----+-------+---------------------+--------------------+--------------------+--------------------+-------------------+-----------+----------------------+-----------+------------------+-------------------+--------------------+-------------------+-------+-------+-------+-------+ +| m0 | 2022-10-31T02:00:00Z | 101 | 101.0 | 0.45202578717835057 | 0.8920048697881602 | 0.5067526002248183 | 1.5707963267948966 | 1.560895660206908 | 1.5509969 | 7.307059979368067e43 | 2.2194037 | 4.61512051684126 | 6.658211482751795 | 2.0043213737826426 | 10.04987562112089 | 10201 | 101.0 | 101.0 | 101.0 | ++------------------+----------------------+-----+-------+---------------------+--------------------+--------------------+--------------------+-------------------+-----------+----------------------+-----------+------------------+-------------------+--------------------+-------------------+-------+-------+-------+-------+ +-- InfluxQL: SELECT log(f64) FROM m0 LIMIT 1; +Error while planning query: Error during planning: invalid number of arguments for log, expected 2, got 1 -- InfluxQL: SELECT f64, asin(f64), acos(f64) FROM m0 LIMIT 1; +------------------+----------------------+------+------+------+ | iox::measurement | time | f64 | asin | acos | diff --git a/iox_query_influxql/src/plan/planner.rs b/iox_query_influxql/src/plan/planner.rs index 2158e78d4b..2ada36aab5 100644 --- a/iox_query_influxql/src/plan/planner.rs +++ b/iox_query_influxql/src/plan/planner.rs @@ -108,7 +108,7 @@ struct Context<'a> { scope: ExprScope, tz: Option, - // + /// `true` if the query projects aggregates. is_aggregate: bool, // GROUP BY information @@ -874,12 +874,26 @@ impl<'a> InfluxQLToLogicalPlan<'a> { args: &[IQLExpr], schemas: &Schemas, ) -> Result { - let fun = BuiltinScalarFunction::from_str(name)?; let args = args .iter() .map(|e| self.expr_to_df_expr(ctx, e, schemas)) .collect::>>()?; - Ok(Expr::ScalarFunction { fun, args }) + + match BuiltinScalarFunction::from_str(name)? { + BuiltinScalarFunction::Log => { + if args.len() != 2 { + Err(DataFusionError::Plan( + "invalid number of arguments for log, expected 2, got 1".to_owned(), + )) + } else { + Ok(Expr::ScalarFunction { + fun: BuiltinScalarFunction::Log, + args: args.into_iter().rev().collect(), + }) + } + } + fun => Ok(Expr::ScalarFunction { fun, args }), + } } /// Map an InfluxQL arithmetic expression to a DataFusion [`Expr`]. @@ -1310,6 +1324,23 @@ mod test { mod select { use super::*; + /// Test InfluxQL-specific behaviour of scalar functions that differ + /// from DataFusion + #[test] + fn test_scalar_functions() { + // LOG requires two arguments, and first argument is field + assert_snapshot!(plan("SELECT LOG(usage_idle, 8) FROM cpu"), @r###" + Sort: time ASC NULLS LAST [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), log:Float64;N] + Projection: Dictionary(Int32, Utf8("cpu")) AS iox::measurement, cpu.time AS time, log(Int64(8), cpu.usage_idle) AS log [iox::measurement:Dictionary(Int32, Utf8), time:Timestamp(Nanosecond, None), log:Float64;N] + TableScan: cpu [cpu:Dictionary(Int32, Utf8);N, host:Dictionary(Int32, Utf8);N, region:Dictionary(Int32, Utf8);N, time:Timestamp(Nanosecond, None), usage_idle:Float64;N, usage_system:Float64;N, usage_user:Float64;N] + "###); + + // Fallible + + // LOG requires two arguments + assert_snapshot!(plan("SELECT LOG(usage_idle) FROM cpu"), @"Error during planning: invalid number of arguments for log, expected 2, got 1"); + } + /// Validate the metadata is correctly encoded in the schema. /// /// Properties that are tested: