Skip to content

v2.x: prepared queries ignore OpenOptions max_derived_facts / max_results #679

Closed

Description

@adityamukho

Problem

PreparedQuery::execute (and PreparedQuery::query) builds its DatalogExecutor with new_with_rules_and_functions and never calls set_limits (src/query/datalog/prepared.rs, execute_inner on main). Every other read path in db.rs passes the database's OpenOptions::max_derived_facts and max_results.

So a prepared rule query runs with the executor's defaults, whatever the database was opened with:

  • a lower limit set to stop a runaway recursive rule early does not apply to prepared queries;
  • a higher limit set for a legitimate large derivation does not apply either, and the prepared query fails with INT-020 where execute of the same query succeeds.

Per-query :max-derived-facts / :max-results in the query text still apply, because they travel inside the query.

Repro (main, checked 2026-10-21)

fn run(opts: OpenOptions) {
    let db = opts.open_memory().unwrap();
    db.execute("(transact [[:a :friend :b] [:b :friend :c] [:c :friend :d] [:d :friend :e]])").unwrap();
    db.execute("(rule [(reach ?x ?y) [?x :friend ?y]])").unwrap();
    db.execute("(rule [(reach ?x ?z) (reach ?x ?y) [?y :friend ?z]])").unwrap();
    // INT-020, as configured
    db.execute("(query [:find ?x ?y :where (reach ?x ?y) [?y :friend :e]])").unwrap_err();
    // succeeds: the configured limit is ignored
    db.prepare("(query [:find ?x ?y :where (reach ?x ?y) [?y :friend $z]])").unwrap()
        .execute(&[("z", BindValue::Val(Value::Keyword(":e".into())))]).unwrap();
}
run(OpenOptions::new().max_derived_facts(3)); // v2.x: per iteration (round 1 derives 4)
run(OpenOptions::new().max_results(5));       // total derived facts (10)

Fix

Fixed on v3 in #676 (#549): PreparedQuery keeps the database's limits from prepare_query and calls executor.set_limits(…) in bind, with the test prepared_rule_queries_use_the_database_limits in tests/memory_limit_test.rs. The backport to main passes (max_derived_facts, max_results) (v2.x has both limits and its set_limits takes both), with the same test and a max_results variant.

Not a data-integrity issue: no wrong rows, only the wrong limit. Under the support policy (PHILOSOPHY.md §7), v2.0.x still takes bug fixes until v3.0.0.

Activity

  1. added
    known-issueBug present in a published release and not yet fixed in one; listed in the pinned known-issues issue
    on Oct 21, 2026
  2. added a commit that references this issue on Oct 23, 2026
  3. adityamukho commented on Oct 23, 2026

    @adityamukho
    CollaboratorAuthor

    Fixed in v2.0.10, released 2026-10-23 (crates.io, CHANGELOG). Also fixed on v3 for v3.0.0. Moved to "Fixed in v2.0.10" in #421.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingknown-issueBug present in a published release and not yet fixed in one; listed in the pinned known-issues issuestabilityStability/panic issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions