use stoolap::Database;
fn create_test_db(name: &str) -> Database {
Database::open(&format!("memory://{}", name)).expect("Failed to create in-memory database")
}
fn collect_i64(db: &Database, sql: &str) -> Vec<i64> {
let result = db.query(sql, ()).unwrap();
let mut values = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get::<i64>(0).unwrap());
}
values
}
fn collect_f64(db: &Database, sql: &str) -> Vec<f64> {
let result = db.query(sql, ()).unwrap();
let mut values = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get::<f64>(0).unwrap());
}
values
}
#[test]
fn test_generate_series_basic() {
let db = create_test_db("gs_basic");
let values = collect_i64(&db, "SELECT * FROM generate_series(1, 5)");
assert_eq!(values, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_generate_series_with_step() {
let db = create_test_db("gs_step");
let values = collect_i64(&db, "SELECT * FROM generate_series(0, 10, 2)");
assert_eq!(values, vec![0, 2, 4, 6, 8, 10]);
}
#[test]
fn test_generate_series_descending() {
let db = create_test_db("gs_desc");
let values = collect_i64(&db, "SELECT * FROM generate_series(5, 1, -1)");
assert_eq!(values, vec![5, 4, 3, 2, 1]);
}
#[test]
fn test_generate_series_auto_descending() {
let db = create_test_db("gs_auto_desc");
let values = collect_i64(&db, "SELECT * FROM generate_series(5, 1)");
assert_eq!(values, vec![5, 4, 3, 2, 1]);
}
#[test]
fn test_generate_series_empty_direction_mismatch() {
let db = create_test_db("gs_empty");
let values = collect_i64(&db, "SELECT * FROM generate_series(1, 5, -1)");
assert_eq!(values, Vec::<i64>::new());
}
#[test]
fn test_generate_series_single_value() {
let db = create_test_db("gs_single");
let values = collect_i64(&db, "SELECT * FROM generate_series(3, 3)");
assert_eq!(values, vec![3]);
}
#[test]
fn test_generate_series_negative_values() {
let db = create_test_db("gs_negative");
let values = collect_i64(&db, "SELECT * FROM generate_series(-3, 3)");
assert_eq!(values, vec![-3, -2, -1, 0, 1, 2, 3]);
}
#[test]
fn test_generate_series_large_step() {
let db = create_test_db("gs_large_step");
let values = collect_i64(&db, "SELECT * FROM generate_series(1, 100, 25)");
assert_eq!(values, vec![1, 26, 51, 76]);
}
#[test]
fn test_generate_series_float() {
let db = create_test_db("gs_float");
let values = collect_f64(&db, "SELECT * FROM generate_series(0.0, 1.0, 0.5)");
assert_eq!(values.len(), 3);
assert!((values[0] - 0.0).abs() < 1e-10);
assert!((values[1] - 0.5).abs() < 1e-10);
assert!((values[2] - 1.0).abs() < 1e-10);
}
#[test]
fn test_generate_series_float_mixed_types() {
let db = create_test_db("gs_float_mix");
let values = collect_f64(&db, "SELECT * FROM generate_series(0, 2, 0.5)");
assert_eq!(values.len(), 5); }
#[test]
fn test_generate_series_with_alias() {
let db = create_test_db("gs_alias");
let values = collect_i64(&db, "SELECT value FROM generate_series(1, 3) AS gs(value)");
assert_eq!(values, vec![1, 2, 3]);
}
#[test]
fn test_generate_series_default_column() {
let db = create_test_db("gs_default_col");
let values = collect_i64(&db, "SELECT value FROM generate_series(1, 3)");
assert_eq!(values, vec![1, 2, 3]);
}
#[test]
fn test_generate_series_implicit_alias() {
let db = create_test_db("gs_impl_alias");
let values = collect_i64(&db, "SELECT n FROM generate_series(1, 3) gs(n)");
assert_eq!(values, vec![1, 2, 3]);
}
#[test]
fn test_generate_series_with_where() {
let db = create_test_db("gs_where");
let values = collect_i64(
&db,
"SELECT * FROM generate_series(1, 10) AS g(value) WHERE value > 7",
);
assert_eq!(values, vec![8, 9, 10]);
}
#[test]
fn test_generate_series_with_order_by_desc() {
let db = create_test_db("gs_order");
let values = collect_i64(
&db,
"SELECT * FROM generate_series(1, 5) AS g(value) ORDER BY value DESC",
);
assert_eq!(values, vec![5, 4, 3, 2, 1]);
}
#[test]
fn test_generate_series_with_limit() {
let db = create_test_db("gs_limit");
let values = collect_i64(
&db,
"SELECT * FROM generate_series(1, 100) AS g(value) LIMIT 5",
);
assert_eq!(values, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_generate_series_with_limit_offset() {
let db = create_test_db("gs_limit_offset");
let values = collect_i64(
&db,
"WITH gs AS (SELECT * FROM generate_series(1, 10) AS g(value)) \
SELECT * FROM gs LIMIT 3 OFFSET 2",
);
assert_eq!(values, vec![3, 4, 5]);
}
#[test]
fn test_generate_series_sum() {
let db = create_test_db("gs_sum");
let result = db
.query(
"SELECT SUM(value) FROM generate_series(1, 100) AS g(value)",
(),
)
.unwrap();
let mut sum = 0i64;
for row in result {
let row = row.unwrap();
sum = row.get(0).unwrap();
}
assert_eq!(sum, 5050);
}
#[test]
fn test_generate_series_count() {
let db = create_test_db("gs_count");
let result = db
.query(
"SELECT COUNT(*) FROM generate_series(1, 1000) AS g(value)",
(),
)
.unwrap();
let mut count = 0i64;
for row in result {
let row = row.unwrap();
count = row.get(0).unwrap();
}
assert_eq!(count, 1000);
}
#[test]
fn test_generate_series_join_with_table() {
let db = create_test_db("gs_join");
db.execute(
"CREATE TABLE test_items (id INTEGER PRIMARY KEY, name TEXT)",
(),
)
.unwrap();
db.execute("INSERT INTO test_items VALUES (1, 'Alice')", ())
.unwrap();
db.execute("INSERT INTO test_items VALUES (2, 'Bob')", ())
.unwrap();
db.execute("INSERT INTO test_items VALUES (3, 'Charlie')", ())
.unwrap();
let result = db
.query(
"SELECT g.n, t.name FROM generate_series(1, 3) AS g(n) \
JOIN test_items t ON g.n = t.id ORDER BY g.n",
(),
)
.unwrap();
let mut rows: Vec<(i64, String)> = Vec::new();
for row in result {
let row = row.unwrap();
let id: i64 = row.get(0).unwrap();
let name: String = row.get(1).unwrap();
rows.push((id, name));
}
assert_eq!(rows.len(), 3);
assert_eq!(rows[0], (1, "Alice".to_string()));
assert_eq!(rows[1], (2, "Bob".to_string()));
assert_eq!(rows[2], (3, "Charlie".to_string()));
}
#[test]
fn test_generate_series_cross_join() {
let db = create_test_db("gs_cross");
let result = db
.query(
"SELECT a.value, b.value FROM generate_series(1, 3) AS a(value) \
CROSS JOIN generate_series(1, 2) AS b(value) ORDER BY a.value, b.value",
(),
)
.unwrap();
let mut rows: Vec<(i64, i64)> = Vec::new();
for row in result {
let row = row.unwrap();
let a: i64 = row.get(0).unwrap();
let b: i64 = row.get(1).unwrap();
rows.push((a, b));
}
assert_eq!(rows.len(), 6);
assert_eq!(rows[0], (1, 1));
assert_eq!(rows[1], (1, 2));
assert_eq!(rows[2], (2, 1));
assert_eq!(rows[3], (2, 2));
assert_eq!(rows[4], (3, 1));
assert_eq!(rows[5], (3, 2));
}
#[test]
fn test_generate_series_in_subquery() {
let db = create_test_db("gs_subquery");
let values = collect_i64(
&db,
"SELECT * FROM (SELECT * FROM generate_series(1, 5) AS g(n)) sub ORDER BY n",
);
assert_eq!(values, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_generate_series_zero_step_error() {
let db = create_test_db("gs_err_zero");
let result = db.query("SELECT * FROM generate_series(1, 10, 0)", ());
assert!(result.is_err());
}
#[test]
fn test_generate_series_wrong_arg_count() {
let db = create_test_db("gs_err_args");
let result = db.query("SELECT * FROM generate_series(1)", ());
assert!(result.is_err());
}
#[test]
fn test_generate_series_scalar_returns_array() {
let db = create_test_db("gs_scalar");
let result = db.query("SELECT generate_series(1, 5)", ()).unwrap();
let mut values = Vec::new();
for row in result {
let row = row.unwrap();
let val: String = row.get(0).unwrap();
values.push(val);
}
assert_eq!(values, vec!["[1, 2, 3, 4, 5]"]);
}
#[test]
fn test_generate_series_scalar_with_step() {
let db = create_test_db("gs_scalar_step");
let result = db.query("SELECT generate_series(0, 10, 2)", ()).unwrap();
let mut values = Vec::new();
for row in result {
let row = row.unwrap();
let val: String = row.get(0).unwrap();
values.push(val);
}
assert_eq!(values, vec!["[0, 2, 4, 6, 8, 10]"]);
}
#[test]
fn test_generate_series_case_insensitive() {
let db = create_test_db("gs_case");
let values = collect_i64(&db, "SELECT * FROM GENERATE_SERIES(1, 3)");
assert_eq!(values, vec![1, 2, 3]);
}
fn collect_string(db: &Database, sql: &str) -> Vec<String> {
let result = db.query(sql, ()).unwrap();
let mut values = Vec::new();
for row in result {
let row = row.unwrap();
values.push(row.get::<String>(0).unwrap());
}
values
}
#[test]
fn test_generate_series_date_days() {
let db = create_test_db("gs_date_days");
let values = collect_string(
&db,
"SELECT * FROM generate_series('2024-01-01', '2024-01-05', '1 day')",
);
assert_eq!(values.len(), 5);
assert!(values[0].starts_with("2024-01-01"));
assert!(values[4].starts_with("2024-01-05"));
}
#[test]
fn test_generate_series_date_auto_step() {
let db = create_test_db("gs_date_auto");
let values = collect_string(
&db,
"SELECT * FROM generate_series('2024-01-01', '2024-01-03')",
);
assert_eq!(values.len(), 3);
assert!(values[0].starts_with("2024-01-01"));
assert!(values[1].starts_with("2024-01-02"));
assert!(values[2].starts_with("2024-01-03"));
}
#[test]
fn test_generate_series_timestamp_hours() {
let db = create_test_db("gs_ts_hours");
let values = collect_string(
&db,
"SELECT * FROM generate_series('2024-01-01 00:00:00', '2024-01-01 06:00:00', '2 hours')",
);
assert_eq!(values.len(), 4); }
#[test]
fn test_generate_series_timestamp_minutes() {
let db = create_test_db("gs_ts_minutes");
let values = collect_string(
&db,
"SELECT * FROM generate_series('2024-01-01 00:00:00', '2024-01-01 00:30:00', '10 minutes')",
);
assert_eq!(values.len(), 4); }
#[test]
fn test_generate_series_date_descending() {
let db = create_test_db("gs_date_desc");
let values = collect_string(
&db,
"SELECT * FROM generate_series('2024-01-05', '2024-01-01', '-1 day')",
);
assert_eq!(values.len(), 5);
assert!(values[0].starts_with("2024-01-05"));
assert!(values[4].starts_with("2024-01-01"));
}
#[test]
fn test_generate_series_date_auto_descending() {
let db = create_test_db("gs_date_auto_desc");
let values = collect_string(
&db,
"SELECT * FROM generate_series('2024-01-03', '2024-01-01')",
);
assert_eq!(values.len(), 3);
assert!(values[0].starts_with("2024-01-03"));
assert!(values[2].starts_with("2024-01-01"));
}
#[test]
fn test_generate_series_date_weeks() {
let db = create_test_db("gs_date_weeks");
let values = collect_string(
&db,
"SELECT * FROM generate_series('2024-01-01', '2024-01-29', '1 week')",
);
assert_eq!(values.len(), 5); assert!(values[0].starts_with("2024-01-01"));
assert!(values[4].starts_with("2024-01-29"));
}
#[test]
fn test_generate_series_date_months() {
let db = create_test_db("gs_date_months");
let values = collect_string(
&db,
"SELECT * FROM generate_series('2024-01-01', '2024-04-01', '1 month')",
);
assert_eq!(values.len(), 4);
}
#[test]
fn test_generate_series_date_empty_mismatch() {
let db = create_test_db("gs_date_empty");
let values = collect_string(
&db,
"SELECT * FROM generate_series('2024-01-05', '2024-01-01', '1 day')",
);
assert_eq!(values.len(), 0);
}
#[test]
fn test_generate_series_date_with_where() {
let db = create_test_db("gs_date_where");
let values = collect_string(
&db,
"SELECT * FROM generate_series('2024-01-01', '2024-01-10', '1 day') AS g(value) \
WHERE value > '2024-01-07'",
);
assert_eq!(values.len(), 3); }
#[test]
fn test_generate_series_date_count() {
let db = create_test_db("gs_date_count");
let result = db
.query(
"SELECT COUNT(*) FROM generate_series('2024-01-01', '2024-12-31', '1 day') AS g(value)",
(),
)
.unwrap();
let mut count = 0i64;
for row in result {
let row = row.unwrap();
count = row.get(0).unwrap();
}
assert_eq!(count, 366); }
#[test]
fn test_generate_series_date_scalar() {
let db = create_test_db("gs_date_scalar");
let result = db
.query(
"SELECT generate_series('2024-01-01', '2024-01-03', '1 day')",
(),
)
.unwrap();
let mut values = Vec::new();
for row in result {
let row = row.unwrap();
let val: String = row.get(0).unwrap();
values.push(val);
}
assert_eq!(values.len(), 1);
let arr = &values[0];
assert!(arr.starts_with('['));
assert!(arr.ends_with(']'));
assert!(arr.contains("2024-01-01"));
assert!(arr.contains("2024-01-03"));
}
#[test]
fn test_generate_series_huge_range_error() {
let db = create_test_db("gs_huge_range");
let result = db.query(
"SELECT * FROM generate_series(-9223372036854775808, 9223372036854775807, 1) LIMIT 1",
(),
);
let result = result.unwrap();
let mut count = 0;
for _ in result {
count += 1;
}
assert_eq!(count, 1);
}
#[test]
fn test_generate_series_tiny_float_step_with_limit() {
let db = create_test_db("gs_tiny_step");
let values = collect_f64(
&db,
"SELECT * FROM generate_series(0.0, 1.0, 0.0001) LIMIT 3",
);
assert_eq!(values.len(), 3);
assert!((values[0] - 0.0).abs() < 1e-10);
assert!((values[1] - 0.0001).abs() < 1e-10);
assert!((values[2] - 0.0002).abs() < 1e-10);
}
#[test]
fn test_generate_series_large_with_limit() {
let db = create_test_db("gs_large_limit");
let values = collect_i64(&db, "SELECT * FROM generate_series(1, 20000000) LIMIT 5");
assert_eq!(values, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_generate_series_limit_offset_pushdown() {
let db = create_test_db("gs_limit_offset_push");
let values = collect_i64(
&db,
"WITH gs AS (SELECT * FROM generate_series(1, 20000000) AS g(value) LIMIT 10) \
SELECT * FROM gs LIMIT 3 OFFSET 2",
);
assert_eq!(values, vec![3, 4, 5]);
}
#[test]
fn test_generate_series_zero_args_error() {
let db = create_test_db("gs_zero_args");
let result = db.query("SELECT * FROM generate_series()", ());
match result {
Err(e) => {
let err_msg = e.to_string();
assert!(
err_msg.contains("2 or 3 arguments") || err_msg.contains("argument"),
"Expected argument count error, got: {}",
err_msg
);
}
Ok(_) => panic!("Expected error for zero-argument generate_series"),
}
}
#[test]
fn test_generate_series_limit_offset_no_double_application() {
let db = create_test_db("limit_offset_no_double");
let values = collect_i64(&db, "SELECT * FROM generate_series(1, 10) LIMIT 3 OFFSET 2");
assert_eq!(values, vec![3, 4, 5]);
}
#[test]
fn test_generate_series_order_by_desc_with_limit() {
let db = create_test_db("order_by_desc_limit");
let values = collect_i64(
&db,
"SELECT * FROM generate_series(1, 100) AS g(value) ORDER BY value DESC LIMIT 5",
);
assert_eq!(values, vec![100, 99, 98, 97, 96]);
}
#[test]
fn test_generate_series_distinct_no_pushdown() {
let db = create_test_db("distinct_no_pushdown");
let values = collect_i64(
&db,
"SELECT DISTINCT * FROM generate_series(1, 10, 2) LIMIT 3",
);
assert_eq!(values.len(), 3);
}
#[test]
fn test_generate_series_order_by_with_offset_limit() {
let db = create_test_db("order_by_offset_limit");
let values = collect_i64(
&db,
"SELECT * FROM generate_series(1, 10) AS g(value) ORDER BY value DESC LIMIT 3 OFFSET 2",
);
assert_eq!(values, vec![8, 7, 6]);
}
#[test]
fn test_generate_series_aggregation_with_order_by_limit() {
let db = create_test_db("agg_order_by_limit");
let result = db
.query(
"SELECT value % 3 AS grp, SUM(value) AS total \
FROM generate_series(1, 9) AS g(value) \
GROUP BY value % 3 ORDER BY total DESC LIMIT 2",
(),
)
.unwrap();
let mut rows = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((row.get::<i64>(0).unwrap(), row.get::<i64>(1).unwrap()));
}
assert_eq!(
rows.len(),
2,
"Expected 2 rows after LIMIT, got {}",
rows.len()
);
assert_eq!(rows[0], (0, 18));
assert_eq!(rows[1], (2, 15));
}
#[test]
fn test_generate_series_window_with_order_by_limit() {
let db = create_test_db("window_order_by_limit");
let result = db
.query(
"SELECT value, ROW_NUMBER() OVER (ORDER BY value) AS rn \
FROM generate_series(1, 10) AS g(value) \
ORDER BY value DESC LIMIT 3",
(),
)
.unwrap();
let mut rows = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((row.get::<i64>(0).unwrap(), row.get::<i64>(1).unwrap()));
}
assert_eq!(
rows.len(),
3,
"Expected 3 rows after LIMIT, got {}",
rows.len()
);
assert_eq!(rows[0].0, 10);
assert_eq!(rows[1].0, 9);
assert_eq!(rows[2].0, 8);
}
#[test]
fn test_generate_series_large_interval_no_panic() {
let db = create_test_db("large_interval");
let result = db.query(
"SELECT * FROM generate_series('2024-01-01', '2024-01-02', '9223372036854775807 years')",
(),
);
assert!(
result.is_err() || {
true
}
);
}
#[test]
fn test_generate_series_window_percent_rank_with_limit() {
let db = create_test_db("window_pr_limit");
let result = db
.query(
"SELECT value, percent_rank() OVER (ORDER BY value) AS pr \
FROM generate_series(1, 10) AS g(value) LIMIT 3",
(),
)
.unwrap();
let mut rows = Vec::new();
for row in result {
let row = row.unwrap();
let value = row.get::<i64>(0).unwrap();
let pr = row.get::<f64>(1).unwrap();
rows.push((value, pr));
}
assert_eq!(rows.len(), 3);
assert!(
(rows[0].1 - 0.0).abs() < 0.001,
"pr[0] should be 0.0, got {}",
rows[0].1
);
assert!(
rows[1].1 > 0.1 && rows[1].1 < 0.12,
"pr[1] should be ~0.111, got {}",
rows[1].1
);
}
#[test]
fn test_generate_series_order_by_non_projected_column() {
let db = create_test_db("order_by_non_projected");
let values = collect_i64(
&db,
"SELECT value + 1 AS x FROM generate_series(1, 5) AS g(value) ORDER BY value DESC LIMIT 2",
);
assert_eq!(values, vec![6, 5]);
}
#[test]
fn test_generate_series_join_with_limit() {
let db = create_test_db("join_limit");
let values = collect_i64(
&db,
"SELECT g.value FROM generate_series(1, 100) AS g(value) \
CROSS JOIN (VALUES (1)) AS v(x) \
ORDER BY g.value LIMIT 3",
);
assert_eq!(values, vec![1, 2, 3]);
}
#[test]
fn test_generate_series_large_interval_units_no_panic() {
let db = create_test_db("large_interval_units");
let cases = [
"SELECT * FROM generate_series('2024-01-01','2024-01-02','9223372036854775807 weeks')",
"SELECT * FROM generate_series('2024-01-01','2024-01-02','9223372036854775807 days')",
"SELECT * FROM generate_series('2024-01-01','2024-01-02','9223372036854775807 hours')",
"SELECT * FROM generate_series('2024-01-01','2024-01-02','9223372036854775807 minutes')",
"SELECT * FROM generate_series('2024-01-01','2024-01-02','9223372036854775807 seconds')",
"SELECT * FROM generate_series('2024-01-01','2024-01-02','9223372036854775807 milliseconds')",
];
for sql in &cases {
match db.query(sql, ()) {
Err(_) => {} Ok(rows) => {
let mut count = 0;
for _ in rows {
count += 1;
}
assert!(count <= 1, "Unexpected row count {} for: {}", count, sql);
}
}
}
}
#[test]
fn test_generate_series_order_by_expression() {
let db = create_test_db("order_by_expr");
let values = collect_i64(
&db,
"SELECT * FROM generate_series(1, 5) AS g(value) ORDER BY -value LIMIT 3",
);
assert_eq!(values, vec![5, 4, 3]);
}
#[test]
fn test_generate_series_aggregation_order_by_aggregate() {
let db = create_test_db("agg_order_by_agg");
let result = db
.query(
"SELECT value % 3 AS grp, SUM(value) AS total \
FROM generate_series(1, 9) AS g(value) \
GROUP BY value % 3 ORDER BY SUM(value) ASC LIMIT 2",
(),
)
.unwrap();
let mut rows = Vec::new();
for row in result {
let row = row.unwrap();
rows.push((row.get::<i64>(0).unwrap(), row.get::<i64>(1).unwrap()));
}
assert_eq!(rows.len(), 2, "Expected 2 rows, got {}", rows.len());
assert_eq!(rows[0], (1, 12));
assert_eq!(rows[1], (2, 15));
}
#[test]
fn test_generate_series_distinct_order_by_limit() {
let db = create_test_db("distinct_order_limit");
let values = collect_i64(
&db,
"SELECT DISTINCT value % 50 AS v \
FROM generate_series(1, 100) AS g(value) \
ORDER BY v LIMIT 3",
);
assert_eq!(values, vec![0, 1, 2]);
}
#[test]
fn test_generate_series_aggregation_with_limit() {
let db = create_test_db("agg_limit");
let values = collect_i64(&db, "SELECT COUNT(*) FROM generate_series(1, 100) LIMIT 1");
assert_eq!(values, vec![100]);
let values = collect_i64(
&db,
"SELECT SUM(value) FROM generate_series(1, 100) AS g(value) LIMIT 1",
);
assert_eq!(values, vec![5050]);
}
#[test]
fn test_generate_series_timestamp_huge_integer_step_no_panic() {
let db = create_test_db("ts_huge_step");
let result = db.query(
"SELECT * FROM generate_series('2024-01-01','2024-01-02',9223372036854775807)",
(),
);
assert!(result.is_err());
}
#[test]
fn test_generate_series_complex_order_by_non_projected_column() {
let db = create_test_db("complex_order_nonproj");
let values = collect_i64(
&db,
"SELECT value + 1 AS x \
FROM generate_series(1, 5) AS g(value) \
ORDER BY -value LIMIT 2",
);
assert_eq!(values, vec![6, 5]);
}
#[test]
fn test_generate_series_where_pushdown_correctness() {
let db = create_test_db("where_pushdown");
let values = collect_i64(
&db,
"SELECT value FROM generate_series(1, 100) AS g(value) WHERE value >= 95",
);
assert_eq!(values, vec![95, 96, 97, 98, 99, 100]);
let values = collect_i64(
&db,
"SELECT value FROM generate_series(1, 10) AS g(value) WHERE value BETWEEN 3 AND 5",
);
assert_eq!(values, vec![3, 4, 5]);
let values = collect_i64(
&db,
"SELECT value FROM generate_series(1, 100) AS g(value) WHERE value = 42",
);
assert_eq!(values, vec![42]);
let values = collect_i64(
&db,
"SELECT value FROM generate_series(1, 100) AS g(value) \
WHERE value > 98 AND value <= 100",
);
assert_eq!(values, vec![99, 100]);
let values = collect_i64(
&db,
"SELECT value FROM generate_series(1, 100) AS g(value) WHERE value < 3",
);
assert_eq!(values, vec![1, 2]);
}
#[test]
fn test_generate_series_where_pushdown_with_alias() {
let db = create_test_db("where_pushdown_alias");
let values = collect_i64(
&db,
"SELECT n FROM generate_series(1, 1000) AS g(n) WHERE n >= 998",
);
assert_eq!(values, vec![998, 999, 1000]);
}
#[test]
fn test_generate_series_where_no_pushdown_with_step() {
let db = create_test_db("where_no_pushdown_step");
let values = collect_i64(
&db,
"SELECT value FROM generate_series(1, 10, 2) AS g(value) WHERE value >= 5",
);
assert_eq!(values, vec![5, 7, 9]);
}
#[test]
fn test_generate_series_where_pushdown_descending() {
let db = create_test_db("where_pushdown_desc");
let values = collect_i64(
&db,
"SELECT value FROM generate_series(10, 1, -1) AS g(value) WHERE value <= 3",
);
assert_eq!(values, vec![3, 2, 1]);
}
#[test]
fn test_generate_series_join_limit_with_filter() {
let db = create_test_db("join_limit_filter");
db.execute(
"CREATE TABLE jl_table (id INTEGER PRIMARY KEY, name TEXT)",
(),
)
.unwrap();
db.execute("INSERT INTO jl_table VALUES (999999, 'a')", ())
.unwrap();
db.execute("INSERT INTO jl_table VALUES (1000000, 'b')", ())
.unwrap();
let values = collect_i64(
&db,
"SELECT g.value FROM generate_series(1, 1000000) AS g(value) \
JOIN jl_table t ON g.value = t.id \
WHERE g.value > 999998 LIMIT 1",
);
assert_eq!(values.len(), 1);
assert!(values[0] == 999999 || values[0] == 1000000);
}
#[test]
fn test_generate_series_where_float_predicate_no_miscompile() {
let db = create_test_db("float_pred");
let values = collect_i64(
&db,
"SELECT value FROM generate_series(1, 10) AS g(value) WHERE value < 3.5",
);
assert_eq!(values, vec![1, 2, 3]);
let values = collect_i64(
&db,
"SELECT value FROM generate_series(1, 10) AS g(value) WHERE value > 2.5",
);
assert_eq!(values, vec![3, 4, 5, 6, 7, 8, 9, 10]);
let values = collect_i64(
&db,
"SELECT value FROM generate_series(1, 10) AS g(value) WHERE value <= 3.5",
);
assert_eq!(values, vec![1, 2, 3]);
let values = collect_i64(
&db,
"SELECT value FROM generate_series(1, 10) AS g(value) WHERE value >= 7.5",
);
assert_eq!(values, vec![8, 9, 10]);
}
#[test]
fn test_generate_series_order_by_case_expression() {
let db = create_test_db("order_by_case");
let values = collect_i64(
&db,
"SELECT value + 1 AS x \
FROM generate_series(1, 5) AS g(value) \
ORDER BY CASE WHEN value > 3 THEN 0 ELSE 1 END \
LIMIT 2",
);
assert_eq!(values, vec![5, 6]);
}
#[test]
fn test_generate_series_large_where_false_returns_empty() {
let db = create_test_db("large_where_false");
let result = db
.query(
"SELECT * FROM generate_series(1, 20000000) AS g(value) WHERE 1=0 LIMIT 1",
(),
)
.unwrap();
let rows: Vec<_> = result.collect();
assert!(rows.is_empty());
let result = db
.query(
"SELECT g.value FROM generate_series(1, 20000000) AS g(value) \
JOIN (VALUES (1)) AS v(x) ON 1=1 WHERE 1=0 LIMIT 1",
(),
)
.unwrap();
let columns = result.columns();
assert!(
!columns.is_empty(),
"Result schema should have columns, got empty"
);
assert_eq!(columns[0], "value", "Column name should be 'value'");
let rows: Vec<_> = result.collect();
assert!(rows.is_empty());
let result = db
.query(
"SELECT g.value FROM generate_series(1, 5) AS g(value) \
JOIN (VALUES (1)) AS v(x) ON 1=1 WHERE 1=0",
(),
)
.unwrap();
let columns = result.columns();
assert!(!columns.is_empty());
let rows: Vec<_> = result.collect();
assert!(rows.is_empty());
}
#[test]
fn test_generate_series_cap_truncates_not_errors() {
let db = create_test_db("cap_truncates");
let values = collect_i64(
&db,
"SELECT COUNT(*) FROM generate_series(1, 20000000) AS g(value)",
);
assert_eq!(values, vec![10_000_000]);
}