| Line | Hits | Source | Commit |
|---|---|---|---|
| 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). |
UnreachableReason 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). |
UnreachableReason 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). |