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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
//! Round 719 — a single integer-only COMPUTED join key takes the i64
//! hash lane (S07 family ①). `ON a.id = b.id + 1` used to pay three
//! taxes the plain-column key did not: a canonical-string hash table,
//! the conjunct re-verified in `residual` against a materialised
//! combined row per matching pair, and an interpreted eval per build
//! row — 5.29× against PG on the 500k self-join, 0.70× after.
//!
//! These pins hold the lane's ANSWERS: every shape ran through the
//! round-719 differential against PG18 (12/12 byte-same, including
//! LEFT / RIGHT / FULL null-extension and the mixed-conjunct form
//! that must NOT take the lane).
use spg_engine::{Engine, QueryResult};
fn one(e: &mut Engine, sql: &str) -> String {
match e.execute(sql).unwrap() {
QueryResult::Rows { rows, .. } => spg_engine::eval::value_to_text(&rows[0].values[0]),
other => panic!("{other:?}"),
}
}
fn seed(e: &mut Engine) {
e.execute("CREATE TABLE j719 (id INT, g INT)").unwrap();
e.execute("INSERT INTO j719 SELECT gg, gg % 3 FROM generate_series(1, 100) gg")
.unwrap();
}
#[test]
fn round719_int_expr_key_joins_answer_as_pg() {
let mut e = Engine::new();
seed(&mut e);
for (sql, want) in [
// id = id + 1: 99 pairs (2..=100 each match one predecessor).
(
"SELECT count(*) FROM j719 a JOIN j719 b ON a.id = b.id + 1",
"99",
),
(
"SELECT count(*) FROM j719 a JOIN j719 b ON a.id = b.id - 3",
"97",
),
// id = id * 2: even ids 2..=100 -> 50 pairs.
(
"SELECT count(*) FROM j719 a JOIN j719 b ON a.id = b.id * 2",
"50",
),
// Anti-join: only a.id = 1 has no b with b.id + 1 = 1.
(
"SELECT count(*) FROM j719 a LEFT JOIN j719 b ON a.id = b.id + 1 \
WHERE b.id IS NULL",
"1",
),
// RIGHT: only b.id = 100 has no a with a.id = 101.
(
"SELECT count(*) FROM j719 a RIGHT JOIN j719 b ON a.id = b.id + 1 \
WHERE a.id IS NULL",
"1",
),
// A SECOND conjunct keeps the residual: id = id + 1 pairs whose
// g also matches — id ≡ id+1 (mod 3) never holds, so zero.
(
"SELECT count(*) FROM j719 a JOIN j719 b ON a.id = b.id + 1 AND a.g = b.g",
"0",
),
// The winning row's VALUES, not just counts.
(
"SELECT sum(a.id) FROM j719 a JOIN j719 b ON a.id = b.id + 99",
"100",
),
] {
assert_eq!(one(&mut e, sql), want, "{sql}");
}
}
/// NULLs on either side of the computed key join nothing (SQL `=`).
#[test]
fn round719_null_keys_never_match() {
let mut e = Engine::new();
seed(&mut e);
e.execute("INSERT INTO j719 VALUES (NULL, 0), (NULL, 1)")
.unwrap();
assert_eq!(
one(
&mut e,
"SELECT count(*) FROM j719 a JOIN j719 b ON a.id = b.id + 1"
),
"99",
"NULL build keys and NULL probe keys both stay out"
);
assert_eq!(
one(
&mut e,
"SELECT count(*) FROM j719 a LEFT JOIN j719 b ON a.id = b.id + 1 \
WHERE b.id IS NULL"
),
"3",
"the two NULL-id left rows null-extend, plus a.id = 1"
);
}
/// v7.39 (round 720) — the MIRROR shape: `<peer column> = <integer-only
/// expression over the joined left side>` (`ON b.id = a.id + 1` — what
/// the EXISTS pull-up emits). Build hashes the peer column, the probe
/// evaluates the left expression per tuple with zero materialisation.
/// The mixed-conjunct form below is the round-720 regression itself: a
/// plain eq_pair beside a probe-side computed key briefly let int_keyed
/// hash on the pair ALONE — 5000-row buckets re-verified per probe, a
/// resurrected round-590 quadratic (the differential hung). Both key
/// halves must land in the composite key.
#[test]
fn round720_mirror_int_expr_key_joins_answer_as_pg() {
let mut e = Engine::new();
seed(&mut e);
for (sql, want) in [
(
"SELECT count(*) FROM j719 a JOIN j719 b ON b.id = a.id + 1",
"99",
),
(
"SELECT count(*) FROM j719 a JOIN j719 b ON b.id = a.id * 2",
"50",
),
// Mixed: id offset by one never keeps g = id % 3 equal.
(
"SELECT count(*) FROM j719 a JOIN j719 b ON b.id = a.id + 1 AND b.g = a.g",
"0",
),
// Mixed where SOME survive: b.id = a.id + 3 preserves g (mod 3).
(
"SELECT count(*) FROM j719 a JOIN j719 b ON b.id = a.id + 3 AND b.g = a.g",
"97",
),
(
"SELECT count(*) FROM j719 a LEFT JOIN j719 b ON b.id = a.id + 99 WHERE b.id IS NULL",
"99",
),
] {
assert_eq!(one(&mut e, sql), want, "{sql}");
}
}
/// v7.39 (round 721) — the ANTI-join pull-up admits a COMPUTED outer
/// correlation half: `NOT EXISTS (SELECT 1 FROM t b WHERE b.id = a.id +
/// K)` becomes LEFT JOIN ON b.id = a.id + K (the round-720 mirror hash
/// shape) + IS NULL, instead of bailing to the per-row correlated
/// executor. Admission bar: negated only, both sides integer-family
/// (checked against the catalog at extraction). Expectations measured
/// against PG18 in the round-721 differential.
#[test]
fn round721_not_exists_computed_key_pulls_up() {
let mut e = Engine::new();
seed(&mut e);
for (sql, want) in [
// b.id = a.id + 99 exists only for a.id = 1 -> 99 rows survive.
(
"SELECT count(*) FROM j719 a WHERE NOT EXISTS (SELECT 1 FROM j719 b WHERE b.id = a.id + 99)",
"99",
),
(
"SELECT count(*) FROM j719 a WHERE NOT EXISTS (SELECT 1 FROM j719 b WHERE b.id = a.id * 2)",
"50",
),
// An all-inner residual rides along in the ON.
(
"SELECT count(*) FROM j719 a WHERE NOT EXISTS (SELECT 1 FROM j719 b WHERE b.id = a.id + 1 AND b.g = 0)",
"67",
),
// sum pins the surviving VALUES.
(
"SELECT sum(a.id) FROM j719 a WHERE NOT EXISTS (SELECT 1 FROM j719 b WHERE b.id = a.id + 50)",
"3775",
),
] {
assert_eq!(one(&mut e, sql), want, "{sql}");
}
}
/// v7.39 (round 725) — positive EXISTS pulls up as a true SEMI join
/// (`JoinKind::Semi`: each outer row keeps at most one pairing), which
/// retires the round-721 uniqueness gate — an INNER join multiplied
/// outer rows on duplicate inner matches, a semi join cannot. The
/// duplicate-heavy shapes here are the exact multiplication trap:
/// g = id % 3 has ~33 duplicates per value, and no column carries a
/// declared UNIQUE. All PG18-measured (round-725 differential, 8/8).
#[test]
fn round725_exists_semi_join_never_multiplies() {
let mut e = Engine::new();
seed(&mut e);
for (sql, want) in [
// Duplicate-bucket probe: every a.id <= 97 has b.id = a.id + 3.
(
"SELECT count(*) FROM j719 a WHERE EXISTS (SELECT 1 FROM j719 b WHERE b.id = a.id + 3)",
"97",
),
// Massive-duplicate inner key (b.g: 33 rows per value): the
// count must be the OUTER row count, not the pairing count.
(
"SELECT count(*) FROM j719 a WHERE EXISTS (SELECT 1 FROM j719 b WHERE b.g = a.g) AND a.id <= 10",
"10",
),
// Computed key + all-inner residual, positive form (the lifted
// round-721 restriction).
(
"SELECT count(*) FROM j719 a WHERE EXISTS (SELECT 1 FROM j719 b WHERE b.id = a.id + 1 AND b.g = 0)",
"33",
),
// Values, not just counts.
(
"SELECT sum(a.id) FROM j719 a WHERE EXISTS (SELECT 1 FROM j719 b WHERE b.id = a.id * 2)",
"1275",
),
] {
assert_eq!(one(&mut e, sql), want, "{sql}");
}
}
/// v7.39 (round 732) — TWO integer keys pack into one exact i128 (the
/// EXISTS pull-up's mixed shape: a plain pair beside a computed key),
/// and on every lane where a probe-expr's value IS in the key, its
/// conjunct leaves residual. Round-732 differential 6/6 byte-same;
/// these pin the mixed-key answers, LEFT null-extension included.
#[test]
fn round732_two_int_keys_answer_as_pg() {
let mut e = Engine::new();
seed(&mut e);
for (sql, want) in [
// g preserved by +3 (mod 3): 97 pairs.
(
"SELECT count(*) FROM j719 a JOIN j719 b ON b.g = a.g AND b.id = a.id + 3",
"97",
),
// g broken by +1: zero.
(
"SELECT count(*) FROM j719 a JOIN j719 b ON b.g = a.g AND b.id = a.id + 1",
"0",
),
(
"SELECT count(*) FROM j719 a LEFT JOIN j719 b ON b.g = a.g AND b.id = a.id + 3 WHERE b.id IS NULL",
"3",
),
(
"SELECT count(*) FROM j719 a WHERE EXISTS (SELECT 1 FROM j719 b WHERE b.g = a.g AND b.id = a.id + 3)",
"97",
),
(
"SELECT sum(b.id) FROM j719 a JOIN j719 b ON b.g = a.g AND b.id = a.id + 99",
"100",
),
] {
assert_eq!(one(&mut e, sql), want, "{sql}");
}
}
/// v7.39 (round 744) — the count-star anti-join fast path accepts a
/// COMPUTED inner key (`ON a.id = b.id + 1 WHERE b.id IS NULL`), with
/// the IS NULL column constrained to one the key expression READS —
/// any other inner column could be NULL on a matched row and the count
/// would be wrong (that shape keeps the general path, pinned).
#[test]
fn round744_anti_join_fast_takes_computed_keys() {
let mut e = Engine::new();
seed(&mut e);
for (sql, want) in [
(
"SELECT count(*) FROM j719 a LEFT JOIN j719 b ON a.id = b.id + 1 WHERE b.id IS NULL",
"1",
),
(
"SELECT count(*) FROM j719 a LEFT JOIN j719 b ON a.id = b.id * 2 WHERE b.id IS NULL",
"50",
),
// g is NOT read by the key: general path, and NULL-g matched
// rows must not be counted (none here — g is never NULL).
(
"SELECT count(*) FROM j719 a LEFT JOIN j719 b ON a.id = b.id + 1 WHERE b.g IS NULL",
"1",
),
] {
assert_eq!(one(&mut e, sql), want, "{sql}");
}
}
/// v7.39 (round 745) — peer-only residual predicates filter the hash
/// BUILD up front (ON-clause semantics: a rejected build row pads
/// exactly like an absent one). LEFT pads and mixed ON predicates are
/// the risk surface — all PG18-measured (round-745 differential 6/6).
#[test]
fn round745_build_side_predicates_answer_as_pg() {
let mut e = Engine::new();
seed(&mut e);
for (sql, want) in [
(
"SELECT count(*) FROM j719 a JOIN j719 b ON a.id = b.id WHERE a.g = 0 AND b.g = 0",
"33",
),
// LEFT: rows failing the ON's peer predicate still pad.
(
"SELECT count(*) FROM j719 a LEFT JOIN j719 b ON a.id = b.id AND b.g = 0 WHERE a.id <= 10",
"10",
),
(
"SELECT count(b.id) FROM j719 a LEFT JOIN j719 b ON a.id = b.id AND b.g = 0 WHERE a.id <= 10",
"3",
),
(
"SELECT sum(b.id) FROM j719 a JOIN j719 b ON a.id = b.id AND b.g = 1 WHERE a.id <= 10",
"22",
),
] {
assert_eq!(one(&mut e, sql), want, "{sql}");
}
}
/// v7.39 (round 746) — the integer-lane hash BUILD shards across the
/// parallel runner (local tables merged in shard order, preserving
/// ascending row order inside every bucket). This engine has no runner,
/// so these exercise the serial walk — the answers the sharded build
/// must reproduce are pinned by the round-746 differential (7/7,
/// including bucket-order-sensitive projections).
#[test]
fn round746_build_answers_hold() {
let mut e = Engine::new();
seed(&mut e);
for (sql, want) in [
(
"SELECT count(*) FROM j719 a JOIN j719 b ON a.id = b.id WHERE a.g = 0 AND b.g = 0",
"33",
),
// Duplicate-key bucket order feeds output order.
(
"SELECT b.g FROM j719 a JOIN j719 b ON a.g = b.g WHERE a.id = 1 AND b.id <= 6 ORDER BY b.id",
"1 / 1",
),
] {
assert_eq!(one_join(&mut e, sql, want), true, "{sql}");
}
}
fn one_join(e: &mut Engine, sql: &str, want: &str) -> bool {
match e.execute(sql).unwrap() {
QueryResult::Rows { rows, .. } => {
let got = rows
.iter()
.map(|r| {
r.values
.iter()
.map(spg_engine::eval::value_to_text)
.collect::<Vec<_>>()
.join("|")
})
.collect::<Vec<_>>()
.join(" / ");
got == want || {
eprintln!("got {got:?} want {want:?}");
false
}
}
other => panic!("{other:?}"),
}
}