diff --git a/src/expr/impl/src/aggregate/first_last_value.rs b/src/expr/impl/src/aggregate/first_last_value.rs new file mode 100644 index 0000000000000..102e51f7c6696 --- /dev/null +++ b/src/expr/impl/src/aggregate/first_last_value.rs @@ -0,0 +1,69 @@ +// Copyright 2024 RisingWave Labs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use risingwave_common::types::{Datum, DatumRef, ScalarRefImpl}; +use risingwave_expr::aggregate; + +/// Note that different from `min` and `max`, `first_value` doesn't ignore `NULL` values. +/// +/// ```slt +/// statement ok +/// create table t(v1 int, ts int); +/// +/// statement ok +/// insert into t values (null, 1), (2, 2), (null, 3); +/// +/// query I +/// select first_value(v1 order by ts) from t; +/// ---- +/// NULL +/// +/// statement ok +/// drop table t; +/// ``` +#[aggregate("first_value(*) -> auto", state = "ref")] +fn first_value(state: Option, _: Option) -> Option { + state +} + +/// Note that different from `min` and `max`, `last_value` doesn't ignore `NULL` values. +/// +/// ```slt +/// statement ok +/// create table t(v1 int, ts int); +/// +/// statement ok +/// insert into t values (null, 1), (2, 2), (null, 3); +/// +/// query I +/// select last_value(v1 order by ts) from t; +/// ---- +/// NULL +/// +/// statement ok +/// drop table t; +/// ``` +#[aggregate("last_value(*) -> auto", state = "ref")] // TODO(): `last_value(any) -> any` +fn last_value(_: Option, input: Option) -> Option { + input +} + +#[aggregate("internal_last_seen_value(*) -> auto", state = "ref", internal)] +fn internal_last_seen_value(state: T, input: T, retract: bool) -> T { + if retract { + state + } else { + input + } +} diff --git a/src/expr/impl/src/aggregate/general.rs b/src/expr/impl/src/aggregate/general.rs index 52ec7909225d4..daaea5e782fd1 100644 --- a/src/expr/impl/src/aggregate/general.rs +++ b/src/expr/impl/src/aggregate/general.rs @@ -124,59 +124,6 @@ fn max(state: T, input: T) -> T { state.max(input) } -/// Note that different from `min` and `max`, `first_value` doesn't ignore `NULL` values. -/// -/// ```slt -/// statement ok -/// create table t(v1 int, ts int); -/// -/// statement ok -/// insert into t values (null, 1), (2, 2), (null, 3); -/// -/// query I -/// select first_value(v1 order by ts) from t; -/// ---- -/// NULL -/// -/// statement ok -/// drop table t; -/// ``` -#[aggregate("first_value(*) -> auto", state = "ref")] -fn first_value(state: Option, _: Option) -> Option { - state -} - -/// Note that different from `min` and `max`, `last_value` doesn't ignore `NULL` values. -/// -/// ```slt -/// statement ok -/// create table t(v1 int, ts int); -/// -/// statement ok -/// insert into t values (null, 1), (2, 2), (null, 3); -/// -/// query I -/// select last_value(v1 order by ts) from t; -/// ---- -/// NULL -/// -/// statement ok -/// drop table t; -/// ``` -#[aggregate("last_value(*) -> auto", state = "ref")] -fn last_value(_: Option, input: Option) -> Option { - input -} - -#[aggregate("internal_last_seen_value(*) -> auto", state = "ref", internal)] -fn internal_last_seen_value(state: T, input: T, retract: bool) -> T { - if retract { - state - } else { - input - } -} - /// Note the following corner cases: /// /// ```slt diff --git a/src/expr/impl/src/aggregate/mod.rs b/src/expr/impl/src/aggregate/mod.rs index 349574018fedf..881465b4cf82f 100644 --- a/src/expr/impl/src/aggregate/mod.rs +++ b/src/expr/impl/src/aggregate/mod.rs @@ -20,6 +20,7 @@ mod bit_or; mod bit_xor; mod bool_and; mod bool_or; +mod first_last_value; mod general; mod jsonb_agg; mod mode;