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