use vibesql_ast::Statement;
use vibesql_parser::Parser;
const TPCDS_Q1: &str = r#"
WITH customer_total_return AS (
SELECT
sr_customer_sk AS ctr_customer_sk,
sr_store_sk AS ctr_store_sk,
SUM(sr_return_amt) AS ctr_total_return
FROM store_returns, date_dim
WHERE sr_returned_date_sk = d_date_sk
AND d_year = 2000
GROUP BY sr_customer_sk, sr_store_sk
)
SELECT c_customer_id
FROM customer_total_return ctr1, store, customer
WHERE ctr1.ctr_total_return > (
SELECT AVG(ctr_total_return) * 1.2
FROM customer_total_return ctr2
WHERE ctr1.ctr_store_sk = ctr2.ctr_store_sk
)
AND s_store_sk = ctr1.ctr_store_sk
AND s_state = 'TN'
AND ctr1.ctr_customer_sk = c_customer_sk
ORDER BY c_customer_id
LIMIT 100
"#;
const TPCDS_Q2: &str = r#"
WITH wscs AS (
SELECT sold_date_sk, sales_price
FROM (
SELECT ws_sold_date_sk sold_date_sk, ws_ext_sales_price sales_price
FROM web_sales
) x
UNION ALL
SELECT cs_sold_date_sk sold_date_sk, cs_ext_sales_price sales_price
FROM catalog_sales
),
wswscs AS (
SELECT
d_week_seq,
SUM(CASE WHEN d_day_name = 'Sunday' THEN sales_price ELSE NULL END) sun_sales,
SUM(CASE WHEN d_day_name = 'Monday' THEN sales_price ELSE NULL END) mon_sales,
SUM(CASE WHEN d_day_name = 'Tuesday' THEN sales_price ELSE NULL END) tue_sales,
SUM(CASE WHEN d_day_name = 'Wednesday' THEN sales_price ELSE NULL END) wed_sales,
SUM(CASE WHEN d_day_name = 'Thursday' THEN sales_price ELSE NULL END) thu_sales,
SUM(CASE WHEN d_day_name = 'Friday' THEN sales_price ELSE NULL END) fri_sales,
SUM(CASE WHEN d_day_name = 'Saturday' THEN sales_price ELSE NULL END) sat_sales
FROM wscs, date_dim
WHERE d_date_sk = sold_date_sk
GROUP BY d_week_seq
)
SELECT
d_week_seq1,
ROUND(sun_sales1 / sun_sales2, 2),
ROUND(mon_sales1 / mon_sales2, 2),
ROUND(tue_sales1 / tue_sales2, 2),
ROUND(wed_sales1 / wed_sales2, 2),
ROUND(thu_sales1 / thu_sales2, 2),
ROUND(fri_sales1 / fri_sales2, 2),
ROUND(sat_sales1 / sat_sales2, 2)
FROM (
SELECT
wswscs.d_week_seq d_week_seq1,
sun_sales sun_sales1, mon_sales mon_sales1, tue_sales tue_sales1,
wed_sales wed_sales1, thu_sales thu_sales1, fri_sales fri_sales1,
sat_sales sat_sales1
FROM wswscs, date_dim
WHERE date_dim.d_week_seq = wswscs.d_week_seq AND d_year = 2001
) y,
(
SELECT
wswscs.d_week_seq d_week_seq2,
sun_sales sun_sales2, mon_sales mon_sales2, tue_sales tue_sales2,
wed_sales wed_sales2, thu_sales thu_sales2, fri_sales fri_sales2,
sat_sales sat_sales2
FROM wswscs, date_dim
WHERE date_dim.d_week_seq = wswscs.d_week_seq AND d_year = 2002
) z
WHERE d_week_seq1 = d_week_seq2 - 53
ORDER BY d_week_seq1
LIMIT 100
"#;
const TPCDS_Q3: &str = r#"
SELECT
d_year,
i_brand_id,
i_brand,
SUM(ss_ext_sales_price) as sum_sales
FROM date_dim, store_sales, item
WHERE d_date_sk = ss_sold_date_sk
AND ss_item_sk = i_item_sk
AND i_manufact_id = 1
AND d_moy = 11
GROUP BY d_year, i_brand_id, i_brand
ORDER BY d_year, sum_sales DESC, i_brand_id
LIMIT 100
"#;
const TPCDS_Q6: &str = r#"
SELECT
a.ca_state state,
COUNT(*) cnt
FROM customer_address a, customer c, store_sales s, date_dim d, item i
WHERE a.ca_address_sk = c.c_current_addr_sk
AND c.c_customer_sk = s.ss_customer_sk
AND s.ss_sold_date_sk = d.d_date_sk
AND s.ss_item_sk = i.i_item_sk
AND d.d_month_seq = (
SELECT DISTINCT d_month_seq
FROM date_dim
WHERE d_year = 2000 AND d_moy = 1
)
AND i.i_current_price > 1.2 * (
SELECT AVG(j.i_current_price)
FROM item j
WHERE j.i_category = i.i_category
)
GROUP BY a.ca_state
HAVING COUNT(*) >= 10
ORDER BY cnt
LIMIT 100
"#;
const TPCDS_Q7: &str = r#"
SELECT
i_item_id,
AVG(ss_quantity) as avg_quantity,
AVG(ss_list_price) as avg_list_price,
AVG(ss_coupon_amt) as avg_coupon_amt,
AVG(ss_sales_price) as avg_sales_price
FROM store_sales, customer, date_dim, item
WHERE ss_sold_date_sk = d_date_sk
AND ss_item_sk = i_item_sk
AND ss_customer_sk = c_customer_sk
AND c_birth_year BETWEEN 1970 AND 1980
AND d_year = 2000
GROUP BY i_item_id
ORDER BY i_item_id
LIMIT 100
"#;
const TPCDS_Q9: &str = r#"
SELECT
CASE WHEN (SELECT COUNT(*) FROM store_sales WHERE ss_quantity BETWEEN 1 AND 20) > 62316685
THEN (SELECT AVG(ss_ext_discount_amt) FROM store_sales WHERE ss_quantity BETWEEN 1 AND 20)
ELSE (SELECT AVG(ss_net_paid) FROM store_sales WHERE ss_quantity BETWEEN 1 AND 20)
END bucket1,
CASE WHEN (SELECT COUNT(*) FROM store_sales WHERE ss_quantity BETWEEN 21 AND 40) > 19045798
THEN (SELECT AVG(ss_ext_discount_amt) FROM store_sales WHERE ss_quantity BETWEEN 21 AND 40)
ELSE (SELECT AVG(ss_net_paid) FROM store_sales WHERE ss_quantity BETWEEN 21 AND 40)
END bucket2
FROM reason
WHERE r_reason_sk = 1
"#;
const TPCDS_Q10: &str = r#"
SELECT
c_customer_id,
c_first_name,
c_last_name,
c_preferred_cust_flag,
c_birth_country,
c_login,
c_email_address
FROM customer c, customer_address ca
WHERE c.c_current_addr_sk = ca.ca_address_sk
AND ca_county IN ('Rush County', 'Toole County', 'Jefferson County')
AND EXISTS (
SELECT 1
FROM store_sales, date_dim
WHERE c.c_customer_sk = ss_customer_sk
AND ss_sold_date_sk = d_date_sk
AND d_year = 2002
AND d_moy BETWEEN 1 AND 4
)
ORDER BY c_customer_id
LIMIT 100
"#;
const TPCDS_Q12: &str = r#"
SELECT
i_item_id,
i_item_desc,
i_category,
i_class,
i_current_price,
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, date_dim
WHERE ws_item_sk = i_item_sk
AND i_category IN ('Sports', 'Books', 'Home')
AND ws_sold_date_sk = d_date_sk
AND d_date BETWEEN '1999-02-22' AND '1999-03-24'
GROUP BY i_item_id, i_item_desc, i_category, i_class, i_current_price
ORDER BY i_category, i_class, i_item_id, i_item_desc, revenueratio
LIMIT 100
"#;
const TPCDS_Q15: &str = r#"
SELECT
ca_zip,
SUM(cs_sales_price)
FROM catalog_sales, customer, customer_address, date_dim
WHERE cs_bill_customer_sk = c_customer_sk
AND c_current_addr_sk = ca_address_sk
AND (SUBSTR(ca_zip, 1, 5) IN ('85669', '86197', '88274', '83405', '86475')
OR ca_state IN ('CA', 'WA', 'GA')
OR cs_sales_price > 500)
AND cs_sold_date_sk = d_date_sk
AND d_qoy = 2
AND d_year = 2001
GROUP BY ca_zip
ORDER BY ca_zip
LIMIT 100
"#;
const TPCDS_Q19: &str = r#"
SELECT
i_brand_id,
i_brand,
i_manufact_id,
i_manufact,
SUM(ss_ext_sales_price) as ext_price
FROM date_dim, store_sales, item, customer, customer_address
WHERE d_date_sk = ss_sold_date_sk
AND ss_item_sk = i_item_sk
AND ss_customer_sk = c_customer_sk
AND c_current_addr_sk = ca_address_sk
AND d_moy = 11
AND d_year = 1999
AND ca_state = 'CA'
GROUP BY i_brand_id, i_brand, i_manufact_id, i_manufact
ORDER BY ext_price DESC, i_brand, i_brand_id, i_manufact_id, i_manufact
LIMIT 100
"#;
const TPCDS_QUERIES: &[(&str, &str)] = &[
("Q1", TPCDS_Q1),
("Q2", TPCDS_Q2),
("Q3", TPCDS_Q3),
("Q6", TPCDS_Q6),
("Q7", TPCDS_Q7),
("Q9", TPCDS_Q9),
("Q10", TPCDS_Q10),
("Q12", TPCDS_Q12),
("Q15", TPCDS_Q15),
("Q19", TPCDS_Q19),
];
#[test]
fn test_tpcds_queries_parse() {
let mut passed = 0;
let mut failed = Vec::new();
for (name, sql) in TPCDS_QUERIES {
match Parser::parse_sql(sql) {
Ok(stmt) => {
if matches!(stmt, Statement::Select(_)) {
passed += 1;
} else {
failed.push((*name, "Parsed but not a SELECT statement".to_string()));
}
}
Err(e) => failed.push((*name, format!("Parse error: {:?}", e))),
}
}
if !failed.is_empty() {
eprintln!("\n=== PARSER FAILURES ===");
for (name, error) in &failed {
eprintln!("Query {}: {}", name, error);
}
panic!("{} queries failed to parse out of {} total", failed.len(), passed + failed.len());
}
eprintln!("\nAll {} TPC-DS queries parsed successfully!", passed);
}
#[test]
fn test_tpcds_q1_parse() {
let result = Parser::parse_sql(TPCDS_Q1);
assert!(result.is_ok(), "Q1 failed to parse: {:?}", result.err());
}
#[test]
fn test_tpcds_q2_parse() {
let result = Parser::parse_sql(TPCDS_Q2);
assert!(result.is_ok(), "Q2 failed to parse: {:?}", result.err());
}
#[test]
fn test_tpcds_q3_parse() {
let result = Parser::parse_sql(TPCDS_Q3);
assert!(result.is_ok(), "Q3 failed to parse: {:?}", result.err());
}
#[test]
fn test_tpcds_q6_parse() {
let result = Parser::parse_sql(TPCDS_Q6);
assert!(result.is_ok(), "Q6 failed to parse: {:?}", result.err());
}
#[test]
fn test_tpcds_q7_parse() {
let result = Parser::parse_sql(TPCDS_Q7);
assert!(result.is_ok(), "Q7 failed to parse: {:?}", result.err());
}
#[test]
fn test_tpcds_q9_parse() {
let result = Parser::parse_sql(TPCDS_Q9);
assert!(result.is_ok(), "Q9 failed to parse: {:?}", result.err());
}
#[test]
fn test_tpcds_q10_parse() {
let result = Parser::parse_sql(TPCDS_Q10);
assert!(result.is_ok(), "Q10 failed to parse: {:?}", result.err());
}
#[test]
fn test_tpcds_q12_parse() {
let result = Parser::parse_sql(TPCDS_Q12);
assert!(result.is_ok(), "Q12 failed to parse: {:?}", result.err());
}
#[test]
fn test_tpcds_q15_parse() {
let result = Parser::parse_sql(TPCDS_Q15);
assert!(result.is_ok(), "Q15 failed to parse: {:?}", result.err());
}
#[test]
fn test_tpcds_q19_parse() {
let result = Parser::parse_sql(TPCDS_Q19);
assert!(result.is_ok(), "Q19 failed to parse: {:?}", result.err());
}
#[test]
fn test_query_count() {
let query_count = TPCDS_QUERIES.len();
eprintln!("\n=== TPC-DS Query Validation Summary ===");
eprintln!("Queries validated: {}", query_count);
assert!(
query_count >= 10,
"Expected at least 10 queries in validation suite, found {}",
query_count
);
}