1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//! v7.39 (round 786, T35 Phase A) — host-provided temporary storage for
//! query-time spilling.
//!
//! The engine is `no_std`: it cannot open a file. Every other host
//! capability it needs — the wall clock, backend signalling, timezone
//! lookups — arrives as an injected `fn` pointer, and spill storage
//! follows the same shape.
//!
//! Why it exists: a large `ORDER BY` is materialised whole today. With
//! `SPG_MAX_QUERY_BYTES` set the query DIES at the ceiling
//! (`QueryBytesExceeded`); with the budget off, resident memory grows
//! with the input — round 785 measured a 60 MB sort taking 240 MB of
//! RSS, while PG18 answered the same query under a 4 MB `work_mem` with
//! `Sort Method: external merge Disk: 61072kB`. Both of SPG's outcomes
//! break its own rules (never-die; resident memory must not grow
//! linearly), and the capability gap is not speed — it is whether the
//! query can finish at all.
//!
//! This module is the seam only. Run generation and the k-way merge
//! land in Phase B/C; with no factory injected the engine behaves
//! exactly as it does today, byte for byte.
use Box;
use String;
/// Why a spill operation could not proceed. The host maps its own I/O
/// errors into `Io`; the engine only ever reports them upward.
/// One spill run: written once in sorted order, then read back once in
/// that same order by a merge cursor.
///
/// The two phases are deliberate — a run is never appended to after it
/// is sealed, and never seeks. That is all an external merge needs, and
/// keeping the contract that narrow means a host implementation is a
/// file handle and nothing else.
///
/// Dropping a run MUST remove its backing storage: a cancelled or
/// panicking query has no other chance to clean up.
/// Host factory: hand back a fresh, empty run.
///
/// `None` on the engine (embedded with no temp dir, or a host that has
/// not opted in) means spilling is unavailable and the ceiling behaves
/// as it does today.
pub type TempRunFactory = fn ;
/// v7.37 (round 884) — what a spill actually cost, for
/// `pg_stat_database.temp_files` / `temp_bytes` and for EXPLAIN
/// ANALYZE's `Sort Method`.
///
/// PG counts these per backend and rolls them into the per-database
/// view; a monitoring query watches `temp_bytes` to find the queries
/// that outgrow `work_mem`. SPG reported 0 for both while it was
/// spilling 26 runs a query, and EXPLAIN said `quicksort` for a sort
/// that had gone to disk — both because nothing was counting.