← Back to Overview

src/backend/nodes/outfuncs.c

Coverage: 28/30 lines (93.3%)
Total Lines
30
modified
Covered
28
93.3%
Uncovered
2
6.7%
Keyboard navigation
_outRPRPattern() lines 732-779
Modified Lines Coverage: 28/30 lines (93.3%)
LineHitsSourceCommit
732 2980 _outRPRPattern(StringInfo str, const RPRPattern *node) c54ba27Row pattern recognition patch (parse/analysis).
733 - { c54ba27Row pattern recognition patch (parse/analysis).
734 2980 WRITE_NODE_TYPE("RPRPATTERN"); c54ba27Row pattern recognition patch (parse/analysis).
735 - c54ba27Row pattern recognition patch (parse/analysis).
736 2980 WRITE_INT_FIELD(numVars); c54ba27Row pattern recognition patch (parse/analysis).
737 2980 WRITE_INT_FIELD(maxDepth); c54ba27Row pattern recognition patch (parse/analysis).
738 2980 WRITE_INT_FIELD(numElements); c54ba27Row pattern recognition patch (parse/analysis).
739 - c54ba27Row pattern recognition patch (parse/analysis).
740 - /* Write varNames array as list of strings */ c54ba27Row pattern recognition patch (parse/analysis).
741 2980 appendStringInfoString(str, " :varNames"); c54ba27Row pattern recognition patch (parse/analysis).
742 2980 if (node->numVars > 0 && node->varNames != NULL) c54ba27Row pattern recognition patch (parse/analysis).
743 - { c54ba27Row pattern recognition patch (parse/analysis).
744 2980 appendStringInfoString(str, " ("); c54ba27Row pattern recognition patch (parse/analysis).
745 10116 for (int i = 0; i < node->numVars; i++) c54ba27Row pattern recognition patch (parse/analysis).
746 - { c54ba27Row pattern recognition patch (parse/analysis).
747 7136 if (i > 0) c54ba27Row pattern recognition patch (parse/analysis).
748 4156 appendStringInfoChar(str, ' '); c54ba27Row pattern recognition patch (parse/analysis).
749 7136 outToken(str, node->varNames[i]); c54ba27Row pattern recognition patch (parse/analysis).
750 - } c54ba27Row pattern recognition patch (parse/analysis).
751 2980 appendStringInfoChar(str, ')'); c54ba27Row pattern recognition patch (parse/analysis).
752 - } c54ba27Row pattern recognition patch (parse/analysis).
753 - else c54ba27Row pattern recognition patch (parse/analysis).
754 0 appendStringInfoString(str, " <>"); c54ba27Row pattern recognition patch (parse/analysis).
UnreachableDefensive (unreachable) · confidence high · _outRPRPattern @754
Reason
Confirmed defensive-unreachable.
Line 754 (`appendStringInfoString(str, " <>")`) is the else branch of the guard `if (node->numVars > 0 && node->varNames != NULL)` at outfuncs.c:742. It executes only when an RPRPattern has numVars <= 0 OR varNames == NULL.
I traced every construction path for RPRPattern:
(1) makeRPRPattern() at rpr.c:1127 is the SOLE original constructor (only call site rpr.c:1938), and it Asserts numVars > 0 (rpr.c:1143) then unconditionally palloc's varNames (rpr.c:1144-1146);
(2) _copyRPRPattern() at copyfuncs.c:171 copies an existing node, Asserts from->numVars > 0 (copyfuncs.c:180) and always palloc's newnode->varNames (copyfuncs.c:181);
(3) the read path reconstructs from out output. numVars is derived from scanRPRPattern over the
PATTERN tree plus collectDefineVariables;
a
PATTERN clause cannot be syntactically empty, so there is always >= 1 primary variable, hence numVars is never 0 and varNames is never NULL.
No SQL/regression input can drive an RPRPattern with zero variables to _outNode, so line 754 cannot be reached.
I could not construct any refuting input.
Note: an identical defensive else exists for :elements at line 776 (also guarded by numElements>=2 Asserts), so this is a consistent defensive idiom rather than a logic flaw.
Recommended fix
Because makeRPRPattern (rpr.c:1143-1144) and _copyRPRPattern (copyfuncs.c:180-181) already enforce numVars > 0 and a non-NULL varNames, the empty-array case at outfuncs.c:753-754 cannot occur.
Option A (minimal, keeps defensive style): leave as-is and accept the line as documented defensive-unreachable, matching the parallel :elements else at line 776. Option B (eliminate the branch): replace the guard with `Assert(node->numVars > 0 && node->varNames != NULL);
` before the loop and emit the `( ... )` list unconditionally (drop lines 753-754), and likewise simplify the matching reader at readfuncs.c:595. If pursuing Option B, do the same to the :elements branch (lines 758,775-776) for consistency, since both rest on the same makeRPRPattern/_copyRPRPattern invariants (numElements >= 2 at rpr.c:1149, copyfuncs.c:186).
Recommend Option A unless the project wants to actively reduce defensive-unreachable line count.
755 - c54ba27Row pattern recognition patch (parse/analysis).
756 - /* Write elements array */ c54ba27Row pattern recognition patch (parse/analysis).
757 2980 appendStringInfoString(str, " :elements"); c54ba27Row pattern recognition patch (parse/analysis).
758 2980 if (node->numElements > 0 && node->elements != NULL) c54ba27Row pattern recognition patch (parse/analysis).
759 - { c54ba27Row pattern recognition patch (parse/analysis).
760 2980 appendStringInfoChar(str, ' '); c54ba27Row pattern recognition patch (parse/analysis).
761 17380 for (int i = 0; i < node->numElements; i++) c54ba27Row pattern recognition patch (parse/analysis).
762 - { c54ba27Row pattern recognition patch (parse/analysis).
763 14400 const RPRPatternElement *elem = &node->elements[i]; c54ba27Row pattern recognition patch (parse/analysis).
764 - c54ba27Row pattern recognition patch (parse/analysis).
765 14400 appendStringInfo(str, "(%d %d %u %d %d %d %d)", c54ba27Row pattern recognition patch (parse/analysis).
766 14400 (int) elem->varId, c54ba27Row pattern recognition patch (parse/analysis).
767 14400 (int) elem->depth, c54ba27Row pattern recognition patch (parse/analysis).
768 14400 (unsigned) elem->flags, c54ba27Row pattern recognition patch (parse/analysis).
769 14400 (int) elem->min, c54ba27Row pattern recognition patch (parse/analysis).
770 14400 (int) elem->max, c54ba27Row pattern recognition patch (parse/analysis).
771 14400 (int) elem->next, c54ba27Row pattern recognition patch (parse/analysis).
772 14400 (int) elem->jump); c54ba27Row pattern recognition patch (parse/analysis).
773 - } c54ba27Row pattern recognition patch (parse/analysis).
774 - } c54ba27Row pattern recognition patch (parse/analysis).
775 - else c54ba27Row pattern recognition patch (parse/analysis).
776 0 appendStringInfoString(str, " <>"); c54ba27Row pattern recognition patch (parse/analysis).
UnreachableDefensive (unreachable) · confidence high · _outRPRPattern @776
Reason
CONFIRMED unreachable from any SQL/regression input.
The else at outfuncs.c:776 emits " <>" only when (node->numElements <= 0 || node->elements == NULL).
The sole RPRPattern producer is makeRPRPattern() in optimizer/plan/rpr.c (only makeNode(RPRPattern) besides the mechanical copyfuncs.c copy).
It Asserts numElements >= 2 (rpr.c:1149) and unconditionally palloc0's the elements array (rpr.c:1150). numElements is computed by scanRPRPattern(), which always adds +1 for the FIN marker (rpr.c:1110) on top of >= 1 VAR element (every RPR_PATTERN_VAR leaf does (*numElements)++ at rpr.c:1030;
a valid
PATTERN must contain at least one variable).
So numElements is always >= 2 and elements is never NULL for any serialized node. copyfuncs.c preserves these fields verbatim under -DCOPY_PARSE_PLAN_TREES, so the COPY/WRITE_READ path cannot zero them either.
I attempted to refute by searching for any path that sets numElements<=0 or elements=NULL on a live node and found none.
Note: the claim cited reader line 647;
the actual reader else is readfuncs.c:645-648 (and the array loop is 599-644) -- minor line-number drift, substance is correct.
Recommended fix
Since makeRPRPattern guarantees numElements >= 2 and elements != NULL, replace the runtime if/else with an unconditional array write guarded by an assertion: add Assert(node->numElements > 0 && node->elements != NULL);
before the loop, drop the if-condition and the else that emits " <>".
Keep the reader in sync by removing the corresponding else (readfuncs.c:645-648) and the "token[0] == '('" / "numElements > 0" guard at readfuncs.c:601, since the writer will always emit '('.
Alternatively, if maximum robustness under WRITE_READ_PARSE_PLAN_TREES is preferred, leave both branches as-is and simply annotate line 776 as defensive (e.g., exclude from coverage), since the cost of the dead branch is negligible and it hardens against future producers.
777 - c54ba27Row pattern recognition patch (parse/analysis).
778 4848 WRITE_BOOL_FIELD(isAbsorbable); c54ba27Row pattern recognition patch (parse/analysis).
779 2980 } c54ba27Row pattern recognition patch (parse/analysis).