use vibesql_catalog::{ColumnSchema, TableSchema};
use vibesql_parser::Parser;
use vibesql_storage::Database;
use vibesql_types::{DataType, SqlValue};
use crate::SelectExecutor;
fn create_test_db() -> Database {
let mut db = Database::new();
let schema = TableSchema::new(
"SALES".to_string(),
vec![
ColumnSchema::new("ID".to_string(), DataType::Integer, false),
ColumnSchema::new("AMOUNT".to_string(), DataType::Integer, false),
ColumnSchema::new("DAY".to_string(), DataType::Integer, false),
],
);
db.create_table(schema).unwrap();
let table = db.get_table_mut("SALES").unwrap();
use vibesql_storage::Row;
table
.insert(Row::new(vec![SqlValue::Integer(1), SqlValue::Integer(100), SqlValue::Integer(1)]))
.unwrap();
table
.insert(Row::new(vec![SqlValue::Integer(2), SqlValue::Integer(200), SqlValue::Integer(2)]))
.unwrap();
table
.insert(Row::new(vec![SqlValue::Integer(3), SqlValue::Integer(300), SqlValue::Integer(3)]))
.unwrap();
db
}
#[test]
fn test_count_star_window_function() {
let db = create_test_db();
let executor = SelectExecutor::new(&db);
let query = "SELECT id, COUNT(*) OVER () as total_count FROM sales";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt).unwrap();
assert_eq!(result.len(), 3);
assert_eq!(result[0].values.len(), 2);
assert_eq!(result[0].values[1], SqlValue::Integer(3));
assert_eq!(result[1].values[1], SqlValue::Integer(3));
assert_eq!(result[2].values[1], SqlValue::Integer(3));
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_sum_window_running_total() {
let db = create_test_db();
let executor = SelectExecutor::new(&db);
let query = "SELECT id, SUM(amount) OVER (ORDER BY \"day\") as running_total FROM sales";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt).unwrap();
assert_eq!(result.len(), 3);
assert_eq!(result[0].values.len(), 2);
assert_eq!(result[0].values[1], SqlValue::Integer(100));
assert_eq!(result[1].values[1], SqlValue::Integer(300));
assert_eq!(result[2].values[1], SqlValue::Integer(600));
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_avg_window_function() {
let db = create_test_db();
let executor = SelectExecutor::new(&db);
let query = "SELECT id, AVG(amount) OVER () as avg_amount FROM sales";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt).unwrap();
assert_eq!(result.len(), 3);
assert_eq!(result[0].values.len(), 2);
assert_eq!(result[0].values[1], SqlValue::Numeric(200.0));
assert_eq!(result[1].values[1], SqlValue::Numeric(200.0));
assert_eq!(result[2].values[1], SqlValue::Numeric(200.0));
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_min_max_window_functions() {
let db = create_test_db();
let executor = SelectExecutor::new(&db);
let query =
"SELECT id, MIN(amount) OVER () as min_amt, MAX(amount) OVER () as max_amt FROM sales";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt).unwrap();
assert_eq!(result.len(), 3);
assert_eq!(result[0].values.len(), 3);
assert_eq!(result[0].values[1], SqlValue::Integer(100));
assert_eq!(result[0].values[2], SqlValue::Integer(300));
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_window_function_in_expression() {
let db = create_test_db();
let executor = SelectExecutor::new(&db);
let query = "SELECT amount, amount * 100 / SUM(amount) OVER () as percentage FROM sales";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt).unwrap();
assert_eq!(result.len(), 3);
assert_eq!(result[0].values.len(), 2);
assert_eq!(result[0].values[1], SqlValue::Numeric(16.666666666666668));
assert_eq!(result[1].values[1], SqlValue::Numeric(33.333333333333336));
assert_eq!(result[2].values[1], SqlValue::Numeric(50.0));
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_window_function_with_moving_frame() {
let db = create_test_db();
let executor = SelectExecutor::new(&db);
let query = "SELECT id, AVG(amount) OVER (ORDER BY id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) as moving_avg FROM sales";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt).unwrap();
assert_eq!(result.len(), 3);
assert_eq!(result[0].values[1], SqlValue::Numeric(100.0));
assert_eq!(result[1].values[1], SqlValue::Numeric(150.0));
assert_eq!(result[2].values[1], SqlValue::Numeric(250.0));
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_multiple_window_functions_same_query() {
let db = create_test_db();
let executor = SelectExecutor::new(&db);
let query = "SELECT id, COUNT(*) OVER () as cnt, SUM(amount) OVER () as total FROM sales";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt).unwrap();
assert_eq!(result.len(), 3);
assert_eq!(result[0].values.len(), 3);
for row in &result {
assert_eq!(row.values[1], SqlValue::Integer(3));
assert_eq!(row.values[2], SqlValue::Integer(600));
}
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_window_function_with_partition_by() {
let mut db = Database::new();
let schema = TableSchema::new(
"EMPLOYEES".to_string(),
vec![
ColumnSchema::new("id".to_string(), DataType::Integer, false),
ColumnSchema::new("DEPT".to_string(), DataType::Integer, false),
ColumnSchema::new("SALARY".to_string(), DataType::Integer, false),
],
);
db.create_table(schema).unwrap();
use vibesql_storage::Row;
let table = db.get_table_mut("EMPLOYEES").unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(1),
SqlValue::Integer(1),
SqlValue::Integer(50000),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(2),
SqlValue::Integer(1),
SqlValue::Integer(60000),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(3),
SqlValue::Integer(2),
SqlValue::Integer(70000),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(4),
SqlValue::Integer(2),
SqlValue::Integer(80000),
]))
.unwrap();
let executor = SelectExecutor::new(&db);
let query = "SELECT dept, AVG(salary) OVER (PARTITION BY dept) as dept_avg FROM employees";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt).unwrap();
assert_eq!(result.len(), 4);
for row in &result {
if row.values[0] == SqlValue::Integer(1) {
assert_eq!(row.values[1], SqlValue::Numeric(55000.0));
} else if row.values[0] == SqlValue::Integer(2) {
assert_eq!(row.values[1], SqlValue::Numeric(75000.0));
}
}
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_order_by_with_window_function() {
use vibesql_storage::Row;
let mut db = Database::new();
let schema = TableSchema::new(
"EMPLOYEES".to_string(),
vec![
ColumnSchema::new("id".to_string(), DataType::Integer, false),
ColumnSchema::new(
"NAME".to_string(),
DataType::Varchar { max_length: Some(50) },
false,
),
ColumnSchema::new("SALARY".to_string(), DataType::Integer, false),
],
);
db.create_table(schema).unwrap();
let table = db.get_table_mut("EMPLOYEES").unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(1),
SqlValue::Varchar(arcstr::ArcStr::from("Alice")),
SqlValue::Integer(50000),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(2),
SqlValue::Varchar(arcstr::ArcStr::from("Bob")),
SqlValue::Integer(60000),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(3),
SqlValue::Varchar(arcstr::ArcStr::from("Charlie")),
SqlValue::Integer(70000),
]))
.unwrap();
let executor = SelectExecutor::new(&db);
let query = "SELECT name, ROW_NUMBER() OVER (ORDER BY salary) as rn FROM employees ORDER BY ROW_NUMBER() OVER (ORDER BY salary)";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt).unwrap();
assert_eq!(result.len(), 3);
assert_eq!(result[0].values[0], SqlValue::Varchar(arcstr::ArcStr::from("Alice")));
assert_eq!(result[0].values[1], SqlValue::Integer(1));
assert_eq!(result[1].values[0], SqlValue::Varchar(arcstr::ArcStr::from("Bob")));
assert_eq!(result[1].values[1], SqlValue::Integer(2));
assert_eq!(result[2].values[0], SqlValue::Varchar(arcstr::ArcStr::from("Charlie")));
assert_eq!(result[2].values[1], SqlValue::Integer(3));
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_order_by_with_window_function_not_in_select() {
use vibesql_storage::Row;
let mut db = Database::new();
let schema = TableSchema::new(
"EMPLOYEES".to_string(),
vec![
ColumnSchema::new("id".to_string(), DataType::Integer, false),
ColumnSchema::new(
"NAME".to_string(),
DataType::Varchar { max_length: Some(50) },
false,
),
ColumnSchema::new("SALARY".to_string(), DataType::Integer, false),
],
);
db.create_table(schema).unwrap();
let table = db.get_table_mut("EMPLOYEES").unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(1),
SqlValue::Varchar(arcstr::ArcStr::from("Alice")),
SqlValue::Integer(50000),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(2),
SqlValue::Varchar(arcstr::ArcStr::from("Bob")),
SqlValue::Integer(60000),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(3),
SqlValue::Varchar(arcstr::ArcStr::from("Charlie")),
SqlValue::Integer(70000),
]))
.unwrap();
let executor = SelectExecutor::new(&db);
let query = "SELECT name FROM employees ORDER BY ROW_NUMBER() OVER (ORDER BY salary DESC)";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt).unwrap();
assert_eq!(result.len(), 3);
assert_eq!(result[0].values[0], SqlValue::Varchar(arcstr::ArcStr::from("Charlie")));
assert_eq!(result[1].values[0], SqlValue::Varchar(arcstr::ArcStr::from("Bob")));
assert_eq!(result[2].values[0], SqlValue::Varchar(arcstr::ArcStr::from("Alice")));
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_window_function_with_group_by_aggregate() {
use vibesql_storage::Row;
let mut db = Database::new();
let schema = TableSchema::new(
"SALES".to_string(),
vec![
ColumnSchema::new("id".to_string(), DataType::Integer, false),
ColumnSchema::new(
"CATEGORY".to_string(),
DataType::Varchar { max_length: Some(50) },
false,
),
ColumnSchema::new("AMOUNT".to_string(), DataType::Integer, false),
],
);
db.create_table(schema).unwrap();
let table = db.get_table_mut("SALES").unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(1),
SqlValue::Varchar(arcstr::ArcStr::from("A")),
SqlValue::Integer(100),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(2),
SqlValue::Varchar(arcstr::ArcStr::from("A")),
SqlValue::Integer(200),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(3),
SqlValue::Varchar(arcstr::ArcStr::from("A")),
SqlValue::Integer(300),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(4),
SqlValue::Varchar(arcstr::ArcStr::from("B")),
SqlValue::Integer(400),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(5),
SqlValue::Varchar(arcstr::ArcStr::from("B")),
SqlValue::Integer(500),
]))
.unwrap();
let executor = SelectExecutor::new(&db);
let query = r#"
SELECT
category,
SUM(amount) as total,
SUM(SUM(amount)) OVER (PARTITION BY category) as partition_total
FROM sales
GROUP BY category
"#;
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt);
assert!(result.is_ok(), "Expected Q12-style window function to work: {:?}", result.err());
let rows = result.unwrap();
assert_eq!(rows.len(), 2);
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_tpcds_q12_revenue_ratio_pattern() {
use vibesql_storage::Row;
let mut db = Database::new();
let schema = TableSchema::new(
"WEB_SALES".to_string(),
vec![
ColumnSchema::new("WS_ITEM_SK".to_string(), DataType::Integer, false),
ColumnSchema::new("WS_EXT_SALES_PRICE".to_string(), DataType::Integer, false),
],
);
db.create_table(schema).unwrap();
let schema = TableSchema::new(
"ITEM".to_string(),
vec![
ColumnSchema::new("I_ITEM_SK".to_string(), DataType::Integer, false),
ColumnSchema::new(
"I_ITEM_ID".to_string(),
DataType::Varchar { max_length: Some(50) },
false,
),
ColumnSchema::new(
"I_CLASS".to_string(),
DataType::Varchar { max_length: Some(50) },
false,
),
],
);
db.create_table(schema).unwrap();
let item_table = db.get_table_mut("ITEM").unwrap();
item_table
.insert(Row::new(vec![
SqlValue::Integer(1),
SqlValue::Varchar(arcstr::ArcStr::from("ITEM001")),
SqlValue::Varchar(arcstr::ArcStr::from("electronics")),
]))
.unwrap();
item_table
.insert(Row::new(vec![
SqlValue::Integer(2),
SqlValue::Varchar(arcstr::ArcStr::from("ITEM002")),
SqlValue::Varchar(arcstr::ArcStr::from("electronics")),
]))
.unwrap();
item_table
.insert(Row::new(vec![
SqlValue::Integer(3),
SqlValue::Varchar(arcstr::ArcStr::from("ITEM003")),
SqlValue::Varchar(arcstr::ArcStr::from("sports")),
]))
.unwrap();
let sales_table = db.get_table_mut("WEB_SALES").unwrap();
sales_table.insert(Row::new(vec![SqlValue::Integer(1), SqlValue::Integer(100)])).unwrap();
sales_table.insert(Row::new(vec![SqlValue::Integer(1), SqlValue::Integer(200)])).unwrap();
sales_table.insert(Row::new(vec![SqlValue::Integer(2), SqlValue::Integer(300)])).unwrap();
sales_table.insert(Row::new(vec![SqlValue::Integer(2), SqlValue::Integer(400)])).unwrap();
sales_table.insert(Row::new(vec![SqlValue::Integer(3), SqlValue::Integer(500)])).unwrap();
let executor = SelectExecutor::new(&db);
let query = r#"
SELECT
i_item_id,
i_class,
SUM(ws_ext_sales_price) AS itemrevenue,
SUM(ws_ext_sales_price) * 100 / SUM(SUM(ws_ext_sales_price)) OVER (PARTITION BY i_class) AS revenueratio
FROM web_sales, item
WHERE ws_item_sk = i_item_sk
GROUP BY i_item_id, i_class
"#;
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt);
assert!(result.is_ok(), "TPC-DS Q12 pattern should work: {:?}", result.err());
let rows = result.unwrap();
assert_eq!(rows.len(), 3);
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_window_function_avg_sum_nested() {
use vibesql_storage::Row;
let mut db = Database::new();
let schema = TableSchema::new(
"SALES".to_string(),
vec![
ColumnSchema::new("id".to_string(), DataType::Integer, false),
ColumnSchema::new(
"CATEGORY".to_string(),
DataType::Varchar { max_length: Some(50) },
false,
),
ColumnSchema::new("MONTH".to_string(), DataType::Integer, false),
ColumnSchema::new("AMOUNT".to_string(), DataType::Integer, false),
],
);
db.create_table(schema).unwrap();
let table = db.get_table_mut("SALES").unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(1),
SqlValue::Varchar(arcstr::ArcStr::from("A")),
SqlValue::Integer(1),
SqlValue::Integer(100),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(2),
SqlValue::Varchar(arcstr::ArcStr::from("A")),
SqlValue::Integer(1),
SqlValue::Integer(200),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(3),
SqlValue::Varchar(arcstr::ArcStr::from("A")),
SqlValue::Integer(2),
SqlValue::Integer(300),
]))
.unwrap();
table
.insert(Row::new(vec![
SqlValue::Integer(4),
SqlValue::Varchar(arcstr::ArcStr::from("A")),
SqlValue::Integer(3),
SqlValue::Integer(400),
]))
.unwrap();
let executor = SelectExecutor::new(&db);
let query = r#"
SELECT
category,
month,
SUM(amount) as total,
AVG(SUM(amount)) OVER (PARTITION BY category) as avg_monthly
FROM sales
GROUP BY category, month
"#;
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt);
assert!(result.is_ok(), "AVG(SUM()) should work: {:?}", result.err());
let rows = result.unwrap();
assert_eq!(rows.len(), 3);
eprintln!("=== AVG(SUM()) test results ===");
for (i, row) in rows.iter().enumerate() {
eprintln!("Row {}: {:?}", i, row.values);
}
for row in &rows {
if let SqlValue::Numeric(avg) = row.values[3] {
assert!((avg - 333.333).abs() < 1.0, "Expected avg ~333.33, got {}", avg);
} else {
panic!("Expected Numeric for avg_monthly, got {:?}", row.values[3]);
}
}
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_window_function_avg_sum_with_frame() {
use vibesql_storage::Row;
let mut db = Database::new();
let schema = TableSchema::new(
"SALES".to_string(),
vec![
ColumnSchema::new("id".to_string(), DataType::Integer, false),
ColumnSchema::new(
"CATEGORY".to_string(),
DataType::Varchar { max_length: Some(50) },
false,
),
ColumnSchema::new("MONTH".to_string(), DataType::Integer, false),
ColumnSchema::new("AMOUNT".to_string(), DataType::Integer, false),
],
);
db.create_table(schema).unwrap();
let table = db.get_table_mut("SALES").unwrap();
for month in 1..=5 {
table
.insert(Row::new(vec![
SqlValue::Integer(month),
SqlValue::Varchar(arcstr::ArcStr::from("A")),
SqlValue::Integer(month),
SqlValue::Integer(month * 100), ]))
.unwrap();
}
let executor = SelectExecutor::new(&db);
let query = r#"
SELECT
category,
month,
SUM(amount) as total,
AVG(SUM(amount)) OVER (
PARTITION BY category
ORDER BY month
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
) as moving_avg
FROM sales
GROUP BY category, month
ORDER BY month
"#;
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let result = executor.execute(&select_stmt);
assert!(result.is_ok(), "AVG(SUM()) with frame should work: {:?}", result.err());
let rows = result.unwrap();
assert_eq!(rows.len(), 5);
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_count_no_arg_window_with_group_by() {
use vibesql_storage::Row;
let mut db = Database::new();
let schema = TableSchema::new(
"T1".to_string(),
vec![
ColumnSchema::new("A".to_string(), DataType::Integer, false),
ColumnSchema::new(
"B".to_string(),
DataType::Varchar { max_length: Some(50) },
false,
),
],
);
db.create_table(schema).unwrap();
let table = db.get_table_mut("T1").unwrap();
for (i, s) in ["abcd", "BCDE", "cdef", "DEFG"].iter().enumerate() {
table
.insert(Row::new(vec![
SqlValue::Integer((i + 1) as i64),
SqlValue::Varchar(arcstr::ArcStr::from(*s)),
]))
.unwrap();
}
let executor = SelectExecutor::new(&db);
let query = "SELECT count() OVER (), a FROM t1 GROUP BY a ORDER BY a";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let rows = executor.execute(&select_stmt).unwrap();
assert_eq!(rows.len(), 4);
for row in &rows {
assert_eq!(
row.values[0],
SqlValue::Integer(4),
"COUNT() OVER () with GROUP BY must count all aggregated rows, got {:?}",
row.values[0]
);
}
} else {
panic!("Expected SELECT statement");
}
let executor = SelectExecutor::new(&db);
let query = "SELECT count(*) OVER (), a FROM t1 GROUP BY a ORDER BY a";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let rows = executor.execute(&select_stmt).unwrap();
assert_eq!(rows.len(), 4);
for row in &rows {
assert_eq!(
row.values[0],
SqlValue::Integer(4),
"COUNT(*) OVER () with GROUP BY must count all aggregated rows, got {:?}",
row.values[0]
);
}
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_window_order_by_references_aggregate_5106() {
let mut db = Database::new();
let schema = TableSchema::new(
"TTT".to_string(),
vec![
ColumnSchema::new("B".to_string(), DataType::Integer, false),
ColumnSchema::new("C".to_string(), DataType::Integer, false),
],
);
db.create_table(schema).unwrap();
let table = db.get_table_mut("TTT").unwrap();
use vibesql_storage::Row;
table.insert(Row::new(vec![SqlValue::Integer(1), SqlValue::Integer(1)])).unwrap();
table.insert(Row::new(vec![SqlValue::Integer(2), SqlValue::Integer(2)])).unwrap();
table.insert(Row::new(vec![SqlValue::Integer(3), SqlValue::Integer(3)])).unwrap();
let executor = SelectExecutor::new(&db);
let query = "SELECT max(b) OVER (ORDER BY max(c)) FROM ttt GROUP BY b";
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let rows = executor.execute(&select_stmt).unwrap();
assert_eq!(rows.len(), 3);
assert_eq!(
rows[0].values[0],
SqlValue::Integer(1),
"Window ORDER BY max(c) ignored: row 0 expected 1, got {:?}",
rows[0].values[0]
);
assert_eq!(
rows[1].values[0],
SqlValue::Integer(2),
"Window ORDER BY max(c) ignored: row 1 expected 2, got {:?}",
rows[1].values[0]
);
assert_eq!(
rows[2].values[0],
SqlValue::Integer(3),
"Window ORDER BY max(c) ignored: row 2 expected 3, got {:?}",
rows[2].values[0]
);
} else {
panic!("Expected SELECT statement");
}
}
fn create_embedded_window_arg_db() -> Database {
let mut db = Database::new();
let schema = TableSchema::new(
"G".to_string(),
vec![
ColumnSchema::new("K".to_string(), DataType::Integer, false),
ColumnSchema::new("C".to_string(), DataType::Integer, false),
],
);
db.create_table(schema).unwrap();
let table = db.get_table_mut("G").unwrap();
use vibesql_storage::Row;
table.insert(Row::new(vec![SqlValue::Integer(1), SqlValue::Integer(10)])).unwrap();
table.insert(Row::new(vec![SqlValue::Integer(1), SqlValue::Integer(20)])).unwrap();
table.insert(Row::new(vec![SqlValue::Integer(2), SqlValue::Integer(5)])).unwrap();
db
}
fn assert_embedded_window_arg_results(query: &str, expected: &[SqlValue]) {
let db = create_embedded_window_arg_db();
let executor = SelectExecutor::new(&db);
let stmt = Parser::parse_sql(query).unwrap();
if let vibesql_ast::Statement::Select(select_stmt) = stmt {
let rows = executor.execute(&select_stmt).unwrap();
assert_eq!(rows.len(), expected.len(), "row count mismatch for: {}", query);
for (i, want) in expected.iter().enumerate() {
assert_eq!(
rows[i].values[1], *want,
"query `{}`: row {} expected {:?}, got {:?}",
query, i, want, rows[i].values[1]
);
}
} else {
panic!("Expected SELECT statement");
}
}
#[test]
fn test_embedded_lead_aggregate_arg_in_coalesce_plus_aggregate_5267() {
assert_embedded_window_arg_results(
"SELECT k, coalesce(lead(sum(c)) OVER(ORDER BY k), -1) + sum(c) FROM g GROUP BY k ORDER BY k",
&[SqlValue::Integer(35), SqlValue::Integer(4)],
);
}
#[test]
fn test_embedded_lead_aggregate_arg_plus_aggregate_5267() {
assert_embedded_window_arg_results(
"SELECT k, lead(sum(c)) OVER(ORDER BY k) + sum(c) FROM g GROUP BY k ORDER BY k",
&[SqlValue::Integer(35), SqlValue::Null],
);
}
#[test]
fn test_embedded_lag_aggregate_arg_in_coalesce_5267() {
assert_embedded_window_arg_results(
"SELECT k, coalesce(lag(sum(c)) OVER(ORDER BY k), -1) FROM g GROUP BY k ORDER BY k",
&[SqlValue::Integer(-1), SqlValue::Integer(30)],
);
}
#[test]
fn test_embedded_first_value_aggregate_arg_in_coalesce_5267() {
assert_embedded_window_arg_results(
"SELECT k, coalesce(first_value(sum(c)) OVER(ORDER BY k), -1) FROM g GROUP BY k ORDER BY k",
&[SqlValue::Integer(30), SqlValue::Integer(30)],
);
}
#[test]
fn test_embedded_last_value_aggregate_arg_in_coalesce_5267() {
assert_embedded_window_arg_results(
"SELECT k, coalesce(last_value(sum(c)) OVER(ORDER BY k), -1) FROM g GROUP BY k ORDER BY k",
&[SqlValue::Integer(30), SqlValue::Integer(5)],
);
}
#[test]
fn test_embedded_nth_value_aggregate_arg_in_coalesce_5267() {
assert_embedded_window_arg_results(
"SELECT k, coalesce(nth_value(sum(c), 1) OVER(ORDER BY k), -1) FROM g GROUP BY k ORDER BY k",
&[SqlValue::Integer(30), SqlValue::Integer(30)],
);
}
#[test]
fn test_embedded_lead_aggregate_arg_with_default_plus_literal_5267() {
assert_embedded_window_arg_results(
"SELECT k, lead(sum(c), 1, 0) OVER(ORDER BY k) + 1 FROM g GROUP BY k ORDER BY k",
&[SqlValue::Integer(6), SqlValue::Integer(1)],
);
}
#[test]
fn test_embedded_aggregate_window_over_aggregate_still_works_5267() {
assert_embedded_window_arg_results(
"SELECT k, coalesce(sum(sum(c)) OVER(ORDER BY k), -1) + 0 FROM g GROUP BY k ORDER BY k",
&[SqlValue::Integer(30), SqlValue::Integer(35)],
);
}
#[test]
fn test_top_level_lead_aggregate_arg_still_works_5267() {
assert_embedded_window_arg_results(
"SELECT k, lead(sum(c)) OVER(ORDER BY k) FROM g GROUP BY k ORDER BY k",
&[SqlValue::Integer(5), SqlValue::Null],
);
}
#[test]
fn test_embedded_lead_aggregate_arg_also_in_over_clause_5267() {
assert_embedded_window_arg_results(
"SELECT k, coalesce(lead(sum(c)) OVER(ORDER BY sum(c)), -1) FROM g GROUP BY k ORDER BY k",
&[SqlValue::Integer(-1), SqlValue::Integer(30)],
);
}