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
//! r1042 — evaluate the constant parts of a predicate once, at prepare
//! time, instead of once per row.
//!
//! The cost this removes is not subtle. On a 400,000-row table, measured
//! through the release sweep's own harness:
//!
//! ```text
//! WHERE id = 7 Index Scan 0.08 ms
//! WHERE id = 7::int Seq Scan 1.86 ms <- 23x
//! WHERE b = '\x…' Index Scan 0.08 ms
//! WHERE b = '\x…'::bytea Seq Scan 2.24 ms <- 28x
//! WHERE n = 1.23::numeric Seq Scan
//! ```
//!
//! A cast to the column's OWN type — a no-op as far as the value goes —
//! turned every one of those seeks into a full scan, because the seek
//! resolver reads an `Expr::Literal` and a `Cast` node is not one. That
//! is the shape an ORM writes (`$1::int`), the shape `pg_dump` writes,
//! and the shape anyone writes when they are being explicit. It had been
//! true for every type since long before the types that made it visible.
//!
//! PostgreSQL does this in `eval_const_expressions` before planning, and
//! prints the folded form in `EXPLAIN`, which is why its plans show
//! `Index Cond: (id = 7)` for both spellings.
//!
//! ## What is folded, and why it is an allowlist
//!
//! The SHAPE test is round 597's `constant_expr`, shared with round 605
//! rather than written again: two answers to "is this expression
//! constant" is how they come to disagree. On top of it this pass adds a
//! CONTEXT test of its own, described below.
//!
//! Literals, casts to a CONTEXT-FREE type, unary operators, and
//! arithmetic between them. No function calls — not because they could
//! not be folded, but because folding one requires knowing its
//! VOLATILITY, and a function whose volatility this engine cannot look
//! up would be folded silently and wrongly (`random()` collapsing to one
//! draw). Rounds 590 and 596 drew the same line for the same reason, in
//! the correlated-subquery key and the computed JOIN key. When there is
//! a volatility table to consult, the allowlist is where the immutable
//! ones get added.
//!
//! "Context-free" is the second half of that rule, and the first version
//! of this pass did not have it. `'u'::regclass` means whatever the
//! CATALOG says it means; folded against the empty context this pass
//! evaluates in, it came back as the text `u`, and twenty-six catalog
//! tests went red comparing an oid column to the string `u`. The failure
//! was not that the fold refused — it is that it SUCCEEDED and was
//! wrong. So the cast targets are listed one by one, and a target this
//! pass has not been shown to be catalog-independent is not folded.
//!
//! An expression that RAISES while being folded is left exactly as it
//! was. `WHERE x = 1/0` keeps raising from where it raised before, so
//! this pass cannot move an error to a new place.
use ;
use Row;
use crate;
/// Fold the constant parts of every predicate in `stmt`.
///
/// WHERE and JOIN ON only: that is where a folded constant changes what
/// the executor DOES (an index seek instead of a scan) rather than only
/// what it costs, and a narrow pass is one whose effects can be stated.
pub
/// Replace every constant subtree of `e` with the value it evaluates to.
///
/// Top-down: a node that folds whole is replaced and not descended into,
/// so `(1 + 2)::text` becomes one literal rather than a cast over one.
/// Evaluate a constant expression, or `None` if it raises.
///
/// `None` leaves the node alone, so an expression that errors keeps
/// erroring from wherever it did before this pass existed.
/// Whether this node is a constant this pass is willing to evaluate.
///
/// Deliberately a list of node kinds rather than "does it mention a
/// column": a node this walk does not know about would otherwise be
/// admitted by default, and the ones it does not know about include
/// every function call.
/// Whether every part of this expression means the same thing without a
/// catalog and without a session.
///
/// Separate from the SHAPE test above on purpose. Round 605 folds these
/// same expressions inside the row loop, where the real `EvalContext` is
/// in hand, so `'u'::regclass` folds there to the oid it means. This pass
/// runs at prepare time against an empty context, and folded that to the
/// text `u` — twenty-six catalog tests went red comparing an oid column
/// to a string. Same question, two different safe answers, because the
/// two folders can supply different amounts of context.
/// Whether a cast to this target means the same thing without a catalog
/// and without a session.
///
/// Listed one by one on purpose. `RegClass` / `RegType` resolve a NAME
/// against the catalog; `Named` is a user type, which may be an enum or
/// a domain with a constraint; both would be folded against nothing at
/// all here. Everything below parses its input by fixed rules that no
/// DDL can change.
/// The sub-expressions to recurse into for a node this pass will not
/// fold whole. Only the positions a predicate can hold — anything not
/// listed simply is not descended into, which costs a missed fold and
/// never costs correctness.