This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-2.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-2.1 by this push:
     new 9fe87a56bdc [cherry-pick](branch-21) support lead/lag function input 
column as third params (#49381) (#50653)
9fe87a56bdc is described below

commit 9fe87a56bdcbc7a56b30f47eea20cc9c7bb990f7
Author: zhangstar333 <[email protected]>
AuthorDate: Wed May 7 23:08:56 2025 +0800

    [cherry-pick](branch-21) support lead/lag function input column as third 
params (#49381) (#50653)
    
    ### What problem does this PR solve?
    
    cherry-pick from master (#49381)
    
    ### Release note
    
    None
    
    ### Check List (For Author)
    
    - Test <!-- At least one of them must be included. -->
        - [ ] Regression test
        - [ ] Unit Test
        - [ ] Manual test (add detailed scripts or steps below)
        - [ ] No need to test or manual test. Explain why:
    - [ ] This is a refactor/code format and no logic has been changed.
            - [ ] Previous test can cover this change.
            - [ ] No code files have been changed.
            - [ ] Other reason <!-- Add your reason?  -->
    
    - Behavior changed:
        - [ ] No.
        - [ ] Yes. <!-- Explain the behavior change -->
    
    - Does this need documentation?
        - [ ] No.
    - [ ] Yes. <!-- Add document PR link here. eg:
    https://github.com/apache/doris-website/pull/1214 -->
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label <!-- Add branch pick label that this PR
    should merge into -->
---
 .../aggregate_function_window.h                    |  64 ++++++++++-----------
 .../trees/expressions/functions/window/Lag.java    |   5 +-
 .../trees/expressions/functions/window/Lead.java   |   5 +-
 .../functions/window/WindowFunction.java           |   6 +-
 .../data/correctness_p0/test_lag_lead_window.out   | Bin 1402 -> 1797 bytes
 .../correctness_p0/test_lag_lead_window.groovy     |  39 +++++++++++++
 6 files changed, 74 insertions(+), 45 deletions(-)

diff --git a/be/src/vec/aggregate_functions/aggregate_function_window.h 
b/be/src/vec/aggregate_functions/aggregate_function_window.h
index 7e22d6c0e1f..9be169d0a20 100644
--- a/be/src/vec/aggregate_functions/aggregate_function_window.h
+++ b/be/src/vec/aggregate_functions/aggregate_function_window.h
@@ -21,13 +21,11 @@
 #pragma once
 
 #include <glog/logging.h>
-#include <stddef.h>
-#include <stdint.h>
 
 #include <algorithm>
 #include <boost/iterator/iterator_facade.hpp>
+#include <cstdint>
 #include <memory>
-#include <ostream>
 
 #include "gutil/integral_types.h"
 #include "vec/aggregate_functions/aggregate_function.h"
@@ -358,15 +356,10 @@ public:
     static constexpr bool result_nullable = result_is_nullable;
     void reset() {
         _data_value.reset();
-        _default_value.reset();
         _is_inited = false;
+        _offset_value = 0;
     }
 
-    bool default_is_null() { return _default_value.is_null(); }
-
-    // here _ptr pointer default column from third
-    void set_value_from_default() { this->_data_value = _default_value; }
-
     void insert_result_into(IColumn& to) const {
         if constexpr (result_is_nullable) {
             if (_data_value.is_null()) {
@@ -383,8 +376,6 @@ public:
         }
     }
 
-    void set_is_null() { this->_data_value.reset(); }
-
     void set_value(const IColumn** columns, size_t pos) {
         if constexpr (arg_is_nullable) {
             if (assert_cast<const 
ColumnNullable*>(columns[0])->is_null_at(pos)) {
@@ -397,39 +388,46 @@ public:
         _data_value.set_value(columns[0], pos);
     }
 
-    void check_default(const IColumn* column) {
-        if (!_is_inited) {
-            if (is_column_nullable(*column)) {
-                const auto* nullable_column = assert_cast<const 
ColumnNullable*>(column);
-                if (nullable_column->is_null_at(0)) {
-                    _default_value.reset();
-                } else {
-                    
_default_value.set_value(nullable_column->get_nested_column_ptr(), 0);
-                }
+    void set_value_from_default(const IColumn* column, size_t pos) {
+        DCHECK_GE(pos, 0);
+        if (is_column_nullable(*column)) {
+            const auto* nullable_column = assert_cast<const 
ColumnNullable*>(column);
+            if (nullable_column->is_null_at(pos)) {
+                this->_data_value.reset();
             } else {
-                _default_value.set_value(column, 0);
+                
this->_data_value.set_value(nullable_column->get_nested_column_ptr().get(), 
pos);
             }
+        } else {
+            this->_data_value.set_value(column, pos);
+        }
+    }
+
+    void set_offset_value(const IColumn* column) {
+        if (!_is_inited) {
+            const auto* column_number = assert_cast<const 
ColumnInt64*>(column);
+            _offset_value = column_number->get_data()[0];
             _is_inited = true;
         }
     }
 
+    int64_t get_offset_value() const { return _offset_value; }
+
 private:
     BaseValue<ColVecType, arg_is_nullable> _data_value;
-    BaseValue<ColVecType, arg_is_nullable> _default_value;
     bool _is_inited = false;
+    int64_t _offset_value = 0;
 };
 
 template <typename Data, bool = false>
 struct WindowFunctionLeadImpl : Data {
     void add_range_single_place(int64_t partition_start, int64_t 
partition_end, int64_t frame_start,
                                 int64_t frame_end, const IColumn** columns) {
-        this->check_default(columns[2]);
         if (frame_end > partition_end) { //output default value, win end is 
under partition
-            if (this->default_is_null()) {
-                this->set_is_null();
-            } else {
-                this->set_value_from_default();
-            }
+            this->set_offset_value(columns[1]);
+            // eg: lead(column, 10, default_value), column size maybe 3 rows
+            // offset value 10 is from second argument, pos: 11 is calculated 
as frame_end
+            auto pos = frame_end - 1 - this->get_offset_value();
+            this->set_value_from_default(columns[2], pos);
             return;
         }
         this->set_value(columns, frame_end - 1);
@@ -442,13 +440,11 @@ template <typename Data, bool = false>
 struct WindowFunctionLagImpl : Data {
     void add_range_single_place(int64_t partition_start, int64_t 
partition_end, int64_t frame_start,
                                 int64_t frame_end, const IColumn** columns) {
-        this->check_default(columns[2]);
+        // window start is beyond partition
         if (partition_start >= frame_end) { //[unbound preceding(0), offset 
preceding(-123)]
-            if (this->default_is_null()) {  // win start is beyond partition
-                this->set_is_null();
-            } else {
-                this->set_value_from_default();
-            }
+            this->set_offset_value(columns[1]);
+            auto pos = frame_end - 1 + this->get_offset_value();
+            this->set_value_from_default(columns[2], pos);
             return;
         }
         this->set_value(columns, frame_end - 1);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Lag.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Lag.java
index fc74cadebfc..58ff2b820f0 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Lag.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Lag.java
@@ -99,7 +99,7 @@ public class Lag extends WindowFunction implements 
TernaryExpression, Explicitly
             return;
         }
         if (children().size() >= 2) {
-            checkValidParams(getOffset(), true);
+            checkValidParams(getOffset());
             if (getOffset() instanceof Literal) {
                 if (((Literal) getOffset()).getDouble() < 0) {
                     throw new AnalysisException(
@@ -109,9 +109,6 @@ public class Lag extends WindowFunction implements 
TernaryExpression, Explicitly
                 throw new AnalysisException(
                     "The offset parameter of LAG must be a constant positive 
integer: " + this.toSql());
             }
-            if (children().size() >= 3) {
-                checkValidParams(getDefaultValue(), false);
-            }
         }
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Lead.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Lead.java
index 251141a68cb..b0de4ad571b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Lead.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/Lead.java
@@ -94,7 +94,7 @@ public class Lead extends WindowFunction implements 
TernaryExpression, Explicitl
             return;
         }
         if (children().size() >= 2) {
-            checkValidParams(getOffset(), true);
+            checkValidParams(getOffset());
             if (getOffset() instanceof Literal) {
                 if (((Literal) getOffset()).getDouble() < 0) {
                     throw new AnalysisException(
@@ -104,9 +104,6 @@ public class Lead extends WindowFunction implements 
TernaryExpression, Explicitl
                 throw new AnalysisException(
                     "The offset parameter of LAG must be a constant positive 
integer: " + this.toSql());
             }
-            if (children().size() >= 3) {
-                checkValidParams(getDefaultValue(), false);
-            }
         }
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/WindowFunction.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/WindowFunction.java
index 1265f685b26..13b4ec58476 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/WindowFunction.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/window/WindowFunction.java
@@ -59,14 +59,14 @@ public abstract class WindowFunction extends BoundFunction 
implements SupportWin
     /**
      * LAG/LEAD param must be const, and offset must be number
      */
-    protected void checkValidParams(Expression param, boolean isOffset) {
+    protected void checkValidParams(Expression param) {
         DataType type = param.getDataType();
-        if (isOffset == true && !type.isNumericType()) {
+        if (!type.isNumericType()) {
             throw new AnalysisException("The offset of LAG/LEAD must be a 
number: " + this.toSql());
         }
         if (!param.isConstant()) {
             throw new AnalysisException(
-                    "The parameter 2 or parameter 3 of LAG/LEAD must be a 
constant value: " + this.toSql());
+                    "The parameter 2 of LAG/LEAD must be a constant value: " + 
this.toSql());
         }
     }
 }
diff --git a/regression-test/data/correctness_p0/test_lag_lead_window.out 
b/regression-test/data/correctness_p0/test_lag_lead_window.out
index 041314a1c65..f9927b708c9 100644
Binary files a/regression-test/data/correctness_p0/test_lag_lead_window.out and 
b/regression-test/data/correctness_p0/test_lag_lead_window.out differ
diff --git a/regression-test/suites/correctness_p0/test_lag_lead_window.groovy 
b/regression-test/suites/correctness_p0/test_lag_lead_window.groovy
index 1dfccca58ee..0cf731e7d9e 100644
--- a/regression-test/suites/correctness_p0/test_lag_lead_window.groovy
+++ b/regression-test/suites/correctness_p0/test_lag_lead_window.groovy
@@ -41,6 +41,12 @@ suite("test_lag_lead_window") {
                                   lead(cc,1,'') over (PARTITION by cc  order 
by aa) as lead_cc 
                            from ${tableName} 
                            order by aa; """
+
+    qt_select_default3 """ select aa,cc,bb,lead(cc,1,bb) over (PARTITION by cc 
 order by aa) as lead_res,
+                                  lag(cc,1,bb) over (PARTITION by cc  order by 
aa) as lag_res 
+                           from ${tableName} 
+                           order by aa; """
+
     sql """ DROP TABLE IF EXISTS test1 """
     sql """ CREATE TABLE IF NOT EXISTS test1 (id varchar(255), create_time 
datetime)
             DISTRIBUTED BY HASH(id) PROPERTIES("replication_num" = "1"); """
@@ -61,4 +67,37 @@ suite("test_lag_lead_window") {
 
     sql """ DROP TABLE IF EXISTS test1 """
 
+
+    qt_select_lead_7 """        SELECT
+        sale_date,
+        product_id,
+        quantity,
+        LEAD (quantity, 1, quantity) OVER (
+            PARTITION BY
+            product_id
+            ORDER BY
+            sale_date
+        ) AS next_day_quantity,
+        LAG (quantity, 1, quantity) OVER (
+            PARTITION BY
+            product_id
+            ORDER BY
+            sale_date
+        ) AS pre_day_quantity
+        FROM 
+            (
+                select 1 AS product_id, '2023-01-01' AS sale_date, 10 AS 
quantity
+                UNION ALL
+                select 1, '2023-01-02', 20
+                UNION ALL
+                select 1, '2023-01-03', 30
+                UNION ALL
+                select 1,  '2023-01-04', NULL
+            ) AS t
+        ORDER BY
+        product_id,
+        sale_date;
+    """
+
+
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to