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

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

commit 13eccc4251b79dfca04bae8e1f1021dc69f53df8
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue Mar 17 09:04:20 2026 +0800

    branch-4.0: [test](doc) Add regression test for ASOF JOIN documentation 
examples #61351 (#61353)
    
    Cherry-picked from #61351
    
    Co-authored-by: zclllyybb <[email protected]>
---
 .../data/doc/query-data/asof-join.md.out           |  65 ++++
 .../suites/doc/query-data/asof-join.md.groovy      | 355 +++++++++++++++++++++
 2 files changed, 420 insertions(+)

diff --git a/regression-test/data/doc/query-data/asof-join.md.out 
b/regression-test/data/doc/query-data/asof-join.md.out
new file mode 100644
index 00000000000..92d04858d56
--- /dev/null
+++ b/regression-test/data/doc/query-data/asof-join.md.out
@@ -0,0 +1,65 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !example1 --
+1      AAPL    2024-01-01T10:00:05     150.50  1       2024-01-01T10:00        
150.00  150.10
+2      AAPL    2024-01-01T10:00:15     151.00  2       2024-01-01T10:00:10     
150.40  150.60
+3      AAPL    2024-01-01T10:00:25     150.75  3       2024-01-01T10:00:20     
150.90  151.10
+4      GOOG    2024-01-01T10:00:10     2800.00 4       2024-01-01T10:00:05     
2795.00 2800.00
+5      GOOG    2024-01-01T10:00:20     2805.00 5       2024-01-01T10:00:15     
2802.00 2808.00
+6      MSFT    2024-01-01T10:00:08     380.00  6       2024-01-01T10:00        
378.00  380.00
+
+-- !example2 --
+1      AAPL    2024-01-01T10:00:05     150.50  2       2024-01-01T10:00:10     
150.40
+2      AAPL    2024-01-01T10:00:15     151.00  3       2024-01-01T10:00:20     
150.90
+3      AAPL    2024-01-01T10:00:25     150.75  \N      \N      \N
+4      GOOG    2024-01-01T10:00:10     2800.00 5       2024-01-01T10:00:15     
2802.00
+5      GOOG    2024-01-01T10:00:20     2805.00 \N      \N      \N
+6      MSFT    2024-01-01T10:00:08     380.00  7       2024-01-01T10:00:10     
379.50
+
+-- !example3 --
+1      AAPL    2024-01-01T10:00:05     150.50  1       2024-01-01T10:00        
150.00
+2      AAPL    2024-01-01T10:00:15     151.00  2       2024-01-01T10:00:10     
150.40
+3      AAPL    2024-01-01T10:00:25     150.75  3       2024-01-01T10:00:20     
150.90
+4      GOOG    2024-01-01T10:00:10     2800.00 4       2024-01-01T10:00:05     
2795.00
+5      GOOG    2024-01-01T10:00:20     2805.00 5       2024-01-01T10:00:15     
2802.00
+6      MSFT    2024-01-01T10:00:08     380.00  6       2024-01-01T10:00        
378.00
+
+-- !example4 --
+1      101     US      2024-01-01T10:00:10     100.00  2024-01-01T10:00
+2      101     US      2024-01-01T10:00:30     102.00  2024-01-01T10:00:20
+3      102     EU      2024-01-01T10:00:15     200.00  2024-01-01T10:00
+4      102     EU      2024-01-01T10:00:45     205.00  2024-01-01T10:00:30
+
+-- !example5 --
+1      2024-01-01T12:00        1       2024-01-01T10:00        snapshot_1
+2      2024-01-01T14:00        3       2024-01-01T13:00        snapshot_3
+3      2024-01-01T13:00        4       2024-01-01T11:00        snapshot_4
+
+-- !example6 --
+1      2024-01-01T10:00:10     100.00  2024-01-01T10:00        500     
2024-01-01T10:00
+2      2024-01-01T10:00:30     102.00  2024-01-01T10:00:20     480     
2024-01-01T10:00:20
+3      2024-01-01T10:00:15     200.00  2024-01-01T10:00        300     
2024-01-01T10:00
+4      2024-01-01T10:00:45     205.00  2024-01-01T10:00:30     290     
2024-01-01T10:00:30
+
+-- !example6_mixed --
+1      Widget A        2024-01-01T10:00:10     100.00
+2      Widget A        2024-01-01T10:00:30     102.00
+3      Widget B        2024-01-01T10:00:15     200.00
+4      Widget B        2024-01-01T10:00:45     205.00
+
+-- !example7 --
+AAPL   3       150.4333
+GOOG   2       2798.5000
+MSFT   1       378.0000
+
+-- !example8 --
+1      2024-01-01T10:00:10     100.00  2024-01-01T10:00        102.00  
2024-01-01T10:00:20
+2      2024-01-01T10:00:30     102.00  2024-01-01T10:00:20     \N      \N
+3      2024-01-01T10:00:15     200.00  2024-01-01T10:00        205.00  
2024-01-01T10:00:30
+4      2024-01-01T10:00:45     205.00  2024-01-01T10:00:30     \N      \N
+
+-- !example9_ge --
+1      2024-01-01T10:00:06     1       2024-01-01T10:00
+
+-- !example9_le --
+1      2024-01-01T10:00:06     2       2024-01-01T10:00:08
+
diff --git a/regression-test/suites/doc/query-data/asof-join.md.groovy 
b/regression-test/suites/doc/query-data/asof-join.md.groovy
new file mode 100644
index 00000000000..bfabe281c13
--- /dev/null
+++ b/regression-test/suites/doc/query-data/asof-join.md.groovy
@@ -0,0 +1,355 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+
+import org.junit.jupiter.api.Assertions;
+
+suite("docs/query-data/asof-join.md") {
+    try {
+        // Preparation: Create trades and quotes tables
+        sql "DROP TABLE IF EXISTS trades"
+        sql """
+        CREATE TABLE trades (
+            trade_id INT,
+            symbol VARCHAR(10),
+            trade_time DATETIME,
+            price DECIMAL(10, 2),
+            quantity INT
+        ) DISTRIBUTED BY HASH(trade_id) BUCKETS 3
+        PROPERTIES("replication_num" = "1")
+        """
+
+        sql "DROP TABLE IF EXISTS quotes"
+        sql """
+        CREATE TABLE quotes (
+            quote_id INT,
+            symbol VARCHAR(10),
+            quote_time DATETIME,
+            bid_price DECIMAL(10, 2),
+            ask_price DECIMAL(10, 2)
+        ) DISTRIBUTED BY HASH(quote_id) BUCKETS 3
+        PROPERTIES("replication_num" = "1")
+        """
+
+        sql """
+        INSERT INTO trades VALUES
+        (1, 'AAPL', '2024-01-01 10:00:05', 150.50, 100),
+        (2, 'AAPL', '2024-01-01 10:00:15', 151.00, 200),
+        (3, 'AAPL', '2024-01-01 10:00:25', 150.75, 150),
+        (4, 'GOOG', '2024-01-01 10:00:10', 2800.00, 50),
+        (5, 'GOOG', '2024-01-01 10:00:20', 2805.00, 75),
+        (6, 'MSFT', '2024-01-01 10:00:08', 380.00, 120)
+        """
+
+        sql """
+        INSERT INTO quotes VALUES
+        (1, 'AAPL', '2024-01-01 10:00:00', 150.00, 150.10),
+        (2, 'AAPL', '2024-01-01 10:00:10', 150.40, 150.60),
+        (3, 'AAPL', '2024-01-01 10:00:20', 150.90, 151.10),
+        (4, 'GOOG', '2024-01-01 10:00:05', 2795.00, 2800.00),
+        (5, 'GOOG', '2024-01-01 10:00:15', 2802.00, 2808.00),
+        (6, 'MSFT', '2024-01-01 10:00:00', 378.00, 380.00),
+        (7, 'MSFT', '2024-01-01 10:00:10', 379.50, 381.00)
+        """
+
+        // Preparation: Create orders and prices tables for examples 4, 6, 8
+        sql "DROP TABLE IF EXISTS orders"
+        sql """
+        CREATE TABLE orders (
+            order_id INT,
+            product_id INT,
+            region VARCHAR(20),
+            order_time DATETIME
+        ) DISTRIBUTED BY HASH(order_id) BUCKETS 3
+        PROPERTIES("replication_num" = "1")
+        """
+
+        sql "DROP TABLE IF EXISTS prices"
+        sql """
+        CREATE TABLE prices (
+            price_id INT,
+            product_id INT,
+            region VARCHAR(20),
+            effective_time DATETIME,
+            price DECIMAL(10, 2)
+        ) DISTRIBUTED BY HASH(price_id) BUCKETS 3
+        PROPERTIES("replication_num" = "1")
+        """
+
+        sql """
+        INSERT INTO orders VALUES
+        (1, 101, 'US', '2024-01-01 10:00:10'),
+        (2, 101, 'US', '2024-01-01 10:00:30'),
+        (3, 102, 'EU', '2024-01-01 10:00:15'),
+        (4, 102, 'EU', '2024-01-01 10:00:45')
+        """
+
+        sql """
+        INSERT INTO prices VALUES
+        (1, 101, 'US', '2024-01-01 10:00:00', 100.00),
+        (2, 101, 'US', '2024-01-01 10:00:20', 102.00),
+        (3, 102, 'EU', '2024-01-01 10:00:00', 200.00),
+        (4, 102, 'EU', '2024-01-01 10:00:30', 205.00)
+        """
+
+        // Preparation: Create inventory and products tables for example 6
+        sql "DROP TABLE IF EXISTS inventory"
+        sql """
+        CREATE TABLE inventory (
+            inv_id INT,
+            product_id INT,
+            region VARCHAR(20),
+            snapshot_time DATETIME,
+            stock_level INT
+        ) DISTRIBUTED BY HASH(inv_id) BUCKETS 3
+        PROPERTIES("replication_num" = "1")
+        """
+
+        sql """
+        INSERT INTO inventory VALUES
+        (1, 101, 'US', '2024-01-01 10:00:00', 500),
+        (2, 101, 'US', '2024-01-01 10:00:20', 480),
+        (3, 102, 'EU', '2024-01-01 10:00:00', 300),
+        (4, 102, 'EU', '2024-01-01 10:00:30', 290)
+        """
+
+        sql "DROP TABLE IF EXISTS products"
+        sql """
+        CREATE TABLE products (
+            product_id INT,
+            product_name VARCHAR(50)
+        ) DISTRIBUTED BY HASH(product_id) BUCKETS 3
+        PROPERTIES("replication_num" = "1")
+        """
+
+        sql """
+        INSERT INTO products VALUES
+        (101, 'Widget A'),
+        (102, 'Widget B')
+        """
+
+        // Preparation: Create left_table and right_table for example 5
+        sql "DROP TABLE IF EXISTS left_table"
+        sql """
+        CREATE TABLE left_table (
+            id INT,
+            grp INT,
+            ts DATETIME,
+            val VARCHAR(50)
+        ) DISTRIBUTED BY HASH(id) BUCKETS 3
+        PROPERTIES("replication_num" = "1")
+        """
+
+        sql "DROP TABLE IF EXISTS right_table"
+        sql """
+        CREATE TABLE right_table (
+            id INT,
+            grp INT,
+            ts DATETIME,
+            data VARCHAR(50)
+        ) DISTRIBUTED BY HASH(id) BUCKETS 3
+        PROPERTIES("replication_num" = "1")
+        """
+
+        sql """
+        INSERT INTO left_table VALUES
+        (1, 1, '2024-01-01 12:00:00', 'event_a'),
+        (2, 1, '2024-01-01 14:00:00', 'event_b'),
+        (3, 2, '2024-01-01 13:00:00', 'event_c')
+        """
+
+        sql """
+        INSERT INTO right_table VALUES
+        (1, 1, '2024-01-01 10:00:00', 'snapshot_1'),
+        (2, 1, '2024-01-01 12:00:00', 'snapshot_2'),
+        (3, 1, '2024-01-01 13:00:00', 'snapshot_3'),
+        (4, 2, '2024-01-01 11:00:00', 'snapshot_4')
+        """
+
+        // Example 1: Find the Most Recent Quote for Each Trade (>=)
+        order_qt_example1 """
+        SELECT t.trade_id, t.symbol, t.trade_time, t.price,
+               q.quote_id, q.quote_time, q.bid_price, q.ask_price
+        FROM trades t
+        ASOF LEFT JOIN quotes q
+            MATCH_CONDITION(t.trade_time >= q.quote_time)
+            ON t.symbol = q.symbol
+        ORDER BY t.trade_id
+        """
+
+        // Example 2: Find the Next Quote After Each Trade (<=)
+        order_qt_example2 """
+        SELECT t.trade_id, t.symbol, t.trade_time, t.price,
+               q.quote_id, q.quote_time, q.bid_price
+        FROM trades t
+        ASOF LEFT JOIN quotes q
+            MATCH_CONDITION(t.trade_time <= q.quote_time)
+            ON t.symbol = q.symbol
+        ORDER BY t.trade_id
+        """
+
+        // Example 3: ASOF INNER JOIN — Exclude Unmatched Rows
+        order_qt_example3 """
+        SELECT t.trade_id, t.symbol, t.trade_time, t.price,
+               q.quote_id, q.quote_time, q.bid_price
+        FROM trades t
+        ASOF INNER JOIN quotes q
+            MATCH_CONDITION(t.trade_time >= q.quote_time)
+            ON t.symbol = q.symbol
+        ORDER BY t.trade_id
+        """
+
+        // Example 4: Multiple Equality Conditions
+        order_qt_example4 """
+        SELECT o.order_id, o.product_id, o.region, o.order_time,
+               p.price, p.effective_time
+        FROM orders o
+        ASOF LEFT JOIN prices p
+            MATCH_CONDITION(o.order_time >= p.effective_time)
+            ON o.product_id = p.product_id AND o.region = p.region
+        ORDER BY o.order_id
+        """
+
+        // Example 5: Expression in MATCH_CONDITION (at least 1 hour gap)
+        order_qt_example5 """
+        SELECT l.id, l.ts, r.id AS rid, r.ts AS rts, r.data
+        FROM left_table l
+        ASOF LEFT JOIN right_table r
+            MATCH_CONDITION(l.ts >= r.ts + INTERVAL 1 HOUR)
+            ON l.grp = r.grp
+        ORDER BY l.id
+        """
+
+        // Example 6: Multi-level ASOF JOIN
+        order_qt_example6 """
+        SELECT o.order_id, o.order_time,
+               p.price, p.effective_time AS price_time,
+               i.stock_level, i.snapshot_time AS inv_time
+        FROM orders o
+        ASOF LEFT JOIN prices p
+            MATCH_CONDITION(o.order_time >= p.effective_time)
+            ON o.product_id = p.product_id AND o.region = p.region
+        ASOF LEFT JOIN inventory i
+            MATCH_CONDITION(o.order_time >= i.snapshot_time)
+            ON o.product_id = i.product_id AND o.region = i.region
+        ORDER BY o.order_id
+        """
+
+        // Example 6 (continued): Mixing ASOF JOIN with regular JOIN
+        order_qt_example6_mixed """
+        SELECT o.order_id, prod.product_name,
+               o.order_time, p.price
+        FROM orders o
+        INNER JOIN products prod ON o.product_id = prod.product_id
+        ASOF LEFT JOIN prices p
+            MATCH_CONDITION(o.order_time >= p.effective_time)
+            ON o.product_id = p.product_id AND o.region = p.region
+        ORDER BY o.order_id
+        """
+
+        // Example 7: ASOF JOIN with Aggregation
+        order_qt_example7 """
+        SELECT t.symbol,
+               COUNT(*) AS trade_count,
+               AVG(q.bid_price) AS avg_bid
+        FROM trades t
+        ASOF LEFT JOIN quotes q
+            MATCH_CONDITION(t.trade_time >= q.quote_time)
+            ON t.symbol = q.symbol
+        GROUP BY t.symbol
+        ORDER BY t.symbol
+        """
+
+        // Example 8: Bidirectional ASOF JOIN — Finding Surrounding Records
+        order_qt_example8 """
+        SELECT o.order_id, o.order_time,
+               p_before.price AS price_before,
+               p_before.effective_time AS time_before,
+               p_after.price AS price_after,
+               p_after.effective_time AS time_after
+        FROM orders o
+        ASOF LEFT JOIN prices p_before
+            MATCH_CONDITION(o.order_time >= p_before.effective_time)
+            ON o.product_id = p_before.product_id AND o.region = 
p_before.region
+        ASOF LEFT JOIN prices p_after
+            MATCH_CONDITION(o.order_time <= p_after.effective_time)
+            ON o.product_id = p_after.product_id AND o.region = p_after.region
+        ORDER BY o.order_id
+        """
+
+        // Example 9: Directional Matching, Not Absolute Nearest (>=)
+        order_qt_example9_ge """
+        WITH left_events AS (
+            SELECT 1 AS event_id, 'AAPL' AS symbol, CAST('2024-01-01 10:00:06' 
AS DATETIME) AS event_time
+        ),
+        right_events AS (
+            SELECT 1 AS right_id, 'AAPL' AS symbol, CAST('2024-01-01 10:00:00' 
AS DATETIME) AS ref_time
+            UNION ALL
+            SELECT 2 AS right_id, 'AAPL' AS symbol, CAST('2024-01-01 10:00:08' 
AS DATETIME) AS ref_time
+        )
+        SELECT l.event_id, l.event_time, r.right_id, r.ref_time
+        FROM left_events l
+        ASOF LEFT JOIN right_events r
+            MATCH_CONDITION(l.event_time >= r.ref_time)
+            ON l.symbol = r.symbol
+        """
+
+        // Example 9: Directional Matching, Not Absolute Nearest (<=)
+        order_qt_example9_le """
+        WITH left_events AS (
+            SELECT 1 AS event_id, 'AAPL' AS symbol, CAST('2024-01-01 10:00:06' 
AS DATETIME) AS event_time
+        ),
+        right_events AS (
+            SELECT 1 AS right_id, 'AAPL' AS symbol, CAST('2024-01-01 10:00:00' 
AS DATETIME) AS ref_time
+            UNION ALL
+            SELECT 2 AS right_id, 'AAPL' AS symbol, CAST('2024-01-01 10:00:08' 
AS DATETIME) AS ref_time
+        )
+        SELECT l.event_id, l.event_time, r.right_id, r.ref_time
+        FROM left_events l
+        ASOF LEFT JOIN right_events r
+            MATCH_CONDITION(l.event_time <= r.ref_time)
+            ON l.symbol = r.symbol
+        """
+
+        // Example 10: Duplicate Match Values (TIMESTAMPTZ) — result is 
non-deterministic, only verify row count
+        // The doc states this may return either right_id=1 or right_id=2
+        // Cast TIMESTAMPTZ columns to STRING to avoid JDBC decoding issues
+        def result10 = sql """
+        WITH left_events AS (
+            SELECT 1 AS event_id, 'AAPL' AS symbol,
+                   CAST('2024-01-01 10:00:05 +00:00' AS TIMESTAMPTZ) AS 
event_time
+        ),
+        right_events AS (
+            SELECT 1 AS right_id, 'AAPL' AS symbol,
+                   CAST('2024-01-01 10:00:00 +00:00' AS TIMESTAMPTZ) AS 
ref_time, 'snapshot_a' AS tag
+            UNION ALL
+            SELECT 2 AS right_id, 'AAPL' AS symbol,
+                   CAST('2024-01-01 10:00:00 +00:00' AS TIMESTAMPTZ) AS 
ref_time, 'snapshot_b' AS tag
+        )
+        SELECT l.event_id, r.right_id, CAST(r.ref_time AS STRING), r.tag
+        FROM left_events l
+        ASOF LEFT JOIN right_events r
+            MATCH_CONDITION(l.event_time >= r.ref_time)
+            ON l.symbol = r.symbol
+        """
+        // Non-deterministic: one row returned, event_id = 1, right_id is 
either 1 or 2
+        assert result10.size() == 1
+        assert result10[0][0] == 1
+
+    } catch (Throwable t) {
+        Assertions.fail("examples in docs/query-data/asof-join.md failed to 
exec, please fix it", t)
+    }
+}


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

Reply via email to