← Back to Overview

src/backend/nodes/nodeFuncs.c

Coverage: 37/48 lines (77.1%)
Total Lines
48
modified
Covered
37
77.1%
Uncovered
11
22.9%
Keyboard navigation
exprType() lines 42-299
Modified Lines Coverage: 3/3 lines (100.0%)
LineHitsSourceCommit
42 - exprType(const Node *expr) -
43 - { -
44 - Oid type; -
45 - -
46 - if (!expr) -
47 - return InvalidOid; -
48 - -
49 - switch (nodeTag(expr)) -
50 - { -
51 - case T_Var: -
52 - type = ((const Var *) expr)->vartype; -
53 - break; -
54 - case T_Const: -
55 - type = ((const Const *) expr)->consttype; -
56 - break; -
57 - case T_Param: -
58 - type = ((const Param *) expr)->paramtype; -
59 - break; -
60 - case T_Aggref: -
61 - type = ((const Aggref *) expr)->aggtype; -
62 - break; -
63 - case T_GroupingFunc: -
64 - type = INT4OID; -
65 - break; -
66 - case T_WindowFunc: -
67 - type = ((const WindowFunc *) expr)->wintype; -
68 - break; -
69 - case T_MergeSupportFunc: -
70 - type = ((const MergeSupportFunc *) expr)->msftype; -
71 - break; -
72 4596 case T_RPRNavExpr: 7521a30Row pattern recognition patch (planner).
73 4596 type = ((const RPRNavExpr *) expr)->resulttype; 7521a30Row pattern recognition patch (planner).
74 4596 break; 7521a30Row pattern recognition patch (planner).
75 - case T_SubscriptingRef: -
76 - type = ((const SubscriptingRef *) expr)->refrestype; -
77 - break; -
78 - case T_FuncExpr: -
79 - type = ((const FuncExpr *) expr)->funcresulttype; -
80 - break; -
81 - case T_NamedArgExpr: -
82 - type = exprType((Node *) ((const NamedArgExpr *) expr)->arg); -
83 - break; -
84 - case T_OpExpr: -
85 - type = ((const OpExpr *) expr)->opresulttype; -
86 - break; -
87 - case T_DistinctExpr: -
88 - type = ((const DistinctExpr *) expr)->opresulttype; -
89 - break; -
90 - case T_NullIfExpr: -
91 - type = ((const NullIfExpr *) expr)->opresulttype; -
92 - break; -
93 - case T_ScalarArrayOpExpr: -
94 - type = BOOLOID; -
95 - break; -
96 - case T_BoolExpr: -
97 - type = BOOLOID; -
98 - break; -
99 - case T_SubLink: -
100 - { -
101 - const SubLink *sublink = (const SubLink *) expr; -
102 - -
103 - if (sublink->subLinkType == EXPR_SUBLINK || -
104 - sublink->subLinkType == ARRAY_SUBLINK) -
105 - { -
106 - /* get the type of the subselect's first target column */ -
107 - Query *qtree = (Query *) sublink->subselect; -
108 - TargetEntry *tent; -
109 - -
110 - if (!qtree || !IsA(qtree, Query)) -
111 - elog(ERROR, "cannot get type for untransformed sublink"); -
112 - tent = linitial_node(TargetEntry, qtree->targetList); -
113 - Assert(!tent->resjunk); -
114 - type = exprType((Node *) tent->expr); -
115 - if (sublink->subLinkType == ARRAY_SUBLINK) -
116 - { -
117 - type = get_promoted_array_type(type); -
118 - if (!OidIsValid(type)) -
119 - ereport(ERROR, -
120 - (errcode(ERRCODE_UNDEFINED_OBJECT), -
121 - errmsg("could not find array type for data type %s", -
122 - format_type_be(exprType((Node *) tent->expr))))); -
123 - } -
124 - } -
125 - else if (sublink->subLinkType == MULTIEXPR_SUBLINK) -
126 - { -
127 - /* MULTIEXPR is always considered to return RECORD */ -
128 - type = RECORDOID; -
129 - } -
130 - else -
131 - { -
132 - /* for all other sublink types, result is boolean */ -
133 - type = BOOLOID; -
134 - } -
135 - } -
136 - break; -
137 - case T_SubPlan: -
138 - { -
139 - const SubPlan *subplan = (const SubPlan *) expr; -
140 - -
141 - if (subplan->subLinkType == EXPR_SUBLINK || -
142 - subplan->subLinkType == ARRAY_SUBLINK) -
143 - { -
144 - /* get the type of the subselect's first target column */ -
145 - type = subplan->firstColType; -
146 - if (subplan->subLinkType == ARRAY_SUBLINK) -
147 - { -
148 - type = get_promoted_array_type(type); -
149 - if (!OidIsValid(type)) -
150 - ereport(ERROR, -
151 - (errcode(ERRCODE_UNDEFINED_OBJECT), -
152 - errmsg("could not find array type for data type %s", -
153 - format_type_be(subplan->firstColType)))); -
154 - } -
155 - } -
156 - else if (subplan->subLinkType == MULTIEXPR_SUBLINK) -
157 - { -
158 - /* MULTIEXPR is always considered to return RECORD */ -
159 - type = RECORDOID; -
160 - } -
161 - else -
162 - { -
163 - /* for all other subplan types, result is boolean */ -
164 - type = BOOLOID; -
165 - } -
166 - } -
167 - break; -
168 - case T_AlternativeSubPlan: -
169 - { -
170 - const AlternativeSubPlan *asplan = (const AlternativeSubPlan *) expr; -
171 - -
172 - /* subplans should all return the same thing */ -
173 - type = exprType((Node *) linitial(asplan->subplans)); -
174 - } -
175 - break; -
176 - case T_FieldSelect: -
177 - type = ((const FieldSelect *) expr)->resulttype; -
178 - break; -
179 - case T_FieldStore: -
180 - type = ((const FieldStore *) expr)->resulttype; -
181 - break; -
182 - case T_RelabelType: -
183 - type = ((const RelabelType *) expr)->resulttype; -
184 - break; -
185 - case T_CoerceViaIO: -
186 - type = ((const CoerceViaIO *) expr)->resulttype; -
187 - break; -
188 - case T_ArrayCoerceExpr: -
189 - type = ((const ArrayCoerceExpr *) expr)->resulttype; -
190 - break; -
191 - case T_ConvertRowtypeExpr: -
192 - type = ((const ConvertRowtypeExpr *) expr)->resulttype; -
193 - break; -
194 - case T_CollateExpr: -
195 - type = exprType((Node *) ((const CollateExpr *) expr)->arg); -
196 - break; -
197 - case T_CaseExpr: -
198 - type = ((const CaseExpr *) expr)->casetype; -
199 - break; -
200 - case T_CaseTestExpr: -
201 - type = ((const CaseTestExpr *) expr)->typeId; -
202 - break; -
203 - case T_ArrayExpr: -
204 - type = ((const ArrayExpr *) expr)->array_typeid; -
205 - break; -
206 - case T_RowExpr: -
207 - type = ((const RowExpr *) expr)->row_typeid; -
208 - break; -
209 - case T_RowCompareExpr: -
210 - type = BOOLOID; -
211 - break; -
212 - case T_CoalesceExpr: -
213 - type = ((const CoalesceExpr *) expr)->coalescetype; -
214 - break; -
215 - case T_MinMaxExpr: -
216 - type = ((const MinMaxExpr *) expr)->minmaxtype; -
217 - break; -
218 - case T_SQLValueFunction: -
219 - type = ((const SQLValueFunction *) expr)->type; -
220 - break; -
221 - case T_XmlExpr: -
222 - if (((const XmlExpr *) expr)->op == IS_DOCUMENT) -
223 - type = BOOLOID; -
224 - else if (((const XmlExpr *) expr)->op == IS_XMLSERIALIZE) -
225 - type = TEXTOID; -
226 - else -
227 - type = XMLOID; -
228 - break; -
229 - case T_JsonValueExpr: -
230 - { -
231 - const JsonValueExpr *jve = (const JsonValueExpr *) expr; -
232 - -
233 - type = exprType((Node *) jve->formatted_expr); -
234 - } -
235 - break; -
236 - case T_JsonConstructorExpr: -
237 - type = ((const JsonConstructorExpr *) expr)->returning->typid; -
238 - break; -
239 - case T_JsonIsPredicate: -
240 - type = BOOLOID; -
241 - break; -
242 - case T_JsonExpr: -
243 - { -
244 - const JsonExpr *jexpr = (const JsonExpr *) expr; -
245 - -
246 - type = jexpr->returning->typid; -
247 - break; -
248 - } -
249 - case T_JsonBehavior: -
250 - { -
251 - const JsonBehavior *behavior = (const JsonBehavior *) expr; -
252 - -
253 - type = exprType(behavior->expr); -
254 - break; -
255 - } -
256 - case T_NullTest: -
257 - type = BOOLOID; -
258 - break; -
259 - case T_BooleanTest: -
260 - type = BOOLOID; -
261 - break; -
262 - case T_CoerceToDomain: -
263 - type = ((const CoerceToDomain *) expr)->resulttype; -
264 - break; -
265 - case T_CoerceToDomainValue: -
266 - type = ((const CoerceToDomainValue *) expr)->typeId; -
267 - break; -
268 - case T_SetToDefault: -
269 - type = ((const SetToDefault *) expr)->typeId; -
270 - break; -
271 - case T_CurrentOfExpr: -
272 - type = BOOLOID; -
273 - break; -
274 - case T_NextValueExpr: -
275 - type = ((const NextValueExpr *) expr)->typeId; -
276 - break; -
277 - case T_InferenceElem: -
278 - { -
279 - const InferenceElem *n = (const InferenceElem *) expr; -
280 - -
281 - type = exprType((Node *) n->expr); -
282 - } -
283 - break; -
284 - case T_ReturningExpr: -
285 - type = exprType((Node *) ((const ReturningExpr *) expr)->retexpr); -
286 - break; -
287 - case T_PlaceHolderVar: -
288 - type = exprType((Node *) ((const PlaceHolderVar *) expr)->phexpr); -
289 - break; -
290 - case T_GraphPropertyRef: -
291 - type = ((const GraphPropertyRef *) expr)->typeId; -
292 - break; -
293 - default: -
294 - elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); -
295 - type = InvalidOid; /* keep compiler quiet */ -
296 - break; -
297 - } -
298 - return type; -
299 - } -
exprTypmod() lines 307-554
Modified Lines Coverage: 0/2 lines (0.0%)
LineHitsSourceCommit
307 - exprTypmod(const Node *expr) -
308 - { -
309 - if (!expr) -
310 - return -1; -
311 - -
312 - switch (nodeTag(expr)) -
313 - { -
314 - case T_Var: -
315 - return ((const Var *) expr)->vartypmod; -
316 - case T_Const: -
317 - return ((const Const *) expr)->consttypmod; -
318 - case T_Param: -
319 - return ((const Param *) expr)->paramtypmod; -
320 - case T_SubscriptingRef: -
321 - return ((const SubscriptingRef *) expr)->reftypmod; -
322 - case T_FuncExpr: -
323 - { -
324 - int32 coercedTypmod; -
325 - -
326 - /* Be smart about length-coercion functions... */ -
327 - if (exprIsLengthCoercion(expr, &coercedTypmod)) -
328 - return coercedTypmod; -
329 - } -
330 - break; -
331 - case T_NamedArgExpr: -
332 - return exprTypmod((Node *) ((const NamedArgExpr *) expr)->arg); -
333 - case T_NullIfExpr: -
334 - { -
335 - /* -
336 - * Result is either first argument or NULL, so we can report -
337 - * first argument's typmod if known. -
338 - */ -
339 - const NullIfExpr *nexpr = (const NullIfExpr *) expr; -
340 - -
341 - return exprTypmod((Node *) linitial(nexpr->args)); -
342 - } -
343 - break; -
344 - case T_SubLink: -
345 - { -
346 - const SubLink *sublink = (const SubLink *) expr; -
347 - -
348 - if (sublink->subLinkType == EXPR_SUBLINK || -
349 - sublink->subLinkType == ARRAY_SUBLINK) -
350 - { -
351 - /* get the typmod of the subselect's first target column */ -
352 - Query *qtree = (Query *) sublink->subselect; -
353 - TargetEntry *tent; -
354 - -
355 - if (!qtree || !IsA(qtree, Query)) -
356 - elog(ERROR, "cannot get type for untransformed sublink"); -
357 - tent = linitial_node(TargetEntry, qtree->targetList); -
358 - Assert(!tent->resjunk); -
359 - return exprTypmod((Node *) tent->expr); -
360 - /* note we don't need to care if it's an array */ -
361 - } -
362 - /* otherwise, result is RECORD or BOOLEAN, typmod is -1 */ -
363 - } -
364 - break; -
365 - case T_SubPlan: -
366 - { -
367 - const SubPlan *subplan = (const SubPlan *) expr; -
368 - -
369 - if (subplan->subLinkType == EXPR_SUBLINK || -
370 - subplan->subLinkType == ARRAY_SUBLINK) -
371 - { -
372 - /* get the typmod of the subselect's first target column */ -
373 - /* note we don't need to care if it's an array */ -
374 - return subplan->firstColTypmod; -
375 - } -
376 - /* otherwise, result is RECORD or BOOLEAN, typmod is -1 */ -
377 - } -
378 - break; -
379 - case T_AlternativeSubPlan: -
380 - { -
381 - const AlternativeSubPlan *asplan = (const AlternativeSubPlan *) expr; -
382 - -
383 - /* subplans should all return the same thing */ -
384 - return exprTypmod((Node *) linitial(asplan->subplans)); -
385 - } -
386 - break; -
387 - case T_FieldSelect: -
388 - return ((const FieldSelect *) expr)->resulttypmod; -
389 - case T_RelabelType: -
390 - return ((const RelabelType *) expr)->resulttypmod; -
391 - case T_ArrayCoerceExpr: -
392 - return ((const ArrayCoerceExpr *) expr)->resulttypmod; -
393 - case T_CollateExpr: -
394 - return exprTypmod((Node *) ((const CollateExpr *) expr)->arg); -
395 0 case T_RPRNavExpr: 7521a30Row pattern recognition patch (planner).
ReachableTestable · confidence high · exprTypmod @395-397 · 2 lines
Covers @395 Testable · @397 Testable
How to test (one test covers this flow)
Add to src/test/regress/sql/rpr.sql a
DEFINE predicate that explicitly casts a navigation result to a length/precision-bearing type. rpr_stock.price is numeric(10,3), so a narrowing/explicit cast triggers coerce_to_target_type -> coerce_type_typmod -> exprTypmod(RPRNavExpr) at nodeFuncs.c:395. Example:

SELECT part_id, rn, price,
       first_value(price) OVER w
FROM rpr_stock
WINDOW w AS (
PARTITION BY part_id
ORDER BY rn
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
    INITIAL
PATTERN (A B+)
DEFINE
      A AS TRUE,
      B AS CAST(PREV(price) AS numeric(8,2)) > 0
  )
ORDER BY part_id, rn;

The CAST(PREV(price) AS numeric(8,2)) is a top-level subexpression of B's boolean predicate.
During parse analysis the explicit type cast routes through coerce_to_target_type(targettypmod = numeric(8,2)'s packed typmod), which calls coerce_type_typmod(result=RPRNavExpr, ...);
its line 761 guard evaluates exprTypmod() on the RPRNavExpr, hitting case T_RPRNavExpr (nodeFuncs.c:395).
The CAST does not run afoul of define_walker (it only restricts nested navigation and offsets;
a cast wrapping a single nav is walked generically).
Equivalently CAST(LAST(price) AS numeric(8,2)) or any varchar(n)/numeric(p,s) cast of a nav arg works.
The proposed
MEASURES-based test must NOT be used because
MEASURES is not implemented on this branch.
396 - /* result has the same type/typmod as the argument expression */ 7521a30Row pattern recognition patch (planner).
397 0 return exprTypmod((Node *) ((const RPRNavExpr *) expr)->arg); 7521a30Row pattern recognition patch (planner).
398 - case T_CaseExpr: -
399 - { -
400 - /* -
401 - * If all the alternatives agree on type/typmod, return that -
402 - * typmod, else use -1 -
403 - */ -
404 - const CaseExpr *cexpr = (const CaseExpr *) expr; -
405 - Oid casetype = cexpr->casetype; -
406 - int32 typmod; -
407 - ListCell *arg; -
408 - -
409 - if (!cexpr->defresult) -
410 - return -1; -
411 - if (exprType((Node *) cexpr->defresult) != casetype) -
412 - return -1; -
413 - typmod = exprTypmod((Node *) cexpr->defresult); -
414 - if (typmod < 0) -
415 - return -1; /* no point in trying harder */ -
416 - foreach(arg, cexpr->args) -
417 - { -
418 - CaseWhen *w = lfirst_node(CaseWhen, arg); -
419 - -
420 - if (exprType((Node *) w->result) != casetype) -
421 - return -1; -
422 - if (exprTypmod((Node *) w->result) != typmod) -
423 - return -1; -
424 - } -
425 - return typmod; -
426 - } -
427 - break; -
428 - case T_CaseTestExpr: -
429 - return ((const CaseTestExpr *) expr)->typeMod; -
430 - case T_ArrayExpr: -
431 - { -
432 - /* -
433 - * If all the elements agree on type/typmod, return that -
434 - * typmod, else use -1 -
435 - */ -
436 - const ArrayExpr *arrayexpr = (const ArrayExpr *) expr; -
437 - Oid commontype; -
438 - int32 typmod; -
439 - ListCell *elem; -
440 - -
441 - if (arrayexpr->elements == NIL) -
442 - return -1; -
443 - typmod = exprTypmod((Node *) linitial(arrayexpr->elements)); -
444 - if (typmod < 0) -
445 - return -1; /* no point in trying harder */ -
446 - if (arrayexpr->multidims) -
447 - commontype = arrayexpr->array_typeid; -
448 - else -
449 - commontype = arrayexpr->element_typeid; -
450 - foreach(elem, arrayexpr->elements) -
451 - { -
452 - Node *e = (Node *) lfirst(elem); -
453 - -
454 - if (exprType(e) != commontype) -
455 - return -1; -
456 - if (exprTypmod(e) != typmod) -
457 - return -1; -
458 - } -
459 - return typmod; -
460 - } -
461 - break; -
462 - case T_CoalesceExpr: -
463 - { -
464 - /* -
465 - * If all the alternatives agree on type/typmod, return that -
466 - * typmod, else use -1 -
467 - */ -
468 - const CoalesceExpr *cexpr = (const CoalesceExpr *) expr; -
469 - Oid coalescetype = cexpr->coalescetype; -
470 - int32 typmod; -
471 - ListCell *arg; -
472 - -
473 - if (exprType((Node *) linitial(cexpr->args)) != coalescetype) -
474 - return -1; -
475 - typmod = exprTypmod((Node *) linitial(cexpr->args)); -
476 - if (typmod < 0) -
477 - return -1; /* no point in trying harder */ -
478 - for_each_from(arg, cexpr->args, 1) -
479 - { -
480 - Node *e = (Node *) lfirst(arg); -
481 - -
482 - if (exprType(e) != coalescetype) -
483 - return -1; -
484 - if (exprTypmod(e) != typmod) -
485 - return -1; -
486 - } -
487 - return typmod; -
488 - } -
489 - break; -
490 - case T_MinMaxExpr: -
491 - { -
492 - /* -
493 - * If all the alternatives agree on type/typmod, return that -
494 - * typmod, else use -1 -
495 - */ -
496 - const MinMaxExpr *mexpr = (const MinMaxExpr *) expr; -
497 - Oid minmaxtype = mexpr->minmaxtype; -
498 - int32 typmod; -
499 - ListCell *arg; -
500 - -
501 - if (exprType((Node *) linitial(mexpr->args)) != minmaxtype) -
502 - return -1; -
503 - typmod = exprTypmod((Node *) linitial(mexpr->args)); -
504 - if (typmod < 0) -
505 - return -1; /* no point in trying harder */ -
506 - for_each_from(arg, mexpr->args, 1) -
507 - { -
508 - Node *e = (Node *) lfirst(arg); -
509 - -
510 - if (exprType(e) != minmaxtype) -
511 - return -1; -
512 - if (exprTypmod(e) != typmod) -
513 - return -1; -
514 - } -
515 - return typmod; -
516 - } -
517 - break; -
518 - case T_SQLValueFunction: -
519 - return ((const SQLValueFunction *) expr)->typmod; -
520 - case T_JsonValueExpr: -
521 - return exprTypmod((Node *) ((const JsonValueExpr *) expr)->formatted_expr); -
522 - case T_JsonConstructorExpr: -
523 - return ((const JsonConstructorExpr *) expr)->returning->typmod; -
524 - case T_JsonExpr: -
525 - { -
526 - const JsonExpr *jexpr = (const JsonExpr *) expr; -
527 - -
528 - return jexpr->returning->typmod; -
529 - } -
530 - break; -
531 - case T_JsonBehavior: -
532 - { -
533 - const JsonBehavior *behavior = (const JsonBehavior *) expr; -
534 - -
535 - return exprTypmod(behavior->expr); -
536 - } -
537 - break; -
538 - case T_CoerceToDomain: -
539 - return ((const CoerceToDomain *) expr)->resulttypmod; -
540 - case T_CoerceToDomainValue: -
541 - return ((const CoerceToDomainValue *) expr)->typeMod; -
542 - case T_SetToDefault: -
543 - return ((const SetToDefault *) expr)->typeMod; -
544 - case T_ReturningExpr: -
545 - return exprTypmod((Node *) ((const ReturningExpr *) expr)->retexpr); -
546 - case T_PlaceHolderVar: -
547 - return exprTypmod((Node *) ((const PlaceHolderVar *) expr)->phexpr); -
548 - case T_GraphPropertyRef: -
549 - return ((const GraphPropertyRef *) expr)->typmod; -
550 - default: -
551 - break; -
552 - } -
553 - return -1; -
554 - } -
exprCollation() lines 832-1092
Modified Lines Coverage: 0/3 lines (0.0%)
LineHitsSourceCommit
832 - exprCollation(const Node *expr) -
833 - { -
834 - Oid coll; -
835 - -
836 - if (!expr) -
837 - return InvalidOid; -
838 - -
839 - switch (nodeTag(expr)) -
840 - { -
841 - case T_Var: -
842 - coll = ((const Var *) expr)->varcollid; -
843 - break; -
844 - case T_Const: -
845 - coll = ((const Const *) expr)->constcollid; -
846 - break; -
847 - case T_Param: -
848 - coll = ((const Param *) expr)->paramcollid; -
849 - break; -
850 - case T_Aggref: -
851 - coll = ((const Aggref *) expr)->aggcollid; -
852 - break; -
853 - case T_GroupingFunc: -
854 - coll = InvalidOid; -
855 - break; -
856 - case T_WindowFunc: -
857 - coll = ((const WindowFunc *) expr)->wincollid; -
858 - break; -
859 - case T_MergeSupportFunc: -
860 - coll = ((const MergeSupportFunc *) expr)->msfcollid; -
861 - break; -
862 0 case T_RPRNavExpr: 7521a30Row pattern recognition patch (planner).
UnreachableDefensive (unreachable) · confidence high · exprCollation @862-864 · 3 lines
Reason
Finding's classification (testable) and root-cause are WRONG.
Empirically refuted.
The exact proposed test already exists in the suite: src/test/regress/sql/rpr.sql:946 has `B AS PREV(tdate::text, 1) > PREV(tdate::text, 2)` (a TEXT column wrapped in nav, compared with `>` forcing collation resolution), present and passing in rpr.out:1804 (20 rows).
Yet current gcov for nodeFuncs.c shows lines 862-863 (exprCollation T_RPRNavExpr) at ##### (0 hits), while exprSetCollation T_RPRNavExpr at lines 1174-1175 shows 1212 hits.
So collation is
SET on RPRNavExpr 1212 times but exprCollation is NEVER called on one.
Mechanism: parse_rpr.c:426 calls assign_expr_collations -> assign_collations_walker, which for RPRNavExpr hits the default case (parse_collate.c:576-762): it recurses bottom-up via expression_tree_walker, bubbles child collation through loccontext, and writes it back with exprSetCollation (751) -- it never reads it via exprCollation.
The parent OpExpr likewise gets its opcollid/inputcollid from the bubbled context, not from exprCollation(nav). execExpr.c:1192-1281 compiles RPRNavExpr without ever calling exprCollation on it. createplan.c calls exprCollation only on partition/order/sort/distinct tle->expr keys, never an RPRNavExpr (which exists only nested inside boolean
DEFINE conditions).
MEASURES/SUBSET are not in gram.y in this branch, so a bare nav can never surface as an output column.
Conclusion: no SQL/regression input reaches 862-864;
this is a defensive completeness case in the exprCollation accessor.
Recommended fix
No code fix required for correctness;
the case is correct defensive completeness for the exprCollation accessor (every collation-bearing node tag should be handled so the accessor never elog/falls through for a valid node).
If coverage hygiene is desired, options are:
(1) leave as-is and document that RPRNavExpr collation is only ever set, never read, in the current feature surface;
or (2) add a targeted C-level test (e.g. in a regression-callable test function) that constructs an RPRNavExpr and asserts exprCollation returns resultcollid.
Do NOT rely on the proposed SQL test -- it has been empirically shown not to execute these lines.
863 0 coll = ((const RPRNavExpr *) expr)->resultcollid; 7521a30Row pattern recognition patch (planner).
864 0 break; 7521a30Row pattern recognition patch (planner).
865 - case T_SubscriptingRef: -
866 - coll = ((const SubscriptingRef *) expr)->refcollid; -
867 - break; -
868 - case T_FuncExpr: -
869 - coll = ((const FuncExpr *) expr)->funccollid; -
870 - break; -
871 - case T_NamedArgExpr: -
872 - coll = exprCollation((Node *) ((const NamedArgExpr *) expr)->arg); -
873 - break; -
874 - case T_OpExpr: -
875 - coll = ((const OpExpr *) expr)->opcollid; -
876 - break; -
877 - case T_DistinctExpr: -
878 - coll = ((const DistinctExpr *) expr)->opcollid; -
879 - break; -
880 - case T_NullIfExpr: -
881 - coll = ((const NullIfExpr *) expr)->opcollid; -
882 - break; -
883 - case T_ScalarArrayOpExpr: -
884 - /* ScalarArrayOpExpr's result is boolean ... */ -
885 - coll = InvalidOid; /* ... so it has no collation */ -
886 - break; -
887 - case T_BoolExpr: -
888 - /* BoolExpr's result is boolean ... */ -
889 - coll = InvalidOid; /* ... so it has no collation */ -
890 - break; -
891 - case T_SubLink: -
892 - { -
893 - const SubLink *sublink = (const SubLink *) expr; -
894 - -
895 - if (sublink->subLinkType == EXPR_SUBLINK || -
896 - sublink->subLinkType == ARRAY_SUBLINK) -
897 - { -
898 - /* get the collation of subselect's first target column */ -
899 - Query *qtree = (Query *) sublink->subselect; -
900 - TargetEntry *tent; -
901 - -
902 - if (!qtree || !IsA(qtree, Query)) -
903 - elog(ERROR, "cannot get collation for untransformed sublink"); -
904 - tent = linitial_node(TargetEntry, qtree->targetList); -
905 - Assert(!tent->resjunk); -
906 - coll = exprCollation((Node *) tent->expr); -
907 - /* collation doesn't change if it's converted to array */ -
908 - } -
909 - else -
910 - { -
911 - /* otherwise, SubLink's result is RECORD or BOOLEAN */ -
912 - coll = InvalidOid; /* ... so it has no collation */ -
913 - } -
914 - } -
915 - break; -
916 - case T_SubPlan: -
917 - { -
918 - const SubPlan *subplan = (const SubPlan *) expr; -
919 - -
920 - if (subplan->subLinkType == EXPR_SUBLINK || -
921 - subplan->subLinkType == ARRAY_SUBLINK) -
922 - { -
923 - /* get the collation of subselect's first target column */ -
924 - coll = subplan->firstColCollation; -
925 - /* collation doesn't change if it's converted to array */ -
926 - } -
927 - else -
928 - { -
929 - /* otherwise, SubPlan's result is RECORD or BOOLEAN */ -
930 - coll = InvalidOid; /* ... so it has no collation */ -
931 - } -
932 - } -
933 - break; -
934 - case T_AlternativeSubPlan: -
935 - { -
936 - const AlternativeSubPlan *asplan = (const AlternativeSubPlan *) expr; -
937 - -
938 - /* subplans should all return the same thing */ -
939 - coll = exprCollation((Node *) linitial(asplan->subplans)); -
940 - } -
941 - break; -
942 - case T_FieldSelect: -
943 - coll = ((const FieldSelect *) expr)->resultcollid; -
944 - break; -
945 - case T_FieldStore: -
946 - /* FieldStore's result is composite ... */ -
947 - coll = InvalidOid; /* ... so it has no collation */ -
948 - break; -
949 - case T_RelabelType: -
950 - coll = ((const RelabelType *) expr)->resultcollid; -
951 - break; -
952 - case T_CoerceViaIO: -
953 - coll = ((const CoerceViaIO *) expr)->resultcollid; -
954 - break; -
955 - case T_ArrayCoerceExpr: -
956 - coll = ((const ArrayCoerceExpr *) expr)->resultcollid; -
957 - break; -
958 - case T_ConvertRowtypeExpr: -
959 - /* ConvertRowtypeExpr's result is composite ... */ -
960 - coll = InvalidOid; /* ... so it has no collation */ -
961 - break; -
962 - case T_CollateExpr: -
963 - coll = ((const CollateExpr *) expr)->collOid; -
964 - break; -
965 - case T_CaseExpr: -
966 - coll = ((const CaseExpr *) expr)->casecollid; -
967 - break; -
968 - case T_CaseTestExpr: -
969 - coll = ((const CaseTestExpr *) expr)->collation; -
970 - break; -
971 - case T_ArrayExpr: -
972 - coll = ((const ArrayExpr *) expr)->array_collid; -
973 - break; -
974 - case T_RowExpr: -
975 - /* RowExpr's result is composite ... */ -
976 - coll = InvalidOid; /* ... so it has no collation */ -
977 - break; -
978 - case T_RowCompareExpr: -
979 - /* RowCompareExpr's result is boolean ... */ -
980 - coll = InvalidOid; /* ... so it has no collation */ -
981 - break; -
982 - case T_CoalesceExpr: -
983 - coll = ((const CoalesceExpr *) expr)->coalescecollid; -
984 - break; -
985 - case T_MinMaxExpr: -
986 - coll = ((const MinMaxExpr *) expr)->minmaxcollid; -
987 - break; -
988 - case T_SQLValueFunction: -
989 - /* Returns either NAME or a non-collatable type */ -
990 - if (((const SQLValueFunction *) expr)->type == NAMEOID) -
991 - coll = C_COLLATION_OID; -
992 - else -
993 - coll = InvalidOid; -
994 - break; -
995 - case T_XmlExpr: -
996 - -
997 - /* -
998 - * XMLSERIALIZE returns text from non-collatable inputs, so its -
999 - * collation is always default. The other cases return boolean or -
1000 - * XML, which are non-collatable. -
1001 - */ -
1002 - if (((const XmlExpr *) expr)->op == IS_XMLSERIALIZE) -
1003 - coll = DEFAULT_COLLATION_OID; -
1004 - else -
1005 - coll = InvalidOid; -
1006 - break; -
1007 - case T_JsonValueExpr: -
1008 - coll = exprCollation((Node *) ((const JsonValueExpr *) expr)->formatted_expr); -
1009 - break; -
1010 - case T_JsonConstructorExpr: -
1011 - { -
1012 - const JsonConstructorExpr *ctor = (const JsonConstructorExpr *) expr; -
1013 - -
1014 - /* -
1015 - * Collation comes from coercion if present, otherwise from -
1016 - * func. The func fallback is needed in cases where func -
1017 - * already produces the final output type and no coercion is -
1018 - * needed (cf. the JSCTOR_JSON_ARRAY_QUERY case). -
1019 - */ -
1020 - if (ctor->coercion) -
1021 - coll = exprCollation((Node *) ctor->coercion); -
1022 - else if (ctor->func) -
1023 - coll = exprCollation((Node *) ctor->func); -
1024 - else -
1025 - coll = InvalidOid; -
1026 - } -
1027 - break; -
1028 - case T_JsonIsPredicate: -
1029 - /* IS JSON's result is boolean ... */ -
1030 - coll = InvalidOid; /* ... so it has no collation */ -
1031 - break; -
1032 - case T_JsonExpr: -
1033 - { -
1034 - const JsonExpr *jsexpr = (const JsonExpr *) expr; -
1035 - -
1036 - coll = jsexpr->collation; -
1037 - } -
1038 - break; -
1039 - case T_JsonBehavior: -
1040 - { -
1041 - const JsonBehavior *behavior = (const JsonBehavior *) expr; -
1042 - -
1043 - if (behavior->expr) -
1044 - coll = exprCollation(behavior->expr); -
1045 - else -
1046 - coll = InvalidOid; -
1047 - } -
1048 - break; -
1049 - case T_NullTest: -
1050 - /* NullTest's result is boolean ... */ -
1051 - coll = InvalidOid; /* ... so it has no collation */ -
1052 - break; -
1053 - case T_BooleanTest: -
1054 - /* BooleanTest's result is boolean ... */ -
1055 - coll = InvalidOid; /* ... so it has no collation */ -
1056 - break; -
1057 - case T_CoerceToDomain: -
1058 - coll = ((const CoerceToDomain *) expr)->resultcollid; -
1059 - break; -
1060 - case T_CoerceToDomainValue: -
1061 - coll = ((const CoerceToDomainValue *) expr)->collation; -
1062 - break; -
1063 - case T_SetToDefault: -
1064 - coll = ((const SetToDefault *) expr)->collation; -
1065 - break; -
1066 - case T_CurrentOfExpr: -
1067 - /* CurrentOfExpr's result is boolean ... */ -
1068 - coll = InvalidOid; /* ... so it has no collation */ -
1069 - break; -
1070 - case T_NextValueExpr: -
1071 - /* NextValueExpr's result is an integer type ... */ -
1072 - coll = InvalidOid; /* ... so it has no collation */ -
1073 - break; -
1074 - case T_InferenceElem: -
1075 - coll = exprCollation((Node *) ((const InferenceElem *) expr)->expr); -
1076 - break; -
1077 - case T_ReturningExpr: -
1078 - coll = exprCollation((Node *) ((const ReturningExpr *) expr)->retexpr); -
1079 - break; -
1080 - case T_PlaceHolderVar: -
1081 - coll = exprCollation((Node *) ((const PlaceHolderVar *) expr)->phexpr); -
1082 - break; -
1083 - case T_GraphPropertyRef: -
1084 - coll = ((const GraphPropertyRef *) expr)->collation; -
1085 - break; -
1086 - default: -
1087 - elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); -
1088 - coll = InvalidOid; /* keep compiler quiet */ -
1089 - break; -
1090 - } -
1091 - return coll; -
1092 - } -
exprSetCollation() lines 1149-1340
Modified Lines Coverage: 3/3 lines (100.0%)
LineHitsSourceCommit
1149 - exprSetCollation(Node *expr, Oid collation) -
1150 - { -
1151 - switch (nodeTag(expr)) -
1152 - { -
1153 - case T_Var: -
1154 - ((Var *) expr)->varcollid = collation; -
1155 - break; -
1156 - case T_Const: -
1157 - ((Const *) expr)->constcollid = collation; -
1158 - break; -
1159 - case T_Param: -
1160 - ((Param *) expr)->paramcollid = collation; -
1161 - break; -
1162 - case T_Aggref: -
1163 - ((Aggref *) expr)->aggcollid = collation; -
1164 - break; -
1165 - case T_GroupingFunc: -
1166 - Assert(!OidIsValid(collation)); -
1167 - break; -
1168 - case T_WindowFunc: -
1169 - ((WindowFunc *) expr)->wincollid = collation; -
1170 - break; -
1171 - case T_MergeSupportFunc: -
1172 - ((MergeSupportFunc *) expr)->msfcollid = collation; -
1173 - break; -
1174 2268 case T_RPRNavExpr: 7521a30Row pattern recognition patch (planner).
1175 2268 ((RPRNavExpr *) expr)->resultcollid = collation; 7521a30Row pattern recognition patch (planner).
1176 2268 break; 7521a30Row pattern recognition patch (planner).
1177 - case T_SubscriptingRef: -
1178 - ((SubscriptingRef *) expr)->refcollid = collation; -
1179 - break; -
1180 - case T_FuncExpr: -
1181 - ((FuncExpr *) expr)->funccollid = collation; -
1182 - break; -
1183 - case T_NamedArgExpr: -
1184 - Assert(collation == exprCollation((Node *) ((NamedArgExpr *) expr)->arg)); -
1185 - break; -
1186 - case T_OpExpr: -
1187 - ((OpExpr *) expr)->opcollid = collation; -
1188 - break; -
1189 - case T_DistinctExpr: -
1190 - ((DistinctExpr *) expr)->opcollid = collation; -
1191 - break; -
1192 - case T_NullIfExpr: -
1193 - ((NullIfExpr *) expr)->opcollid = collation; -
1194 - break; -
1195 - case T_ScalarArrayOpExpr: -
1196 - /* ScalarArrayOpExpr's result is boolean ... */ -
1197 - Assert(!OidIsValid(collation)); /* ... so never set a collation */ -
1198 - break; -
1199 - case T_BoolExpr: -
1200 - /* BoolExpr's result is boolean ... */ -
1201 - Assert(!OidIsValid(collation)); /* ... so never set a collation */ -
1202 - break; -
1203 - case T_SubLink: -
1204 - #ifdef USE_ASSERT_CHECKING -
1205 - { -
1206 - SubLink *sublink = (SubLink *) expr; -
1207 - -
1208 - if (sublink->subLinkType == EXPR_SUBLINK || -
1209 - sublink->subLinkType == ARRAY_SUBLINK) -
1210 - { -
1211 - /* get the collation of subselect's first target column */ -
1212 - Query *qtree = (Query *) sublink->subselect; -
1213 - TargetEntry *tent; -
1214 - -
1215 - if (!qtree || !IsA(qtree, Query)) -
1216 - elog(ERROR, "cannot set collation for untransformed sublink"); -
1217 - tent = linitial_node(TargetEntry, qtree->targetList); -
1218 - Assert(!tent->resjunk); -
1219 - Assert(collation == exprCollation((Node *) tent->expr)); -
1220 - } -
1221 - else -
1222 - { -
1223 - /* otherwise, result is RECORD or BOOLEAN */ -
1224 - Assert(!OidIsValid(collation)); -
1225 - } -
1226 - } -
1227 - #endif /* USE_ASSERT_CHECKING */ -
1228 - break; -
1229 - case T_FieldSelect: -
1230 - ((FieldSelect *) expr)->resultcollid = collation; -
1231 - break; -
1232 - case T_FieldStore: -
1233 - /* FieldStore's result is composite ... */ -
1234 - Assert(!OidIsValid(collation)); /* ... so never set a collation */ -
1235 - break; -
1236 - case T_RelabelType: -
1237 - ((RelabelType *) expr)->resultcollid = collation; -
1238 - break; -
1239 - case T_CoerceViaIO: -
1240 - ((CoerceViaIO *) expr)->resultcollid = collation; -
1241 - break; -
1242 - case T_ArrayCoerceExpr: -
1243 - ((ArrayCoerceExpr *) expr)->resultcollid = collation; -
1244 - break; -
1245 - case T_ConvertRowtypeExpr: -
1246 - /* ConvertRowtypeExpr's result is composite ... */ -
1247 - Assert(!OidIsValid(collation)); /* ... so never set a collation */ -
1248 - break; -
1249 - case T_CaseExpr: -
1250 - ((CaseExpr *) expr)->casecollid = collation; -
1251 - break; -
1252 - case T_ArrayExpr: -
1253 - ((ArrayExpr *) expr)->array_collid = collation; -
1254 - break; -
1255 - case T_RowExpr: -
1256 - /* RowExpr's result is composite ... */ -
1257 - Assert(!OidIsValid(collation)); /* ... so never set a collation */ -
1258 - break; -
1259 - case T_RowCompareExpr: -
1260 - /* RowCompareExpr's result is boolean ... */ -
1261 - Assert(!OidIsValid(collation)); /* ... so never set a collation */ -
1262 - break; -
1263 - case T_CoalesceExpr: -
1264 - ((CoalesceExpr *) expr)->coalescecollid = collation; -
1265 - break; -
1266 - case T_MinMaxExpr: -
1267 - ((MinMaxExpr *) expr)->minmaxcollid = collation; -
1268 - break; -
1269 - case T_SQLValueFunction: -
1270 - Assert((((SQLValueFunction *) expr)->type == NAMEOID) ? -
1271 - (collation == C_COLLATION_OID) : -
1272 - (collation == InvalidOid)); -
1273 - break; -
1274 - case T_XmlExpr: -
1275 - Assert((((XmlExpr *) expr)->op == IS_XMLSERIALIZE) ? -
1276 - (collation == DEFAULT_COLLATION_OID) : -
1277 - (collation == InvalidOid)); -
1278 - break; -
1279 - case T_JsonValueExpr: -
1280 - exprSetCollation((Node *) ((JsonValueExpr *) expr)->formatted_expr, -
1281 - collation); -
1282 - break; -
1283 - case T_JsonConstructorExpr: -
1284 - { -
1285 - JsonConstructorExpr *ctor = (JsonConstructorExpr *) expr; -
1286 - -
1287 - /* See comment in exprCollation() */ -
1288 - if (ctor->coercion) -
1289 - exprSetCollation((Node *) ctor->coercion, collation); -
1290 - else if (ctor->func) -
1291 - exprSetCollation((Node *) ctor->func, collation); -
1292 - else -
1293 - Assert(!OidIsValid(collation)); /* result is always a -
1294 - * json[b] type */ -
1295 - } -
1296 - break; -
1297 - case T_JsonIsPredicate: -
1298 - Assert(!OidIsValid(collation)); /* result is always boolean */ -
1299 - break; -
1300 - case T_JsonExpr: -
1301 - { -
1302 - JsonExpr *jexpr = (JsonExpr *) expr; -
1303 - -
1304 - jexpr->collation = collation; -
1305 - } -
1306 - break; -
1307 - case T_JsonBehavior: -
1308 - Assert(((JsonBehavior *) expr)->expr == NULL || -
1309 - exprCollation(((JsonBehavior *) expr)->expr) == collation); -
1310 - break; -
1311 - case T_NullTest: -
1312 - /* NullTest's result is boolean ... */ -
1313 - Assert(!OidIsValid(collation)); /* ... so never set a collation */ -
1314 - break; -
1315 - case T_BooleanTest: -
1316 - /* BooleanTest's result is boolean ... */ -
1317 - Assert(!OidIsValid(collation)); /* ... so never set a collation */ -
1318 - break; -
1319 - case T_CoerceToDomain: -
1320 - ((CoerceToDomain *) expr)->resultcollid = collation; -
1321 - break; -
1322 - case T_CoerceToDomainValue: -
1323 - ((CoerceToDomainValue *) expr)->collation = collation; -
1324 - break; -
1325 - case T_SetToDefault: -
1326 - ((SetToDefault *) expr)->collation = collation; -
1327 - break; -
1328 - case T_CurrentOfExpr: -
1329 - /* CurrentOfExpr's result is boolean ... */ -
1330 - Assert(!OidIsValid(collation)); /* ... so never set a collation */ -
1331 - break; -
1332 - case T_NextValueExpr: -
1333 - /* NextValueExpr's result is an integer type ... */ -
1334 - Assert(!OidIsValid(collation)); /* ... so never set a collation */ -
1335 - break; -
1336 - default: -
1337 - elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr)); -
1338 - break; -
1339 - } -
1340 - } -
exprLocation() lines 1415-1848
Modified Lines Coverage: 6/6 lines (100.0%)
LineHitsSourceCommit
1415 - exprLocation(const Node *expr) -
1416 - { -
1417 - int loc; -
1418 - -
1419 - if (expr == NULL) -
1420 - return -1; -
1421 - switch (nodeTag(expr)) -
1422 - { -
1423 - case T_RangeVar: -
1424 - loc = ((const RangeVar *) expr)->location; -
1425 - break; -
1426 - case T_TableFunc: -
1427 - loc = ((const TableFunc *) expr)->location; -
1428 - break; -
1429 - case T_Var: -
1430 - loc = ((const Var *) expr)->location; -
1431 - break; -
1432 - case T_Const: -
1433 - loc = ((const Const *) expr)->location; -
1434 - break; -
1435 - case T_Param: -
1436 - loc = ((const Param *) expr)->location; -
1437 - break; -
1438 - case T_Aggref: -
1439 - /* function name should always be the first thing */ -
1440 - loc = ((const Aggref *) expr)->location; -
1441 - break; -
1442 - case T_GroupingFunc: -
1443 - loc = ((const GroupingFunc *) expr)->location; -
1444 - break; -
1445 - case T_WindowFunc: -
1446 - /* function name should always be the first thing */ -
1447 - loc = ((const WindowFunc *) expr)->location; -
1448 - break; -
1449 - case T_MergeSupportFunc: -
1450 - loc = ((const MergeSupportFunc *) expr)->location; -
1451 - break; -
1452 4 case T_RPRNavExpr: 7521a30Row pattern recognition patch (planner).
1453 4 loc = ((const RPRNavExpr *) expr)->location; 7521a30Row pattern recognition patch (planner).
1454 4 break; 7521a30Row pattern recognition patch (planner).
1455 4 case T_RPRPatternNode: 7521a30Row pattern recognition patch (planner).
1456 4 loc = ((const RPRPatternNode *) expr)->location; 7521a30Row pattern recognition patch (planner).
1457 4 break; 7521a30Row pattern recognition patch (planner).
1458 - case T_SubscriptingRef: -
1459 - /* just use container argument's location */ -
1460 - loc = exprLocation((Node *) ((const SubscriptingRef *) expr)->refexpr); -
1461 - break; -
1462 - case T_FuncExpr: -
1463 - { -
1464 - const FuncExpr *fexpr = (const FuncExpr *) expr; -
1465 - -
1466 - /* consider both function name and leftmost arg */ -
1467 - loc = leftmostLoc(fexpr->location, -
1468 - exprLocation((Node *) fexpr->args)); -
1469 - } -
1470 - break; -
1471 - case T_NamedArgExpr: -
1472 - { -
1473 - const NamedArgExpr *na = (const NamedArgExpr *) expr; -
1474 - -
1475 - /* consider both argument name and value */ -
1476 - loc = leftmostLoc(na->location, -
1477 - exprLocation((Node *) na->arg)); -
1478 - } -
1479 - break; -
1480 - case T_OpExpr: -
1481 - case T_DistinctExpr: /* struct-equivalent to OpExpr */ -
1482 - case T_NullIfExpr: /* struct-equivalent to OpExpr */ -
1483 - { -
1484 - const OpExpr *opexpr = (const OpExpr *) expr; -
1485 - -
1486 - /* consider both operator name and leftmost arg */ -
1487 - loc = leftmostLoc(opexpr->location, -
1488 - exprLocation((Node *) opexpr->args)); -
1489 - } -
1490 - break; -
1491 - case T_ScalarArrayOpExpr: -
1492 - { -
1493 - const ScalarArrayOpExpr *saopexpr = (const ScalarArrayOpExpr *) expr; -
1494 - -
1495 - /* consider both operator name and leftmost arg */ -
1496 - loc = leftmostLoc(saopexpr->location, -
1497 - exprLocation((Node *) saopexpr->args)); -
1498 - } -
1499 - break; -
1500 - case T_BoolExpr: -
1501 - { -
1502 - const BoolExpr *bexpr = (const BoolExpr *) expr; -
1503 - -
1504 - /* -
1505 - * Same as above, to handle either NOT or AND/OR. We can't -
1506 - * special-case NOT because of the way that it's used for -
1507 - * things like IS NOT BETWEEN. -
1508 - */ -
1509 - loc = leftmostLoc(bexpr->location, -
1510 - exprLocation((Node *) bexpr->args)); -
1511 - } -
1512 - break; -
1513 - case T_SubLink: -
1514 - { -
1515 - const SubLink *sublink = (const SubLink *) expr; -
1516 - -
1517 - /* check the testexpr, if any, and the operator/keyword */ -
1518 - loc = leftmostLoc(exprLocation(sublink->testexpr), -
1519 - sublink->location); -
1520 - } -
1521 - break; -
1522 - case T_FieldSelect: -
1523 - /* just use argument's location */ -
1524 - loc = exprLocation((Node *) ((const FieldSelect *) expr)->arg); -
1525 - break; -
1526 - case T_FieldStore: -
1527 - /* just use argument's location */ -
1528 - loc = exprLocation((Node *) ((const FieldStore *) expr)->arg); -
1529 - break; -
1530 - case T_RelabelType: -
1531 - { -
1532 - const RelabelType *rexpr = (const RelabelType *) expr; -
1533 - -
1534 - /* Much as above */ -
1535 - loc = leftmostLoc(rexpr->location, -
1536 - exprLocation((Node *) rexpr->arg)); -
1537 - } -
1538 - break; -
1539 - case T_CoerceViaIO: -
1540 - { -
1541 - const CoerceViaIO *cexpr = (const CoerceViaIO *) expr; -
1542 - -
1543 - /* Much as above */ -
1544 - loc = leftmostLoc(cexpr->location, -
1545 - exprLocation((Node *) cexpr->arg)); -
1546 - } -
1547 - break; -
1548 - case T_ArrayCoerceExpr: -
1549 - { -
1550 - const ArrayCoerceExpr *cexpr = (const ArrayCoerceExpr *) expr; -
1551 - -
1552 - /* Much as above */ -
1553 - loc = leftmostLoc(cexpr->location, -
1554 - exprLocation((Node *) cexpr->arg)); -
1555 - } -
1556 - break; -
1557 - case T_ConvertRowtypeExpr: -
1558 - { -
1559 - const ConvertRowtypeExpr *cexpr = (const ConvertRowtypeExpr *) expr; -
1560 - -
1561 - /* Much as above */ -
1562 - loc = leftmostLoc(cexpr->location, -
1563 - exprLocation((Node *) cexpr->arg)); -
1564 - } -
1565 - break; -
1566 - case T_CollateExpr: -
1567 - /* just use argument's location */ -
1568 - loc = exprLocation((Node *) ((const CollateExpr *) expr)->arg); -
1569 - break; -
1570 - case T_CaseExpr: -
1571 - /* CASE keyword should always be the first thing */ -
1572 - loc = ((const CaseExpr *) expr)->location; -
1573 - break; -
1574 - case T_CaseWhen: -
1575 - /* WHEN keyword should always be the first thing */ -
1576 - loc = ((const CaseWhen *) expr)->location; -
1577 - break; -
1578 - case T_ArrayExpr: -
1579 - /* the location points at ARRAY or [, which must be leftmost */ -
1580 - loc = ((const ArrayExpr *) expr)->location; -
1581 - break; -
1582 - case T_RowExpr: -
1583 - /* the location points at ROW or (, which must be leftmost */ -
1584 - loc = ((const RowExpr *) expr)->location; -
1585 - break; -
1586 - case T_RowCompareExpr: -
1587 - /* just use leftmost argument's location */ -
1588 - loc = exprLocation((Node *) ((const RowCompareExpr *) expr)->largs); -
1589 - break; -
1590 - case T_CoalesceExpr: -
1591 - /* COALESCE keyword should always be the first thing */ -
1592 - loc = ((const CoalesceExpr *) expr)->location; -
1593 - break; -
1594 - case T_MinMaxExpr: -
1595 - /* GREATEST/LEAST keyword should always be the first thing */ -
1596 - loc = ((const MinMaxExpr *) expr)->location; -
1597 - break; -
1598 - case T_SQLValueFunction: -
1599 - /* function keyword should always be the first thing */ -
1600 - loc = ((const SQLValueFunction *) expr)->location; -
1601 - break; -
1602 - case T_XmlExpr: -
1603 - { -
1604 - const XmlExpr *xexpr = (const XmlExpr *) expr; -
1605 - -
1606 - /* consider both function name and leftmost arg */ -
1607 - loc = leftmostLoc(xexpr->location, -
1608 - exprLocation((Node *) xexpr->args)); -
1609 - } -
1610 - break; -
1611 - case T_JsonFormat: -
1612 - loc = ((const JsonFormat *) expr)->location; -
1613 - break; -
1614 - case T_JsonValueExpr: -
1615 - loc = exprLocation((Node *) ((const JsonValueExpr *) expr)->raw_expr); -
1616 - break; -
1617 - case T_JsonConstructorExpr: -
1618 - loc = ((const JsonConstructorExpr *) expr)->location; -
1619 - break; -
1620 - case T_JsonIsPredicate: -
1621 - loc = ((const JsonIsPredicate *) expr)->location; -
1622 - break; -
1623 - case T_JsonExpr: -
1624 - { -
1625 - const JsonExpr *jsexpr = (const JsonExpr *) expr; -
1626 - -
1627 - /* consider both function name and leftmost arg */ -
1628 - loc = leftmostLoc(jsexpr->location, -
1629 - exprLocation(jsexpr->formatted_expr)); -
1630 - } -
1631 - break; -
1632 - case T_JsonBehavior: -
1633 - loc = exprLocation(((const JsonBehavior *) expr)->expr); -
1634 - break; -
1635 - case T_NullTest: -
1636 - { -
1637 - const NullTest *nexpr = (const NullTest *) expr; -
1638 - -
1639 - /* Much as above */ -
1640 - loc = leftmostLoc(nexpr->location, -
1641 - exprLocation((Node *) nexpr->arg)); -
1642 - } -
1643 - break; -
1644 - case T_BooleanTest: -
1645 - { -
1646 - const BooleanTest *bexpr = (const BooleanTest *) expr; -
1647 - -
1648 - /* Much as above */ -
1649 - loc = leftmostLoc(bexpr->location, -
1650 - exprLocation((Node *) bexpr->arg)); -
1651 - } -
1652 - break; -
1653 - case T_CoerceToDomain: -
1654 - { -
1655 - const CoerceToDomain *cexpr = (const CoerceToDomain *) expr; -
1656 - -
1657 - /* Much as above */ -
1658 - loc = leftmostLoc(cexpr->location, -
1659 - exprLocation((Node *) cexpr->arg)); -
1660 - } -
1661 - break; -
1662 - case T_CoerceToDomainValue: -
1663 - loc = ((const CoerceToDomainValue *) expr)->location; -
1664 - break; -
1665 - case T_SetToDefault: -
1666 - loc = ((const SetToDefault *) expr)->location; -
1667 - break; -
1668 - case T_ReturningExpr: -
1669 - loc = exprLocation((Node *) ((const ReturningExpr *) expr)->retexpr); -
1670 - break; -
1671 - case T_TargetEntry: -
1672 - /* just use argument's location */ -
1673 - loc = exprLocation((Node *) ((const TargetEntry *) expr)->expr); -
1674 - break; -
1675 - case T_IntoClause: -
1676 - /* use the contained RangeVar's location --- close enough */ -
1677 - loc = exprLocation((Node *) ((const IntoClause *) expr)->rel); -
1678 - break; -
1679 - case T_List: -
1680 - { -
1681 - /* report location of first list member that has a location */ -
1682 - ListCell *lc; -
1683 - -
1684 - loc = -1; /* just to suppress compiler warning */ -
1685 - foreach(lc, (const List *) expr) -
1686 - { -
1687 - loc = exprLocation((Node *) lfirst(lc)); -
1688 - if (loc >= 0) -
1689 - break; -
1690 - } -
1691 - } -
1692 - break; -
1693 - case T_A_Expr: -
1694 - { -
1695 - const A_Expr *aexpr = (const A_Expr *) expr; -
1696 - -
1697 - /* use leftmost of operator or left operand (if any) */ -
1698 - /* we assume right operand can't be to left of operator */ -
1699 - loc = leftmostLoc(aexpr->location, -
1700 - exprLocation(aexpr->lexpr)); -
1701 - } -
1702 - break; -
1703 - case T_ColumnRef: -
1704 - loc = ((const ColumnRef *) expr)->location; -
1705 - break; -
1706 - case T_ParamRef: -
1707 - loc = ((const ParamRef *) expr)->location; -
1708 - break; -
1709 - case T_A_Const: -
1710 - loc = ((const A_Const *) expr)->location; -
1711 - break; -
1712 - case T_FuncCall: -
1713 - { -
1714 - const FuncCall *fc = (const FuncCall *) expr; -
1715 - -
1716 - /* consider both function name and leftmost arg */ -
1717 - /* (we assume any ORDER BY nodes must be to right of name) */ -
1718 - loc = leftmostLoc(fc->location, -
1719 - exprLocation((Node *) fc->args)); -
1720 - } -
1721 - break; -
1722 - case T_A_ArrayExpr: -
1723 - /* the location points at ARRAY or [, which must be leftmost */ -
1724 - loc = ((const A_ArrayExpr *) expr)->location; -
1725 - break; -
1726 - case T_ResTarget: -
1727 - /* we need not examine the contained expression (if any) */ -
1728 - loc = ((const ResTarget *) expr)->location; -
1729 - break; -
1730 - case T_MultiAssignRef: -
1731 - loc = exprLocation(((const MultiAssignRef *) expr)->source); -
1732 - break; -
1733 - case T_TypeCast: -
1734 - { -
1735 - const TypeCast *tc = (const TypeCast *) expr; -
1736 - -
1737 - /* -
1738 - * This could represent CAST(), ::, or TypeName 'literal', so -
1739 - * any of the components might be leftmost. -
1740 - */ -
1741 - loc = exprLocation(tc->arg); -
1742 - loc = leftmostLoc(loc, tc->typeName->location); -
1743 - loc = leftmostLoc(loc, tc->location); -
1744 - } -
1745 - break; -
1746 - case T_CollateClause: -
1747 - /* just use argument's location */ -
1748 - loc = exprLocation(((const CollateClause *) expr)->arg); -
1749 - break; -
1750 - case T_SortBy: -
1751 - /* just use argument's location (ignore operator, if any) */ -
1752 - loc = exprLocation(((const SortBy *) expr)->node); -
1753 - break; -
1754 - case T_WindowDef: -
1755 - loc = ((const WindowDef *) expr)->location; -
1756 - break; -
1757 - case T_RangeTableSample: -
1758 - loc = ((const RangeTableSample *) expr)->location; -
1759 - break; -
1760 - case T_TypeName: -
1761 - loc = ((const TypeName *) expr)->location; -
1762 - break; -
1763 - case T_ColumnDef: -
1764 - loc = ((const ColumnDef *) expr)->location; -
1765 - break; -
1766 - case T_IndexElem: -
1767 - loc = ((const IndexElem *) expr)->location; -
1768 - break; -
1769 - case T_Constraint: -
1770 - loc = ((const Constraint *) expr)->location; -
1771 - break; -
1772 - case T_FunctionParameter: -
1773 - loc = ((const FunctionParameter *) expr)->location; -
1774 - break; -
1775 - case T_XmlSerialize: -
1776 - /* XMLSERIALIZE keyword should always be the first thing */ -
1777 - loc = ((const XmlSerialize *) expr)->location; -
1778 - break; -
1779 - case T_GroupingSet: -
1780 - loc = ((const GroupingSet *) expr)->location; -
1781 - break; -
1782 - case T_WithClause: -
1783 - loc = ((const WithClause *) expr)->location; -
1784 - break; -
1785 - case T_InferClause: -
1786 - loc = ((const InferClause *) expr)->location; -
1787 - break; -
1788 - case T_OnConflictClause: -
1789 - loc = ((const OnConflictClause *) expr)->location; -
1790 - break; -
1791 - case T_CTESearchClause: -
1792 - loc = ((const CTESearchClause *) expr)->location; -
1793 - break; -
1794 - case T_CTECycleClause: -
1795 - loc = ((const CTECycleClause *) expr)->location; -
1796 - break; -
1797 - case T_CommonTableExpr: -
1798 - loc = ((const CommonTableExpr *) expr)->location; -
1799 - break; -
1800 - case T_JsonKeyValue: -
1801 - /* just use the key's location */ -
1802 - loc = exprLocation((Node *) ((const JsonKeyValue *) expr)->key); -
1803 - break; -
1804 - case T_JsonObjectConstructor: -
1805 - loc = ((const JsonObjectConstructor *) expr)->location; -
1806 - break; -
1807 - case T_JsonArrayConstructor: -
1808 - loc = ((const JsonArrayConstructor *) expr)->location; -
1809 - break; -
1810 - case T_JsonArrayQueryConstructor: -
1811 - loc = ((const JsonArrayQueryConstructor *) expr)->location; -
1812 - break; -
1813 - case T_JsonAggConstructor: -
1814 - loc = ((const JsonAggConstructor *) expr)->location; -
1815 - break; -
1816 - case T_JsonObjectAgg: -
1817 - loc = exprLocation((Node *) ((const JsonObjectAgg *) expr)->constructor); -
1818 - break; -
1819 - case T_JsonArrayAgg: -
1820 - loc = exprLocation((Node *) ((const JsonArrayAgg *) expr)->constructor); -
1821 - break; -
1822 - case T_PlaceHolderVar: -
1823 - /* just use argument's location */ -
1824 - loc = exprLocation((Node *) ((const PlaceHolderVar *) expr)->phexpr); -
1825 - break; -
1826 - case T_InferenceElem: -
1827 - /* just use nested expr's location */ -
1828 - loc = exprLocation((Node *) ((const InferenceElem *) expr)->expr); -
1829 - break; -
1830 - case T_PartitionElem: -
1831 - loc = ((const PartitionElem *) expr)->location; -
1832 - break; -
1833 - case T_PartitionSpec: -
1834 - loc = ((const PartitionSpec *) expr)->location; -
1835 - break; -
1836 - case T_PartitionBoundSpec: -
1837 - loc = ((const PartitionBoundSpec *) expr)->location; -
1838 - break; -
1839 - case T_PartitionRangeDatum: -
1840 - loc = ((const PartitionRangeDatum *) expr)->location; -
1841 - break; -
1842 - default: -
1843 - /* for any other node type it's just unknown... */ -
1844 - loc = -1; -
1845 - break; -
1846 - } -
1847 - return loc; -
1848 - } -
expression_tree_walker_impl() lines 2129-2772
Modified Lines Coverage: 6/8 lines (75.0%)
LineHitsSourceCommit
2129 - expression_tree_walker_impl(Node *node, -
2130 - tree_walker_callback walker, -
2131 - void *context) -
2132 - { -
2133 - ListCell *temp; -
2134 - -
2135 - /* -
2136 - * The walker has already visited the current node, and so we need only -
2137 - * recurse into any sub-nodes it has. -
2138 - * -
2139 - * We assume that the walker is not interested in List nodes per se, so -
2140 - * when we expect a List we just recurse directly to self without -
2141 - * bothering to call the walker. -
2142 - */ -
2143 - #define WALK(n) walker((Node *) (n), context) -
2144 - -
2145 - #define LIST_WALK(l) expression_tree_walker_impl((Node *) (l), walker, context) -
2146 - -
2147 - if (node == NULL) -
2148 - return false; -
2149 - -
2150 - /* Guard against stack overflow due to overly complex expressions */ -
2151 - check_stack_depth(); -
2152 - -
2153 - switch (nodeTag(node)) -
2154 - { -
2155 - case T_Var: -
2156 - case T_Const: -
2157 - case T_Param: -
2158 - case T_CaseTestExpr: -
2159 - case T_SQLValueFunction: -
2160 - case T_CoerceToDomainValue: -
2161 - case T_SetToDefault: -
2162 - case T_CurrentOfExpr: -
2163 - case T_NextValueExpr: -
2164 - case T_RangeTblRef: -
2165 - case T_SortGroupClause: -
2166 - case T_CTESearchClause: -
2167 - case T_GraphLabelRef: -
2168 - case T_GraphPropertyRef: -
2169 - case T_MergeSupportFunc: -
2170 - /* primitive node types with no expression subnodes */ -
2171 - break; -
2172 - case T_WithCheckOption: -
2173 - return WALK(((WithCheckOption *) node)->qual); -
2174 - case T_Aggref: -
2175 - { -
2176 - Aggref *expr = (Aggref *) node; -
2177 - -
2178 - /* recurse directly on Lists */ -
2179 - if (LIST_WALK(expr->aggdirectargs)) -
2180 - return true; -
2181 - if (LIST_WALK(expr->args)) -
2182 - return true; -
2183 - if (LIST_WALK(expr->aggorder)) -
2184 - return true; -
2185 - if (LIST_WALK(expr->aggdistinct)) -
2186 - return true; -
2187 - if (WALK(expr->aggfilter)) -
2188 - return true; -
2189 - } -
2190 - break; -
2191 - case T_GroupingFunc: -
2192 - { -
2193 - GroupingFunc *grouping = (GroupingFunc *) node; -
2194 - -
2195 - if (LIST_WALK(grouping->args)) -
2196 - return true; -
2197 - } -
2198 - break; -
2199 - case T_WindowFunc: -
2200 - { -
2201 - WindowFunc *expr = (WindowFunc *) node; -
2202 - -
2203 - /* recurse directly on List */ -
2204 - if (LIST_WALK(expr->args)) -
2205 - return true; -
2206 - if (WALK(expr->aggfilter)) -
2207 - return true; -
2208 - if (WALK(expr->runCondition)) -
2209 - return true; -
2210 - } -
2211 - break; -
2212 - case T_WindowFuncRunCondition: -
2213 - { -
2214 - WindowFuncRunCondition *expr = (WindowFuncRunCondition *) node; -
2215 - -
2216 - if (WALK(expr->arg)) -
2217 - return true; -
2218 - } -
2219 - break; -
2220 12551 case T_RPRNavExpr: 7521a30Row pattern recognition patch (planner).
2221 - { 7521a30Row pattern recognition patch (planner).
2222 12551 RPRNavExpr *expr = (RPRNavExpr *) node; 7521a30Row pattern recognition patch (planner).
2223 - 7521a30Row pattern recognition patch (planner).
2224 12551 if (WALK(expr->arg)) 7521a30Row pattern recognition patch (planner).
2225 - return true; 7521a30Row pattern recognition patch (planner).
2226 12547 if (expr->offset_arg && WALK(expr->offset_arg)) 7521a30Row pattern recognition patch (planner).
2227 - return true; 7521a30Row pattern recognition patch (planner).
2228 12543 if (expr->compound_offset_arg && WALK(expr->compound_offset_arg)) 7521a30Row pattern recognition patch (planner).
2229 0 return true; 7521a30Row pattern recognition patch (planner).
UnreachableHard to reach · confidence high · expression_tree_walker_impl @2229
Reason
Confirmed line 2229 (return true for compound_offset_arg WALK) is genuine executable code, never executed.
Empirically verified against the RPR coverage build (PG19beta1): condition on 2228 runs 2370x across all RPR test files but the WALK on compound_offset_arg never returns true.
The root-cause claim is WRONG that no executed test runs a valid compound nav with an outer offset: rpr.sql:1260 (PREV(FIRST(val,$1),$2)) is EXECUTEd with a Param outer offset, and 1134/1156 etc. run compound navs with Const outer offsets;
re-running all five rpr sql files left 2229 at #####.
The proposed test is materially identical to these existing cases and will NOT cover 2229. Structural reason: arg (walked first at 2224) ALWAYS holds the required column Var, so Var-seeking walkers short-circuit there and never reach 2228. To hit 2229 a walker must ignore Vars yet return true on compound_offset_arg content.
Parse validation restricts an RPR offset to a runtime constant:
I confirmed volatile funcs rejected (random() -> error), subqueries rejected, no nav/agg/windowfunc/column-ref allowed;
only Const/PARAM_EXTERN/immutable exprs remain.
No standard walker returns true on that:
PARAM_EXTERN is explicitly ignored by max_parallel_hazard_walker (clauses.c:949).
Forcing a PARALLEL UNSAFE immutable func offset under debug_parallel_query short-circuited at the WindowFunc level before descending into the nav (case block 0 hits).
The analogous offset_arg return (2227) fired only ONCE and only in a cross-file combined run (0 in any single file) -- a fragile caching artifact, not a reproducible trigger.
2230 - } 7521a30Row pattern recognition patch (planner).
2231 - break; 7521a30Row pattern recognition patch (planner).
2232 - case T_SubscriptingRef: -
2233 - { -
2234 - SubscriptingRef *sbsref = (SubscriptingRef *) node; -
2235 - -
2236 - /* recurse directly for upper/lower container index lists */ -
2237 - if (LIST_WALK(sbsref->refupperindexpr)) -
2238 - return true; -
2239 - if (LIST_WALK(sbsref->reflowerindexpr)) -
2240 - return true; -
2241 - /* walker must see the refexpr and refassgnexpr, however */ -
2242 - if (WALK(sbsref->refexpr)) -
2243 - return true; -
2244 - -
2245 - if (WALK(sbsref->refassgnexpr)) -
2246 - return true; -
2247 - } -
2248 - break; -
2249 - case T_FuncExpr: -
2250 - { -
2251 - FuncExpr *expr = (FuncExpr *) node; -
2252 - -
2253 - if (LIST_WALK(expr->args)) -
2254 - return true; -
2255 - } -
2256 - break; -
2257 - case T_NamedArgExpr: -
2258 - return WALK(((NamedArgExpr *) node)->arg); -
2259 - case T_OpExpr: -
2260 - case T_DistinctExpr: /* struct-equivalent to OpExpr */ -
2261 - case T_NullIfExpr: /* struct-equivalent to OpExpr */ -
2262 - { -
2263 - OpExpr *expr = (OpExpr *) node; -
2264 - -
2265 - if (LIST_WALK(expr->args)) -
2266 - return true; -
2267 - } -
2268 - break; -
2269 - case T_ScalarArrayOpExpr: -
2270 - { -
2271 - ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node; -
2272 - -
2273 - if (LIST_WALK(expr->args)) -
2274 - return true; -
2275 - } -
2276 - break; -
2277 - case T_BoolExpr: -
2278 - { -
2279 - BoolExpr *expr = (BoolExpr *) node; -
2280 - -
2281 - if (LIST_WALK(expr->args)) -
2282 - return true; -
2283 - } -
2284 - break; -
2285 - case T_SubLink: -
2286 - { -
2287 - SubLink *sublink = (SubLink *) node; -
2288 - -
2289 - if (WALK(sublink->testexpr)) -
2290 - return true; -
2291 - -
2292 - /* -
2293 - * Also invoke the walker on the sublink's Query node, so it -
2294 - * can recurse into the sub-query if it wants to. -
2295 - */ -
2296 - return WALK(sublink->subselect); -
2297 - } -
2298 - break; -
2299 - case T_SubPlan: -
2300 - { -
2301 - SubPlan *subplan = (SubPlan *) node; -
2302 - -
2303 - /* recurse into the testexpr, but not into the Plan */ -
2304 - if (WALK(subplan->testexpr)) -
2305 - return true; -
2306 - /* also examine args list */ -
2307 - if (LIST_WALK(subplan->args)) -
2308 - return true; -
2309 - } -
2310 - break; -
2311 - case T_AlternativeSubPlan: -
2312 - return LIST_WALK(((AlternativeSubPlan *) node)->subplans); -
2313 - case T_FieldSelect: -
2314 - return WALK(((FieldSelect *) node)->arg); -
2315 - case T_FieldStore: -
2316 - { -
2317 - FieldStore *fstore = (FieldStore *) node; -
2318 - -
2319 - if (WALK(fstore->arg)) -
2320 - return true; -
2321 - if (WALK(fstore->newvals)) -
2322 - return true; -
2323 - } -
2324 - break; -
2325 - case T_RelabelType: -
2326 - return WALK(((RelabelType *) node)->arg); -
2327 - case T_CoerceViaIO: -
2328 - return WALK(((CoerceViaIO *) node)->arg); -
2329 - case T_ArrayCoerceExpr: -
2330 - { -
2331 - ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; -
2332 - -
2333 - if (WALK(acoerce->arg)) -
2334 - return true; -
2335 - if (WALK(acoerce->elemexpr)) -
2336 - return true; -
2337 - } -
2338 - break; -
2339 - case T_ConvertRowtypeExpr: -
2340 - return WALK(((ConvertRowtypeExpr *) node)->arg); -
2341 - case T_CollateExpr: -
2342 - return WALK(((CollateExpr *) node)->arg); -
2343 - case T_CaseExpr: -
2344 - { -
2345 - CaseExpr *caseexpr = (CaseExpr *) node; -
2346 - -
2347 - if (WALK(caseexpr->arg)) -
2348 - return true; -
2349 - /* we assume walker doesn't care about CaseWhens, either */ -
2350 - foreach(temp, caseexpr->args) -
2351 - { -
2352 - CaseWhen *when = lfirst_node(CaseWhen, temp); -
2353 - -
2354 - if (WALK(when->expr)) -
2355 - return true; -
2356 - if (WALK(when->result)) -
2357 - return true; -
2358 - } -
2359 - if (WALK(caseexpr->defresult)) -
2360 - return true; -
2361 - } -
2362 - break; -
2363 - case T_ArrayExpr: -
2364 - return WALK(((ArrayExpr *) node)->elements); -
2365 - case T_RowExpr: -
2366 - /* Assume colnames isn't interesting */ -
2367 - return WALK(((RowExpr *) node)->args); -
2368 - case T_RowCompareExpr: -
2369 - { -
2370 - RowCompareExpr *rcexpr = (RowCompareExpr *) node; -
2371 - -
2372 - if (WALK(rcexpr->largs)) -
2373 - return true; -
2374 - if (WALK(rcexpr->rargs)) -
2375 - return true; -
2376 - } -
2377 - break; -
2378 - case T_CoalesceExpr: -
2379 - return WALK(((CoalesceExpr *) node)->args); -
2380 - case T_MinMaxExpr: -
2381 - return WALK(((MinMaxExpr *) node)->args); -
2382 - case T_XmlExpr: -
2383 - { -
2384 - XmlExpr *xexpr = (XmlExpr *) node; -
2385 - -
2386 - if (WALK(xexpr->named_args)) -
2387 - return true; -
2388 - /* we assume walker doesn't care about arg_names */ -
2389 - if (WALK(xexpr->args)) -
2390 - return true; -
2391 - } -
2392 - break; -
2393 - case T_JsonValueExpr: -
2394 - { -
2395 - JsonValueExpr *jve = (JsonValueExpr *) node; -
2396 - -
2397 - if (WALK(jve->raw_expr)) -
2398 - return true; -
2399 - if (WALK(jve->formatted_expr)) -
2400 - return true; -
2401 - } -
2402 - break; -
2403 - case T_JsonConstructorExpr: -
2404 - { -
2405 - JsonConstructorExpr *ctor = (JsonConstructorExpr *) node; -
2406 - -
2407 - if (WALK(ctor->args)) -
2408 - return true; -
2409 - if (WALK(ctor->func)) -
2410 - return true; -
2411 - if (WALK(ctor->coercion)) -
2412 - return true; -
2413 - } -
2414 - break; -
2415 - case T_JsonIsPredicate: -
2416 - return WALK(((JsonIsPredicate *) node)->expr); -
2417 - case T_JsonExpr: -
2418 - { -
2419 - JsonExpr *jexpr = (JsonExpr *) node; -
2420 - -
2421 - if (WALK(jexpr->formatted_expr)) -
2422 - return true; -
2423 - if (WALK(jexpr->path_spec)) -
2424 - return true; -
2425 - if (WALK(jexpr->passing_values)) -
2426 - return true; -
2427 - /* we assume walker doesn't care about passing_names */ -
2428 - if (WALK(jexpr->on_empty)) -
2429 - return true; -
2430 - if (WALK(jexpr->on_error)) -
2431 - return true; -
2432 - } -
2433 - break; -
2434 - case T_JsonBehavior: -
2435 - { -
2436 - JsonBehavior *behavior = (JsonBehavior *) node; -
2437 - -
2438 - if (WALK(behavior->expr)) -
2439 - return true; -
2440 - } -
2441 - break; -
2442 - case T_NullTest: -
2443 - return WALK(((NullTest *) node)->arg); -
2444 - case T_BooleanTest: -
2445 - return WALK(((BooleanTest *) node)->arg); -
2446 - case T_CoerceToDomain: -
2447 - return WALK(((CoerceToDomain *) node)->arg); -
2448 - case T_TargetEntry: -
2449 - return WALK(((TargetEntry *) node)->expr); -
2450 - case T_Query: -
2451 - /* Do nothing with a sub-Query, per discussion above */ -
2452 - break; -
2453 - case T_WindowClause: -
2454 - { -
2455 - WindowClause *wc = (WindowClause *) node; -
2456 - -
2457 - if (WALK(wc->partitionClause)) -
2458 - return true; -
2459 - if (WALK(wc->orderClause)) -
2460 - return true; -
2461 - if (WALK(wc->startOffset)) -
2462 - return true; -
2463 - if (WALK(wc->endOffset)) -
2464 - return true; -
2465 1918 if (WALK(wc->defineClause)) 7521a30Row pattern recognition patch (planner).
2466 0 return true; 7521a30Row pattern recognition patch (planner).
UnreachableDefensive (unreachable) · confidence high · expression_tree_walker_impl @2466
Reason
REFUTED the claimed classification (testable) and the proposed test.
Line 2466 is the `return true;
` after `if (WALK(wc->defineClause))` inside the T_WindowClause arm of expression_tree_walker (nodeFuncs.c:2453-2468).
I traced exactly who reaches this arm and whether the WALK can ever return true.

WHO REACHES THE ARM:
A bare WindowClause node is dispatched to expression_tree_walker's T_WindowClause arm ONLY when some walker does WALK(query->windowClause) on the List.
In query_tree_walker this happens solely in the QTW_EXAMINE_SORTGROUP branch (nodeFuncs.c:2834-2843).
Every OTHER walker (planner/optimizer, the JOIN scenario in the proposal) takes the ELSE branch (nodeFuncs.c:2851-2863) which walks startOffset/endOffset/defineClause DIRECTLY and never enters the T_WindowClause arm, so it cannot hit 2466. A backend-wide grep shows QTW_EXAMINE_SORTGROUP has exactly ONE caller: find_expr_references_walker in dependency.c:2390-2394 (dependency recording during CREATE VIEW / stored rules).
That walker also special-cases WindowClause at dependency.c:2238 then falls through to expression_tree_walker (dependency.c:2461), which is the one and only execution of the T_WindowClause arm.
This arm IS already executed today by the many RPR views in rpr_explain.sql/rpr_base.sql (that is why line 2465, the WALK call, is covered and not flagged).

WHY 2466 NEVER FIRES: find_expr_references_walker is a pure collector;
it returns false on every traversal path (dependency.c:1805/1832/1854/1969/2236/2461).
The only `return true`s in that file (2566, 2824) live in unrelated subroutines is_objectclass_supported/guc helper, not the walker.
Therefore WALK(wc->defineClause) at 2465 ALWAYS returns false for the sole caller that reaches this arm, and control always falls to break at 2468 — line 2466 is unreachable.

WHY THE PROPOSED TEST FAILS:
A JOIN+RPR query exercises planner walkers, which use the ELSE branch (2851-2863), not the T_WindowClause arm.
Even if it did reach the arm, a var-collecting walker is not what runs there;
the actual walker (find_expr_references_walker) never returns true.
So the JOIN test drives neither this arm in a returning-true mode nor line 2466 at all. testWillCover=false.

This is a defensive `return true` mirroring every other WALK(...)/return-true line in the function.
It is structurally unreachable by any SQL/regression input because no backend walker both (a) walks a WindowClause as a node and (b) returns true from its defineClause subtree.
Making it reachable would require ADDING a new C walker that sets QTW_EXAMINE_SORTGROUP (or otherwise WALKs windowClause) and returns true on a Var/expr inside defineClause — which cannot be produced by SQL input.
Recommended fix
Either accept as defensive/unreachable (consistent with all sibling WALK(...)/return-true lines in expression_tree_walker and acceptable to leave uncovered), or, if 100% coverage of modified lines is desired, drop the redundant short-circuit since defineClause is the LAST field walked in this arm: replace lines 2465-2467 `if (WALK(wc->defineClause)) return true;
` with `return WALK(wc->defineClause);
` (mirroring the tail-return style used by sibling arms like T_NullTest at 2443).
That preserves identical behavior, removes the unreachable standalone `return true;
`, and the single remaining return is already exercised by the existing CREATE VIEW RPR tests.
2467 - } -
2468 - break; -
2469 - case T_CTECycleClause: -
2470 - { -
2471 - CTECycleClause *cc = (CTECycleClause *) node; -
2472 - -
2473 - if (WALK(cc->cycle_mark_value)) -
2474 - return true; -
2475 - if (WALK(cc->cycle_mark_default)) -
2476 - return true; -
2477 - } -
2478 - break; -
2479 - case T_CommonTableExpr: -
2480 - { -
2481 - CommonTableExpr *cte = (CommonTableExpr *) node; -
2482 - -
2483 - /* -
2484 - * Invoke the walker on the CTE's Query node, so it can -
2485 - * recurse into the sub-query if it wants to. -
2486 - */ -
2487 - if (WALK(cte->ctequery)) -
2488 - return true; -
2489 - -
2490 - if (WALK(cte->search_clause)) -
2491 - return true; -
2492 - if (WALK(cte->cycle_clause)) -
2493 - return true; -
2494 - } -
2495 - break; -
2496 - case T_JsonKeyValue: -
2497 - { -
2498 - JsonKeyValue *kv = (JsonKeyValue *) node; -
2499 - -
2500 - if (WALK(kv->key)) -
2501 - return true; -
2502 - if (WALK(kv->value)) -
2503 - return true; -
2504 - } -
2505 - break; -
2506 - case T_JsonObjectConstructor: -
2507 - { -
2508 - JsonObjectConstructor *ctor = (JsonObjectConstructor *) node; -
2509 - -
2510 - if (LIST_WALK(ctor->exprs)) -
2511 - return true; -
2512 - } -
2513 - break; -
2514 - case T_JsonArrayConstructor: -
2515 - { -
2516 - JsonArrayConstructor *ctor = (JsonArrayConstructor *) node; -
2517 - -
2518 - if (LIST_WALK(ctor->exprs)) -
2519 - return true; -
2520 - } -
2521 - break; -
2522 - case T_JsonArrayQueryConstructor: -
2523 - { -
2524 - JsonArrayQueryConstructor *ctor = (JsonArrayQueryConstructor *) node; -
2525 - -
2526 - if (WALK(ctor->query)) -
2527 - return true; -
2528 - } -
2529 - break; -
2530 - case T_JsonAggConstructor: -
2531 - { -
2532 - JsonAggConstructor *ctor = (JsonAggConstructor *) node; -
2533 - -
2534 - if (WALK(ctor->agg_filter)) -
2535 - return true; -
2536 - if (WALK(ctor->agg_order)) -
2537 - return true; -
2538 - if (WALK(ctor->over)) -
2539 - return true; -
2540 - } -
2541 - break; -
2542 - case T_JsonObjectAgg: -
2543 - { -
2544 - JsonObjectAgg *ctor = (JsonObjectAgg *) node; -
2545 - -
2546 - if (WALK(ctor->constructor)) -
2547 - return true; -
2548 - if (WALK(ctor->arg)) -
2549 - return true; -
2550 - } -
2551 - break; -
2552 - case T_JsonArrayAgg: -
2553 - { -
2554 - JsonArrayAgg *ctor = (JsonArrayAgg *) node; -
2555 - -
2556 - if (WALK(ctor->constructor)) -
2557 - return true; -
2558 - if (WALK(ctor->arg)) -
2559 - return true; -
2560 - } -
2561 - break; -
2562 - -
2563 - case T_PartitionBoundSpec: -
2564 - { -
2565 - PartitionBoundSpec *pbs = (PartitionBoundSpec *) node; -
2566 - -
2567 - if (WALK(pbs->listdatums)) -
2568 - return true; -
2569 - if (WALK(pbs->lowerdatums)) -
2570 - return true; -
2571 - if (WALK(pbs->upperdatums)) -
2572 - return true; -
2573 - } -
2574 - break; -
2575 - case T_PartitionRangeDatum: -
2576 - { -
2577 - PartitionRangeDatum *prd = (PartitionRangeDatum *) node; -
2578 - -
2579 - if (WALK(prd->value)) -
2580 - return true; -
2581 - } -
2582 - break; -
2583 - case T_List: -
2584 - foreach(temp, (List *) node) -
2585 - { -
2586 - if (WALK(lfirst(temp))) -
2587 - return true; -
2588 - } -
2589 - break; -
2590 - case T_FromExpr: -
2591 - { -
2592 - FromExpr *from = (FromExpr *) node; -
2593 - -
2594 - if (LIST_WALK(from->fromlist)) -
2595 - return true; -
2596 - if (WALK(from->quals)) -
2597 - return true; -
2598 - } -
2599 - break; -
2600 - case T_OnConflictExpr: -
2601 - { -
2602 - OnConflictExpr *onconflict = (OnConflictExpr *) node; -
2603 - -
2604 - if (WALK(onconflict->arbiterElems)) -
2605 - return true; -
2606 - if (WALK(onconflict->arbiterWhere)) -
2607 - return true; -
2608 - if (WALK(onconflict->onConflictSet)) -
2609 - return true; -
2610 - if (WALK(onconflict->onConflictWhere)) -
2611 - return true; -
2612 - if (WALK(onconflict->exclRelTlist)) -
2613 - return true; -
2614 - } -
2615 - break; -
2616 - case T_MergeAction: -
2617 - { -
2618 - MergeAction *action = (MergeAction *) node; -
2619 - -
2620 - if (WALK(action->qual)) -
2621 - return true; -
2622 - if (WALK(action->targetList)) -
2623 - return true; -
2624 - } -
2625 - break; -
2626 - case T_ForPortionOfExpr: -
2627 - { -
2628 - ForPortionOfExpr *forPortionOf = (ForPortionOfExpr *) node; -
2629 - -
2630 - if (WALK(forPortionOf->rangeVar)) -
2631 - return true; -
2632 - if (WALK(forPortionOf->targetFrom)) -
2633 - return true; -
2634 - if (WALK(forPortionOf->targetTo)) -
2635 - return true; -
2636 - if (WALK(forPortionOf->targetRange)) -
2637 - return true; -
2638 - if (WALK(forPortionOf->overlapsExpr)) -
2639 - return true; -
2640 - if (WALK(forPortionOf->rangeTargetList)) -
2641 - return true; -
2642 - } -
2643 - break; -
2644 - case T_PartitionPruneStepOp: -
2645 - { -
2646 - PartitionPruneStepOp *opstep = (PartitionPruneStepOp *) node; -
2647 - -
2648 - if (WALK(opstep->exprs)) -
2649 - return true; -
2650 - } -
2651 - break; -
2652 - case T_PartitionPruneStepCombine: -
2653 - /* no expression subnodes */ -
2654 - break; -
2655 - case T_JoinExpr: -
2656 - { -
2657 - JoinExpr *join = (JoinExpr *) node; -
2658 - -
2659 - if (WALK(join->larg)) -
2660 - return true; -
2661 - if (WALK(join->rarg)) -
2662 - return true; -
2663 - if (WALK(join->quals)) -
2664 - return true; -
2665 - -
2666 - /* -
2667 - * alias clause, using list are deemed uninteresting. -
2668 - */ -
2669 - } -
2670 - break; -
2671 - case T_SetOperationStmt: -
2672 - { -
2673 - SetOperationStmt *setop = (SetOperationStmt *) node; -
2674 - -
2675 - if (WALK(setop->larg)) -
2676 - return true; -
2677 - if (WALK(setop->rarg)) -
2678 - return true; -
2679 - -
2680 - /* groupClauses are deemed uninteresting */ -
2681 - } -
2682 - break; -
2683 - case T_IndexClause: -
2684 - { -
2685 - IndexClause *iclause = (IndexClause *) node; -
2686 - -
2687 - if (WALK(iclause->rinfo)) -
2688 - return true; -
2689 - if (LIST_WALK(iclause->indexquals)) -
2690 - return true; -
2691 - } -
2692 - break; -
2693 - case T_PlaceHolderVar: -
2694 - return WALK(((PlaceHolderVar *) node)->phexpr); -
2695 - case T_InferenceElem: -
2696 - return WALK(((InferenceElem *) node)->expr); -
2697 - case T_ReturningExpr: -
2698 - return WALK(((ReturningExpr *) node)->retexpr); -
2699 - case T_AppendRelInfo: -
2700 - { -
2701 - AppendRelInfo *appinfo = (AppendRelInfo *) node; -
2702 - -
2703 - if (LIST_WALK(appinfo->translated_vars)) -
2704 - return true; -
2705 - } -
2706 - break; -
2707 - case T_PlaceHolderInfo: -
2708 - return WALK(((PlaceHolderInfo *) node)->ph_var); -
2709 - case T_RangeTblFunction: -
2710 - return WALK(((RangeTblFunction *) node)->funcexpr); -
2711 - case T_TableSampleClause: -
2712 - { -
2713 - TableSampleClause *tsc = (TableSampleClause *) node; -
2714 - -
2715 - if (LIST_WALK(tsc->args)) -
2716 - return true; -
2717 - if (WALK(tsc->repeatable)) -
2718 - return true; -
2719 - } -
2720 - break; -
2721 - case T_TableFunc: -
2722 - { -
2723 - TableFunc *tf = (TableFunc *) node; -
2724 - -
2725 - if (WALK(tf->ns_uris)) -
2726 - return true; -
2727 - if (WALK(tf->docexpr)) -
2728 - return true; -
2729 - if (WALK(tf->rowexpr)) -
2730 - return true; -
2731 - if (WALK(tf->colexprs)) -
2732 - return true; -
2733 - if (WALK(tf->coldefexprs)) -
2734 - return true; -
2735 - if (WALK(tf->colvalexprs)) -
2736 - return true; -
2737 - if (WALK(tf->passingvalexprs)) -
2738 - return true; -
2739 - } -
2740 - break; -
2741 - case T_GraphElementPattern: -
2742 - { -
2743 - GraphElementPattern *gep = (GraphElementPattern *) node; -
2744 - -
2745 - if (WALK(gep->labelexpr)) -
2746 - return true; -
2747 - if (WALK(gep->subexpr)) -
2748 - return true; -
2749 - if (WALK(gep->whereClause)) -
2750 - return true; -
2751 - } -
2752 - break; -
2753 - case T_GraphPattern: -
2754 - { -
2755 - GraphPattern *gp = (GraphPattern *) node; -
2756 - -
2757 - if (LIST_WALK(gp->path_pattern_list)) -
2758 - return true; -
2759 - if (WALK(gp->whereClause)) -
2760 - return true; -
2761 - } -
2762 - break; -
2763 - default: -
2764 - elog(ERROR, "unrecognized node type: %d", -
2765 - (int) nodeTag(node)); -
2766 - break; -
2767 - } -
2768 - return false; -
2769 - -
2770 - /* The WALK() macro can be re-used below, but LIST_WALK() not so much */ -
2771 - #undef LIST_WALK -
2772 - } -
query_tree_walker_impl() lines 2790-2889
Modified Lines Coverage: 1/1 lines (100.0%)
LineHitsSourceCommit
2790 - query_tree_walker_impl(Query *query, -
2791 - tree_walker_callback walker, -
2792 - void *context, -
2793 - int flags) -
2794 - { -
2795 - Assert(query != NULL && IsA(query, Query)); -
2796 - -
2797 - /* -
2798 - * We don't walk any utilityStmt here. However, we can't easily assert -
2799 - * that it is absent, since there are at least two code paths by which -
2800 - * action statements from CREATE RULE end up here, and NOTIFY is allowed -
2801 - * in a rule action. -
2802 - */ -
2803 - -
2804 - if (WALK(query->targetList)) -
2805 - return true; -
2806 - if (WALK(query->withCheckOptions)) -
2807 - return true; -
2808 - if (WALK(query->onConflict)) -
2809 - return true; -
2810 - if (WALK(query->mergeActionList)) -
2811 - return true; -
2812 - if (WALK(query->mergeJoinCondition)) -
2813 - return true; -
2814 - if (WALK(query->forPortionOf)) -
2815 - return true; -
2816 - if (WALK(query->returningList)) -
2817 - return true; -
2818 - if (WALK(query->jointree)) -
2819 - return true; -
2820 - if (WALK(query->setOperations)) -
2821 - return true; -
2822 - if (WALK(query->havingQual)) -
2823 - return true; -
2824 - if (WALK(query->limitOffset)) -
2825 - return true; -
2826 - if (WALK(query->limitCount)) -
2827 - return true; -
2828 - -
2829 - /* -
2830 - * Most callers aren't interested in SortGroupClause nodes since those -
2831 - * don't contain actual expressions. However they do contain OIDs which -
2832 - * may be needed by dependency walkers etc. -
2833 - */ -
2834 - if ((flags & QTW_EXAMINE_SORTGROUP)) -
2835 - { -
2836 - if (WALK(query->groupClause)) -
2837 - return true; -
2838 - if (WALK(query->windowClause)) -
2839 - return true; -
2840 - if (WALK(query->sortClause)) -
2841 - return true; -
2842 - if (WALK(query->distinctClause)) -
2843 - return true; -
2844 - } -
2845 - else -
2846 - { -
2847 - /* -
2848 - * But we need to walk the expressions under WindowClause nodes even -
2849 - * if we're not interested in SortGroupClause nodes. -
2850 - */ -
2851 - ListCell *lc; -
2852 - -
2853 - foreach(lc, query->windowClause) -
2854 - { -
2855 - WindowClause *wc = lfirst_node(WindowClause, lc); -
2856 - -
2857 - if (WALK(wc->startOffset)) -
2858 - return true; -
2859 - if (WALK(wc->endOffset)) -
2860 - return true; -
2861 14148 if (WALK(wc->defineClause)) 7521a30Row pattern recognition patch (planner).
2862 - return true; 7521a30Row pattern recognition patch (planner).
2863 - } -
2864 - } -
2865 - -
2866 - /* -
2867 - * groupingSets and rowMarks are not walked: -
2868 - * -
2869 - * groupingSets contain only ressortgrouprefs (integers) which are -
2870 - * meaningless without the corresponding groupClause or tlist. -
2871 - * Accordingly, any walker that needs to care about them needs to handle -
2872 - * them itself in its Query processing. -
2873 - * -
2874 - * rowMarks is not walked because it contains only rangetable indexes (and -
2875 - * flags etc.) and therefore should be handled at Query level similarly. -
2876 - */ -
2877 - -
2878 - if (!(flags & QTW_IGNORE_CTE_SUBQUERIES)) -
2879 - { -
2880 - if (WALK(query->cteList)) -
2881 - return true; -
2882 - } -
2883 - if (!(flags & QTW_IGNORE_RANGE_TABLE)) -
2884 - { -
2885 - if (range_table_walker(query->rtable, walker, context, flags)) -
2886 - return true; -
2887 - } -
2888 - return false; -
2889 - } -
expression_tree_mutator_impl() lines 3052-3911
Modified Lines Coverage: 9/10 lines (90.0%)
LineHitsSourceCommit
3052 - expression_tree_mutator_impl(Node *node, -
3053 - tree_mutator_callback mutator, -
3054 - void *context) -
3055 - { -
3056 - /* -
3057 - * The mutator has already decided not to modify the current node, but we -
3058 - * must call the mutator for any sub-nodes. -
3059 - */ -
3060 - -
3061 - #define FLATCOPY(newnode, node, nodetype) \ -
3062 - ( (newnode) = palloc_object(nodetype), \ -
3063 - memcpy((newnode), (node), sizeof(nodetype)) ) -
3064 - -
3065 - #define MUTATE(newfield, oldfield, fieldtype) \ -
3066 - ( (newfield) = (fieldtype) mutator((Node *) (oldfield), context) ) -
3067 - -
3068 - if (node == NULL) -
3069 - return NULL; -
3070 - -
3071 - /* Guard against stack overflow due to overly complex expressions */ -
3072 - check_stack_depth(); -
3073 - -
3074 - switch (nodeTag(node)) -
3075 - { -
3076 - /* -
3077 - * Primitive node types with no expression subnodes. Var and -
3078 - * Const are frequent enough to deserve special cases, the others -
3079 - * we just use copyObject for. -
3080 - */ -
3081 - case T_Var: -
3082 - { -
3083 - Var *var = (Var *) node; -
3084 - Var *newnode; -
3085 - -
3086 - FLATCOPY(newnode, var, Var); -
3087 - /* Assume we need not copy the varnullingrels bitmapset */ -
3088 - return (Node *) newnode; -
3089 - } -
3090 - break; -
3091 - case T_Const: -
3092 - { -
3093 - Const *oldnode = (Const *) node; -
3094 - Const *newnode; -
3095 - -
3096 - FLATCOPY(newnode, oldnode, Const); -
3097 - /* XXX we don't bother with datumCopy; should we? */ -
3098 - return (Node *) newnode; -
3099 - } -
3100 - break; -
3101 - case T_Param: -
3102 - case T_CaseTestExpr: -
3103 - case T_SQLValueFunction: -
3104 - case T_JsonFormat: -
3105 - case T_CoerceToDomainValue: -
3106 - case T_SetToDefault: -
3107 - case T_CurrentOfExpr: -
3108 - case T_NextValueExpr: -
3109 - case T_RangeTblRef: -
3110 - case T_SortGroupClause: -
3111 - case T_CTESearchClause: -
3112 - case T_GraphLabelRef: -
3113 - case T_GraphPropertyRef: -
3114 - case T_MergeSupportFunc: -
3115 - return copyObject(node); -
3116 - case T_WithCheckOption: -
3117 - { -
3118 - WithCheckOption *wco = (WithCheckOption *) node; -
3119 - WithCheckOption *newnode; -
3120 - -
3121 - FLATCOPY(newnode, wco, WithCheckOption); -
3122 - MUTATE(newnode->qual, wco->qual, Node *); -
3123 - return (Node *) newnode; -
3124 - } -
3125 - case T_Aggref: -
3126 - { -
3127 - Aggref *aggref = (Aggref *) node; -
3128 - Aggref *newnode; -
3129 - -
3130 - FLATCOPY(newnode, aggref, Aggref); -
3131 - /* assume mutation doesn't change types of arguments */ -
3132 - newnode->aggargtypes = list_copy(aggref->aggargtypes); -
3133 - MUTATE(newnode->aggdirectargs, aggref->aggdirectargs, List *); -
3134 - MUTATE(newnode->args, aggref->args, List *); -
3135 - MUTATE(newnode->aggorder, aggref->aggorder, List *); -
3136 - MUTATE(newnode->aggdistinct, aggref->aggdistinct, List *); -
3137 - MUTATE(newnode->aggfilter, aggref->aggfilter, Expr *); -
3138 - return (Node *) newnode; -
3139 - } -
3140 - break; -
3141 - case T_GroupingFunc: -
3142 - { -
3143 - GroupingFunc *grouping = (GroupingFunc *) node; -
3144 - GroupingFunc *newnode; -
3145 - -
3146 - FLATCOPY(newnode, grouping, GroupingFunc); -
3147 - MUTATE(newnode->args, grouping->args, List *); -
3148 - -
3149 - /* -
3150 - * We assume here that mutating the arguments does not change -
3151 - * the semantics, i.e. that the arguments are not mutated in a -
3152 - * way that makes them semantically different from their -
3153 - * previously matching expressions in the GROUP BY clause. -
3154 - * -
3155 - * If a mutator somehow wanted to do this, it would have to -
3156 - * handle the refs and cols lists itself as appropriate. -
3157 - */ -
3158 - newnode->refs = list_copy(grouping->refs); -
3159 - newnode->cols = list_copy(grouping->cols); -
3160 - -
3161 - return (Node *) newnode; -
3162 - } -
3163 - break; -
3164 - case T_WindowFunc: -
3165 - { -
3166 - WindowFunc *wfunc = (WindowFunc *) node; -
3167 - WindowFunc *newnode; -
3168 - -
3169 - FLATCOPY(newnode, wfunc, WindowFunc); -
3170 - MUTATE(newnode->args, wfunc->args, List *); -
3171 - MUTATE(newnode->aggfilter, wfunc->aggfilter, Expr *); -
3172 - return (Node *) newnode; -
3173 - } -
3174 - break; -
3175 - case T_WindowFuncRunCondition: -
3176 - { -
3177 - WindowFuncRunCondition *wfuncrc = (WindowFuncRunCondition *) node; -
3178 - WindowFuncRunCondition *newnode; -
3179 - -
3180 - FLATCOPY(newnode, wfuncrc, WindowFuncRunCondition); -
3181 - MUTATE(newnode->arg, wfuncrc->arg, Expr *); -
3182 - return (Node *) newnode; -
3183 - } -
3184 - break; -
3185 2890 case T_RPRNavExpr: 7521a30Row pattern recognition patch (planner).
3186 - { 7521a30Row pattern recognition patch (planner).
3187 2890 RPRNavExpr *nav = (RPRNavExpr *) node; 7521a30Row pattern recognition patch (planner).
3188 2890 RPRNavExpr *newnode; 7521a30Row pattern recognition patch (planner).
3189 - 7521a30Row pattern recognition patch (planner).
3190 2890 FLATCOPY(newnode, nav, RPRNavExpr); 7521a30Row pattern recognition patch (planner).
3191 2890 MUTATE(newnode->arg, nav->arg, Expr *); 7521a30Row pattern recognition patch (planner).
3192 2890 MUTATE(newnode->offset_arg, nav->offset_arg, Expr *); 7521a30Row pattern recognition patch (planner).
3193 2890 MUTATE(newnode->compound_offset_arg, nav->compound_offset_arg, Expr *); 7521a30Row pattern recognition patch (planner).
3194 2890 return (Node *) newnode; 7521a30Row pattern recognition patch (planner).
3195 - } 7521a30Row pattern recognition patch (planner).
3196 57219 break; 7521a30Row pattern recognition patch (planner).
3197 - case T_SubscriptingRef: -
3198 - { -
3199 - SubscriptingRef *sbsref = (SubscriptingRef *) node; -
3200 - SubscriptingRef *newnode; -
3201 - -
3202 - FLATCOPY(newnode, sbsref, SubscriptingRef); -
3203 - MUTATE(newnode->refupperindexpr, sbsref->refupperindexpr, -
3204 - List *); -
3205 - MUTATE(newnode->reflowerindexpr, sbsref->reflowerindexpr, -
3206 - List *); -
3207 - MUTATE(newnode->refexpr, sbsref->refexpr, -
3208 - Expr *); -
3209 - MUTATE(newnode->refassgnexpr, sbsref->refassgnexpr, -
3210 - Expr *); -
3211 - -
3212 - return (Node *) newnode; -
3213 - } -
3214 - break; -
3215 - case T_FuncExpr: -
3216 - { -
3217 - FuncExpr *expr = (FuncExpr *) node; -
3218 - FuncExpr *newnode; -
3219 - -
3220 - FLATCOPY(newnode, expr, FuncExpr); -
3221 - MUTATE(newnode->args, expr->args, List *); -
3222 - return (Node *) newnode; -
3223 - } -
3224 - break; -
3225 - case T_NamedArgExpr: -
3226 - { -
3227 - NamedArgExpr *nexpr = (NamedArgExpr *) node; -
3228 - NamedArgExpr *newnode; -
3229 - -
3230 - FLATCOPY(newnode, nexpr, NamedArgExpr); -
3231 - MUTATE(newnode->arg, nexpr->arg, Expr *); -
3232 - return (Node *) newnode; -
3233 - } -
3234 - break; -
3235 - case T_OpExpr: -
3236 - { -
3237 - OpExpr *expr = (OpExpr *) node; -
3238 - OpExpr *newnode; -
3239 - -
3240 - FLATCOPY(newnode, expr, OpExpr); -
3241 - MUTATE(newnode->args, expr->args, List *); -
3242 - return (Node *) newnode; -
3243 - } -
3244 - break; -
3245 - case T_DistinctExpr: -
3246 - { -
3247 - DistinctExpr *expr = (DistinctExpr *) node; -
3248 - DistinctExpr *newnode; -
3249 - -
3250 - FLATCOPY(newnode, expr, DistinctExpr); -
3251 - MUTATE(newnode->args, expr->args, List *); -
3252 - return (Node *) newnode; -
3253 - } -
3254 - break; -
3255 - case T_NullIfExpr: -
3256 - { -
3257 - NullIfExpr *expr = (NullIfExpr *) node; -
3258 - NullIfExpr *newnode; -
3259 - -
3260 - FLATCOPY(newnode, expr, NullIfExpr); -
3261 - MUTATE(newnode->args, expr->args, List *); -
3262 - return (Node *) newnode; -
3263 - } -
3264 - break; -
3265 - case T_ScalarArrayOpExpr: -
3266 - { -
3267 - ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node; -
3268 - ScalarArrayOpExpr *newnode; -
3269 - -
3270 - FLATCOPY(newnode, expr, ScalarArrayOpExpr); -
3271 - MUTATE(newnode->args, expr->args, List *); -
3272 - return (Node *) newnode; -
3273 - } -
3274 - break; -
3275 - case T_BoolExpr: -
3276 - { -
3277 - BoolExpr *expr = (BoolExpr *) node; -
3278 - BoolExpr *newnode; -
3279 - -
3280 - FLATCOPY(newnode, expr, BoolExpr); -
3281 - MUTATE(newnode->args, expr->args, List *); -
3282 - return (Node *) newnode; -
3283 - } -
3284 - break; -
3285 - case T_SubLink: -
3286 - { -
3287 - SubLink *sublink = (SubLink *) node; -
3288 - SubLink *newnode; -
3289 - -
3290 - FLATCOPY(newnode, sublink, SubLink); -
3291 - MUTATE(newnode->testexpr, sublink->testexpr, Node *); -
3292 - -
3293 - /* -
3294 - * Also invoke the mutator on the sublink's Query node, so it -
3295 - * can recurse into the sub-query if it wants to. -
3296 - */ -
3297 - MUTATE(newnode->subselect, sublink->subselect, Node *); -
3298 - return (Node *) newnode; -
3299 - } -
3300 - break; -
3301 - case T_SubPlan: -
3302 - { -
3303 - SubPlan *subplan = (SubPlan *) node; -
3304 - SubPlan *newnode; -
3305 - -
3306 - FLATCOPY(newnode, subplan, SubPlan); -
3307 - /* transform testexpr */ -
3308 - MUTATE(newnode->testexpr, subplan->testexpr, Node *); -
3309 - /* transform args list (params to be passed to subplan) */ -
3310 - MUTATE(newnode->args, subplan->args, List *); -
3311 - /* but not the sub-Plan itself, which is referenced as-is */ -
3312 - return (Node *) newnode; -
3313 - } -
3314 - break; -
3315 - case T_AlternativeSubPlan: -
3316 - { -
3317 - AlternativeSubPlan *asplan = (AlternativeSubPlan *) node; -
3318 - AlternativeSubPlan *newnode; -
3319 - -
3320 - FLATCOPY(newnode, asplan, AlternativeSubPlan); -
3321 - MUTATE(newnode->subplans, asplan->subplans, List *); -
3322 - return (Node *) newnode; -
3323 - } -
3324 - break; -
3325 - case T_FieldSelect: -
3326 - { -
3327 - FieldSelect *fselect = (FieldSelect *) node; -
3328 - FieldSelect *newnode; -
3329 - -
3330 - FLATCOPY(newnode, fselect, FieldSelect); -
3331 - MUTATE(newnode->arg, fselect->arg, Expr *); -
3332 - return (Node *) newnode; -
3333 - } -
3334 - break; -
3335 - case T_FieldStore: -
3336 - { -
3337 - FieldStore *fstore = (FieldStore *) node; -
3338 - FieldStore *newnode; -
3339 - -
3340 - FLATCOPY(newnode, fstore, FieldStore); -
3341 - MUTATE(newnode->arg, fstore->arg, Expr *); -
3342 - MUTATE(newnode->newvals, fstore->newvals, List *); -
3343 - newnode->fieldnums = list_copy(fstore->fieldnums); -
3344 - return (Node *) newnode; -
3345 - } -
3346 - break; -
3347 - case T_RelabelType: -
3348 - { -
3349 - RelabelType *relabel = (RelabelType *) node; -
3350 - RelabelType *newnode; -
3351 - -
3352 - FLATCOPY(newnode, relabel, RelabelType); -
3353 - MUTATE(newnode->arg, relabel->arg, Expr *); -
3354 - return (Node *) newnode; -
3355 - } -
3356 - break; -
3357 - case T_CoerceViaIO: -
3358 - { -
3359 - CoerceViaIO *iocoerce = (CoerceViaIO *) node; -
3360 - CoerceViaIO *newnode; -
3361 - -
3362 - FLATCOPY(newnode, iocoerce, CoerceViaIO); -
3363 - MUTATE(newnode->arg, iocoerce->arg, Expr *); -
3364 - return (Node *) newnode; -
3365 - } -
3366 - break; -
3367 - case T_ArrayCoerceExpr: -
3368 - { -
3369 - ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; -
3370 - ArrayCoerceExpr *newnode; -
3371 - -
3372 - FLATCOPY(newnode, acoerce, ArrayCoerceExpr); -
3373 - MUTATE(newnode->arg, acoerce->arg, Expr *); -
3374 - MUTATE(newnode->elemexpr, acoerce->elemexpr, Expr *); -
3375 - return (Node *) newnode; -
3376 - } -
3377 - break; -
3378 - case T_ConvertRowtypeExpr: -
3379 - { -
3380 - ConvertRowtypeExpr *convexpr = (ConvertRowtypeExpr *) node; -
3381 - ConvertRowtypeExpr *newnode; -
3382 - -
3383 - FLATCOPY(newnode, convexpr, ConvertRowtypeExpr); -
3384 - MUTATE(newnode->arg, convexpr->arg, Expr *); -
3385 - return (Node *) newnode; -
3386 - } -
3387 - break; -
3388 - case T_CollateExpr: -
3389 - { -
3390 - CollateExpr *collate = (CollateExpr *) node; -
3391 - CollateExpr *newnode; -
3392 - -
3393 - FLATCOPY(newnode, collate, CollateExpr); -
3394 - MUTATE(newnode->arg, collate->arg, Expr *); -
3395 - return (Node *) newnode; -
3396 - } -
3397 - break; -
3398 - case T_CaseExpr: -
3399 - { -
3400 - CaseExpr *caseexpr = (CaseExpr *) node; -
3401 - CaseExpr *newnode; -
3402 - -
3403 - FLATCOPY(newnode, caseexpr, CaseExpr); -
3404 - MUTATE(newnode->arg, caseexpr->arg, Expr *); -
3405 - MUTATE(newnode->args, caseexpr->args, List *); -
3406 - MUTATE(newnode->defresult, caseexpr->defresult, Expr *); -
3407 - return (Node *) newnode; -
3408 - } -
3409 - break; -
3410 - case T_CaseWhen: -
3411 - { -
3412 - CaseWhen *casewhen = (CaseWhen *) node; -
3413 - CaseWhen *newnode; -
3414 - -
3415 - FLATCOPY(newnode, casewhen, CaseWhen); -
3416 - MUTATE(newnode->expr, casewhen->expr, Expr *); -
3417 - MUTATE(newnode->result, casewhen->result, Expr *); -
3418 - return (Node *) newnode; -
3419 - } -
3420 - break; -
3421 - case T_ArrayExpr: -
3422 - { -
3423 - ArrayExpr *arrayexpr = (ArrayExpr *) node; -
3424 - ArrayExpr *newnode; -
3425 - -
3426 - FLATCOPY(newnode, arrayexpr, ArrayExpr); -
3427 - MUTATE(newnode->elements, arrayexpr->elements, List *); -
3428 - return (Node *) newnode; -
3429 - } -
3430 - break; -
3431 - case T_RowExpr: -
3432 - { -
3433 - RowExpr *rowexpr = (RowExpr *) node; -
3434 - RowExpr *newnode; -
3435 - -
3436 - FLATCOPY(newnode, rowexpr, RowExpr); -
3437 - MUTATE(newnode->args, rowexpr->args, List *); -
3438 - /* Assume colnames needn't be duplicated */ -
3439 - return (Node *) newnode; -
3440 - } -
3441 - break; -
3442 - case T_RowCompareExpr: -
3443 - { -
3444 - RowCompareExpr *rcexpr = (RowCompareExpr *) node; -
3445 - RowCompareExpr *newnode; -
3446 - -
3447 - FLATCOPY(newnode, rcexpr, RowCompareExpr); -
3448 - MUTATE(newnode->largs, rcexpr->largs, List *); -
3449 - MUTATE(newnode->rargs, rcexpr->rargs, List *); -
3450 - return (Node *) newnode; -
3451 - } -
3452 - break; -
3453 - case T_CoalesceExpr: -
3454 - { -
3455 - CoalesceExpr *coalesceexpr = (CoalesceExpr *) node; -
3456 - CoalesceExpr *newnode; -
3457 - -
3458 - FLATCOPY(newnode, coalesceexpr, CoalesceExpr); -
3459 - MUTATE(newnode->args, coalesceexpr->args, List *); -
3460 - return (Node *) newnode; -
3461 - } -
3462 - break; -
3463 - case T_MinMaxExpr: -
3464 - { -
3465 - MinMaxExpr *minmaxexpr = (MinMaxExpr *) node; -
3466 - MinMaxExpr *newnode; -
3467 - -
3468 - FLATCOPY(newnode, minmaxexpr, MinMaxExpr); -
3469 - MUTATE(newnode->args, minmaxexpr->args, List *); -
3470 - return (Node *) newnode; -
3471 - } -
3472 - break; -
3473 - case T_XmlExpr: -
3474 - { -
3475 - XmlExpr *xexpr = (XmlExpr *) node; -
3476 - XmlExpr *newnode; -
3477 - -
3478 - FLATCOPY(newnode, xexpr, XmlExpr); -
3479 - MUTATE(newnode->named_args, xexpr->named_args, List *); -
3480 - /* assume mutator does not care about arg_names */ -
3481 - MUTATE(newnode->args, xexpr->args, List *); -
3482 - return (Node *) newnode; -
3483 - } -
3484 - break; -
3485 - case T_JsonReturning: -
3486 - { -
3487 - JsonReturning *jr = (JsonReturning *) node; -
3488 - JsonReturning *newnode; -
3489 - -
3490 - FLATCOPY(newnode, jr, JsonReturning); -
3491 - MUTATE(newnode->format, jr->format, JsonFormat *); -
3492 - -
3493 - return (Node *) newnode; -
3494 - } -
3495 - case T_JsonValueExpr: -
3496 - { -
3497 - JsonValueExpr *jve = (JsonValueExpr *) node; -
3498 - JsonValueExpr *newnode; -
3499 - -
3500 - FLATCOPY(newnode, jve, JsonValueExpr); -
3501 - MUTATE(newnode->raw_expr, jve->raw_expr, Expr *); -
3502 - MUTATE(newnode->formatted_expr, jve->formatted_expr, Expr *); -
3503 - MUTATE(newnode->format, jve->format, JsonFormat *); -
3504 - -
3505 - return (Node *) newnode; -
3506 - } -
3507 - case T_JsonConstructorExpr: -
3508 - { -
3509 - JsonConstructorExpr *jce = (JsonConstructorExpr *) node; -
3510 - JsonConstructorExpr *newnode; -
3511 - -
3512 - FLATCOPY(newnode, jce, JsonConstructorExpr); -
3513 - MUTATE(newnode->args, jce->args, List *); -
3514 - MUTATE(newnode->func, jce->func, Expr *); -
3515 - MUTATE(newnode->coercion, jce->coercion, Expr *); -
3516 - MUTATE(newnode->returning, jce->returning, JsonReturning *); -
3517 - -
3518 - return (Node *) newnode; -
3519 - } -
3520 - case T_JsonIsPredicate: -
3521 - { -
3522 - JsonIsPredicate *pred = (JsonIsPredicate *) node; -
3523 - JsonIsPredicate *newnode; -
3524 - -
3525 - FLATCOPY(newnode, pred, JsonIsPredicate); -
3526 - MUTATE(newnode->expr, pred->expr, Node *); -
3527 - MUTATE(newnode->format, pred->format, JsonFormat *); -
3528 - -
3529 - return (Node *) newnode; -
3530 - } -
3531 - case T_JsonExpr: -
3532 - { -
3533 - JsonExpr *jexpr = (JsonExpr *) node; -
3534 - JsonExpr *newnode; -
3535 - -
3536 - FLATCOPY(newnode, jexpr, JsonExpr); -
3537 - MUTATE(newnode->formatted_expr, jexpr->formatted_expr, Node *); -
3538 - MUTATE(newnode->path_spec, jexpr->path_spec, Node *); -
3539 - MUTATE(newnode->passing_values, jexpr->passing_values, List *); -
3540 - /* assume mutator does not care about passing_names */ -
3541 - MUTATE(newnode->on_empty, jexpr->on_empty, JsonBehavior *); -
3542 - MUTATE(newnode->on_error, jexpr->on_error, JsonBehavior *); -
3543 - return (Node *) newnode; -
3544 - } -
3545 - break; -
3546 - case T_JsonBehavior: -
3547 - { -
3548 - JsonBehavior *behavior = (JsonBehavior *) node; -
3549 - JsonBehavior *newnode; -
3550 - -
3551 - FLATCOPY(newnode, behavior, JsonBehavior); -
3552 - MUTATE(newnode->expr, behavior->expr, Node *); -
3553 - return (Node *) newnode; -
3554 - } -
3555 - break; -
3556 - case T_NullTest: -
3557 - { -
3558 - NullTest *ntest = (NullTest *) node; -
3559 - NullTest *newnode; -
3560 - -
3561 - FLATCOPY(newnode, ntest, NullTest); -
3562 - MUTATE(newnode->arg, ntest->arg, Expr *); -
3563 - return (Node *) newnode; -
3564 - } -
3565 - break; -
3566 - case T_BooleanTest: -
3567 - { -
3568 - BooleanTest *btest = (BooleanTest *) node; -
3569 - BooleanTest *newnode; -
3570 - -
3571 - FLATCOPY(newnode, btest, BooleanTest); -
3572 - MUTATE(newnode->arg, btest->arg, Expr *); -
3573 - return (Node *) newnode; -
3574 - } -
3575 - break; -
3576 - case T_CoerceToDomain: -
3577 - { -
3578 - CoerceToDomain *ctest = (CoerceToDomain *) node; -
3579 - CoerceToDomain *newnode; -
3580 - -
3581 - FLATCOPY(newnode, ctest, CoerceToDomain); -
3582 - MUTATE(newnode->arg, ctest->arg, Expr *); -
3583 - return (Node *) newnode; -
3584 - } -
3585 - break; -
3586 - case T_ReturningExpr: -
3587 - { -
3588 - ReturningExpr *rexpr = (ReturningExpr *) node; -
3589 - ReturningExpr *newnode; -
3590 - -
3591 - FLATCOPY(newnode, rexpr, ReturningExpr); -
3592 - MUTATE(newnode->retexpr, rexpr->retexpr, Expr *); -
3593 - return (Node *) newnode; -
3594 - } -
3595 - break; -
3596 - case T_TargetEntry: -
3597 - { -
3598 - TargetEntry *targetentry = (TargetEntry *) node; -
3599 - TargetEntry *newnode; -
3600 - -
3601 - FLATCOPY(newnode, targetentry, TargetEntry); -
3602 - MUTATE(newnode->expr, targetentry->expr, Expr *); -
3603 - return (Node *) newnode; -
3604 - } -
3605 - break; -
3606 - case T_Query: -
3607 - /* Do nothing with a sub-Query, per discussion above */ -
3608 - return node; -
3609 - case T_WindowClause: -
3610 - { -
3611 - WindowClause *wc = (WindowClause *) node; -
3612 - WindowClause *newnode; -
3613 - -
3614 - FLATCOPY(newnode, wc, WindowClause); -
3615 - MUTATE(newnode->partitionClause, wc->partitionClause, List *); -
3616 - MUTATE(newnode->orderClause, wc->orderClause, List *); -
3617 - MUTATE(newnode->startOffset, wc->startOffset, Node *); -
3618 - MUTATE(newnode->endOffset, wc->endOffset, Node *); -
3619 0 MUTATE(newnode->defineClause, wc->defineClause, List *); 7521a30Row pattern recognition patch (planner).
UnreachableDefensive (unreachable) · confidence high · expression_tree_mutator_impl @3619
Reason
REFUTED.
The claimed classification "testable" and its proposed test are wrong.
Line 3619 (MUTATE(newnode->defineClause,...) in the T_WindowClause case of expression_tree_mutator) is reached ONLY when a mutator descends into query->windowClause as a LIST, which happens exclusively via nodeFuncs.c:3971 inside the `if (flags & QTW_EXAMINE_SORTGROUP)` branch of query_tree_mutator_impl.
I exhaustively enumerated every in-tree query_tree_mutator caller (var.c:960 flatten_join_alias_vars uses QTW_IGNORE_JOINALIASES;
var.c:1115 QTW_IGNORE_GROUPEXPRS;
clauses.c:6191/6208 =0;
rewriteManip.c:1323/1413/1526/1684 =0;
parse_agg.c:1618 =0).
NONE pass QTW_EXAMINE_SORTGROUP.
The only code in the tree that uses QTW_EXAMINE_SORTGROUP is dependency.c:2394, and that calls query_tree_WALKER (hitting walker line 2834), not the mutator. gcov confirms: line 3971 is #####(uncovered) and the ENTIRE mutator T_WindowClause case lines 3614-3619 is ##### -- including pre-RPR lines 3614-3618 (partitionClause/orderClause/startOffset/endOffset).
Only 3619 shows in the RPR diff because it is the one line the patch added;
the dead case block predates RPR.
The proposed JOIN test triggers flatten_join_alias_vars, which passes QTW_IGNORE_JOINALIASES and thus takes the ELSE branch (3975-3998), hitting the inline line 3993 (defineClause mutation, gcov shows 9 hits, already covered) -- NOT line 3619. So the proposed test exercises a different, already-covered line.
No SQL/regression input can reach 3619 without a C change.
Recommended fix
Leave the code as-is for API completeness (the case mirrors the walker's T_WindowClause handling and the inline else-branch at 3993).
It is harmless symmetry code.
For coverage accounting, mark lines 3614-3619 as defensive/unreachable rather than a testability gap, since the entire case block (including the pre-existing non-RPR lines 3617-3618) is dead given no mutator passes QTW_EXAMINE_SORTGROUP.
If coverage of dead code is undesirable, an alternative is to omit the defineClause mutation here and rely solely on the inline else-branch handling (3993), but keeping it is the safer, consistent choice.
3620 - return (Node *) newnode; -
3621 - } -
3622 - break; -
3623 - case T_CTECycleClause: -
3624 - { -
3625 - CTECycleClause *cc = (CTECycleClause *) node; -
3626 - CTECycleClause *newnode; -
3627 - -
3628 - FLATCOPY(newnode, cc, CTECycleClause); -
3629 - MUTATE(newnode->cycle_mark_value, cc->cycle_mark_value, Node *); -
3630 - MUTATE(newnode->cycle_mark_default, cc->cycle_mark_default, Node *); -
3631 - return (Node *) newnode; -
3632 - } -
3633 - break; -
3634 - case T_CommonTableExpr: -
3635 - { -
3636 - CommonTableExpr *cte = (CommonTableExpr *) node; -
3637 - CommonTableExpr *newnode; -
3638 - -
3639 - FLATCOPY(newnode, cte, CommonTableExpr); -
3640 - -
3641 - /* -
3642 - * Also invoke the mutator on the CTE's Query node, so it can -
3643 - * recurse into the sub-query if it wants to. -
3644 - */ -
3645 - MUTATE(newnode->ctequery, cte->ctequery, Node *); -
3646 - -
3647 - MUTATE(newnode->search_clause, cte->search_clause, CTESearchClause *); -
3648 - MUTATE(newnode->cycle_clause, cte->cycle_clause, CTECycleClause *); -
3649 - -
3650 - return (Node *) newnode; -
3651 - } -
3652 - break; -
3653 - case T_PartitionBoundSpec: -
3654 - { -
3655 - PartitionBoundSpec *pbs = (PartitionBoundSpec *) node; -
3656 - PartitionBoundSpec *newnode; -
3657 - -
3658 - FLATCOPY(newnode, pbs, PartitionBoundSpec); -
3659 - MUTATE(newnode->listdatums, pbs->listdatums, List *); -
3660 - MUTATE(newnode->lowerdatums, pbs->lowerdatums, List *); -
3661 - MUTATE(newnode->upperdatums, pbs->upperdatums, List *); -
3662 - return (Node *) newnode; -
3663 - } -
3664 - break; -
3665 - case T_PartitionRangeDatum: -
3666 - { -
3667 - PartitionRangeDatum *prd = (PartitionRangeDatum *) node; -
3668 - PartitionRangeDatum *newnode; -
3669 - -
3670 - FLATCOPY(newnode, prd, PartitionRangeDatum); -
3671 - MUTATE(newnode->value, prd->value, Node *); -
3672 - return (Node *) newnode; -
3673 - } -
3674 - break; -
3675 - case T_List: -
3676 - { -
3677 - /* -
3678 - * We assume the mutator isn't interested in the list nodes -
3679 - * per se, so just invoke it on each list element. NOTE: this -
3680 - * would fail badly on a list with integer elements! -
3681 - */ -
3682 - List *resultlist; -
3683 - ListCell *temp; -
3684 - -
3685 - resultlist = NIL; -
3686 - foreach(temp, (List *) node) -
3687 - { -
3688 - resultlist = lappend(resultlist, -
3689 - mutator((Node *) lfirst(temp), -
3690 - context)); -
3691 - } -
3692 - return (Node *) resultlist; -
3693 - } -
3694 - break; -
3695 - case T_FromExpr: -
3696 - { -
3697 - FromExpr *from = (FromExpr *) node; -
3698 - FromExpr *newnode; -
3699 - -
3700 - FLATCOPY(newnode, from, FromExpr); -
3701 - MUTATE(newnode->fromlist, from->fromlist, List *); -
3702 - MUTATE(newnode->quals, from->quals, Node *); -
3703 - return (Node *) newnode; -
3704 - } -
3705 - break; -
3706 - case T_OnConflictExpr: -
3707 - { -
3708 - OnConflictExpr *oc = (OnConflictExpr *) node; -
3709 - OnConflictExpr *newnode; -
3710 - -
3711 - FLATCOPY(newnode, oc, OnConflictExpr); -
3712 - MUTATE(newnode->arbiterElems, oc->arbiterElems, List *); -
3713 - MUTATE(newnode->arbiterWhere, oc->arbiterWhere, Node *); -
3714 - MUTATE(newnode->onConflictSet, oc->onConflictSet, List *); -
3715 - MUTATE(newnode->onConflictWhere, oc->onConflictWhere, Node *); -
3716 - MUTATE(newnode->exclRelTlist, oc->exclRelTlist, List *); -
3717 - -
3718 - return (Node *) newnode; -
3719 - } -
3720 - break; -
3721 - case T_MergeAction: -
3722 - { -
3723 - MergeAction *action = (MergeAction *) node; -
3724 - MergeAction *newnode; -
3725 - -
3726 - FLATCOPY(newnode, action, MergeAction); -
3727 - MUTATE(newnode->qual, action->qual, Node *); -
3728 - MUTATE(newnode->targetList, action->targetList, List *); -
3729 - -
3730 - return (Node *) newnode; -
3731 - } -
3732 - break; -
3733 - case T_ForPortionOfExpr: -
3734 - { -
3735 - ForPortionOfExpr *fpo = (ForPortionOfExpr *) node; -
3736 - ForPortionOfExpr *newnode; -
3737 - -
3738 - FLATCOPY(newnode, fpo, ForPortionOfExpr); -
3739 - MUTATE(newnode->rangeVar, fpo->rangeVar, Var *); -
3740 - MUTATE(newnode->targetFrom, fpo->targetFrom, Node *); -
3741 - MUTATE(newnode->targetTo, fpo->targetTo, Node *); -
3742 - MUTATE(newnode->targetRange, fpo->targetRange, Node *); -
3743 - MUTATE(newnode->overlapsExpr, fpo->overlapsExpr, Node *); -
3744 - MUTATE(newnode->rangeTargetList, fpo->rangeTargetList, List *); -
3745 - -
3746 - return (Node *) newnode; -
3747 - } -
3748 - break; -
3749 - case T_PartitionPruneStepOp: -
3750 - { -
3751 - PartitionPruneStepOp *opstep = (PartitionPruneStepOp *) node; -
3752 - PartitionPruneStepOp *newnode; -
3753 - -
3754 - FLATCOPY(newnode, opstep, PartitionPruneStepOp); -
3755 - MUTATE(newnode->exprs, opstep->exprs, List *); -
3756 - -
3757 - return (Node *) newnode; -
3758 - } -
3759 - break; -
3760 - case T_PartitionPruneStepCombine: -
3761 - /* no expression sub-nodes */ -
3762 - return copyObject(node); -
3763 - case T_JoinExpr: -
3764 - { -
3765 - JoinExpr *join = (JoinExpr *) node; -
3766 - JoinExpr *newnode; -
3767 - -
3768 - FLATCOPY(newnode, join, JoinExpr); -
3769 - MUTATE(newnode->larg, join->larg, Node *); -
3770 - MUTATE(newnode->rarg, join->rarg, Node *); -
3771 - MUTATE(newnode->quals, join->quals, Node *); -
3772 - /* We do not mutate alias or using by default */ -
3773 - return (Node *) newnode; -
3774 - } -
3775 - break; -
3776 - case T_SetOperationStmt: -
3777 - { -
3778 - SetOperationStmt *setop = (SetOperationStmt *) node; -
3779 - SetOperationStmt *newnode; -
3780 - -
3781 - FLATCOPY(newnode, setop, SetOperationStmt); -
3782 - MUTATE(newnode->larg, setop->larg, Node *); -
3783 - MUTATE(newnode->rarg, setop->rarg, Node *); -
3784 - /* We do not mutate groupClauses by default */ -
3785 - return (Node *) newnode; -
3786 - } -
3787 - break; -
3788 - case T_IndexClause: -
3789 - { -
3790 - IndexClause *iclause = (IndexClause *) node; -
3791 - IndexClause *newnode; -
3792 - -
3793 - FLATCOPY(newnode, iclause, IndexClause); -
3794 - MUTATE(newnode->rinfo, iclause->rinfo, RestrictInfo *); -
3795 - MUTATE(newnode->indexquals, iclause->indexquals, List *); -
3796 - return (Node *) newnode; -
3797 - } -
3798 - break; -
3799 - case T_PlaceHolderVar: -
3800 - { -
3801 - PlaceHolderVar *phv = (PlaceHolderVar *) node; -
3802 - PlaceHolderVar *newnode; -
3803 - -
3804 - FLATCOPY(newnode, phv, PlaceHolderVar); -
3805 - MUTATE(newnode->phexpr, phv->phexpr, Expr *); -
3806 - /* Assume we need not copy the relids bitmapsets */ -
3807 - return (Node *) newnode; -
3808 - } -
3809 - break; -
3810 - case T_InferenceElem: -
3811 - { -
3812 - InferenceElem *inferenceelemdexpr = (InferenceElem *) node; -
3813 - InferenceElem *newnode; -
3814 - -
3815 - FLATCOPY(newnode, inferenceelemdexpr, InferenceElem); -
3816 - MUTATE(newnode->expr, newnode->expr, Node *); -
3817 - return (Node *) newnode; -
3818 - } -
3819 - break; -
3820 - case T_AppendRelInfo: -
3821 - { -
3822 - AppendRelInfo *appinfo = (AppendRelInfo *) node; -
3823 - AppendRelInfo *newnode; -
3824 - -
3825 - FLATCOPY(newnode, appinfo, AppendRelInfo); -
3826 - MUTATE(newnode->translated_vars, appinfo->translated_vars, List *); -
3827 - /* Assume nothing need be done with parent_colnos[] */ -
3828 - return (Node *) newnode; -
3829 - } -
3830 - break; -
3831 - case T_PlaceHolderInfo: -
3832 - { -
3833 - PlaceHolderInfo *phinfo = (PlaceHolderInfo *) node; -
3834 - PlaceHolderInfo *newnode; -
3835 - -
3836 - FLATCOPY(newnode, phinfo, PlaceHolderInfo); -
3837 - MUTATE(newnode->ph_var, phinfo->ph_var, PlaceHolderVar *); -
3838 - /* Assume we need not copy the relids bitmapsets */ -
3839 - return (Node *) newnode; -
3840 - } -
3841 - break; -
3842 - case T_RangeTblFunction: -
3843 - { -
3844 - RangeTblFunction *rtfunc = (RangeTblFunction *) node; -
3845 - RangeTblFunction *newnode; -
3846 - -
3847 - FLATCOPY(newnode, rtfunc, RangeTblFunction); -
3848 - MUTATE(newnode->funcexpr, rtfunc->funcexpr, Node *); -
3849 - /* Assume we need not copy the coldef info lists */ -
3850 - return (Node *) newnode; -
3851 - } -
3852 - break; -
3853 - case T_TableSampleClause: -
3854 - { -
3855 - TableSampleClause *tsc = (TableSampleClause *) node; -
3856 - TableSampleClause *newnode; -
3857 - -
3858 - FLATCOPY(newnode, tsc, TableSampleClause); -
3859 - MUTATE(newnode->args, tsc->args, List *); -
3860 - MUTATE(newnode->repeatable, tsc->repeatable, Expr *); -
3861 - return (Node *) newnode; -
3862 - } -
3863 - break; -
3864 - case T_TableFunc: -
3865 - { -
3866 - TableFunc *tf = (TableFunc *) node; -
3867 - TableFunc *newnode; -
3868 - -
3869 - FLATCOPY(newnode, tf, TableFunc); -
3870 - MUTATE(newnode->ns_uris, tf->ns_uris, List *); -
3871 - MUTATE(newnode->docexpr, tf->docexpr, Node *); -
3872 - MUTATE(newnode->rowexpr, tf->rowexpr, Node *); -
3873 - MUTATE(newnode->colexprs, tf->colexprs, List *); -
3874 - MUTATE(newnode->coldefexprs, tf->coldefexprs, List *); -
3875 - MUTATE(newnode->colvalexprs, tf->colvalexprs, List *); -
3876 - MUTATE(newnode->passingvalexprs, tf->passingvalexprs, List *); -
3877 - return (Node *) newnode; -
3878 - } -
3879 - break; -
3880 - case T_GraphElementPattern: -
3881 - { -
3882 - GraphElementPattern *gep = (GraphElementPattern *) node; -
3883 - GraphElementPattern *newnode; -
3884 - -
3885 - FLATCOPY(newnode, gep, GraphElementPattern); -
3886 - MUTATE(newnode->labelexpr, gep->labelexpr, Node *); -
3887 - MUTATE(newnode->subexpr, gep->subexpr, List *); -
3888 - MUTATE(newnode->whereClause, gep->whereClause, Node *); -
3889 - newnode->quantifier = list_copy(gep->quantifier); -
3890 - return (Node *) newnode; -
3891 - } -
3892 - break; -
3893 - case T_GraphPattern: -
3894 - { -
3895 - GraphPattern *gp = (GraphPattern *) node; -
3896 - GraphPattern *newnode; -
3897 - -
3898 - FLATCOPY(newnode, gp, GraphPattern); -
3899 - MUTATE(newnode->path_pattern_list, gp->path_pattern_list, List *); -
3900 - MUTATE(newnode->whereClause, gp->whereClause, Node *); -
3901 - return (Node *) newnode; -
3902 - } -
3903 - break; -
3904 - default: -
3905 - elog(ERROR, "unrecognized node type: %d", -
3906 - (int) nodeTag(node)); -
3907 - break; -
3908 - } -
3909 - /* can't get here, but keep compiler happy */ -
3910 - return NULL; -
3911 - } -
query_tree_mutator_impl() lines 3934-4019
Modified Lines Coverage: 1/1 lines (100.0%)
LineHitsSourceCommit
3934 - query_tree_mutator_impl(Query *query, -
3935 - tree_mutator_callback mutator, -
3936 - void *context, -
3937 - int flags) -
3938 - { -
3939 - Assert(query != NULL && IsA(query, Query)); -
3940 - -
3941 - if (!(flags & QTW_DONT_COPY_QUERY)) -
3942 - { -
3943 - Query *newquery; -
3944 - -
3945 - FLATCOPY(newquery, query, Query); -
3946 - query = newquery; -
3947 - } -
3948 - -
3949 - MUTATE(query->targetList, query->targetList, List *); -
3950 - MUTATE(query->withCheckOptions, query->withCheckOptions, List *); -
3951 - MUTATE(query->onConflict, query->onConflict, OnConflictExpr *); -
3952 - MUTATE(query->mergeActionList, query->mergeActionList, List *); -
3953 - MUTATE(query->mergeJoinCondition, query->mergeJoinCondition, Node *); -
3954 - MUTATE(query->forPortionOf, query->forPortionOf, ForPortionOfExpr *); -
3955 - MUTATE(query->returningList, query->returningList, List *); -
3956 - MUTATE(query->jointree, query->jointree, FromExpr *); -
3957 - MUTATE(query->setOperations, query->setOperations, Node *); -
3958 - MUTATE(query->havingQual, query->havingQual, Node *); -
3959 - MUTATE(query->limitOffset, query->limitOffset, Node *); -
3960 - MUTATE(query->limitCount, query->limitCount, Node *); -
3961 - -
3962 - /* -
3963 - * Most callers aren't interested in SortGroupClause nodes since those -
3964 - * don't contain actual expressions. However they do contain OIDs, which -
3965 - * may be of interest to some mutators. -
3966 - */ -
3967 - -
3968 - if ((flags & QTW_EXAMINE_SORTGROUP)) -
3969 - { -
3970 - MUTATE(query->groupClause, query->groupClause, List *); -
3971 - MUTATE(query->windowClause, query->windowClause, List *); -
3972 - MUTATE(query->sortClause, query->sortClause, List *); -
3973 - MUTATE(query->distinctClause, query->distinctClause, List *); -
3974 - } -
3975 - else -
3976 - { -
3977 - /* -
3978 - * But we need to mutate the expressions under WindowClause nodes even -
3979 - * if we're not interested in SortGroupClause nodes. -
3980 - */ -
3981 - List *resultlist; -
3982 - ListCell *temp; -
3983 - -
3984 - resultlist = NIL; -
3985 - foreach(temp, query->windowClause) -
3986 - { -
3987 - WindowClause *wc = lfirst_node(WindowClause, temp); -
3988 - WindowClause *newnode; -
3989 - -
3990 - FLATCOPY(newnode, wc, WindowClause); -
3991 - MUTATE(newnode->startOffset, wc->startOffset, Node *); -
3992 - MUTATE(newnode->endOffset, wc->endOffset, Node *); -
3993 149 MUTATE(newnode->defineClause, wc->defineClause, List *); 7521a30Row pattern recognition patch (planner).
3994 - -
3995 - resultlist = lappend(resultlist, (Node *) newnode); -
3996 - } -
3997 - query->windowClause = resultlist; -
3998 - } -
3999 - -
4000 - /* -
4001 - * groupingSets and rowMarks are not mutated: -
4002 - * -
4003 - * groupingSets contain only ressortgroup refs (integers) which are -
4004 - * meaningless without the groupClause or tlist. Accordingly, any mutator -
4005 - * that needs to care about them needs to handle them itself in its Query -
4006 - * processing. -
4007 - * -
4008 - * rowMarks contains only rangetable indexes (and flags etc.) and -
4009 - * therefore should be handled at Query level similarly. -
4010 - */ -
4011 - -
4012 - if (!(flags & QTW_IGNORE_CTE_SUBQUERIES)) -
4013 - MUTATE(query->cteList, query->cteList, List *); -
4014 - else /* else copy CTE list as-is */ -
4015 - query->cteList = copyObject(query->cteList); -
4016 - query->rtable = range_table_mutator(query->rtable, -
4017 - mutator, context, flags); -
4018 - return query; -
4019 - } -
raw_expression_tree_walker_impl() lines 4163-4931
Modified Lines Coverage: 8/11 lines (72.7%)
LineHitsSourceCommit
4163 - raw_expression_tree_walker_impl(Node *node, -
4164 - tree_walker_callback walker, -
4165 - void *context) -
4166 - { -
4167 - ListCell *temp; -
4168 - -
4169 - /* -
4170 - * The walker has already visited the current node, and so we need only -
4171 - * recurse into any sub-nodes it has. -
4172 - */ -
4173 - if (node == NULL) -
4174 - return false; -
4175 - -
4176 - /* Guard against stack overflow due to overly complex expressions */ -
4177 - check_stack_depth(); -
4178 - -
4179 - switch (nodeTag(node)) -
4180 - { -
4181 - case T_JsonFormat: -
4182 - case T_SetToDefault: -
4183 - case T_CurrentOfExpr: -
4184 - case T_SQLValueFunction: -
4185 - case T_Integer: -
4186 - case T_Float: -
4187 - case T_Boolean: -
4188 - case T_String: -
4189 - case T_BitString: -
4190 - case T_ParamRef: -
4191 - case T_A_Const: -
4192 - case T_A_Star: -
4193 - case T_MergeSupportFunc: -
4194 - case T_ReturningOption: -
4195 - /* primitive node types with no subnodes */ -
4196 - break; -
4197 - case T_Alias: -
4198 - /* we assume the colnames list isn't interesting */ -
4199 - break; -
4200 - case T_RangeVar: -
4201 - return WALK(((RangeVar *) node)->alias); -
4202 - case T_GroupingFunc: -
4203 - return WALK(((GroupingFunc *) node)->args); -
4204 - case T_SubLink: -
4205 - { -
4206 - SubLink *sublink = (SubLink *) node; -
4207 - -
4208 - if (WALK(sublink->testexpr)) -
4209 - return true; -
4210 - /* we assume the operName is not interesting */ -
4211 - if (WALK(sublink->subselect)) -
4212 - return true; -
4213 - } -
4214 - break; -
4215 - case T_CaseExpr: -
4216 - { -
4217 - CaseExpr *caseexpr = (CaseExpr *) node; -
4218 - -
4219 - if (WALK(caseexpr->arg)) -
4220 - return true; -
4221 - /* we assume walker doesn't care about CaseWhens, either */ -
4222 - foreach(temp, caseexpr->args) -
4223 - { -
4224 - CaseWhen *when = lfirst_node(CaseWhen, temp); -
4225 - -
4226 - if (WALK(when->expr)) -
4227 - return true; -
4228 - if (WALK(when->result)) -
4229 - return true; -
4230 - } -
4231 - if (WALK(caseexpr->defresult)) -
4232 - return true; -
4233 - } -
4234 - break; -
4235 - case T_RowExpr: -
4236 - /* Assume colnames isn't interesting */ -
4237 - return WALK(((RowExpr *) node)->args); -
4238 - case T_CoalesceExpr: -
4239 - return WALK(((CoalesceExpr *) node)->args); -
4240 - case T_MinMaxExpr: -
4241 - return WALK(((MinMaxExpr *) node)->args); -
4242 - case T_XmlExpr: -
4243 - { -
4244 - XmlExpr *xexpr = (XmlExpr *) node; -
4245 - -
4246 - if (WALK(xexpr->named_args)) -
4247 - return true; -
4248 - /* we assume walker doesn't care about arg_names */ -
4249 - if (WALK(xexpr->args)) -
4250 - return true; -
4251 - } -
4252 - break; -
4253 - case T_JsonReturning: -
4254 - return WALK(((JsonReturning *) node)->format); -
4255 - case T_JsonValueExpr: -
4256 - { -
4257 - JsonValueExpr *jve = (JsonValueExpr *) node; -
4258 - -
4259 - if (WALK(jve->raw_expr)) -
4260 - return true; -
4261 - if (WALK(jve->formatted_expr)) -
4262 - return true; -
4263 - if (WALK(jve->format)) -
4264 - return true; -
4265 - } -
4266 - break; -
4267 - case T_JsonParseExpr: -
4268 - { -
4269 - JsonParseExpr *jpe = (JsonParseExpr *) node; -
4270 - -
4271 - if (WALK(jpe->expr)) -
4272 - return true; -
4273 - if (WALK(jpe->output)) -
4274 - return true; -
4275 - } -
4276 - break; -
4277 - case T_JsonScalarExpr: -
4278 - { -
4279 - JsonScalarExpr *jse = (JsonScalarExpr *) node; -
4280 - -
4281 - if (WALK(jse->expr)) -
4282 - return true; -
4283 - if (WALK(jse->output)) -
4284 - return true; -
4285 - } -
4286 - break; -
4287 - case T_JsonSerializeExpr: -
4288 - { -
4289 - JsonSerializeExpr *jse = (JsonSerializeExpr *) node; -
4290 - -
4291 - if (WALK(jse->expr)) -
4292 - return true; -
4293 - if (WALK(jse->output)) -
4294 - return true; -
4295 - } -
4296 - break; -
4297 - case T_JsonConstructorExpr: -
4298 - { -
4299 - JsonConstructorExpr *ctor = (JsonConstructorExpr *) node; -
4300 - -
4301 - if (WALK(ctor->args)) -
4302 - return true; -
4303 - if (WALK(ctor->func)) -
4304 - return true; -
4305 - if (WALK(ctor->coercion)) -
4306 - return true; -
4307 - if (WALK(ctor->returning)) -
4308 - return true; -
4309 - } -
4310 - break; -
4311 - case T_JsonIsPredicate: -
4312 - return WALK(((JsonIsPredicate *) node)->expr); -
4313 - case T_JsonArgument: -
4314 - return WALK(((JsonArgument *) node)->val); -
4315 - case T_JsonFuncExpr: -
4316 - { -
4317 - JsonFuncExpr *jfe = (JsonFuncExpr *) node; -
4318 - -
4319 - if (WALK(jfe->context_item)) -
4320 - return true; -
4321 - if (WALK(jfe->pathspec)) -
4322 - return true; -
4323 - if (WALK(jfe->passing)) -
4324 - return true; -
4325 - if (WALK(jfe->output)) -
4326 - return true; -
4327 - if (WALK(jfe->on_empty)) -
4328 - return true; -
4329 - if (WALK(jfe->on_error)) -
4330 - return true; -
4331 - } -
4332 - break; -
4333 - case T_JsonBehavior: -
4334 - { -
4335 - JsonBehavior *jb = (JsonBehavior *) node; -
4336 - -
4337 - if (WALK(jb->expr)) -
4338 - return true; -
4339 - } -
4340 - break; -
4341 - case T_JsonTable: -
4342 - { -
4343 - JsonTable *jt = (JsonTable *) node; -
4344 - -
4345 - if (WALK(jt->context_item)) -
4346 - return true; -
4347 - if (WALK(jt->pathspec)) -
4348 - return true; -
4349 - if (WALK(jt->passing)) -
4350 - return true; -
4351 - if (WALK(jt->columns)) -
4352 - return true; -
4353 - if (WALK(jt->on_error)) -
4354 - return true; -
4355 - } -
4356 - break; -
4357 - case T_JsonTableColumn: -
4358 - { -
4359 - JsonTableColumn *jtc = (JsonTableColumn *) node; -
4360 - -
4361 - if (WALK(jtc->typeName)) -
4362 - return true; -
4363 - if (WALK(jtc->on_empty)) -
4364 - return true; -
4365 - if (WALK(jtc->on_error)) -
4366 - return true; -
4367 - if (WALK(jtc->columns)) -
4368 - return true; -
4369 - } -
4370 - break; -
4371 - case T_JsonTablePathSpec: -
4372 - return WALK(((JsonTablePathSpec *) node)->string); -
4373 - case T_NullTest: -
4374 - return WALK(((NullTest *) node)->arg); -
4375 - case T_BooleanTest: -
4376 - return WALK(((BooleanTest *) node)->arg); -
4377 - case T_JoinExpr: -
4378 - { -
4379 - JoinExpr *join = (JoinExpr *) node; -
4380 - -
4381 - if (WALK(join->larg)) -
4382 - return true; -
4383 - if (WALK(join->rarg)) -
4384 - return true; -
4385 - if (WALK(join->quals)) -
4386 - return true; -
4387 - if (WALK(join->alias)) -
4388 - return true; -
4389 - /* using list is deemed uninteresting */ -
4390 - } -
4391 - break; -
4392 - case T_IntoClause: -
4393 - { -
4394 - IntoClause *into = (IntoClause *) node; -
4395 - -
4396 - if (WALK(into->rel)) -
4397 - return true; -
4398 - /* colNames, options are deemed uninteresting */ -
4399 - /* viewQuery should be null in raw parsetree, but check it */ -
4400 - if (WALK(into->viewQuery)) -
4401 - return true; -
4402 - } -
4403 - break; -
4404 - case T_List: -
4405 - foreach(temp, (List *) node) -
4406 - { -
4407 - if (WALK((Node *) lfirst(temp))) -
4408 - return true; -
4409 - } -
4410 - break; -
4411 - case T_InsertStmt: -
4412 - { -
4413 - InsertStmt *stmt = (InsertStmt *) node; -
4414 - -
4415 - if (WALK(stmt->relation)) -
4416 - return true; -
4417 - if (WALK(stmt->cols)) -
4418 - return true; -
4419 - if (WALK(stmt->selectStmt)) -
4420 - return true; -
4421 - if (WALK(stmt->onConflictClause)) -
4422 - return true; -
4423 - if (WALK(stmt->returningClause)) -
4424 - return true; -
4425 - if (WALK(stmt->withClause)) -
4426 - return true; -
4427 - } -
4428 - break; -
4429 - case T_DeleteStmt: -
4430 - { -
4431 - DeleteStmt *stmt = (DeleteStmt *) node; -
4432 - -
4433 - if (WALK(stmt->relation)) -
4434 - return true; -
4435 - if (WALK(stmt->usingClause)) -
4436 - return true; -
4437 - if (WALK(stmt->whereClause)) -
4438 - return true; -
4439 - if (WALK(stmt->returningClause)) -
4440 - return true; -
4441 - if (WALK(stmt->withClause)) -
4442 - return true; -
4443 - } -
4444 - break; -
4445 - case T_UpdateStmt: -
4446 - { -
4447 - UpdateStmt *stmt = (UpdateStmt *) node; -
4448 - -
4449 - if (WALK(stmt->relation)) -
4450 - return true; -
4451 - if (WALK(stmt->targetList)) -
4452 - return true; -
4453 - if (WALK(stmt->whereClause)) -
4454 - return true; -
4455 - if (WALK(stmt->fromClause)) -
4456 - return true; -
4457 - if (WALK(stmt->returningClause)) -
4458 - return true; -
4459 - if (WALK(stmt->withClause)) -
4460 - return true; -
4461 - } -
4462 - break; -
4463 - case T_MergeStmt: -
4464 - { -
4465 - MergeStmt *stmt = (MergeStmt *) node; -
4466 - -
4467 - if (WALK(stmt->relation)) -
4468 - return true; -
4469 - if (WALK(stmt->sourceRelation)) -
4470 - return true; -
4471 - if (WALK(stmt->joinCondition)) -
4472 - return true; -
4473 - if (WALK(stmt->mergeWhenClauses)) -
4474 - return true; -
4475 - if (WALK(stmt->returningClause)) -
4476 - return true; -
4477 - if (WALK(stmt->withClause)) -
4478 - return true; -
4479 - } -
4480 - break; -
4481 - case T_MergeWhenClause: -
4482 - { -
4483 - MergeWhenClause *mergeWhenClause = (MergeWhenClause *) node; -
4484 - -
4485 - if (WALK(mergeWhenClause->condition)) -
4486 - return true; -
4487 - if (WALK(mergeWhenClause->targetList)) -
4488 - return true; -
4489 - if (WALK(mergeWhenClause->values)) -
4490 - return true; -
4491 - } -
4492 - break; -
4493 - case T_ReturningClause: -
4494 - { -
4495 - ReturningClause *returning = (ReturningClause *) node; -
4496 - -
4497 - if (WALK(returning->options)) -
4498 - return true; -
4499 - if (WALK(returning->exprs)) -
4500 - return true; -
4501 - } -
4502 - break; -
4503 - case T_SelectStmt: -
4504 - { -
4505 - SelectStmt *stmt = (SelectStmt *) node; -
4506 - -
4507 - if (WALK(stmt->distinctClause)) -
4508 - return true; -
4509 - if (WALK(stmt->intoClause)) -
4510 - return true; -
4511 - if (WALK(stmt->targetList)) -
4512 - return true; -
4513 - if (WALK(stmt->fromClause)) -
4514 - return true; -
4515 - if (WALK(stmt->whereClause)) -
4516 - return true; -
4517 - if (WALK(stmt->groupClause)) -
4518 - return true; -
4519 - if (WALK(stmt->havingClause)) -
4520 - return true; -
4521 - if (WALK(stmt->windowClause)) -
4522 - return true; -
4523 - if (WALK(stmt->valuesLists)) -
4524 - return true; -
4525 - if (WALK(stmt->sortClause)) -
4526 - return true; -
4527 - if (WALK(stmt->limitOffset)) -
4528 - return true; -
4529 - if (WALK(stmt->limitCount)) -
4530 - return true; -
4531 - if (WALK(stmt->lockingClause)) -
4532 - return true; -
4533 - if (WALK(stmt->withClause)) -
4534 - return true; -
4535 - if (WALK(stmt->larg)) -
4536 - return true; -
4537 - if (WALK(stmt->rarg)) -
4538 - return true; -
4539 - } -
4540 - break; -
4541 - case T_PLAssignStmt: -
4542 - { -
4543 - PLAssignStmt *stmt = (PLAssignStmt *) node; -
4544 - -
4545 - if (WALK(stmt->indirection)) -
4546 - return true; -
4547 - if (WALK(stmt->val)) -
4548 - return true; -
4549 - } -
4550 - break; -
4551 - case T_A_Expr: -
4552 - { -
4553 - A_Expr *expr = (A_Expr *) node; -
4554 - -
4555 - if (WALK(expr->lexpr)) -
4556 - return true; -
4557 - if (WALK(expr->rexpr)) -
4558 - return true; -
4559 - /* operator name is deemed uninteresting */ -
4560 - } -
4561 - break; -
4562 - case T_BoolExpr: -
4563 - { -
4564 - BoolExpr *expr = (BoolExpr *) node; -
4565 - -
4566 - if (WALK(expr->args)) -
4567 - return true; -
4568 - } -
4569 - break; -
4570 - case T_ColumnRef: -
4571 - /* we assume the fields contain nothing interesting */ -
4572 - break; -
4573 - case T_FuncCall: -
4574 - { -
4575 - FuncCall *fcall = (FuncCall *) node; -
4576 - -
4577 - if (WALK(fcall->args)) -
4578 - return true; -
4579 - if (WALK(fcall->agg_order)) -
4580 - return true; -
4581 - if (WALK(fcall->agg_filter)) -
4582 - return true; -
4583 - if (WALK(fcall->over)) -
4584 - return true; -
4585 - /* function name is deemed uninteresting */ -
4586 - } -
4587 - break; -
4588 - case T_NamedArgExpr: -
4589 - return WALK(((NamedArgExpr *) node)->arg); -
4590 - case T_A_Indices: -
4591 - { -
4592 - A_Indices *indices = (A_Indices *) node; -
4593 - -
4594 - if (WALK(indices->lidx)) -
4595 - return true; -
4596 - if (WALK(indices->uidx)) -
4597 - return true; -
4598 - } -
4599 - break; -
4600 - case T_A_Indirection: -
4601 - { -
4602 - A_Indirection *indir = (A_Indirection *) node; -
4603 - -
4604 - if (WALK(indir->arg)) -
4605 - return true; -
4606 - if (WALK(indir->indirection)) -
4607 - return true; -
4608 - } -
4609 - break; -
4610 - case T_A_ArrayExpr: -
4611 - return WALK(((A_ArrayExpr *) node)->elements); -
4612 - case T_ResTarget: -
4613 - { -
4614 - ResTarget *rt = (ResTarget *) node; -
4615 - -
4616 - if (WALK(rt->indirection)) -
4617 - return true; -
4618 - if (WALK(rt->val)) -
4619 - return true; -
4620 - } -
4621 - break; -
4622 - case T_MultiAssignRef: -
4623 - return WALK(((MultiAssignRef *) node)->source); -
4624 - case T_TypeCast: -
4625 - { -
4626 - TypeCast *tc = (TypeCast *) node; -
4627 - -
4628 - if (WALK(tc->arg)) -
4629 - return true; -
4630 - if (WALK(tc->typeName)) -
4631 - return true; -
4632 - } -
4633 - break; -
4634 - case T_CollateClause: -
4635 - return WALK(((CollateClause *) node)->arg); -
4636 - case T_SortBy: -
4637 - return WALK(((SortBy *) node)->node); -
4638 - case T_WindowDef: -
4639 - { -
4640 - WindowDef *wd = (WindowDef *) node; -
4641 - -
4642 - if (WALK(wd->partitionClause)) -
4643 - return true; -
4644 - if (WALK(wd->orderClause)) -
4645 - return true; -
4646 - if (WALK(wd->startOffset)) -
4647 - return true; -
4648 - if (WALK(wd->endOffset)) -
4649 - return true; -
4650 14033 if (WALK(wd->rpCommonSyntax)) 7521a30Row pattern recognition patch (planner).
4651 0 return true; 7521a30Row pattern recognition patch (planner).
UnreachableDefensive (unreachable) · confidence high · raw_expression_tree_walker_impl @4651
Reason
REFUTED root-cause mechanism;
line is defensive-unreachable, not "hard-to-reach via CTE".
Line 4651 is the standard `return true;
` that propagates a true result from WALK(wd->rpCommonSyntax) in the T_WindowDef case. gcov confirms 4650 ran 4542x but 4651 is ##### (0).
Reaching 4651 requires some raw_expression_tree_walker callback to return true on a node living inside rpCommonSyntax.
I enumerated ALL four callbacks in the tree:
(1) test_raw_expression_coverage (analyze.c:4091) never returns true on its own, it only forwards recursion results that bottom out false -- this is exactly why 4650 is hit 4542x but 4651 is 0;
(2) makeDependencyGraphWalker (parse_cte.c:700) NEVER returns true -- on a CTE-referencing RangeVar it merely records a dependency via bms_add_member and returns false (line 754).
The root cause claim that this walker "aborts/returns true when it finds a RangeVar naming a CTE" is factually WRONG;
(3) checkWellFormedRecursionWalker (parse_cte.c) discards child return values and returns false explicitly;
(4) contain_rpr_walker (parse_cte.c:1309) is the ONLY walker that returns true, but it short-circuits at IsA(node,WindowDef)&&rpCommonSyntax!=NULL (line 1320) BEFORE the raw walker's WindowDef case ever descends into rpCommonSyntax.
The raw walker reaches the WindowDef case only for WindowDefs where contain_rpr_walker did not short-circuit (rpCommonSyntax==NULL), so WALK(NULL) returns false.
A nested RPR window inside an outer window's
DEFINE is also unreachable because the outer WindowDef short-circuits first.
Hence no existing input drives 4651.
Recommended fix
No code fix needed.
Line 4651 is correct, intentional defensive boilerplate that mirrors every other `if (WALK(child)) return true;
` arm in raw_expression_tree_walker_impl;
it is required for correctness if any future walker callback returns true on a node inside rpCommonSyntax.
It should remain uncovered/excluded from coverage goals (same status as countless sibling `return true;
` lines in this function that depend on a walker that returns true at that depth).
The coverage report's classification should be changed from "hard-to-reach" to "defensive-unreachable", and the cited root-cause mechanism (makeDependencyGraphWalker returning true on a CTE RangeVar) should be corrected since that walker never returns true.
4652 - } -
4653 - break; -
4654 - case T_RangeSubselect: -
4655 - { -
4656 - RangeSubselect *rs = (RangeSubselect *) node; -
4657 - -
4658 - if (WALK(rs->subquery)) -
4659 - return true; -
4660 - if (WALK(rs->alias)) -
4661 - return true; -
4662 - } -
4663 - break; -
4664 - case T_RangeFunction: -
4665 - { -
4666 - RangeFunction *rf = (RangeFunction *) node; -
4667 - -
4668 - if (WALK(rf->functions)) -
4669 - return true; -
4670 - if (WALK(rf->alias)) -
4671 - return true; -
4672 - if (WALK(rf->coldeflist)) -
4673 - return true; -
4674 - } -
4675 - break; -
4676 - case T_RangeTableSample: -
4677 - { -
4678 - RangeTableSample *rts = (RangeTableSample *) node; -
4679 - -
4680 - if (WALK(rts->relation)) -
4681 - return true; -
4682 - /* method name is deemed uninteresting */ -
4683 - if (WALK(rts->args)) -
4684 - return true; -
4685 - if (WALK(rts->repeatable)) -
4686 - return true; -
4687 - } -
4688 - break; -
4689 - case T_RangeTableFunc: -
4690 - { -
4691 - RangeTableFunc *rtf = (RangeTableFunc *) node; -
4692 - -
4693 - if (WALK(rtf->docexpr)) -
4694 - return true; -
4695 - if (WALK(rtf->rowexpr)) -
4696 - return true; -
4697 - if (WALK(rtf->namespaces)) -
4698 - return true; -
4699 - if (WALK(rtf->columns)) -
4700 - return true; -
4701 - if (WALK(rtf->alias)) -
4702 - return true; -
4703 - } -
4704 - break; -
4705 - case T_RangeTableFuncCol: -
4706 - { -
4707 - RangeTableFuncCol *rtfc = (RangeTableFuncCol *) node; -
4708 - -
4709 - if (WALK(rtfc->colexpr)) -
4710 - return true; -
4711 - if (WALK(rtfc->coldefexpr)) -
4712 - return true; -
4713 - } -
4714 - break; -
4715 - case T_RangeGraphTable: -
4716 - { -
4717 - RangeGraphTable *rgt = (RangeGraphTable *) node; -
4718 - -
4719 - if (WALK(rgt->graph_pattern)) -
4720 - return true; -
4721 - if (WALK(rgt->columns)) -
4722 - return true; -
4723 - if (WALK(rgt->alias)) -
4724 - return true; -
4725 - } -
4726 - break; -
4727 - case T_TypeName: -
4728 - { -
4729 - TypeName *tn = (TypeName *) node; -
4730 - -
4731 - if (WALK(tn->typmods)) -
4732 - return true; -
4733 - if (WALK(tn->arrayBounds)) -
4734 - return true; -
4735 - /* type name itself is deemed uninteresting */ -
4736 - } -
4737 - break; -
4738 - case T_ColumnDef: -
4739 - { -
4740 - ColumnDef *coldef = (ColumnDef *) node; -
4741 - -
4742 - if (WALK(coldef->typeName)) -
4743 - return true; -
4744 - if (WALK(coldef->raw_default)) -
4745 - return true; -
4746 - if (WALK(coldef->collClause)) -
4747 - return true; -
4748 - /* for now, constraints are ignored */ -
4749 - } -
4750 - break; -
4751 - case T_IndexElem: -
4752 - { -
4753 - IndexElem *indelem = (IndexElem *) node; -
4754 - -
4755 - if (WALK(indelem->expr)) -
4756 - return true; -
4757 - /* collation and opclass names are deemed uninteresting */ -
4758 - } -
4759 - break; -
4760 - case T_GroupingSet: -
4761 - return WALK(((GroupingSet *) node)->content); -
4762 - case T_LockingClause: -
4763 - return WALK(((LockingClause *) node)->lockedRels); -
4764 - case T_XmlSerialize: -
4765 - { -
4766 - XmlSerialize *xs = (XmlSerialize *) node; -
4767 - -
4768 - if (WALK(xs->expr)) -
4769 - return true; -
4770 - if (WALK(xs->typeName)) -
4771 - return true; -
4772 - } -
4773 - break; -
4774 - case T_WithClause: -
4775 - return WALK(((WithClause *) node)->ctes); -
4776 - case T_InferClause: -
4777 - { -
4778 - InferClause *stmt = (InferClause *) node; -
4779 - -
4780 - if (WALK(stmt->indexElems)) -
4781 - return true; -
4782 - if (WALK(stmt->whereClause)) -
4783 - return true; -
4784 - } -
4785 - break; -
4786 - case T_OnConflictClause: -
4787 - { -
4788 - OnConflictClause *stmt = (OnConflictClause *) node; -
4789 - -
4790 - if (WALK(stmt->infer)) -
4791 - return true; -
4792 - if (WALK(stmt->targetList)) -
4793 - return true; -
4794 - if (WALK(stmt->whereClause)) -
4795 - return true; -
4796 - } -
4797 - break; -
4798 - case T_CommonTableExpr: -
4799 - /* search_clause and cycle_clause are not interesting here */ -
4800 - return WALK(((CommonTableExpr *) node)->ctequery); -
4801 - case T_JsonOutput: -
4802 - { -
4803 - JsonOutput *out = (JsonOutput *) node; -
4804 - -
4805 - if (WALK(out->typeName)) -
4806 - return true; -
4807 - if (WALK(out->returning)) -
4808 - return true; -
4809 - } -
4810 - break; -
4811 - case T_JsonKeyValue: -
4812 - { -
4813 - JsonKeyValue *jkv = (JsonKeyValue *) node; -
4814 - -
4815 - if (WALK(jkv->key)) -
4816 - return true; -
4817 - if (WALK(jkv->value)) -
4818 - return true; -
4819 - } -
4820 - break; -
4821 - case T_JsonObjectConstructor: -
4822 - { -
4823 - JsonObjectConstructor *joc = (JsonObjectConstructor *) node; -
4824 - -
4825 - if (WALK(joc->output)) -
4826 - return true; -
4827 - if (WALK(joc->exprs)) -
4828 - return true; -
4829 - } -
4830 - break; -
4831 - case T_JsonArrayConstructor: -
4832 - { -
4833 - JsonArrayConstructor *jac = (JsonArrayConstructor *) node; -
4834 - -
4835 - if (WALK(jac->output)) -
4836 - return true; -
4837 - if (WALK(jac->exprs)) -
4838 - return true; -
4839 - } -
4840 - break; -
4841 - case T_JsonAggConstructor: -
4842 - { -
4843 - JsonAggConstructor *ctor = (JsonAggConstructor *) node; -
4844 - -
4845 - if (WALK(ctor->output)) -
4846 - return true; -
4847 - if (WALK(ctor->agg_order)) -
4848 - return true; -
4849 - if (WALK(ctor->agg_filter)) -
4850 - return true; -
4851 - if (WALK(ctor->over)) -
4852 - return true; -
4853 - } -
4854 - break; -
4855 - case T_JsonObjectAgg: -
4856 - { -
4857 - JsonObjectAgg *joa = (JsonObjectAgg *) node; -
4858 - -
4859 - if (WALK(joa->constructor)) -
4860 - return true; -
4861 - if (WALK(joa->arg)) -
4862 - return true; -
4863 - } -
4864 - break; -
4865 - case T_JsonArrayAgg: -
4866 - { -
4867 - JsonArrayAgg *jaa = (JsonArrayAgg *) node; -
4868 - -
4869 - if (WALK(jaa->constructor)) -
4870 - return true; -
4871 - if (WALK(jaa->arg)) -
4872 - return true; -
4873 - } -
4874 - break; -
4875 - case T_JsonArrayQueryConstructor: -
4876 - { -
4877 - JsonArrayQueryConstructor *jaqc = (JsonArrayQueryConstructor *) node; -
4878 - -
4879 - if (WALK(jaqc->output)) -
4880 - return true; -
4881 - if (WALK(jaqc->query)) -
4882 - return true; -
4883 - } -
4884 - break; -
4885 - case T_GraphElementPattern: -
4886 - { -
4887 - GraphElementPattern *gep = (GraphElementPattern *) node; -
4888 - -
4889 - if (WALK(gep->labelexpr)) -
4890 - return true; -
4891 - if (WALK(gep->subexpr)) -
4892 - return true; -
4893 - if (WALK(gep->whereClause)) -
4894 - return true; -
4895 - } -
4896 - break; -
4897 - case T_GraphPattern: -
4898 - { -
4899 - GraphPattern *gp = (GraphPattern *) node; -
4900 - -
4901 - if (WALK(gp->path_pattern_list)) -
4902 - return true; -
4903 - if (WALK(gp->whereClause)) -
4904 - return true; -
4905 - } -
4906 - break; -
4907 4601 case T_RPCommonSyntax: 7521a30Row pattern recognition patch (planner).
4908 - { 7521a30Row pattern recognition patch (planner).
4909 4601 RPCommonSyntax *rc = (RPCommonSyntax *) node; 7521a30Row pattern recognition patch (planner).
4910 - 7521a30Row pattern recognition patch (planner).
4911 4601 if (WALK(rc->rpPattern)) 7521a30Row pattern recognition patch (planner).
4912 - return true; 7521a30Row pattern recognition patch (planner).
4913 4601 if (WALK(rc->rpDefs)) 7521a30Row pattern recognition patch (planner).
4914 0 return true; 7521a30Row pattern recognition patch (planner).
UnreachableDefensive (unreachable) · confidence high · raw_expression_tree_walker_impl @4914
Reason
REFUTED root cause;
line is defensive-unreachable, not hard-to-reach.
Line 4914 is the `return true;
` that fires only if WALK(rc->rpDefs) returns true.
Exactly three callbacks ever drive raw_expression_tree_walker:
(1) test_raw_expression_coverage (analyze.c:4091) ALWAYS returns false -- it covers the condition evaluation at 4913 but can never make the body at 4914 run;
(2) contain_rpr_walker (parse_cte.c:1309) returns true at the WindowDef when wd->rpCommonSyntax != NULL, BEFORE recursing into the RPCommonSyntax case, so it never walks rpDefs to return true;
(3) makeDependencyGraphWalker (parse_cte.c:700) NEVER returns true -- even when it matches a CTE-referencing RangeVar it returns false at line 754, only recording a dependency as a side effect.
The proposed root cause ('only the CTE dependency walker returns true') is factually wrong: makeDependencyGraphWalker returns false on CTE matches.
Hence no SQL input can make rpDefs's sub-walk return true, so 4914 is unreachable.
This is standard defensive early-exit boilerplate identical to every other `if (WALK(x)) return true;
` in the function;
it is correct and would be needed by a hypothetical future callback that returns true, but no current caller exercises it.
The companion line 4651 is unreachable for the same reason.
Recommended fix
No functional fix needed;
the line is correct and necessary defensive boilerplate consistent with the rest of raw_expression_tree_walker.
To eliminate it from the coverage report, options are:
(a) accept it as defensive-unreachable and exclude/annotate it (preferred -- matches existing PostgreSQL practice for walker early-exit lines);
or (b) if strict coverage is required, the only way to exercise it is to add a test-only walker callback (under DEBUG_NODE_TESTS_ENABLED) that returns true when it encounters a node placed inside a
DEFINE expression -- but this changes production-adjacent code purely for coverage and is not recommended.
4915 - } 7521a30Row pattern recognition patch (planner).
4916 - break; 7521a30Row pattern recognition patch (planner).
4917 20859 case T_RPRPatternNode: 7521a30Row pattern recognition patch (planner).
4918 - { 7521a30Row pattern recognition patch (planner).
4919 20859 RPRPatternNode *rp = (RPRPatternNode *) node; 7521a30Row pattern recognition patch (planner).
4920 - 7521a30Row pattern recognition patch (planner).
4921 20859 if (WALK(rp->children)) 7521a30Row pattern recognition patch (planner).
4922 0 return true; 7521a30Row pattern recognition patch (planner).
UnreachableDefensive (unreachable) · confidence high · raw_expression_tree_walker_impl @4922
Reason
CONFIRMED defensive-unreachable.
Line 4922 is the `return true;
` body of `if (WALK(rp->children)) return true;
` in the T_RPRPatternNode case.
The WALK call on 4921 executes and is covered, but its true-branch is unreachable by any SQL/regression input.
Two (and only two) walkers run through this function:
(1) test_raw_expression_coverage (the DEBUG_NODE_TESTS harness) at analyze.c:4091, which has no search target and only returns false except when node==NULL -- it can never make WALK return true;
(2) contain_rpr_walker at parse_cte.c:1309, which returns true ONLY when it encounters a WindowDef whose rpCommonSyntax != NULL (line 1320).
An RPRPatternNode's `children` list is grammatically guaranteed (gram.y:17646,17653,17678,17685,17727 etc.) to contain only other RPRPatternNodes (VAR/SEQ/ALT/GROUP).
PATTERN syntax admits no WindowDef, subquery, RangeVar, SubLink, or any node a raw walker aborts on;
DEFINE expressions (which could embed window subqueries) live in RPCommonSyntax.rpDefs (handled at line 4913), not inside RPRPatternNode.children.
Therefore WALK(rp->children) can never return true, and line 4922 cannot execute.
I tried to refute via a nested CTE+WindowDef-with-PATTERN (the only real caller that returns true) but the true-return fires at the WindowDef node in the body's T_WindowDef arm / location stash, never from within the
PATTERN subtree.
No input refutes the finding.
Recommended fix
Keep line 4922 for structural consistency with every other `if (WALK(...)) return true;
` arm;
removing it would make the walker silently incorrect if a future node type is ever placed under
PATTERN.
Do NOT add an Assert (the WALK call must still recurse to validate child node tags via the harness).
Optionally add a brief comment in the T_RPRPatternNode case noting that children currently contain only RPRPatternNodes, so the true-return is presently unreachable but retained for forward-compatibility.
Treat as accepted defensive code, not a coverage gap.
4923 - } 7521a30Row pattern recognition patch (planner).
4924 - break; 7521a30Row pattern recognition patch (planner).
4925 - default: -
4926 - elog(ERROR, "unrecognized node type: %d", -
4927 - (int) nodeTag(node)); -
4928 - break; -
4929 - } -
4930 - return false; -
4931 - } -