velesdb-core 3.1.0

High-performance vector database engine written in Rust
Documentation
//! Robustness regression tests for parser panic-prone paths.

use crate::velesql::{CompareOp, Condition, Parser, Value};

#[test]
fn parse_join_condition_handles_quoted_identifiers_with_dots() {
    let query = r#"SELECT * FROM users AS u JOIN orders AS o ON `tenant.users`.id = "order.items"."user""id""#;

    let parsed = Parser::parse(query).expect("query with quoted JOIN identifiers should parse");
    let join = parsed
        .select
        .joins
        .first()
        .expect("expected one JOIN clause");
    let condition = join
        .condition
        .as_ref()
        .expect("expected JOIN condition in ON clause");

    assert_eq!(condition.left.table.as_deref(), Some("tenant.users"));
    assert_eq!(condition.left.column, "id");
    assert_eq!(condition.right.table.as_deref(), Some("order.items"));
    assert_eq!(condition.right.column, "user\"id");
}

#[test]
fn parse_rejects_excessive_condition_nesting_depth() {
    // #896: deeply nested parentheses are now rejected by the raw-byte
    // pre-scan BEFORE pest can build the tree (and before the AST-level
    // MAX_CONDITION_DEPTH guard would have fired).
    let depth = 257;
    let mut query = String::from("SELECT * FROM t WHERE ");
    for _ in 0..depth {
        query.push_str("NOT (");
    }
    query.push_str("x = 1");
    for _ in 0..depth {
        query.push(')');
    }

    let err = Parser::parse(&query).expect_err("deeply nested condition should be rejected");
    assert!(
        err.to_string().contains("Query nesting too deep"),
        "unexpected parser error: {err}"
    );
}

/// #896 vector 1: ~3000 nested parens in WHERE `primary_expr` previously
/// overflowed pest's recursive descent (SIGABRT). Must now `Err` quickly.
#[test]
fn parse_rejects_deeply_nested_where_parens_without_overflow() {
    let depth = 5000;
    let query = format!(
        "SELECT * FROM t WHERE {}x = 1{}",
        "(".repeat(depth),
        ")".repeat(depth)
    );

    let err = Parser::parse(&query).expect_err("deeply nested WHERE parens must be rejected");
    assert!(
        err.to_string().contains("Query nesting too deep"),
        "unexpected parser error: {err}"
    );
}

/// #896 vector 2: ~3000 nested parens in ORDER BY `arithmetic_atom`.
#[test]
fn parse_rejects_deeply_nested_order_by_arithmetic_without_overflow() {
    let depth = 5000;
    let query = format!(
        "SELECT * FROM t ORDER BY {}1{}",
        "(".repeat(depth),
        ")".repeat(depth)
    );

    let err =
        Parser::parse(&query).expect_err("deeply nested ORDER BY arithmetic must be rejected");
    assert!(
        err.to_string().contains("Query nesting too deep"),
        "unexpected parser error: {err}"
    );
}

/// #896 vector 3: deeply nested `(SELECT … WHERE x = (SELECT …))` subqueries.
#[test]
fn parse_rejects_deeply_nested_subqueries_without_overflow() {
    // Depth kept under max_query_length (16384 bytes) so the nesting guard,
    // not the length guard, is the rejecting check. 200 levels still far
    // exceeds the 64-level nesting bound.
    let depth = 200;
    let mut query = String::from("SELECT * FROM t WHERE x = ");
    for _ in 0..depth {
        query.push_str("(SELECT id FROM t WHERE y = ");
    }
    query.push('1');
    query.push_str(&")".repeat(depth));

    let err = Parser::parse(&query).expect_err("deeply nested subqueries must be rejected");
    assert!(
        err.to_string().contains("Query nesting too deep"),
        "unexpected parser error: {err}"
    );
}

/// Parens inside a string literal must NOT count toward the nesting depth
/// (no false positive from the pre-scan).
#[test]
fn parse_does_not_count_parens_inside_string_literal() {
    let payload = "(".repeat(5000);
    let query = format!("SELECT * FROM t WHERE name = '{payload}'");

    // Must not be rejected for nesting; the literal parses fine.
    let parsed = Parser::parse(&query)
        .expect("parens inside a string literal must not trip the depth guard");
    let where_clause = parsed.select.where_clause.expect("WHERE clause present");
    let Condition::Comparison(cmp) = where_clause else {
        panic!("expected a Comparison, got {where_clause:?}");
    };
    assert_eq!(cmp.column, "name");
    assert_eq!(cmp.operator, CompareOp::Eq);
    assert!(
        matches!(&cmp.value, Value::String(s) if s.len() == 5000 && s.bytes().all(|b| b == b'(')),
        "the 5000 '(' string literal must be preserved intact, got {:?}",
        cmp.value
    );
}

/// A normal moderately-nested query still parses fine (no regression).
#[test]
fn parse_accepts_moderately_nested_query() {
    let query = "SELECT * FROM t WHERE ((a = 1 AND b = 2) OR (c = 3 AND (d = 4 OR e = 5)))";
    let parsed = Parser::parse(query).expect("moderately nested query should parse");
    let where_clause = parsed
        .select
        .where_clause
        .expect("moderately nested query should parse");
    // Outermost parens -> Group; its child is the OR of two AND-groups.
    let Condition::Group(inner) = where_clause else {
        panic!("expected outer Group, got {where_clause:?}");
    };
    assert!(
        matches!(*inner, Condition::Or(ref left, ref right)
            if matches!(**left, Condition::Group(ref l) if matches!(**l, Condition::And(..)))
            && matches!(**right, Condition::Group(ref r) if matches!(**r, Condition::And(..)))),
        "expected Group(Or(Group(And), Group(And))), got {inner:?}"
    );
}

/// #896 follow-up defect 1 (critical): a bracket-free `NOT NOT NOT …` chain
/// recurses through `not_expr = { ^"NOT" ~ primary_expr }` with NO delimiter,
/// so the bracket-only scan missed it and pest overflowed the stack (SIGABRT).
/// The prefix-run metric must now reject it quickly without parsing.
#[test]
fn parse_rejects_bracket_free_not_chain_without_overflow() {
    // 4000 `NOT ` = 16000 bytes, deliberately under the 16384 length cap so the
    // prefix-run depth metric (not the length guard) is the rejecting check.
    let query = format!("SELECT * FROM t WHERE {}a = 1", "NOT ".repeat(4000));

    let err = Parser::parse(&query).expect_err("bracket-free NOT chain must be rejected");
    assert!(
        err.to_string().contains("Query nesting too deep"),
        "unexpected parser error: {err}"
    );
}

/// #896 follow-up defect 2 (critical): an apostrophe inside a `--` comment must
/// NOT flip the scanner into a never-closing single-quote state. If it did, the
/// deep real parens after the comment would be treated as in-string and the
/// guard would be bypassed (SIGABRT). Comment-skipping must neutralise it.
#[test]
fn parse_rejects_deep_parens_after_comment_with_apostrophe() {
    let query = format!(
        "SELECT * FROM t -- it's deep\nWHERE {}a = 1{}",
        "(".repeat(5000),
        ")".repeat(5000)
    );

    let err =
        Parser::parse(&query).expect_err("deep parens after a poisoned comment must be rejected");
    assert!(
        err.to_string().contains("Query nesting too deep"),
        "unexpected parser error: {err}"
    );
}

/// #896 follow-up defect 3 (false positive): brackets/quotes inside a `--`
/// line comment must NOT be counted, so a query with a comment full of `(((`
/// and an apostrophe still parses normally.
#[test]
fn parse_does_not_count_brackets_inside_line_comment() {
    let comment = "(".repeat(5000);
    let query = format!("SELECT * FROM t -- {comment} it's fine\nWHERE a = 1");

    let parsed =
        Parser::parse(&query).expect("brackets inside a -- comment must not trip the depth guard");
    let where_clause = parsed
        .select
        .where_clause
        .expect("WHERE clause after the comment must be parsed");
    let Condition::Comparison(cmp) = where_clause else {
        panic!("expected a Comparison condition, got {where_clause:?}");
    };
    assert_eq!(cmp.column, "a");
    assert_eq!(cmp.operator, CompareOp::Eq);
    assert_eq!(cmp.value, Value::Integer(1));
}

/// No regression: a small legitimate `NOT` nesting under the bound parses fine
/// and the prefix run does not accumulate falsely across operands.
#[test]
fn parse_accepts_small_not_nesting() {
    let query = "SELECT * FROM t WHERE NOT NOT a = 1 AND NOT b = 2";
    let parsed = Parser::parse(query).expect("small NOT nesting should parse");
    // Verified shape: And(Not(Not(a = 1)), Not(b = 2)) — the prefix-run reset on the
    // operand boundary must NOT corrupt the AST.
    match parsed.select.where_clause {
        Some(Condition::And(left, right)) => {
            // left side: the double `NOT NOT a = 1`
            match *left {
                Condition::Not(inner1) => match *inner1 {
                    Condition::Not(inner2) => assert!(
                        matches!(*inner2, Condition::Comparison(_)),
                        "inner of double NOT should be `a = 1` comparison, got {inner2:?}"
                    ),
                    other => panic!("expected double NOT on left, got Not({other:?})"),
                },
                other => panic!("expected double NOT on left, got {other:?}"),
            }
            // right side: the single `NOT b = 2`
            match *right {
                Condition::Not(inner) => assert!(
                    matches!(*inner, Condition::Comparison(_)),
                    "inner of single NOT should be `b = 2` comparison, got {inner:?}"
                ),
                other => panic!("expected single NOT on right, got {other:?}"),
            }
        }
        other => panic!("expected top-level And, got {other:?}"),
    }
}