Skip to main content

spg_sql/
lib.rs

1//! SPG SQL front-end. v0.2 ships only the lexer + a minimal recursive-descent
2//! parser for the `SELECT [..] FROM [..] WHERE [..]` subset.
3//!
4//! Layers (each in its own module):
5//!
6//! - [`lexer`]  — byte stream → tokens
7//! - [`ast`]    — abstract syntax tree types + `Display` (pretty-print)
8//! - [`parser`] — tokens → AST (Pratt parser for expression precedence)
9#![no_std]
10
11extern crate alloc;
12
13pub mod ast;
14pub mod charset;
15pub mod lexer;
16pub mod parser;
17
18/// v7.12.4 — convenience re-export of the PL/pgSQL body parser.
19/// Used by the engine-side trigger executor to lazy-re-parse the
20/// function body that the catalog stores as raw source text.
21pub use parser::parse_function_body;
22
23/// v7.37.14 (A2.5-stub) — process-wide counter of silent
24/// FOR UPDATE / FOR SHARE / FOR KEY SHARE / FOR NO KEY UPDATE
25/// clauses the parser accepted-and-discarded.
26///
27/// Pre-v7.37.15 the parser silently absorbs row-lock clauses so
28/// mailrs / Rails / Django code paths that emit `SELECT … FOR
29/// UPDATE` for advisory pessimistic locking load without a parser
30/// error. The clauses are not enforced — SPG is currently single-
31/// writer + Arc snapshot,which already satisfies the implicit
32/// ordering most callers want.
33///
34/// v7.37.15 (B2.5 / fine-grained MVCC) will land per-row tuple
35/// locking and start honouring these clauses. Until then, this
36/// counter is the *observability hook* so operators can surface
37/// "FOR UPDATE is widely used in this workload — once 7.37.15
38/// ships, ensure the application semantics are still correct".
39///
40/// Bumped once per FOR clause consumed (so `FOR UPDATE OF t1 FOR
41/// SHARE OF t2` increments by 2). Reads via [`silent_for_update_count`].
42static SILENT_FOR_UPDATE_COUNT: core::sync::atomic::AtomicU64 =
43    core::sync::atomic::AtomicU64::new(0);
44
45/// v7.37.14 (A2.5-stub) — bump the silent-FOR-UPDATE counter.
46/// Called from the parser's `consume_optional_for_lock_clauses`
47/// path. Public-but-low-traffic API; not part of the stable parser
48/// surface.
49#[doc(hidden)]
50pub fn record_silent_for_update_clause() {
51    SILENT_FOR_UPDATE_COUNT.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
52}
53
54/// v7.37.14 (A2.5-stub) — read the process-wide silent-FOR-UPDATE
55/// counter. Engines / spgctl / monitoring use this to surface
56/// "how many advisory row locks did the workload ask for since
57/// process start". Returns 0 if no FOR UPDATE / FOR SHARE clause
58/// has hit the parser yet.
59#[must_use]
60pub fn silent_for_update_count() -> u64 {
61    SILENT_FOR_UPDATE_COUNT.load(core::sync::atomic::Ordering::Relaxed)
62}