Calendar math and ISO-8601 text conversion for PropertyValue::Date/
PropertyValue::Duration – kept out of marsdb-graph deliberately
(that crate stores the value, it doesn’t know Cypher’s construction/
formatting rules – see PropertyValue’s own doc comment) and out of
executor.rs (which owns dispatching to these, not the arithmetic
itself, matching the split apply_arith/compare already have from
e.g. the planner).
A procedure’s declared shape – everything Executor needs to validate
a CALL at the point it’s about to run (arity, coarse argument-type
compatibility, output column names for YIELD), before ever asking
ProcedureProvider::call to actually produce rows.
Arc<dyn ProcedureProvider> wrapper – same “manual Debug, derived
Clone” shape executor::ExecutionObserver already uses for its own
Arc<dyn Fn(..)>, so ExecutionOptions (which embeds this) can keep
deriving both.
Coarse, stable outcome category for telemetry. Error messages and query
text are deliberately excluded to avoid leaking user data through an
observer by default.
One element of a Value::Path — a path is node, edge, node, edge, ..., node, alternating, as a single Vec, not two parallel node/edge
vecs (which would create an unenforced nodes.len() == edges.len() + 1 invariant across every place a path gets built or read).
Implemented by whatever embeds MarsDB to make CALL resolve to real
behavior. Executor calls signature once per CALL (for compile-
time-shaped validation) and call once per input row (standalone: once
total, since there’s no input row to iterate).
A statement never mutates anything iff it’s a MATCH ... RETURN with no
DELETE/DETACH DELETE/SET tail and no MERGE clause anywhere in
it (MERGE (n) RETURN n has a Tail::Return, but still writes whenever
it has to create — checking tail alone here would be a real bug, not
just an incomplete check: it would send a MERGE-that-creates through a
ReadTransaction, which has no .insert). Statement::Create and
every other Tail variant always write. Confirmed by tracing every
function reachable from pattern/WHERE/WITH evaluation: none of them
ever call a table-mutating *_in_txn method for a Tail::Return
statement with no MERGE clause (a label-filtered scan looks up an
existing label id, it never allocates one — allocation only happens in
create_node_in_txn/create_edge_in_txn). Executor::execute uses
this to decide whether to open a ReadTransaction (no contention with
concurrent readers or a concurrent writer) or a WriteTransaction.
Returns whether executing stmt can mutate the graph. Public so callers
which execute generated or otherwise untrusted Cypher can enforce a
read-only policy using the same classification as the executor.
The real implementation behind lib.rs’s public parse_many –
parses a ;-separated batch of one or more statements ("CREATE (a); CREATE (b); MATCH (n) RETURN n"). Splits the input into individual
statements itself (split_statements, respecting Cypher’s quoting
rules) and parses each one independently via parse_antlr, rather
than parsing the whole batch as one shared ANTLR tree the way the
grammar’s own queries : query (SEMI query)* EOF rule (a
mars-specific extension, see grammar/README.md) would: building one
tree for a large batch means every statement’s tree is alive in
memory simultaneously until the last one is converted to a
lightweight Statement and the whole tree can finally drop.
Confirmed via /usr/bin/time -l: a real 29MB/9,771-statement import
script peaked at 13GB RSS in the parse step alone (before any
execution) parsed the old way. Splitting first means only the
largest single statement’s tree is ever alive at once.
Resolves every $name placeholder in stmt to a concrete Literal
using params, in place. Called before execution so the executor never
sees Literal::Param — see the unreachable! in
executor::literal_to_value.