| Line | Hits | Source | Commit |
|---|---|---|---|
| 105 | 1910 | rprPatternEqual(RPRPatternNode *a, RPRPatternNode *b) | 7521a30Row pattern recognition patch (planner). |
| 106 | - | { | 7521a30Row pattern recognition patch (planner). |
| 107 | - | /* Pattern nodes in children lists must never be NULL */ | 7521a30Row pattern recognition patch (planner). |
| 108 | 1910 | Assert(a != NULL && b != NULL); | 7521a30Row pattern recognition patch (planner). |
| 109 | - | 7521a30Row pattern recognition patch (planner). | |
| 110 | - | /* Must have same node type and quantifiers */ | 7521a30Row pattern recognition patch (planner). |
| 111 | 1910 | if (a->nodeType != b->nodeType) | 7521a30Row pattern recognition patch (planner). |
| 112 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 113 | 1605 | if (a->min != b->min || a->max != b->max) | 7521a30Row pattern recognition patch (planner). |
| 114 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 115 | 1510 | if (a->reluctant != b->reluctant) | 7521a30Row pattern recognition patch (planner). |
| 116 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 117 | - | 7521a30Row pattern recognition patch (planner). | |
| 118 | 1505 | switch (a->nodeType) | 7521a30Row pattern recognition patch (planner). |
| 119 | - | { | 7521a30Row pattern recognition patch (planner). |
| 120 | 1345 | case RPR_PATTERN_VAR: | 7521a30Row pattern recognition patch (planner). |
| 121 | 1345 | return strcmp(a->varName, b->varName) == 0; | 7521a30Row pattern recognition patch (planner). |
| 122 | - | 7521a30Row pattern recognition patch (planner). | |
| 123 | 160 | case RPR_PATTERN_SEQ: | 7521a30Row pattern recognition patch (planner). |
| 124 | - | case RPR_PATTERN_ALT: | 7521a30Row pattern recognition patch (planner). |
| 125 | - | case RPR_PATTERN_GROUP: | 7521a30Row pattern recognition patch (planner). |
| 126 | 160 | return rprPatternChildrenEqual(a->children, b->children); | 7521a30Row pattern recognition patch (planner). |
| 127 | - | } | 7521a30Row pattern recognition patch (planner). |
| 128 | - | 7521a30Row pattern recognition patch (planner). | |
| 129 | 0 | pg_unreachable(); | 7521a30Row pattern recognition patch (planner). |
UnreachableReason Confirmed defensive-unreachable. RPRPatternNodeType (parsenodes.h:615-621) has exactly four values: RPR_PATTERN_VAR, RPR_PATTERN_SEQ, RPR_PATTERN_ALT, RPR_PATTERN_GROUP. The switch at rpr.c:118-127 handles all four and every case ends in a return (VAR returns strcmp; SEQ/ALT/GROUP share the rprPatternChildrenEqual return). Control therefore can never fall through to pg_unreachable() at line 129. Every assignment to ->nodeType in the backend (gram.y:17652/17684/17713/17726/21425/21484) uses one of the four valid constants, set only by the grammar; nothing can inject a fifth value, and the node tree is never constructed with an uninitialized nodeType reachable from SQL. The two early-return guards (a->nodeType != b->nodeType, etc.) further mean a is always inspected with a valid value. No SQL or regression input can drive line 129. The claim's root cause is accurate.Recommended fix Keep as-is. pg_unreachable() is the standard PostgreSQL idiom for an exhaustive enum switch and correctly documents that control cannot reach here. Optionally the trailing "return false; " is only present to satisfy compilers that do not treat pg_unreachable() as noreturn; no functional change is warranted. No source change needed. | |||
| 130 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 131 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 140 | 535 | rprPatternChildrenEqual(List *a, List *b) | 7521a30Row pattern recognition patch (planner). |
| 141 | - | { | 7521a30Row pattern recognition patch (planner). |
| 142 | 535 | ListCell *lca, | 7521a30Row pattern recognition patch (planner). |
| 143 | - | *lcb; | 7521a30Row pattern recognition patch (planner). |
| 144 | - | 7521a30Row pattern recognition patch (planner). | |
| 145 | 1605 | if (list_length(a) != list_length(b)) | 7521a30Row pattern recognition patch (planner). |
| 146 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 147 | - | 7521a30Row pattern recognition patch (planner). | |
| 148 | 960 | forboth(lca, a, lcb, b) | 7521a30Row pattern recognition patch (planner). |
| 149 | - | { | 7521a30Row pattern recognition patch (planner). |
| 150 | 690 | if (!rprPatternEqual((RPRPatternNode *) lfirst(lca), | 7521a30Row pattern recognition patch (planner). |
| 151 | 690 | (RPRPatternNode *) lfirst(lcb))) | 7521a30Row pattern recognition patch (planner). |
| 152 | 185 | return false; | 7521a30Row pattern recognition patch (planner). |
| 153 | - | } | 7521a30Row pattern recognition patch (planner). |
| 154 | - | 7521a30Row pattern recognition patch (planner). | |
| 155 | 270 | return true; | 7521a30Row pattern recognition patch (planner). |
| 156 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 171 | 3655 | tryUnwrapSingleChild(RPRPatternNode *pattern) | 7521a30Row pattern recognition patch (planner). |
| 172 | - | { | 7521a30Row pattern recognition patch (planner). |
| 173 | 3655 | if (list_length(pattern->children) == 1) | 7521a30Row pattern recognition patch (planner). |
| 174 | 145 | return (RPRPatternNode *) linitial(pattern->children); | 7521a30Row pattern recognition patch (planner). |
| 175 | - | 7521a30Row pattern recognition patch (planner). | |
| 176 | - | return pattern; | 7521a30Row pattern recognition patch (planner). |
| 177 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 190 | 2745 | flattenSeqChildren(List *children) | 7521a30Row pattern recognition patch (planner). |
| 191 | - | { | 7521a30Row pattern recognition patch (planner). |
| 192 | 2745 | List *newChildren = NIL; | 7521a30Row pattern recognition patch (planner). |
| 193 | - | 7521a30Row pattern recognition patch (planner). | |
| 194 | 10490 | foreach_node(RPRPatternNode, child, children) | 7521a30Row pattern recognition patch (planner). |
| 195 | - | { | 7521a30Row pattern recognition patch (planner). |
| 196 | 7745 | RPRPatternNode *opt = optimizeRPRPattern(child); | 7521a30Row pattern recognition patch (planner). |
| 197 | - | 7521a30Row pattern recognition patch (planner). | |
| 198 | - | /* GROUP{1,1} should have been unwrapped by optimizeGroupPattern */ | 7521a30Row pattern recognition patch (planner). |
| 199 | 7745 | Assert(!(opt->nodeType == RPR_PATTERN_GROUP && | 7521a30Row pattern recognition patch (planner). |
| 200 | - | opt->min == 1 && opt->max == 1 && opt->reluctant == false)); | 7521a30Row pattern recognition patch (planner). |
| 201 | - | 7521a30Row pattern recognition patch (planner). | |
| 202 | 7745 | if (opt->nodeType == RPR_PATTERN_SEQ) | 7521a30Row pattern recognition patch (planner). |
| 203 | - | { | 7521a30Row pattern recognition patch (planner). |
| 204 | 50 | newChildren = list_concat(newChildren, | 7521a30Row pattern recognition patch (planner). |
| 205 | 50 | list_copy(opt->children)); | 7521a30Row pattern recognition patch (planner). |
| 206 | - | } | 7521a30Row pattern recognition patch (planner). |
| 207 | - | else | 7521a30Row pattern recognition patch (planner). |
| 208 | - | { | 7521a30Row pattern recognition patch (planner). |
| 209 | 7695 | newChildren = lappend(newChildren, opt); | 7521a30Row pattern recognition patch (planner). |
| 210 | - | } | 7521a30Row pattern recognition patch (planner). |
| 211 | - | } | 7521a30Row pattern recognition patch (planner). |
| 212 | - | 7521a30Row pattern recognition patch (planner). | |
| 213 | 2745 | return newChildren; | 7521a30Row pattern recognition patch (planner). |
| 214 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 226 | 2745 | mergeConsecutiveVars(List *children) | 7521a30Row pattern recognition patch (planner). |
| 227 | - | { | 7521a30Row pattern recognition patch (planner). |
| 228 | 2745 | List *mergedChildren = NIL; | 7521a30Row pattern recognition patch (planner). |
| 229 | 2745 | RPRPatternNode *prev = NULL; | 7521a30Row pattern recognition patch (planner). |
| 230 | - | 7521a30Row pattern recognition patch (planner). | |
| 231 | 10540 | foreach_node(RPRPatternNode, child, children) | 7521a30Row pattern recognition patch (planner). |
| 232 | - | { | 7521a30Row pattern recognition patch (planner). |
| 233 | 7795 | if (child->nodeType == RPR_PATTERN_VAR && child->reluctant == false) | 7521a30Row pattern recognition patch (planner). |
| 234 | - | { | 7521a30Row pattern recognition patch (planner). |
| 235 | - | /* ---------------------- | 7521a30Row pattern recognition patch (planner). |
| 236 | - | * Can merge consecutive VAR nodes if: | 7521a30Row pattern recognition patch (planner). |
| 237 | - | * 1. Same variable name | 7521a30Row pattern recognition patch (planner). |
| 238 | - | * 2. No min overflow: prev->min + child->min < INF | 7521a30Row pattern recognition patch (planner). |
| 239 | - | * 3. No max overflow: prev->max + child->max < INF (or either is INF) | 7521a30Row pattern recognition patch (planner). |
| 240 | - | * | 7521a30Row pattern recognition patch (planner). |
| 241 | - | * Strict <: a sum equal to INF would alias the unbounded sentinel | 7521a30Row pattern recognition patch (planner). |
| 242 | - | * (min must stay finite; a finite max must not become INF). | 7521a30Row pattern recognition patch (planner). |
| 243 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 244 | 6920 | if (prev != NULL && | 7521a30Row pattern recognition patch (planner). |
| 245 | 4175 | strcmp(prev->varName, child->varName) == 0 && | 7521a30Row pattern recognition patch (planner). |
| 246 | 125 | prev->min < RPR_QUANTITY_INF - child->min && | 7521a30Row pattern recognition patch (planner). |
| 247 | 120 | (prev->max < RPR_QUANTITY_INF - child->max || | 7521a30Row pattern recognition patch (planner). |
| 248 | 10 | prev->max == RPR_QUANTITY_INF || | 7521a30Row pattern recognition patch (planner). |
| 249 | - | child->max == RPR_QUANTITY_INF)) | 7521a30Row pattern recognition patch (planner). |
| 250 | - | { | 7521a30Row pattern recognition patch (planner). |
| 251 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 252 | - | * Merge: accumulate min/max into prev. prev is guaranteed to | 7521a30Row pattern recognition patch (planner). |
| 253 | - | * be a non-reluctant VAR by the outer condition. | 7521a30Row pattern recognition patch (planner). |
| 254 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 255 | 120 | Assert(prev->nodeType == RPR_PATTERN_VAR && prev->reluctant == false); | 7521a30Row pattern recognition patch (planner). |
| 256 | - | 7521a30Row pattern recognition patch (planner). | |
| 257 | 120 | prev->min += child->min; | 7521a30Row pattern recognition patch (planner). |
| 258 | - | 7521a30Row pattern recognition patch (planner). | |
| 259 | 120 | if (prev->max == RPR_QUANTITY_INF || | 7521a30Row pattern recognition patch (planner). |
| 260 | 95 | child->max == RPR_QUANTITY_INF) | 7521a30Row pattern recognition patch (planner). |
| 261 | 35 | prev->max = RPR_QUANTITY_INF; | 7521a30Row pattern recognition patch (planner). |
| 262 | - | else | 7521a30Row pattern recognition patch (planner). |
| 263 | 85 | prev->max += child->max; | 7521a30Row pattern recognition patch (planner). |
| 264 | - | } | 7521a30Row pattern recognition patch (planner). |
| 265 | - | else | 7521a30Row pattern recognition patch (planner). |
| 266 | - | { | 7521a30Row pattern recognition patch (planner). |
| 267 | - | /* Flush previous and start new */ | 7521a30Row pattern recognition patch (planner). |
| 268 | - | if (prev != NULL) | 7521a30Row pattern recognition patch (planner). |
| 269 | 4055 | mergedChildren = lappend(mergedChildren, prev); | 7521a30Row pattern recognition patch (planner). |
| 270 | - | prev = child; | 7521a30Row pattern recognition patch (planner). |
| 271 | - | } | 7521a30Row pattern recognition patch (planner). |
| 272 | - | } | 7521a30Row pattern recognition patch (planner). |
| 273 | - | else | 7521a30Row pattern recognition patch (planner). |
| 274 | - | { | 7521a30Row pattern recognition patch (planner). |
| 275 | - | /* Non-mergeable - flush previous */ | 7521a30Row pattern recognition patch (planner). |
| 276 | 875 | if (prev != NULL) | 7521a30Row pattern recognition patch (planner). |
| 277 | 270 | mergedChildren = lappend(mergedChildren, prev); | 7521a30Row pattern recognition patch (planner). |
| 278 | 875 | mergedChildren = lappend(mergedChildren, child); | 7521a30Row pattern recognition patch (planner). |
| 279 | - | prev = NULL; | 7521a30Row pattern recognition patch (planner). |
| 280 | - | } | 7521a30Row pattern recognition patch (planner). |
| 281 | - | } | 7521a30Row pattern recognition patch (planner). |
| 282 | - | 7521a30Row pattern recognition patch (planner). | |
| 283 | - | /* Flush remaining */ | 7521a30Row pattern recognition patch (planner). |
| 284 | 2745 | if (prev != NULL) | 7521a30Row pattern recognition patch (planner). |
| 285 | 2475 | mergedChildren = lappend(mergedChildren, prev); | 7521a30Row pattern recognition patch (planner). |
| 286 | - | 7521a30Row pattern recognition patch (planner). | |
| 287 | 2745 | return mergedChildren; | 7521a30Row pattern recognition patch (planner). |
| 288 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 300 | 2745 | mergeConsecutiveGroups(List *children) | 7521a30Row pattern recognition patch (planner). |
| 301 | - | { | 7521a30Row pattern recognition patch (planner). |
| 302 | 2745 | List *mergedChildren = NIL; | 7521a30Row pattern recognition patch (planner). |
| 303 | 2745 | RPRPatternNode *prev = NULL; | 7521a30Row pattern recognition patch (planner). |
| 304 | - | 7521a30Row pattern recognition patch (planner). | |
| 305 | 10420 | foreach_node(RPRPatternNode, child, children) | 7521a30Row pattern recognition patch (planner). |
| 306 | - | { | 7521a30Row pattern recognition patch (planner). |
| 307 | 7675 | if (child->nodeType == RPR_PATTERN_GROUP && child->reluctant == false) | 7521a30Row pattern recognition patch (planner). |
| 308 | - | { | 7521a30Row pattern recognition patch (planner). |
| 309 | - | /* ---------------------- | 7521a30Row pattern recognition patch (planner). |
| 310 | - | * Can merge consecutive GROUP nodes if: | 7521a30Row pattern recognition patch (planner). |
| 311 | - | * 1. Identical children | 7521a30Row pattern recognition patch (planner). |
| 312 | - | * 2. No min overflow: prev->min + child->min < INF | 7521a30Row pattern recognition patch (planner). |
| 313 | - | * 3. No max overflow: prev->max + child->max < INF (or either is INF) | 7521a30Row pattern recognition patch (planner). |
| 314 | - | * | 7521a30Row pattern recognition patch (planner). |
| 315 | - | * Strict <: a sum equal to INF would alias the unbounded sentinel | 7521a30Row pattern recognition patch (planner). |
| 316 | - | * (min must stay finite; a finite max must not become INF). | 7521a30Row pattern recognition patch (planner). |
| 317 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 318 | 385 | if (prev != NULL && | 7521a30Row pattern recognition patch (planner). |
| 319 | 40 | rprPatternChildrenEqual(prev->children, child->children) && | 7521a30Row pattern recognition patch (planner). |
| 320 | 25 | prev->min < RPR_QUANTITY_INF - child->min && | 7521a30Row pattern recognition patch (planner). |
| 321 | 20 | (prev->max < RPR_QUANTITY_INF - child->max || | 7521a30Row pattern recognition patch (planner). |
| 322 | 5 | prev->max == RPR_QUANTITY_INF || | 7521a30Row pattern recognition patch (planner). |
| 323 | - | child->max == RPR_QUANTITY_INF)) | 7521a30Row pattern recognition patch (planner). |
| 324 | - | { | 7521a30Row pattern recognition patch (planner). |
| 325 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 326 | - | * Merge: accumulate min/max into prev. prev is guaranteed to | 7521a30Row pattern recognition patch (planner). |
| 327 | - | * be a non-reluctant GROUP by the outer condition. | 7521a30Row pattern recognition patch (planner). |
| 328 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 329 | 20 | Assert(prev->nodeType == RPR_PATTERN_GROUP && prev->reluctant == false); | 7521a30Row pattern recognition patch (planner). |
| 330 | - | 7521a30Row pattern recognition patch (planner). | |
| 331 | 20 | prev->min += child->min; | 7521a30Row pattern recognition patch (planner). |
| 332 | - | 7521a30Row pattern recognition patch (planner). | |
| 333 | 20 | if (prev->max == RPR_QUANTITY_INF || | 7521a30Row pattern recognition patch (planner). |
| 334 | 10 | child->max == RPR_QUANTITY_INF) | 7521a30Row pattern recognition patch (planner). |
| 335 | 15 | prev->max = RPR_QUANTITY_INF; | 7521a30Row pattern recognition patch (planner). |
| 336 | - | else | 7521a30Row pattern recognition patch (planner). |
| 337 | 5 | prev->max += child->max; | 7521a30Row pattern recognition patch (planner). |
| 338 | - | } | 7521a30Row pattern recognition patch (planner). |
| 339 | - | else | 7521a30Row pattern recognition patch (planner). |
| 340 | - | { | 7521a30Row pattern recognition patch (planner). |
| 341 | - | /* Flush previous and start new */ | 7521a30Row pattern recognition patch (planner). |
| 342 | - | if (prev != NULL) | 7521a30Row pattern recognition patch (planner). |
| 343 | 20 | mergedChildren = lappend(mergedChildren, prev); | 7521a30Row pattern recognition patch (planner). |
| 344 | - | prev = child; | 7521a30Row pattern recognition patch (planner). |
| 345 | - | } | 7521a30Row pattern recognition patch (planner). |
| 346 | - | } | 7521a30Row pattern recognition patch (planner). |
| 347 | - | else | 7521a30Row pattern recognition patch (planner). |
| 348 | - | { | 7521a30Row pattern recognition patch (planner). |
| 349 | - | /* Non-mergeable - flush previous */ | 7521a30Row pattern recognition patch (planner). |
| 350 | 7330 | if (prev != NULL) | 7521a30Row pattern recognition patch (planner). |
| 351 | 190 | mergedChildren = lappend(mergedChildren, prev); | 7521a30Row pattern recognition patch (planner). |
| 352 | 7330 | mergedChildren = lappend(mergedChildren, child); | 7521a30Row pattern recognition patch (planner). |
| 353 | - | prev = NULL; | 7521a30Row pattern recognition patch (planner). |
| 354 | - | } | 7521a30Row pattern recognition patch (planner). |
| 355 | - | } | 7521a30Row pattern recognition patch (planner). |
| 356 | - | 7521a30Row pattern recognition patch (planner). | |
| 357 | - | /* Flush remaining */ | 7521a30Row pattern recognition patch (planner). |
| 358 | 2745 | if (prev != NULL) | 7521a30Row pattern recognition patch (planner). |
| 359 | 115 | mergedChildren = lappend(mergedChildren, prev); | 7521a30Row pattern recognition patch (planner). |
| 360 | - | 7521a30Row pattern recognition patch (planner). | |
| 361 | 2745 | return mergedChildren; | 7521a30Row pattern recognition patch (planner). |
| 362 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 376 | 2745 | mergeConsecutiveAlts(List *children) | 7521a30Row pattern recognition patch (planner). |
| 377 | - | { | 7521a30Row pattern recognition patch (planner). |
| 378 | 2745 | List *mergedChildren = NIL; | 7521a30Row pattern recognition patch (planner). |
| 379 | 2745 | RPRPatternNode *prev = NULL; | 7521a30Row pattern recognition patch (planner). |
| 380 | 2745 | int count = 0; | 7521a30Row pattern recognition patch (planner). |
| 381 | - | 7521a30Row pattern recognition patch (planner). | |
| 382 | 10400 | foreach_node(RPRPatternNode, child, children) | 7521a30Row pattern recognition patch (planner). |
| 383 | - | { | 7521a30Row pattern recognition patch (planner). |
| 384 | 7655 | if (child->nodeType == RPR_PATTERN_ALT && child->reluctant == false) | 7521a30Row pattern recognition patch (planner). |
| 385 | - | { | 7521a30Row pattern recognition patch (planner). |
| 386 | 540 | if (prev != NULL && | 7521a30Row pattern recognition patch (planner). |
| 387 | 120 | rprPatternChildrenEqual(prev->children, child->children)) | 7521a30Row pattern recognition patch (planner). |
| 388 | - | { | 7521a30Row pattern recognition patch (planner). |
| 389 | - | /* Same ALT as prev - accumulate */ | 7521a30Row pattern recognition patch (planner). |
| 390 | 80 | count++; | 7521a30Row pattern recognition patch (planner). |
| 391 | - | } | 7521a30Row pattern recognition patch (planner). |
| 392 | - | else | 7521a30Row pattern recognition patch (planner). |
| 393 | - | { | 7521a30Row pattern recognition patch (planner). |
| 394 | - | /* Different ALT or first ALT - flush previous */ | 7521a30Row pattern recognition patch (planner). |
| 395 | 40 | if (prev != NULL) | 7521a30Row pattern recognition patch (planner). |
| 396 | - | { | 7521a30Row pattern recognition patch (planner). |
| 397 | 40 | if (count > 1) | 7521a30Row pattern recognition patch (planner). |
| 398 | - | { | 7521a30Row pattern recognition patch (planner). |
| 399 | - | /* Wrap in GROUP{count,count}(ALT) */ | 7521a30Row pattern recognition patch (planner). |
| 400 | 5 | RPRPatternNode *group = makeNode(RPRPatternNode); | 7521a30Row pattern recognition patch (planner). |
| 401 | - | 7521a30Row pattern recognition patch (planner). | |
| 402 | 5 | group->nodeType = RPR_PATTERN_GROUP; | 7521a30Row pattern recognition patch (planner). |
| 403 | 5 | group->min = count; | 7521a30Row pattern recognition patch (planner). |
| 404 | 5 | group->max = count; | 7521a30Row pattern recognition patch (planner). |
| 405 | 5 | group->reluctant = false; | 7521a30Row pattern recognition patch (planner). |
| 406 | 5 | group->location = -1; | 7521a30Row pattern recognition patch (planner). |
| 407 | 5 | group->children = list_make1(prev); | 7521a30Row pattern recognition patch (planner). |
| 408 | 5 | mergedChildren = lappend(mergedChildren, group); | 7521a30Row pattern recognition patch (planner). |
| 409 | - | } | 7521a30Row pattern recognition patch (planner). |
| 410 | - | else | 7521a30Row pattern recognition patch (planner). |
| 411 | 35 | mergedChildren = lappend(mergedChildren, prev); | 7521a30Row pattern recognition patch (planner). |
| 412 | - | } | 7521a30Row pattern recognition patch (planner). |
| 413 | - | prev = child; | 7521a30Row pattern recognition patch (planner). |
| 414 | - | count = 1; | 7521a30Row pattern recognition patch (planner). |
| 415 | - | } | 7521a30Row pattern recognition patch (planner). |
| 416 | - | } | 7521a30Row pattern recognition patch (planner). |
| 417 | - | else | 7521a30Row pattern recognition patch (planner). |
| 418 | - | { | 7521a30Row pattern recognition patch (planner). |
| 419 | - | /* Non-ALT - flush previous */ | 7521a30Row pattern recognition patch (planner). |
| 420 | 7235 | if (prev != NULL) | 7521a30Row pattern recognition patch (planner). |
| 421 | - | { | 7521a30Row pattern recognition patch (planner). |
| 422 | 160 | if (count > 1) | 7521a30Row pattern recognition patch (planner). |
| 423 | - | { | 7521a30Row pattern recognition patch (planner). |
| 424 | 5 | RPRPatternNode *group = makeNode(RPRPatternNode); | 7521a30Row pattern recognition patch (planner). |
| 425 | - | 7521a30Row pattern recognition patch (planner). | |
| 426 | 5 | group->nodeType = RPR_PATTERN_GROUP; | 7521a30Row pattern recognition patch (planner). |
| 427 | 5 | group->min = count; | 7521a30Row pattern recognition patch (planner). |
| 428 | 5 | group->max = count; | 7521a30Row pattern recognition patch (planner). |
| 429 | 5 | group->reluctant = false; | 7521a30Row pattern recognition patch (planner). |
| 430 | 5 | group->location = -1; | 7521a30Row pattern recognition patch (planner). |
| 431 | 5 | group->children = list_make1(prev); | 7521a30Row pattern recognition patch (planner). |
| 432 | 5 | mergedChildren = lappend(mergedChildren, group); | 7521a30Row pattern recognition patch (planner). |
| 433 | - | } | 7521a30Row pattern recognition patch (planner). |
| 434 | - | else | 7521a30Row pattern recognition patch (planner). |
| 435 | 155 | mergedChildren = lappend(mergedChildren, prev); | 7521a30Row pattern recognition patch (planner). |
| 436 | - | } | 7521a30Row pattern recognition patch (planner). |
| 437 | 7235 | mergedChildren = lappend(mergedChildren, child); | 7521a30Row pattern recognition patch (planner). |
| 438 | - | prev = NULL; | 7521a30Row pattern recognition patch (planner). |
| 439 | - | count = 0; | 7521a30Row pattern recognition patch (planner). |
| 440 | - | } | 7521a30Row pattern recognition patch (planner). |
| 441 | - | } | 7521a30Row pattern recognition patch (planner). |
| 442 | - | 7521a30Row pattern recognition patch (planner). | |
| 443 | - | /* Flush remaining */ | 7521a30Row pattern recognition patch (planner). |
| 444 | 2745 | if (prev != NULL) | 7521a30Row pattern recognition patch (planner). |
| 445 | - | { | 7521a30Row pattern recognition patch (planner). |
| 446 | 140 | if (count > 1) | 7521a30Row pattern recognition patch (planner). |
| 447 | - | { | 7521a30Row pattern recognition patch (planner). |
| 448 | 10 | RPRPatternNode *group = makeNode(RPRPatternNode); | 7521a30Row pattern recognition patch (planner). |
| 449 | - | 7521a30Row pattern recognition patch (planner). | |
| 450 | 10 | group->nodeType = RPR_PATTERN_GROUP; | 7521a30Row pattern recognition patch (planner). |
| 451 | 10 | group->min = count; | 7521a30Row pattern recognition patch (planner). |
| 452 | 10 | group->max = count; | 7521a30Row pattern recognition patch (planner). |
| 453 | 10 | group->reluctant = false; | 7521a30Row pattern recognition patch (planner). |
| 454 | 10 | group->location = -1; | 7521a30Row pattern recognition patch (planner). |
| 455 | 10 | group->children = list_make1(prev); | 7521a30Row pattern recognition patch (planner). |
| 456 | 10 | mergedChildren = lappend(mergedChildren, group); | 7521a30Row pattern recognition patch (planner). |
| 457 | - | } | 7521a30Row pattern recognition patch (planner). |
| 458 | - | else | 7521a30Row pattern recognition patch (planner). |
| 459 | 130 | mergedChildren = lappend(mergedChildren, prev); | 7521a30Row pattern recognition patch (planner). |
| 460 | - | } | 7521a30Row pattern recognition patch (planner). |
| 461 | - | 7521a30Row pattern recognition patch (planner). | |
| 462 | 2745 | return mergedChildren; | 7521a30Row pattern recognition patch (planner). |
| 463 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 488 | 2745 | mergeGroupPrefixSuffix(List *children) | 7521a30Row pattern recognition patch (planner). |
| 489 | - | { | 7521a30Row pattern recognition patch (planner). |
| 490 | 2745 | List *result = NIL; | 7521a30Row pattern recognition patch (planner). |
| 491 | 2745 | int numChildren = list_length(children); | 7521a30Row pattern recognition patch (planner). |
| 492 | 2745 | int i; | 7521a30Row pattern recognition patch (planner). |
| 493 | 2745 | int skipUntil = -1; /* skip suffix elements already merged */ | 7521a30Row pattern recognition patch (planner). |
| 494 | - | 7521a30Row pattern recognition patch (planner). | |
| 495 | 10210 | for (i = 0; i < numChildren; i++) | 7521a30Row pattern recognition patch (planner). |
| 496 | - | { | 7521a30Row pattern recognition patch (planner). |
| 497 | 7465 | RPRPatternNode *child = (RPRPatternNode *) list_nth(children, i); | 7521a30Row pattern recognition patch (planner). |
| 498 | - | 7521a30Row pattern recognition patch (planner). | |
| 499 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 500 | - | * The suffix merge logic below adjusts i to skip merged elements, | 7521a30Row pattern recognition patch (planner). |
| 501 | - | * ensuring we never revisit them. Verify this invariant. | 7521a30Row pattern recognition patch (planner). |
| 502 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 503 | 7465 | Assert(i >= skipUntil); | 7521a30Row pattern recognition patch (planner). |
| 504 | - | 7521a30Row pattern recognition patch (planner). | |
| 505 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 506 | - | * If this is a GROUP, see if preceding/following elements match its | 7521a30Row pattern recognition patch (planner). |
| 507 | - | * children. GROUP's content may be wrapped in a SEQ - unwrap for | 7521a30Row pattern recognition patch (planner). |
| 508 | - | * comparison. | 7521a30Row pattern recognition patch (planner). |
| 509 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 510 | 7465 | if (child->nodeType == RPR_PATTERN_GROUP && child->reluctant == false) | 7521a30Row pattern recognition patch (planner). |
| 511 | - | { | 7521a30Row pattern recognition patch (planner). |
| 512 | 345 | List *groupContent = child->children; | 7521a30Row pattern recognition patch (planner). |
| 513 | 345 | int groupChildCount; | 7521a30Row pattern recognition patch (planner). |
| 514 | 345 | int prefixLen = list_length(result); | 7521a30Row pattern recognition patch (planner). |
| 515 | 345 | List *trimmed; | 7521a30Row pattern recognition patch (planner). |
| 516 | - | 7521a30Row pattern recognition patch (planner). | |
| 517 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 518 | - | * If GROUP has single SEQ child, compare with SEQ's children. | 7521a30Row pattern recognition patch (planner). |
| 519 | - | * e.g., (A B)+ internally contains sequence A B; compare against | 7521a30Row pattern recognition patch (planner). |
| 520 | - | * that. | 7521a30Row pattern recognition patch (planner). |
| 521 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 522 | 345 | if (list_length(groupContent) == 1) | 7521a30Row pattern recognition patch (planner). |
| 523 | - | { | 7521a30Row pattern recognition patch (planner). |
| 524 | 345 | RPRPatternNode *inner = (RPRPatternNode *) linitial(groupContent); | 7521a30Row pattern recognition patch (planner). |
| 525 | - | 7521a30Row pattern recognition patch (planner). | |
| 526 | 345 | if (inner->nodeType == RPR_PATTERN_SEQ) | 7521a30Row pattern recognition patch (planner). |
| 527 | 260 | groupContent = inner->children; | 7521a30Row pattern recognition patch (planner). |
| 528 | - | } | 7521a30Row pattern recognition patch (planner). |
| 529 | - | 7521a30Row pattern recognition patch (planner). | |
| 530 | 345 | groupChildCount = list_length(groupContent); | 7521a30Row pattern recognition patch (planner). |
| 531 | - | 7521a30Row pattern recognition patch (planner). | |
| 532 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 533 | - | * PREFIX MERGE: Check if preceding elements match. Keep merging | 7521a30Row pattern recognition patch (planner). |
| 534 | - | * as long as we have matching prefixes. | 7521a30Row pattern recognition patch (planner). |
| 535 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 536 | 405 | while (prefixLen >= groupChildCount && groupChildCount > 0) | 7521a30Row pattern recognition patch (planner). |
| 537 | - | { | 7521a30Row pattern recognition patch (planner). |
| 538 | 95 | List *prefixElements = NIL; | 7521a30Row pattern recognition patch (planner). |
| 539 | 95 | int j; | 7521a30Row pattern recognition patch (planner). |
| 540 | - | 7521a30Row pattern recognition patch (planner). | |
| 541 | - | /* Extract last groupChildCount elements from prefix */ | 7521a30Row pattern recognition patch (planner). |
| 542 | 265 | for (j = prefixLen - groupChildCount; j < prefixLen; j++) | 7521a30Row pattern recognition patch (planner). |
| 543 | - | { | 7521a30Row pattern recognition patch (planner). |
| 544 | 170 | prefixElements = lappend(prefixElements, | 7521a30Row pattern recognition patch (planner). |
| 545 | - | list_nth(result, j)); | 7521a30Row pattern recognition patch (planner). |
| 546 | - | } | 7521a30Row pattern recognition patch (planner). |
| 547 | - | 7521a30Row pattern recognition patch (planner). | |
| 548 | - | /* Compare with GROUP's (possibly unwrapped) children */ | 7521a30Row pattern recognition patch (planner). |
| 549 | 95 | if (rprPatternChildrenEqual(prefixElements, groupContent) && | 7521a30Row pattern recognition patch (planner). |
| 550 | 60 | child->min < RPR_QUANTITY_INF - 1 && | 7521a30Row pattern recognition patch (planner). |
| 551 | 60 | (child->max == RPR_QUANTITY_INF || | 7521a30Row pattern recognition patch (planner). |
| 552 | - | child->max < RPR_QUANTITY_INF - 1)) | 7521a30Row pattern recognition patch (planner). |
| 553 | - | { | 7521a30Row pattern recognition patch (planner). |
| 554 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 555 | - | * Match! Merge by incrementing GROUP's quantifier. Remove | 7521a30Row pattern recognition patch (planner). |
| 556 | - | * the prefix elements from output. | 7521a30Row pattern recognition patch (planner). |
| 557 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 558 | 60 | child->min += 1; | 7521a30Row pattern recognition patch (planner). |
| 559 | 60 | if (child->max != RPR_QUANTITY_INF) | 7521a30Row pattern recognition patch (planner). |
| 560 | 5 | child->max += 1; | 7521a30Row pattern recognition patch (planner). |
| 561 | - | 7521a30Row pattern recognition patch (planner). | |
| 562 | - | /* Rebuild result without matched prefix */ | 7521a30Row pattern recognition patch (planner). |
| 563 | - | trimmed = NIL; | 7521a30Row pattern recognition patch (planner). |
| 564 | 85 | for (j = 0; j < prefixLen - groupChildCount; j++) | 7521a30Row pattern recognition patch (planner). |
| 565 | - | { | 7521a30Row pattern recognition patch (planner). |
| 566 | 25 | trimmed = lappend(trimmed, | 7521a30Row pattern recognition patch (planner). |
| 567 | - | list_nth(result, j)); | 7521a30Row pattern recognition patch (planner). |
| 568 | - | } | 7521a30Row pattern recognition patch (planner). |
| 569 | 60 | result = trimmed; | 7521a30Row pattern recognition patch (planner). |
| 570 | 60 | prefixLen = list_length(result); | 7521a30Row pattern recognition patch (planner). |
| 571 | - | } | 7521a30Row pattern recognition patch (planner). |
| 572 | - | else | 7521a30Row pattern recognition patch (planner). |
| 573 | - | { | 7521a30Row pattern recognition patch (planner). |
| 574 | 35 | list_free(prefixElements); | 7521a30Row pattern recognition patch (planner). |
| 575 | 35 | break; | 7521a30Row pattern recognition patch (planner). |
| 576 | - | } | 7521a30Row pattern recognition patch (planner). |
| 577 | - | 7521a30Row pattern recognition patch (planner). | |
| 578 | 60 | list_free(prefixElements); | 7521a30Row pattern recognition patch (planner). |
| 579 | - | } | 7521a30Row pattern recognition patch (planner). |
| 580 | - | 7521a30Row pattern recognition patch (planner). | |
| 581 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 582 | - | * SUFFIX MERGE: Check if following elements match. Keep merging | 7521a30Row pattern recognition patch (planner). |
| 583 | - | * as long as we have matching suffixes. | 7521a30Row pattern recognition patch (planner). |
| 584 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 585 | 405 | while (i + groupChildCount < numChildren && groupChildCount > 0) | 7521a30Row pattern recognition patch (planner). |
| 586 | - | { | 7521a30Row pattern recognition patch (planner). |
| 587 | 120 | List *suffixElements = NIL; | 7521a30Row pattern recognition patch (planner). |
| 588 | 120 | int j; | 7521a30Row pattern recognition patch (planner). |
| 589 | 120 | int suffixStart = i + 1; | 7521a30Row pattern recognition patch (planner). |
| 590 | - | 7521a30Row pattern recognition patch (planner). | |
| 591 | - | /* suffixStart always >= skipUntil after i adjustment */ | 7521a30Row pattern recognition patch (planner). |
| 592 | 120 | Assert(skipUntil <= suffixStart); | 7521a30Row pattern recognition patch (planner). |
| 593 | - | 7521a30Row pattern recognition patch (planner). | |
| 594 | - | /* Extract next groupChildCount elements as suffix */ | 7521a30Row pattern recognition patch (planner). |
| 595 | 295 | for (j = 0; j < groupChildCount; j++) | 7521a30Row pattern recognition patch (planner). |
| 596 | - | { | 7521a30Row pattern recognition patch (planner). |
| 597 | 175 | int idx = suffixStart + j; | 7521a30Row pattern recognition patch (planner). |
| 598 | - | 7521a30Row pattern recognition patch (planner). | |
| 599 | - | /* while condition guarantees idx < numChildren */ | 7521a30Row pattern recognition patch (planner). |
| 600 | 175 | Assert(idx < numChildren); | 7521a30Row pattern recognition patch (planner). |
| 601 | 175 | suffixElements = lappend(suffixElements, | 7521a30Row pattern recognition patch (planner). |
| 602 | - | list_nth(children, idx)); | 7521a30Row pattern recognition patch (planner). |
| 603 | - | } | 7521a30Row pattern recognition patch (planner). |
| 604 | - | 7521a30Row pattern recognition patch (planner). | |
| 605 | - | /* Compare with GROUP's children */ | 7521a30Row pattern recognition patch (planner). |
| 606 | 360 | if (list_length(suffixElements) == groupChildCount && | 7521a30Row pattern recognition patch (planner). |
| 607 | 120 | rprPatternChildrenEqual(suffixElements, groupContent) && | 7521a30Row pattern recognition patch (planner). |
| 608 | 60 | child->min < RPR_QUANTITY_INF - 1 && | 7521a30Row pattern recognition patch (planner). |
| 609 | 60 | (child->max == RPR_QUANTITY_INF || | 7521a30Row pattern recognition patch (planner). |
| 610 | - | child->max < RPR_QUANTITY_INF - 1)) | 7521a30Row pattern recognition patch (planner). |
| 611 | - | { | 7521a30Row pattern recognition patch (planner). |
| 612 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 613 | - | * Match! Merge suffix by incrementing quantifier and | 7521a30Row pattern recognition patch (planner). |
| 614 | - | * skipping. | 7521a30Row pattern recognition patch (planner). |
| 615 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 616 | 60 | child->min += 1; | 7521a30Row pattern recognition patch (planner). |
| 617 | 60 | if (child->max != RPR_QUANTITY_INF) | 7521a30Row pattern recognition patch (planner). |
| 618 | 5 | child->max += 1; | 7521a30Row pattern recognition patch (planner). |
| 619 | 60 | skipUntil = suffixStart + groupChildCount; | 7521a30Row pattern recognition patch (planner). |
| 620 | - | 7521a30Row pattern recognition patch (planner). | |
| 621 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 622 | - | * Update i to continue suffix check after merged elements | 7521a30Row pattern recognition patch (planner). |
| 623 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 624 | 60 | i = skipUntil - 1; | 7521a30Row pattern recognition patch (planner). |
| 625 | - | } | 7521a30Row pattern recognition patch (planner). |
| 626 | - | else | 7521a30Row pattern recognition patch (planner). |
| 627 | - | { | 7521a30Row pattern recognition patch (planner). |
| 628 | 60 | list_free(suffixElements); | 7521a30Row pattern recognition patch (planner). |
| 629 | 60 | break; | 7521a30Row pattern recognition patch (planner). |
| 630 | - | } | 7521a30Row pattern recognition patch (planner). |
| 631 | - | 7521a30Row pattern recognition patch (planner). | |
| 632 | 60 | list_free(suffixElements); | 7521a30Row pattern recognition patch (planner). |
| 633 | - | } | 7521a30Row pattern recognition patch (planner). |
| 634 | - | } | 7521a30Row pattern recognition patch (planner). |
| 635 | - | 7521a30Row pattern recognition patch (planner). | |
| 636 | 7465 | result = lappend(result, child); | 7521a30Row pattern recognition patch (planner). |
| 637 | - | } | 7521a30Row pattern recognition patch (planner). |
| 638 | - | 7521a30Row pattern recognition patch (planner). | |
| 639 | 2745 | return result; | 7521a30Row pattern recognition patch (planner). |
| 640 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 655 | 2745 | optimizeSeqPattern(RPRPatternNode *pattern) | 7521a30Row pattern recognition patch (planner). |
| 656 | - | { | 7521a30Row pattern recognition patch (planner). |
| 657 | - | /* Recursively optimize children and flatten nested SEQ/GROUP{1,1} */ | 7521a30Row pattern recognition patch (planner). |
| 658 | 2745 | pattern->children = flattenSeqChildren(pattern->children); | 7521a30Row pattern recognition patch (planner). |
| 659 | - | 7521a30Row pattern recognition patch (planner). | |
| 660 | - | /* Merge consecutive identical VAR nodes */ | 7521a30Row pattern recognition patch (planner). |
| 661 | 2745 | pattern->children = mergeConsecutiveVars(pattern->children); | 7521a30Row pattern recognition patch (planner). |
| 662 | - | 7521a30Row pattern recognition patch (planner). | |
| 663 | - | /* Merge consecutive identical GROUP nodes */ | 7521a30Row pattern recognition patch (planner). |
| 664 | 2745 | pattern->children = mergeConsecutiveGroups(pattern->children); | 7521a30Row pattern recognition patch (planner). |
| 665 | - | 7521a30Row pattern recognition patch (planner). | |
| 666 | - | /* Merge consecutive identical ALT nodes into GROUP */ | 7521a30Row pattern recognition patch (planner). |
| 667 | 2745 | pattern->children = mergeConsecutiveAlts(pattern->children); | 7521a30Row pattern recognition patch (planner). |
| 668 | - | 7521a30Row pattern recognition patch (planner). | |
| 669 | - | /* Merge prefix/suffix into GROUP with matching children */ | 7521a30Row pattern recognition patch (planner). |
| 670 | 2745 | pattern->children = mergeGroupPrefixSuffix(pattern->children); | 7521a30Row pattern recognition patch (planner). |
| 671 | - | 7521a30Row pattern recognition patch (planner). | |
| 672 | - | /* Unwrap single-item SEQ */ | 7521a30Row pattern recognition patch (planner). |
| 673 | 2745 | return tryUnwrapSingleChild(pattern); | 7521a30Row pattern recognition patch (planner). |
| 674 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 687 | 910 | flattenAltChildren(List *children) | 7521a30Row pattern recognition patch (planner). |
| 688 | - | { | 7521a30Row pattern recognition patch (planner). |
| 689 | 910 | List *newChildren = NIL; | 7521a30Row pattern recognition patch (planner). |
| 690 | - | 7521a30Row pattern recognition patch (planner). | |
| 691 | 2860 | foreach_node(RPRPatternNode, child, children) | 7521a30Row pattern recognition patch (planner). |
| 692 | - | { | 7521a30Row pattern recognition patch (planner). |
| 693 | 1950 | RPRPatternNode *opt = optimizeRPRPattern(child); | 7521a30Row pattern recognition patch (planner). |
| 694 | - | 7521a30Row pattern recognition patch (planner). | |
| 695 | 1950 | if (opt->nodeType == RPR_PATTERN_ALT) | 7521a30Row pattern recognition patch (planner). |
| 696 | 10 | newChildren = list_concat(newChildren, list_copy(opt->children)); | 7521a30Row pattern recognition patch (planner). |
| 697 | - | else | 7521a30Row pattern recognition patch (planner). |
| 698 | 1940 | newChildren = lappend(newChildren, opt); | 7521a30Row pattern recognition patch (planner). |
| 699 | - | } | 7521a30Row pattern recognition patch (planner). |
| 700 | - | 7521a30Row pattern recognition patch (planner). | |
| 701 | 910 | return newChildren; | 7521a30Row pattern recognition patch (planner). |
| 702 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 715 | 910 | removeDuplicateAlternatives(List *children) | 7521a30Row pattern recognition patch (planner). |
| 716 | - | { | 7521a30Row pattern recognition patch (planner). |
| 717 | 910 | List *uniqueChildren = NIL; | 7521a30Row pattern recognition patch (planner). |
| 718 | - | 7521a30Row pattern recognition patch (planner). | |
| 719 | 2870 | foreach_node(RPRPatternNode, child, children) | 7521a30Row pattern recognition patch (planner). |
| 720 | - | { | 7521a30Row pattern recognition patch (planner). |
| 721 | - | bool isDuplicate = false; | 7521a30Row pattern recognition patch (planner). |
| 722 | - | 7521a30Row pattern recognition patch (planner). | |
| 723 | 3160 | foreach_node(RPRPatternNode, uchild, uniqueChildren) | 7521a30Row pattern recognition patch (planner). |
| 724 | - | { | 7521a30Row pattern recognition patch (planner). |
| 725 | 1220 | if (rprPatternEqual(uchild, child)) | 7521a30Row pattern recognition patch (planner). |
| 726 | - | { | 7521a30Row pattern recognition patch (planner). |
| 727 | - | isDuplicate = true; | 7521a30Row pattern recognition patch (planner). |
| 728 | - | break; | 7521a30Row pattern recognition patch (planner). |
| 729 | - | } | 7521a30Row pattern recognition patch (planner). |
| 730 | - | } | 7521a30Row pattern recognition patch (planner). |
| 731 | - | 7521a30Row pattern recognition patch (planner). | |
| 732 | 1960 | if (!isDuplicate) | 7521a30Row pattern recognition patch (planner). |
| 733 | 1940 | uniqueChildren = lappend(uniqueChildren, child); | 7521a30Row pattern recognition patch (planner). |
| 734 | - | } | 7521a30Row pattern recognition patch (planner). |
| 735 | - | 7521a30Row pattern recognition patch (planner). | |
| 736 | 910 | return uniqueChildren; | 7521a30Row pattern recognition patch (planner). |
| 737 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 749 | 910 | optimizeAltPattern(RPRPatternNode *pattern) | 7521a30Row pattern recognition patch (planner). |
| 750 | - | { | 7521a30Row pattern recognition patch (planner). |
| 751 | - | /* Recursively optimize children and flatten nested ALT */ | 7521a30Row pattern recognition patch (planner). |
| 752 | 910 | pattern->children = flattenAltChildren(pattern->children); | 7521a30Row pattern recognition patch (planner). |
| 753 | - | 7521a30Row pattern recognition patch (planner). | |
| 754 | - | /* Remove duplicate alternatives */ | 7521a30Row pattern recognition patch (planner). |
| 755 | 910 | pattern->children = removeDuplicateAlternatives(pattern->children); | 7521a30Row pattern recognition patch (planner). |
| 756 | - | 7521a30Row pattern recognition patch (planner). | |
| 757 | - | /* Unwrap single-item ALT */ | 7521a30Row pattern recognition patch (planner). |
| 758 | 910 | return tryUnwrapSingleChild(pattern); | 7521a30Row pattern recognition patch (planner). |
| 759 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 787 | 4041 | tryMultiplyQuantifiers(RPRPatternNode *pattern) | 7521a30Row pattern recognition patch (planner). |
| 788 | - | { | 7521a30Row pattern recognition patch (planner). |
| 789 | 4041 | RPRPatternNode *child; | 7521a30Row pattern recognition patch (planner). |
| 790 | 4041 | bool safe; | 7521a30Row pattern recognition patch (planner). |
| 791 | 4041 | int64 new_min_64; | 7521a30Row pattern recognition patch (planner). |
| 792 | 4041 | int64 new_max_64; | 7521a30Row pattern recognition patch (planner). |
| 793 | - | 7521a30Row pattern recognition patch (planner). | |
| 794 | - | /* Parser always creates GROUP with exactly one child */ | 7521a30Row pattern recognition patch (planner). |
| 795 | 4041 | Assert(list_length(pattern->children) == 1); | 7521a30Row pattern recognition patch (planner). |
| 796 | - | 7521a30Row pattern recognition patch (planner). | |
| 797 | 4041 | if (pattern->reluctant) | 7521a30Row pattern recognition patch (planner). |
| 798 | - | return pattern; | 7521a30Row pattern recognition patch (planner). |
| 799 | - | 7521a30Row pattern recognition patch (planner). | |
| 800 | 1680 | child = (RPRPatternNode *) linitial(pattern->children); | 7521a30Row pattern recognition patch (planner). |
| 801 | - | 7521a30Row pattern recognition patch (planner). | |
| 802 | 1680 | if ((child->nodeType != RPR_PATTERN_VAR && | 7521a30Row pattern recognition patch (planner). |
| 803 | 410 | child->nodeType != RPR_PATTERN_GROUP) || | 7521a30Row pattern recognition patch (planner). |
| 804 | 410 | child->reluctant) | 7521a30Row pattern recognition patch (planner). |
| 805 | - | return pattern; | 7521a30Row pattern recognition patch (planner). |
| 806 | - | 7521a30Row pattern recognition patch (planner). | |
| 807 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 808 | - | * Decide whether the achievable counts form one contiguous interval. The | 7521a30Row pattern recognition patch (planner). |
| 809 | - | * child quantifier is {child->min, child->max} and the outer one is | 7521a30Row pattern recognition patch (planner). |
| 810 | - | * {pattern->min, pattern->max}; either max may be RPR_QUANTITY_INF. | 7521a30Row pattern recognition patch (planner). |
| 811 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 812 | 380 | if (pattern->min == pattern->max || child->min == 0) | 7521a30Row pattern recognition patch (planner). |
| 813 | - | safe = true; | 7521a30Row pattern recognition patch (planner). |
| 814 | - | else | 7521a30Row pattern recognition patch (planner). |
| 815 | - | { | 7521a30Row pattern recognition patch (planner). |
| 816 | 170 | bool touch; | 7521a30Row pattern recognition patch (planner). |
| 817 | 170 | bool zero_ok; | 7521a30Row pattern recognition patch (planner). |
| 818 | - | 7521a30Row pattern recognition patch (planner). | |
| 819 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 820 | - | * Consecutive intervals [t*min, t*max] and [(t+1)*min, (t+1)*max] | 7521a30Row pattern recognition patch (planner). |
| 821 | - | * touch when (t+1)*min <= t*max + 1, i.e. min <= t*(max-min) + 1. | 7521a30Row pattern recognition patch (planner). |
| 822 | - | * This is tightest at the smallest t in play, Max(pattern->min, 1). | 7521a30Row pattern recognition patch (planner). |
| 823 | - | * An unbounded child->max makes every interval reach INF, so they | 7521a30Row pattern recognition patch (planner). |
| 824 | - | * always touch. | 7521a30Row pattern recognition patch (planner). |
| 825 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 826 | 170 | if (child->max == RPR_QUANTITY_INF) | 7521a30Row pattern recognition patch (planner). |
| 827 | - | touch = true; | 7521a30Row pattern recognition patch (planner). |
| 828 | - | else | 7521a30Row pattern recognition patch (planner). |
| 829 | 100 | touch = ((int64) child->min <= | 7521a30Row pattern recognition patch (planner). |
| 830 | 100 | (int64) Max(pattern->min, 1) * (child->max - child->min) + 1); | 7521a30Row pattern recognition patch (planner). |
| 831 | - | 7521a30Row pattern recognition patch (planner). | |
| 832 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 833 | - | * A skippable outer (min 0) also needs {0} adjacent to the child | 7521a30Row pattern recognition patch (planner). |
| 834 | - | * range. | 7521a30Row pattern recognition patch (planner). |
| 835 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 836 | 170 | zero_ok = (pattern->min >= 1 || child->min <= 1); | 7521a30Row pattern recognition patch (planner). |
| 837 | - | 7521a30Row pattern recognition patch (planner). | |
| 838 | 145 | safe = touch && zero_ok; | 7521a30Row pattern recognition patch (planner). |
| 839 | - | } | 7521a30Row pattern recognition patch (planner). |
| 840 | - | 7521a30Row pattern recognition patch (planner). | |
| 841 | 145 | if (!safe) | 7521a30Row pattern recognition patch (planner). |
| 842 | - | return pattern; | 7521a30Row pattern recognition patch (planner). |
| 843 | - | 7521a30Row pattern recognition patch (planner). | |
| 844 | - | /* Flatten the child quantifier, guarding against overflow. */ | 7521a30Row pattern recognition patch (planner). |
| 845 | 305 | new_min_64 = (int64) pattern->min * child->min; | 7521a30Row pattern recognition patch (planner). |
| 846 | 305 | if (new_min_64 >= RPR_QUANTITY_INF) | 7521a30Row pattern recognition patch (planner). |
| 847 | - | return pattern; /* overflow, skip optimization */ | 7521a30Row pattern recognition patch (planner). |
| 848 | - | 7521a30Row pattern recognition patch (planner). | |
| 849 | 295 | if (pattern->max == RPR_QUANTITY_INF || child->max == RPR_QUANTITY_INF) | 7521a30Row pattern recognition patch (planner). |
| 850 | - | new_max_64 = RPR_QUANTITY_INF; | 7521a30Row pattern recognition patch (planner). |
| 851 | - | else | 7521a30Row pattern recognition patch (planner). |
| 852 | - | { | 7521a30Row pattern recognition patch (planner). |
| 853 | 145 | new_max_64 = (int64) pattern->max * child->max; | 7521a30Row pattern recognition patch (planner). |
| 854 | 145 | if (new_max_64 >= RPR_QUANTITY_INF) | 7521a30Row pattern recognition patch (planner). |
| 855 | - | return pattern; | 7521a30Row pattern recognition patch (planner). |
| 856 | - | } | 7521a30Row pattern recognition patch (planner). |
| 857 | - | 7521a30Row pattern recognition patch (planner). | |
| 858 | 290 | child->min = (int) new_min_64; | 7521a30Row pattern recognition patch (planner). |
| 859 | 290 | child->max = (int) new_max_64; | 7521a30Row pattern recognition patch (planner). |
| 860 | 290 | return child; | 7521a30Row pattern recognition patch (planner). |
| 861 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 881 | 3751 | tryUnwrapGroup(RPRPatternNode *pattern) | 7521a30Row pattern recognition patch (planner). |
| 882 | - | { | 7521a30Row pattern recognition patch (planner). |
| 883 | 3751 | RPRPatternNode *child; | 7521a30Row pattern recognition patch (planner). |
| 884 | - | 7521a30Row pattern recognition patch (planner). | |
| 885 | - | /* Parser always creates GROUP with single child */ | 7521a30Row pattern recognition patch (planner). |
| 886 | 3751 | Assert(list_length(pattern->children) == 1); | 7521a30Row pattern recognition patch (planner). |
| 887 | - | 7521a30Row pattern recognition patch (planner). | |
| 888 | 3751 | child = (RPRPatternNode *) linitial(pattern->children); | 7521a30Row pattern recognition patch (planner). |
| 889 | - | 7521a30Row pattern recognition patch (planner). | |
| 890 | - | /* GROUP{1,1}: unwrap directly (reluctant on {1,1} is meaningless) */ | 7521a30Row pattern recognition patch (planner). |
| 891 | 3751 | if (pattern->min == 1 && pattern->max == 1) | 7521a30Row pattern recognition patch (planner). |
| 892 | - | return child; | 7521a30Row pattern recognition patch (planner). |
| 893 | - | 7521a30Row pattern recognition patch (planner). | |
| 894 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 895 | - | * Single VAR child with default {1,1}: propagate GROUP's quantifier to | 7521a30Row pattern recognition patch (planner). |
| 896 | - | * the child and unwrap. E.g., (A)?? -> A??, (A)+? -> A+? | 7521a30Row pattern recognition patch (planner). |
| 897 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 898 | 3176 | if (child->nodeType == RPR_PATTERN_VAR && | 7521a30Row pattern recognition patch (planner). |
| 899 | 109 | child->min == 1 && child->max == 1 && child->reluctant == false) | 7521a30Row pattern recognition patch (planner). |
| 900 | - | { | 7521a30Row pattern recognition patch (planner). |
| 901 | 5 | child->min = pattern->min; | 7521a30Row pattern recognition patch (planner). |
| 902 | 5 | child->max = pattern->max; | 7521a30Row pattern recognition patch (planner). |
| 903 | 5 | child->reluctant = pattern->reluctant; | 7521a30Row pattern recognition patch (planner). |
| 904 | 5 | return child; | 7521a30Row pattern recognition patch (planner). |
| 905 | - | } | 7521a30Row pattern recognition patch (planner). |
| 906 | - | 7521a30Row pattern recognition patch (planner). | |
| 907 | - | return pattern; | 7521a30Row pattern recognition patch (planner). |
| 908 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 919 | 4041 | optimizeGroupPattern(RPRPatternNode *pattern) | 7521a30Row pattern recognition patch (planner). |
| 920 | - | { | 7521a30Row pattern recognition patch (planner). |
| 921 | 4041 | List *newChildren; | 7521a30Row pattern recognition patch (planner). |
| 922 | 4041 | RPRPatternNode *result; | 7521a30Row pattern recognition patch (planner). |
| 923 | - | 7521a30Row pattern recognition patch (planner). | |
| 924 | - | /* Recursively optimize children */ | 7521a30Row pattern recognition patch (planner). |
| 925 | 4041 | newChildren = NIL; | 7521a30Row pattern recognition patch (planner). |
| 926 | 8082 | foreach_node(RPRPatternNode, child, pattern->children) | 7521a30Row pattern recognition patch (planner). |
| 927 | - | { | 7521a30Row pattern recognition patch (planner). |
| 928 | 4041 | newChildren = lappend(newChildren, optimizeRPRPattern(child)); | 7521a30Row pattern recognition patch (planner). |
| 929 | - | } | 7521a30Row pattern recognition patch (planner). |
| 930 | 4041 | pattern->children = newChildren; | 7521a30Row pattern recognition patch (planner). |
| 931 | - | 7521a30Row pattern recognition patch (planner). | |
| 932 | - | /* Try quantifier multiplication */ | 7521a30Row pattern recognition patch (planner). |
| 933 | 4041 | result = tryMultiplyQuantifiers(pattern); | 7521a30Row pattern recognition patch (planner). |
| 934 | 4041 | if (result != pattern) | 7521a30Row pattern recognition patch (planner). |
| 935 | - | return result; | 7521a30Row pattern recognition patch (planner). |
| 936 | - | 7521a30Row pattern recognition patch (planner). | |
| 937 | - | /* Try unwrapping GROUP{1,1} */ | 7521a30Row pattern recognition patch (planner). |
| 938 | 3751 | return tryUnwrapGroup(pattern); | 7521a30Row pattern recognition patch (planner). |
| 939 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 949 | 17465 | optimizeRPRPattern(RPRPatternNode *pattern) | 7521a30Row pattern recognition patch (planner). |
| 950 | - | { | 7521a30Row pattern recognition patch (planner). |
| 951 | - | /* Pattern nodes from parser are never NULL */ | 7521a30Row pattern recognition patch (planner). |
| 952 | 17465 | Assert(pattern != NULL); | 7521a30Row pattern recognition patch (planner). |
| 953 | - | 7521a30Row pattern recognition patch (planner). | |
| 954 | 17465 | check_stack_depth(); | 7521a30Row pattern recognition patch (planner). |
| 955 | - | 7521a30Row pattern recognition patch (planner). | |
| 956 | 17465 | switch (pattern->nodeType) | 7521a30Row pattern recognition patch (planner). |
| 957 | - | { | 7521a30Row pattern recognition patch (planner). |
| 958 | - | case RPR_PATTERN_VAR: | 7521a30Row pattern recognition patch (planner). |
| 959 | - | return pattern; | 7521a30Row pattern recognition patch (planner). |
| 960 | 2745 | case RPR_PATTERN_SEQ: | 7521a30Row pattern recognition patch (planner). |
| 961 | 2745 | return optimizeSeqPattern(pattern); | 7521a30Row pattern recognition patch (planner). |
| 962 | 910 | case RPR_PATTERN_ALT: | 7521a30Row pattern recognition patch (planner). |
| 963 | 910 | return optimizeAltPattern(pattern); | 7521a30Row pattern recognition patch (planner). |
| 964 | 4041 | case RPR_PATTERN_GROUP: | 7521a30Row pattern recognition patch (planner). |
| 965 | 4041 | return optimizeGroupPattern(pattern); | 7521a30Row pattern recognition patch (planner). |
| 966 | - | } | 7521a30Row pattern recognition patch (planner). |
| 967 | - | 7521a30Row pattern recognition patch (planner). | |
| 968 | 0 | pg_unreachable(); | 7521a30Row pattern recognition patch (planner). |
UnreachableReason Confirmed unreachable. The switch at rpr.c:956 enumerates all four members of RPRPatternNodeType (RPR_PATTERN_VAR/SEQ/ALT/GROUP, parsenodes.h:617-620) and every case ends in a return, so control falls through to pg_unreachable() at line 968 only if pattern->nodeType holds a value outside the enum. nodeType is set exclusively by the parser when building the pattern tree (always a valid member), and under -DWRITE_READ_PARSE_PLAN_TREES the round-trip uses WRITE_ENUM_FIELD/READ_ENUM_FIELD (outfuncs.funcs.c:1131, readfuncs.funcs.c:1296), which serializes and restores the identical integer it was given. No SQL or regression input can inject an out-of-range nodeType. I tried to refute via the read path (deserialization) and the parser path; both only yield the four valid values. The Assert(pattern != NULL) and check_stack_depth above are unrelated to line 968.Recommended fix Keep as-is. The pg_unreachable() + return is the standard PostgreSQL exhaustive-switch guard. No change needed; this line should be excluded from coverage expectations. | |||
| 969 | - | return pattern; | 7521a30Row pattern recognition patch (planner). |
| 970 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 981 | 3729 | collectDefineVariables(List *defineVariableList, char **varNames) | 7521a30Row pattern recognition patch (planner). |
| 982 | - | { | 7521a30Row pattern recognition patch (planner). |
| 983 | 3729 | int numVars = 0; | 7521a30Row pattern recognition patch (planner). |
| 984 | - | 7521a30Row pattern recognition patch (planner). | |
| 985 | 12388 | foreach_node(String, varname, defineVariableList) | 7521a30Row pattern recognition patch (planner). |
| 986 | - | { | 7521a30Row pattern recognition patch (planner). |
| 987 | - | /* Parser already checked this limit in transformDefineClause */ | 7521a30Row pattern recognition patch (planner). |
| 988 | 8659 | Assert(numVars <= RPR_VARID_MAX); | 7521a30Row pattern recognition patch (planner). |
| 989 | - | 7521a30Row pattern recognition patch (planner). | |
| 990 | 8659 | varNames[numVars++] = strVal(varname); | 7521a30Row pattern recognition patch (planner). |
| 991 | - | } | 7521a30Row pattern recognition patch (planner). |
| 992 | - | 7521a30Row pattern recognition patch (planner). | |
| 993 | 3729 | return numVars; | 7521a30Row pattern recognition patch (planner). |
| 994 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1005 | 15685 | scanRPRPatternRecursive(RPRPatternNode *node, char **varNames, int *numVars, | 7521a30Row pattern recognition patch (planner). |
| 1006 | - | int *numElements, RPRDepth depth, RPRDepth *maxDepth) | 7521a30Row pattern recognition patch (planner). |
| 1007 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1008 | 15685 | int i; | 7521a30Row pattern recognition patch (planner). |
| 1009 | - | 7521a30Row pattern recognition patch (planner). | |
| 1010 | - | /* Pattern nodes from parser are never NULL */ | 7521a30Row pattern recognition patch (planner). |
| 1011 | 15685 | Assert(node != NULL); | 7521a30Row pattern recognition patch (planner). |
| 1012 | - | 7521a30Row pattern recognition patch (planner). | |
| 1013 | 15685 | check_stack_depth(); | 7521a30Row pattern recognition patch (planner). |
| 1014 | - | 7521a30Row pattern recognition patch (planner). | |
| 1015 | - | /* Check recursion depth limit before overflow occurs */ | 7521a30Row pattern recognition patch (planner). |
| 1016 | 15685 | if (depth >= RPR_DEPTH_MAX) | 7521a30Row pattern recognition patch (planner). |
| 1017 | 4 | ereport(ERROR, | 7521a30Row pattern recognition patch (planner). |
| 1018 | - | errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | 7521a30Row pattern recognition patch (planner). |
| 1019 | - | errmsg("pattern nesting too deep"), | 7521a30Row pattern recognition patch (planner). |
| 1020 | - | errdetail("Pattern nesting depth %d exceeds maximum %d.", | 7521a30Row pattern recognition patch (planner). |
| 1021 | - | depth, RPR_DEPTH_MAX - 1)); | 7521a30Row pattern recognition patch (planner). |
| 1022 | - | 7521a30Row pattern recognition patch (planner). | |
| 1023 | - | /* Track maximum depth */ | 7521a30Row pattern recognition patch (planner). |
| 1024 | 15681 | *maxDepth = Max(*maxDepth, depth); | 7521a30Row pattern recognition patch (planner). |
| 1025 | - | 7521a30Row pattern recognition patch (planner). | |
| 1026 | 15681 | switch (node->nodeType) | 7521a30Row pattern recognition patch (planner). |
| 1027 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1028 | 9180 | case RPR_PATTERN_VAR: | 7521a30Row pattern recognition patch (planner). |
| 1029 | - | /* Count element */ | 7521a30Row pattern recognition patch (planner). |
| 1030 | 9180 | (*numElements)++; | 7521a30Row pattern recognition patch (planner). |
| 1031 | - | 7521a30Row pattern recognition patch (planner). | |
| 1032 | - | /* Collect variable name if not already present */ | 7521a30Row pattern recognition patch (planner). |
| 1033 | 159975 | for (i = 0; i < *numVars; i++) | 7521a30Row pattern recognition patch (planner). |
| 1034 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1035 | 159710 | if (strcmp(varNames[i], node->varName) == 0) | 7521a30Row pattern recognition patch (planner). |
| 1036 | - | return; /* Already have this variable */ | 7521a30Row pattern recognition patch (planner). |
| 1037 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1038 | - | 7521a30Row pattern recognition patch (planner). | |
| 1039 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 1040 | - | * Variable not in DEFINE clause - this is valid per ISO/IEC | 7521a30Row pattern recognition patch (planner). |
| 1041 | - | * 19075-5 Feature R020. Such variables are implicitly TRUE. Add | 7521a30Row pattern recognition patch (planner). |
| 1042 | - | * to varNames so they get a varId >= defineVariableList length, | 7521a30Row pattern recognition patch (planner). |
| 1043 | - | * which executor treats as TRUE. | 7521a30Row pattern recognition patch (planner). |
| 1044 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 1045 | 265 | Assert(*numVars <= RPR_VARID_MAX); | 7521a30Row pattern recognition patch (planner). |
| 1046 | 265 | varNames[(*numVars)++] = node->varName; | 7521a30Row pattern recognition patch (planner). |
| 1047 | 265 | break; | 7521a30Row pattern recognition patch (planner). |
| 1048 | - | 7521a30Row pattern recognition patch (planner). | |
| 1049 | - | case RPR_PATTERN_SEQ: | 7521a30Row pattern recognition patch (planner). |
| 1050 | - | /* Sequence: just recurse into children */ | 7521a30Row pattern recognition patch (planner). |
| 1051 | 9610 | foreach_node(RPRPatternNode, child, node->children) | 7521a30Row pattern recognition patch (planner). |
| 1052 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1053 | 7070 | scanRPRPatternRecursive(child, varNames, | 7521a30Row pattern recognition patch (planner). |
| 1054 | - | numVars, numElements, depth, maxDepth); | 7521a30Row pattern recognition patch (planner). |
| 1055 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1056 | - | break; | 7521a30Row pattern recognition patch (planner). |
| 1057 | - | 7521a30Row pattern recognition patch (planner). | |
| 1058 | 3166 | case RPR_PATTERN_GROUP: | 7521a30Row pattern recognition patch (planner). |
| 1059 | - | 7521a30Row pattern recognition patch (planner). | |
| 1060 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 1061 | - | * Add BEGIN element if group has non-trivial quantifier (not | 7521a30Row pattern recognition patch (planner). |
| 1062 | - | * {1,1}) | 7521a30Row pattern recognition patch (planner). |
| 1063 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 1064 | 3166 | if (node->min != 1 || node->max != 1) | 7521a30Row pattern recognition patch (planner). |
| 1065 | 3166 | (*numElements)++; | 7521a30Row pattern recognition patch (planner). |
| 1066 | - | 7521a30Row pattern recognition patch (planner). | |
| 1067 | - | /* Recurse into children at increased depth */ | 7521a30Row pattern recognition patch (planner). |
| 1068 | 5316 | foreach_node(RPRPatternNode, child, node->children) | 7521a30Row pattern recognition patch (planner). |
| 1069 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1070 | 3166 | scanRPRPatternRecursive(child, varNames, | 7521a30Row pattern recognition patch (planner). |
| 1071 | 3166 | numVars, numElements, depth + 1, maxDepth); | 7521a30Row pattern recognition patch (planner). |
| 1072 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1073 | - | 7521a30Row pattern recognition patch (planner). | |
| 1074 | - | /* Add END element if group has non-trivial quantifier (not {1,1}) */ | 7521a30Row pattern recognition patch (planner). |
| 1075 | 2150 | if (node->min != 1 || node->max != 1) | 7521a30Row pattern recognition patch (planner). |
| 1076 | 2150 | (*numElements)++; | 7521a30Row pattern recognition patch (planner). |
| 1077 | - | break; | 7521a30Row pattern recognition patch (planner). |
| 1078 | - | 7521a30Row pattern recognition patch (planner). | |
| 1079 | 795 | case RPR_PATTERN_ALT: | 7521a30Row pattern recognition patch (planner). |
| 1080 | - | /* Count ALT start element */ | 7521a30Row pattern recognition patch (planner). |
| 1081 | 795 | (*numElements)++; | 7521a30Row pattern recognition patch (planner). |
| 1082 | - | 7521a30Row pattern recognition patch (planner). | |
| 1083 | - | /* Recurse into children at increased depth */ | 7521a30Row pattern recognition patch (planner). |
| 1084 | 2515 | foreach_node(RPRPatternNode, child, node->children) | 7521a30Row pattern recognition patch (planner). |
| 1085 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1086 | 1720 | scanRPRPatternRecursive(child, varNames, | 7521a30Row pattern recognition patch (planner). |
| 1087 | 1720 | numVars, numElements, depth + 1, maxDepth); | 7521a30Row pattern recognition patch (planner). |
| 1088 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1089 | - | break; | 7521a30Row pattern recognition patch (planner). |
| 1090 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1091 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1102 | 3729 | scanRPRPattern(RPRPatternNode *node, char **varNames, int *numVars, | 7521a30Row pattern recognition patch (planner). |
| 1103 | - | int *numElements, RPRDepth *maxDepth) | 7521a30Row pattern recognition patch (planner). |
| 1104 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1105 | 3729 | *numElements = 0; | 7521a30Row pattern recognition patch (planner). |
| 1106 | 3729 | *maxDepth = 0; | 7521a30Row pattern recognition patch (planner). |
| 1107 | - | 7521a30Row pattern recognition patch (planner). | |
| 1108 | 3729 | scanRPRPatternRecursive(node, varNames, numVars, numElements, 0, maxDepth); | 7521a30Row pattern recognition patch (planner). |
| 1109 | - | 7521a30Row pattern recognition patch (planner). | |
| 1110 | 3725 | (*numElements)++; /* +1 for FIN marker */ | 7521a30Row pattern recognition patch (planner). |
| 1111 | - | 7521a30Row pattern recognition patch (planner). | |
| 1112 | 3725 | if (*numElements > RPR_ELEMIDX_MAX) | 7521a30Row pattern recognition patch (planner). |
| 1113 | 0 | ereport(ERROR, | 7521a30Row pattern recognition patch (planner). |
ReachableHow to test Use alternating distinct variables so the optimizer's mergeConsecutiveVars cannot collapse them, while staying within RPR_VARID_MAX (only 2 distinct vars).
Programmatic test (avoid a giant literal in rpr.sql for .out portability):
SELECT format($$SELECT count(*) OVER w
FROM (SELECT 1 i) t
WINDOW w AS (ORDER BY i
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
INITIAL
PATTERN (%s)
DEFINE A AS TRUE, B AS TRUE)$$,
repeat('A B ', 16384)) \gexec
Expected (LC_MESSAGES=C):
ERROR: pattern too complex
DETAIL:
Pattern has 32769 elements, maximum is 32767.
Mechanism: 16384 'A B ' pairs = 32768 VAR elements;
scanRPRPattern adds +1 FIN (rpr.c:1110) -> 32769 > RPR_ELEMIDX_MAX (PG_INT16_MAX = 32767), firing line 1113. mergeConsecutiveVars only merges same-name neighbors, so alternating A/B survives optimization.
Verified live: 16383 pairs (32767 elements) passes, 16384 pairs (32769 elements) errors.
The originally proposed repeat('A ', 32767) does NOT work.VerdictLine 1113 is genuinely reachable (classification hard-to-reach is correct), but the PROPOSED test is WRONG and would NOT cover it.
I empirically triggered the line on the RPR build (ERROR: pattern too complex / DETAIL:
Pattern has 32769 elements, maximum is 32767) using ALTERNATING variables, and empirically confirmed the proposed single-variable test (repeat('A ', 32767), even 100000 reps) SUCCEEDS with no error.
Root cause of the refutation: buildRPRPattern (rpr.c:1929) calls optimizeRPRPattern BEFORE scanRPRPattern (rpr.c:1935).
The pass mergeConsecutiveVars (rpr.c:225-288) merges consecutive identical non-reluctant VARs into one element with summed quantifiers (A A A -> A{3,3}).
So repeating the SAME variable collapses to a single element and never approaches RPR_ELEMIDX_MAX.
The proposal's stated mechanism (repetition of one var inflating numElements) is false.
Fix the test by alternating two distinct variable names (A B A B ...) which the merge cannot combine, staying within RPR_VARID_MAX=240 (only 2 vars used).
Boundary verified: 16383 'A B' pairs (32767 elements) passes;
16384 pairs (32769 elements) errors at line 1113. Also the proposed query syntax was invalid: the RPR grammar (gram.y:17361-17595) has no
MEASURES in the window spec, and clause order is frame then [AFTER MATCH SKIP] [INITIAL]
PATTERN (...)
DEFINE. | |||
| 1114 | - | errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | 7521a30Row pattern recognition patch (planner). |
| 1115 | - | errmsg("pattern too complex"), | 7521a30Row pattern recognition patch (planner). |
| 1116 | - | errdetail("Pattern has %d elements, maximum is %d.", | 7521a30Row pattern recognition patch (planner). |
| 1117 | - | *numElements, RPR_ELEMIDX_MAX)); | 7521a30Row pattern recognition patch (planner). |
| 1118 | 3725 | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1128 | 3725 | makeRPRPattern(int numVars, int numElements, RPRDepth maxDepth, | 7521a30Row pattern recognition patch (planner). |
| 1129 | - | char **varNamesStack) | 7521a30Row pattern recognition patch (planner). |
| 1130 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1131 | 3725 | RPRPattern *result; | 7521a30Row pattern recognition patch (planner). |
| 1132 | 3725 | int i; | 7521a30Row pattern recognition patch (planner). |
| 1133 | - | 7521a30Row pattern recognition patch (planner). | |
| 1134 | 3725 | result = makeNode(RPRPattern); | 7521a30Row pattern recognition patch (planner). |
| 1135 | 3725 | result->numVars = numVars; | 7521a30Row pattern recognition patch (planner). |
| 1136 | - | 7521a30Row pattern recognition patch (planner). | |
| 1137 | - | /* depth < RPR_DEPTH_MAX, so maxDepth+1 never aliases RPR_DEPTH_NONE. */ | 7521a30Row pattern recognition patch (planner). |
| 1138 | 3725 | Assert(maxDepth < RPR_DEPTH_MAX); | 7521a30Row pattern recognition patch (planner). |
| 1139 | 3725 | result->maxDepth = maxDepth + 1; /* +1: depth is 0-based */ | 7521a30Row pattern recognition patch (planner). |
| 1140 | 3725 | result->numElements = numElements; | 7521a30Row pattern recognition patch (planner). |
| 1141 | - | 7521a30Row pattern recognition patch (planner). | |
| 1142 | - | /* Copy varNames (pattern must have at least one variable) */ | 7521a30Row pattern recognition patch (planner). |
| 1143 | 3725 | Assert(numVars > 0); | 7521a30Row pattern recognition patch (planner). |
| 1144 | 3725 | result->varNames = palloc(numVars * sizeof(char *)); | 7521a30Row pattern recognition patch (planner). |
| 1145 | 12645 | for (i = 0; i < numVars; i++) | 7521a30Row pattern recognition patch (planner). |
| 1146 | 8920 | result->varNames[i] = pstrdup(varNamesStack[i]); | 7521a30Row pattern recognition patch (planner). |
| 1147 | - | 7521a30Row pattern recognition patch (planner). | |
| 1148 | - | /* Allocate elements array (zero-init for reserved fields) */ | 7521a30Row pattern recognition patch (planner). |
| 1149 | 3725 | Assert(numElements >= 2); | 7521a30Row pattern recognition patch (planner). |
| 1150 | 3725 | result->elements = palloc0(numElements * sizeof(RPRPatternElement)); | 7521a30Row pattern recognition patch (planner). |
| 1151 | - | 7521a30Row pattern recognition patch (planner). | |
| 1152 | 3725 | return result; | 7521a30Row pattern recognition patch (planner). |
| 1153 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1162 | 9180 | getVarIdFromPattern(RPRPattern *pat, const char *varName) | 7521a30Row pattern recognition patch (planner). |
| 1163 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1164 | 159975 | for (int i = 0; i < pat->numVars; i++) | 7521a30Row pattern recognition patch (planner). |
| 1165 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1166 | 159975 | if (strcmp(pat->varNames[i], varName) == 0) | 7521a30Row pattern recognition patch (planner). |
| 1167 | 9180 | return (RPRVarId) i; | 7521a30Row pattern recognition patch (planner). |
| 1168 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1169 | - | 7521a30Row pattern recognition patch (planner). | |
| 1170 | - | /* Should not happen - variable should already be collected */ | 7521a30Row pattern recognition patch (planner). |
| 1171 | 0 | elog(ERROR, "pattern variable \"%s\" not found", varName); | 7521a30Row pattern recognition patch (planner). |
UnreachableReason Confirmed unreachable via any SQL/regression input. getVarIdFromPattern has a single call site (rpr.c:1187) inside fillRPRPatternVar, passing node->varName from a RPR_PATTERN_VAR node. buildRPRPattern (rpr.c:1929-1942) builds one optimized tree, scans it in pass 1 (scanRPRPattern -> scanRPRPatternRecursive), then fills the SAME tree in pass 2 (fillRPRPattern). In pass 1, every RPR_PATTERN_VAR node unconditionally appends its varName to varNames (rpr.c:1046) unless already present (rpr.c:1036), and the switch recurses identically into SEQ/GROUP/ALT children. makeRPRPattern (rpr.c:1144-1146) copies all numVars names. Thus when pass 2 reaches a VAR node, its name is guaranteed already in pat->varNames, so the loop at 1164 always returns before line 1171. Hitting 1171 would require a VAR node in the fill pass that was absent from the scan pass; since both passes traverse the identical optimized pointer with no intervening mutation or re-optimization, this cannot occur. I attempted to refute by looking for a tree-shape mismatch or a VAR introduced after scanning -- none exists. This is a legitimate internal-invariant guard.Recommended fix Keep the elog(ERROR) as an internal-error consistency guard followed by pg_unreachable(); no behavioral change. Downgrading to Assert is possible but elog provides a safer hard-failure for production builds where Asserts are compiled out, so the current code is appropriate. Marking the line as deliberately uncovered (or wrapping with a coverage-exclusion comment) is the only reasonable action. | |||
| 1172 | - | pg_unreachable(); | 7521a30Row pattern recognition patch (planner). |
| 1173 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1182 | 9180 | fillRPRPatternVar(RPRPatternNode *node, RPRPattern *pat, int *idx, RPRDepth depth) | 7521a30Row pattern recognition patch (planner). |
| 1183 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1184 | 9180 | RPRPatternElement *elem = &pat->elements[*idx]; | 7521a30Row pattern recognition patch (planner). |
| 1185 | - | 7521a30Row pattern recognition patch (planner). | |
| 1186 | 9180 | memset(elem, 0, sizeof(RPRPatternElement)); | 7521a30Row pattern recognition patch (planner). |
| 1187 | 9180 | elem->varId = getVarIdFromPattern(pat, node->varName); | 7521a30Row pattern recognition patch (planner). |
| 1188 | 9180 | elem->depth = depth; | 7521a30Row pattern recognition patch (planner). |
| 1189 | 9180 | elem->min = node->min; | 7521a30Row pattern recognition patch (planner). |
| 1190 | 9180 | elem->max = (node->max == PG_INT32_MAX) ? RPR_QUANTITY_INF : node->max; | 7521a30Row pattern recognition patch (planner). |
| 1191 | 9180 | Assert(elem->min >= 0 && elem->min < RPR_QUANTITY_INF && | 7521a30Row pattern recognition patch (planner). |
| 1192 | - | elem->max >= 1 && | 7521a30Row pattern recognition patch (planner). |
| 1193 | - | (elem->max == RPR_QUANTITY_INF || elem->min <= elem->max)); | 7521a30Row pattern recognition patch (planner). |
| 1194 | 9180 | elem->next = RPR_ELEMIDX_INVALID; | 7521a30Row pattern recognition patch (planner). |
| 1195 | 9180 | elem->jump = RPR_ELEMIDX_INVALID; | 7521a30Row pattern recognition patch (planner). |
| 1196 | 9180 | if (node->reluctant) | 7521a30Row pattern recognition patch (planner). |
| 1197 | 235 | elem->flags |= RPR_ELEM_RELUCTANT; | 7521a30Row pattern recognition patch (planner). |
| 1198 | 9180 | (*idx)++; | 7521a30Row pattern recognition patch (planner). |
| 1199 | - | 7521a30Row pattern recognition patch (planner). | |
| 1200 | 9180 | return (node->min == 0); | 7521a30Row pattern recognition patch (planner). |
| 1201 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1226 | 2150 | fillRPRPatternGroup(RPRPatternNode *node, RPRPattern *pat, int *idx, RPRDepth depth) | 7521a30Row pattern recognition patch (planner). |
| 1227 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1228 | 2150 | int groupStartIdx = *idx; | 7521a30Row pattern recognition patch (planner). |
| 1229 | 2150 | int beginIdx = -1; | 7521a30Row pattern recognition patch (planner). |
| 1230 | 2150 | bool bodyNullable = true; | 7521a30Row pattern recognition patch (planner). |
| 1231 | - | 7521a30Row pattern recognition patch (planner). | |
| 1232 | - | /* Add BEGIN marker if group has non-trivial quantifier (not {1,1}) */ | 7521a30Row pattern recognition patch (planner). |
| 1233 | 2150 | if (node->min != 1 || node->max != 1) | 7521a30Row pattern recognition patch (planner). |
| 1234 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1235 | 2150 | RPRPatternElement *elem = &pat->elements[*idx]; | 7521a30Row pattern recognition patch (planner). |
| 1236 | - | 7521a30Row pattern recognition patch (planner). | |
| 1237 | 2150 | beginIdx = *idx; | 7521a30Row pattern recognition patch (planner). |
| 1238 | 2150 | memset(elem, 0, sizeof(RPRPatternElement)); | 7521a30Row pattern recognition patch (planner). |
| 1239 | 2150 | elem->varId = RPR_VARID_BEGIN; | 7521a30Row pattern recognition patch (planner). |
| 1240 | 2150 | elem->depth = depth; | 7521a30Row pattern recognition patch (planner). |
| 1241 | 2150 | elem->min = node->min; | 7521a30Row pattern recognition patch (planner). |
| 1242 | 2150 | elem->max = (node->max == PG_INT32_MAX) ? RPR_QUANTITY_INF : node->max; | 7521a30Row pattern recognition patch (planner). |
| 1243 | 2150 | Assert(elem->min >= 0 && elem->min < RPR_QUANTITY_INF && | 7521a30Row pattern recognition patch (planner). |
| 1244 | - | elem->max >= 1 && | 7521a30Row pattern recognition patch (planner). |
| 1245 | - | (elem->max == RPR_QUANTITY_INF || elem->min <= elem->max)); | 7521a30Row pattern recognition patch (planner). |
| 1246 | 2150 | elem->next = RPR_ELEMIDX_INVALID; /* set by finalize */ | 7521a30Row pattern recognition patch (planner). |
| 1247 | 2150 | elem->jump = RPR_ELEMIDX_INVALID; /* set after END */ | 7521a30Row pattern recognition patch (planner). |
| 1248 | 2150 | if (node->reluctant) | 7521a30Row pattern recognition patch (planner). |
| 1249 | 1340 | elem->flags |= RPR_ELEM_RELUCTANT; | 7521a30Row pattern recognition patch (planner). |
| 1250 | 2150 | (*idx)++; | 7521a30Row pattern recognition patch (planner). |
| 1251 | 2150 | groupStartIdx = *idx; /* children start after BEGIN */ | 7521a30Row pattern recognition patch (planner). |
| 1252 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1253 | - | 7521a30Row pattern recognition patch (planner). | |
| 1254 | 4300 | foreach_node(RPRPatternNode, child, node->children) | 7521a30Row pattern recognition patch (planner). |
| 1255 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1256 | 2150 | if (!fillRPRPattern(child, pat, idx, depth + 1)) | 7521a30Row pattern recognition patch (planner). |
| 1257 | 2080 | bodyNullable = false; | 7521a30Row pattern recognition patch (planner). |
| 1258 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1259 | - | 7521a30Row pattern recognition patch (planner). | |
| 1260 | - | /* Add group end marker if group has non-trivial quantifier (not {1,1}) */ | 7521a30Row pattern recognition patch (planner). |
| 1261 | 2150 | if (node->min != 1 || node->max != 1) | 7521a30Row pattern recognition patch (planner). |
| 1262 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1263 | 2150 | RPRPatternElement *beginElem = &pat->elements[beginIdx]; | 7521a30Row pattern recognition patch (planner). |
| 1264 | 2150 | RPRPatternElement *endElem = &pat->elements[*idx]; | 7521a30Row pattern recognition patch (planner). |
| 1265 | - | 7521a30Row pattern recognition patch (planner). | |
| 1266 | 2150 | memset(endElem, 0, sizeof(RPRPatternElement)); | 7521a30Row pattern recognition patch (planner). |
| 1267 | 2150 | endElem->varId = RPR_VARID_END; | 7521a30Row pattern recognition patch (planner). |
| 1268 | 2150 | endElem->depth = depth; | 7521a30Row pattern recognition patch (planner). |
| 1269 | 2150 | endElem->min = node->min; | 7521a30Row pattern recognition patch (planner). |
| 1270 | 2150 | endElem->max = (node->max == PG_INT32_MAX) ? RPR_QUANTITY_INF : node->max; | 7521a30Row pattern recognition patch (planner). |
| 1271 | 2150 | Assert(endElem->min >= 0 && endElem->min < RPR_QUANTITY_INF && | 7521a30Row pattern recognition patch (planner). |
| 1272 | - | endElem->max >= 1 && | 7521a30Row pattern recognition patch (planner). |
| 1273 | - | (endElem->max == RPR_QUANTITY_INF || endElem->min <= endElem->max)); | 7521a30Row pattern recognition patch (planner). |
| 1274 | 2150 | endElem->next = RPR_ELEMIDX_INVALID; | 7521a30Row pattern recognition patch (planner). |
| 1275 | 2150 | endElem->jump = groupStartIdx; /* loop to first child */ | 7521a30Row pattern recognition patch (planner). |
| 1276 | 2150 | if (node->reluctant) | 7521a30Row pattern recognition patch (planner). |
| 1277 | 1340 | endElem->flags |= RPR_ELEM_RELUCTANT; | 7521a30Row pattern recognition patch (planner). |
| 1278 | - | 7521a30Row pattern recognition patch (planner). | |
| 1279 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 1280 | - | * If the group body is nullable (all paths can match empty), mark the | 7521a30Row pattern recognition patch (planner). |
| 1281 | - | * END element so that nfa_advance_end can fast-forward the iteration | 7521a30Row pattern recognition patch (planner). |
| 1282 | - | * count to min when reached via empty-match skip paths. | 7521a30Row pattern recognition patch (planner). |
| 1283 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 1284 | 2150 | if (bodyNullable) | 7521a30Row pattern recognition patch (planner). |
| 1285 | 70 | endElem->flags |= RPR_ELEM_EMPTY_LOOP; | 7521a30Row pattern recognition patch (planner). |
| 1286 | - | 7521a30Row pattern recognition patch (planner). | |
| 1287 | 2150 | (*idx)++; | 7521a30Row pattern recognition patch (planner). |
| 1288 | - | 7521a30Row pattern recognition patch (planner). | |
| 1289 | - | /* Set BEGIN skip pointer (next is set by finalize) */ | 7521a30Row pattern recognition patch (planner). |
| 1290 | 2150 | beginElem->jump = *idx; /* skip: go to after END */ | 7521a30Row pattern recognition patch (planner). |
| 1291 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1292 | - | 7521a30Row pattern recognition patch (planner). | |
| 1293 | 2150 | return (node->min == 0 || bodyNullable); | 7521a30Row pattern recognition patch (planner). |
| 1294 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1307 | 795 | fillRPRPatternAlt(RPRPatternNode *node, RPRPattern *pat, int *idx, RPRDepth depth) | 7521a30Row pattern recognition patch (planner). |
| 1308 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1309 | 795 | ListCell *lc; | 7521a30Row pattern recognition patch (planner). |
| 1310 | 795 | ListCell *lc2; | 7521a30Row pattern recognition patch (planner). |
| 1311 | 795 | RPRPatternElement *elem; | 7521a30Row pattern recognition patch (planner). |
| 1312 | 795 | List *altBranchStarts = NIL; | 7521a30Row pattern recognition patch (planner). |
| 1313 | 795 | List *altEndPositions = NIL; | 7521a30Row pattern recognition patch (planner). |
| 1314 | 795 | int afterAltIdx; | 7521a30Row pattern recognition patch (planner). |
| 1315 | 795 | bool anyNullable = false; | 7521a30Row pattern recognition patch (planner). |
| 1316 | - | 7521a30Row pattern recognition patch (planner). | |
| 1317 | - | /* Add alternation start marker */ | 7521a30Row pattern recognition patch (planner). |
| 1318 | 795 | elem = &pat->elements[*idx]; | 7521a30Row pattern recognition patch (planner). |
| 1319 | 795 | memset(elem, 0, sizeof(RPRPatternElement)); | 7521a30Row pattern recognition patch (planner). |
| 1320 | 795 | elem->varId = RPR_VARID_ALT; | 7521a30Row pattern recognition patch (planner). |
| 1321 | 795 | elem->depth = depth; | 7521a30Row pattern recognition patch (planner). |
| 1322 | 795 | elem->min = 1; | 7521a30Row pattern recognition patch (planner). |
| 1323 | 795 | elem->max = 1; | 7521a30Row pattern recognition patch (planner). |
| 1324 | 795 | elem->next = RPR_ELEMIDX_INVALID; | 7521a30Row pattern recognition patch (planner). |
| 1325 | 795 | elem->jump = RPR_ELEMIDX_INVALID; | 7521a30Row pattern recognition patch (planner). |
| 1326 | 795 | (*idx)++; | 7521a30Row pattern recognition patch (planner). |
| 1327 | - | 7521a30Row pattern recognition patch (planner). | |
| 1328 | - | /* Fill each alternative */ | 7521a30Row pattern recognition patch (planner). |
| 1329 | 2515 | foreach_node(RPRPatternNode, alt, node->children) | 7521a30Row pattern recognition patch (planner). |
| 1330 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1331 | 1720 | int branchStart = *idx; | 7521a30Row pattern recognition patch (planner). |
| 1332 | - | 7521a30Row pattern recognition patch (planner). | |
| 1333 | 1720 | altBranchStarts = lappend_int(altBranchStarts, branchStart); | 7521a30Row pattern recognition patch (planner). |
| 1334 | 1720 | if (fillRPRPattern(alt, pat, idx, depth + 1)) | 7521a30Row pattern recognition patch (planner). |
| 1335 | 35 | anyNullable = true; | 7521a30Row pattern recognition patch (planner). |
| 1336 | 1720 | altEndPositions = lappend_int(altEndPositions, *idx - 1); | 7521a30Row pattern recognition patch (planner). |
| 1337 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1338 | - | 7521a30Row pattern recognition patch (planner). | |
| 1339 | - | /* Set jump on first element of each alternative to next alternative */ | 7521a30Row pattern recognition patch (planner). |
| 1340 | 2515 | foreach(lc, altBranchStarts) | 7521a30Row pattern recognition patch (planner). |
| 1341 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1342 | 1720 | int firstElemIdx = lfirst_int(lc); | 7521a30Row pattern recognition patch (planner). |
| 1343 | - | 7521a30Row pattern recognition patch (planner). | |
| 1344 | 1720 | if (lnext(altBranchStarts, lc) != NULL) | 7521a30Row pattern recognition patch (planner). |
| 1345 | 925 | pat->elements[firstElemIdx].jump = lfirst_int(lnext(altBranchStarts, lc)); | 7521a30Row pattern recognition patch (planner). |
| 1346 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1347 | - | 7521a30Row pattern recognition patch (planner). | |
| 1348 | - | /* Set next on last element of each alternative to after the alternation */ | 7521a30Row pattern recognition patch (planner). |
| 1349 | 795 | afterAltIdx = *idx; | 7521a30Row pattern recognition patch (planner). |
| 1350 | - | 7521a30Row pattern recognition patch (planner). | |
| 1351 | 2515 | forboth(lc, altEndPositions, lc2, altBranchStarts) | 7521a30Row pattern recognition patch (planner). |
| 1352 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1353 | 1720 | int endPos = lfirst_int(lc); | 7521a30Row pattern recognition patch (planner). |
| 1354 | 1720 | int branchStart = lfirst_int(lc2); | 7521a30Row pattern recognition patch (planner). |
| 1355 | - | 7521a30Row pattern recognition patch (planner). | |
| 1356 | 1720 | if (pat->elements[endPos].next != RPR_ELEMIDX_INVALID) | 7521a30Row pattern recognition patch (planner). |
| 1357 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1358 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 1359 | - | * An inner ALT already set next on this element. Redirect all | 7521a30Row pattern recognition patch (planner). |
| 1360 | - | * elements in this branch that share the same target to point to | 7521a30Row pattern recognition patch (planner). |
| 1361 | - | * after this ALT instead. | 7521a30Row pattern recognition patch (planner). |
| 1362 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 1363 | - | int oldTarget = pat->elements[endPos].next; | 7521a30Row pattern recognition patch (planner). |
| 1364 | - | int j; | 7521a30Row pattern recognition patch (planner). |
| 1365 | - | 7521a30Row pattern recognition patch (planner). | |
| 1366 | 425 | for (j = branchStart; j <= endPos; j++) | 7521a30Row pattern recognition patch (planner). |
| 1367 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1368 | 365 | if (pat->elements[j].next == oldTarget) | 7521a30Row pattern recognition patch (planner). |
| 1369 | 160 | pat->elements[j].next = afterAltIdx; | 7521a30Row pattern recognition patch (planner). |
| 1370 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1371 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1372 | - | else | 7521a30Row pattern recognition patch (planner). |
| 1373 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1374 | 1660 | pat->elements[endPos].next = afterAltIdx; | 7521a30Row pattern recognition patch (planner). |
| 1375 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1376 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1377 | - | 7521a30Row pattern recognition patch (planner). | |
| 1378 | 795 | list_free(altBranchStarts); | 7521a30Row pattern recognition patch (planner). |
| 1379 | 795 | list_free(altEndPositions); | 7521a30Row pattern recognition patch (planner). |
| 1380 | - | 7521a30Row pattern recognition patch (planner). | |
| 1381 | 795 | return anyNullable; | 7521a30Row pattern recognition patch (planner). |
| 1382 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1396 | 14665 | fillRPRPattern(RPRPatternNode *node, RPRPattern *pat, int *idx, RPRDepth depth) | 7521a30Row pattern recognition patch (planner). |
| 1397 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1398 | 14665 | bool allNullable = true; | 7521a30Row pattern recognition patch (planner). |
| 1399 | - | 7521a30Row pattern recognition patch (planner). | |
| 1400 | - | /* Pattern nodes from parser are never NULL */ | 7521a30Row pattern recognition patch (planner). |
| 1401 | 14665 | Assert(node != NULL); | 7521a30Row pattern recognition patch (planner). |
| 1402 | - | 7521a30Row pattern recognition patch (planner). | |
| 1403 | 14665 | check_stack_depth(); | 7521a30Row pattern recognition patch (planner). |
| 1404 | - | 7521a30Row pattern recognition patch (planner). | |
| 1405 | 14665 | switch (node->nodeType) | 7521a30Row pattern recognition patch (planner). |
| 1406 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1407 | - | case RPR_PATTERN_SEQ: | 7521a30Row pattern recognition patch (planner). |
| 1408 | 9610 | foreach_node(RPRPatternNode, child, node->children) | 7521a30Row pattern recognition patch (planner). |
| 1409 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1410 | 7070 | if (!fillRPRPattern(child, pat, idx, depth)) | 7521a30Row pattern recognition patch (planner). |
| 1411 | 6835 | allNullable = false; | 7521a30Row pattern recognition patch (planner). |
| 1412 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1413 | - | return allNullable; | 7521a30Row pattern recognition patch (planner). |
| 1414 | - | 7521a30Row pattern recognition patch (planner). | |
| 1415 | 9180 | case RPR_PATTERN_VAR: | 7521a30Row pattern recognition patch (planner). |
| 1416 | 9180 | return fillRPRPatternVar(node, pat, idx, depth); | 7521a30Row pattern recognition patch (planner). |
| 1417 | - | 7521a30Row pattern recognition patch (planner). | |
| 1418 | 2150 | case RPR_PATTERN_GROUP: | 7521a30Row pattern recognition patch (planner). |
| 1419 | 2150 | return fillRPRPatternGroup(node, pat, idx, depth); | 7521a30Row pattern recognition patch (planner). |
| 1420 | - | 7521a30Row pattern recognition patch (planner). | |
| 1421 | 795 | case RPR_PATTERN_ALT: | 7521a30Row pattern recognition patch (planner). |
| 1422 | 795 | return fillRPRPatternAlt(node, pat, idx, depth); | 7521a30Row pattern recognition patch (planner). |
| 1423 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1424 | - | 7521a30Row pattern recognition patch (planner). | |
| 1425 | 0 | pg_unreachable(); | 7521a30Row pattern recognition patch (planner). |
UnreachableReason Confirmed defensive-unreachable. The switch at rpr.c:1405 dispatches on RPRPatternNode->nodeType, whose type RPRPatternNodeType (parsenodes.h:615-621) is an enum with exactly four values: RPR_PATTERN_VAR, RPR_PATTERN_SEQ, RPR_PATTERN_ALT, RPR_PATTERN_GROUP. All four are handled by case labels at lines 1407/1415/1418/1421, and every branch returns unconditionally (no break/fall-through). I checked every site that sets nodeType (gram.y:17652/17684/17713/17726/21425/21484 and the makeRPR* helpers) and each assigns one of the four valid values. There is no makeNode/palloc0 path that leaves nodeType zero-initialized to an out-of-enum sentinel before it reaches fillRPRPattern; the parser always populates it. Therefore the fall-through pg_unreachable() at line 1425 can only fire on memory corruption or an enum extension never produced by any SQL/regression input. No input reaches it.Recommended fix Keep as-is. The pg_unreachable() following an exhaustive enum switch is the standard PostgreSQL idiom for an exhaustive-switch guard and silences compiler warnings about missing return. No change needed. | |||
| 1426 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 1427 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1439 | 3725 | finalizeRPRPattern(RPRPattern *result) | 7521a30Row pattern recognition patch (planner). |
| 1440 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1441 | 3725 | int finIdx = result->numElements - 1; | 7521a30Row pattern recognition patch (planner). |
| 1442 | 3725 | int i; | 7521a30Row pattern recognition patch (planner). |
| 1443 | 3725 | RPRPatternElement *finElem; | 7521a30Row pattern recognition patch (planner). |
| 1444 | - | 7521a30Row pattern recognition patch (planner). | |
| 1445 | - | /* Initialize absorption flag */ | 7521a30Row pattern recognition patch (planner). |
| 1446 | 3725 | result->isAbsorbable = false; | 7521a30Row pattern recognition patch (planner). |
| 1447 | - | 7521a30Row pattern recognition patch (planner). | |
| 1448 | - | /* Set up next pointers for elements that don't have one */ | 7521a30Row pattern recognition patch (planner). |
| 1449 | 18000 | for (i = 0; i < finIdx; i++) | 7521a30Row pattern recognition patch (planner). |
| 1450 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1451 | 14275 | RPRPatternElement *elem = &result->elements[i]; | 7521a30Row pattern recognition patch (planner). |
| 1452 | - | 7521a30Row pattern recognition patch (planner). | |
| 1453 | 14275 | if (elem->next == RPR_ELEMIDX_INVALID) | 7521a30Row pattern recognition patch (planner). |
| 1454 | 12615 | elem->next = (i < finIdx - 1) ? i + 1 : finIdx; | 7521a30Row pattern recognition patch (planner). |
| 1455 | - | 7521a30Row pattern recognition patch (planner). | |
| 1456 | - | /* Verify quantifier range is valid */ | 7521a30Row pattern recognition patch (planner). |
| 1457 | 14275 | Assert(elem->min >= 0 && elem->min < RPR_QUANTITY_INF && | 7521a30Row pattern recognition patch (planner). |
| 1458 | - | elem->max >= 1 && | 7521a30Row pattern recognition patch (planner). |
| 1459 | - | (elem->max == RPR_QUANTITY_INF || elem->min <= elem->max)); | 7521a30Row pattern recognition patch (planner). |
| 1460 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1461 | - | 7521a30Row pattern recognition patch (planner). | |
| 1462 | - | /* Add FIN marker at the end */ | 7521a30Row pattern recognition patch (planner). |
| 1463 | 3725 | finElem = &result->elements[finIdx]; | 7521a30Row pattern recognition patch (planner). |
| 1464 | 3725 | memset(finElem, 0, sizeof(RPRPatternElement)); | 7521a30Row pattern recognition patch (planner). |
| 1465 | 3725 | finElem->varId = RPR_VARID_FIN; | 7521a30Row pattern recognition patch (planner). |
| 1466 | 3725 | finElem->depth = 0; | 7521a30Row pattern recognition patch (planner). |
| 1467 | 3725 | finElem->min = 1; | 7521a30Row pattern recognition patch (planner). |
| 1468 | 3725 | finElem->max = 1; | 7521a30Row pattern recognition patch (planner). |
| 1469 | 3725 | finElem->next = RPR_ELEMIDX_INVALID; | 7521a30Row pattern recognition patch (planner). |
| 1470 | 3725 | finElem->jump = RPR_ELEMIDX_INVALID; | 7521a30Row pattern recognition patch (planner). |
| 1471 | 3725 | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1574 | 163470 | isFixedLengthChildren(RPRPattern *pattern, RPRElemIdx idx, RPRDepth scopeDepth) | 7521a30Row pattern recognition patch (planner). |
| 1575 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1576 | 163470 | RPRPatternElement *e = &pattern->elements[idx]; | 7521a30Row pattern recognition patch (planner). |
| 1577 | - | 7521a30Row pattern recognition patch (planner). | |
| 1578 | 163470 | check_stack_depth(); | 7521a30Row pattern recognition patch (planner). |
| 1579 | - | 7521a30Row pattern recognition patch (planner). | |
| 1580 | 168025 | while (e->depth == scopeDepth) | 7521a30Row pattern recognition patch (planner). |
| 1581 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1582 | 166675 | if (RPRElemIsVar(e)) | 7521a30Row pattern recognition patch (planner). |
| 1583 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1584 | 6600 | if (e->min != e->max) | 7521a30Row pattern recognition patch (planner). |
| 1585 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 1586 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1587 | 160075 | else if (RPRElemIsBegin(e)) | 7521a30Row pattern recognition patch (planner). |
| 1588 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1589 | 159550 | RPRElemIdx childIdx = e->next; | 7521a30Row pattern recognition patch (planner). |
| 1590 | - | 7521a30Row pattern recognition patch (planner). | |
| 1591 | - | /* Recurse into subgroup children at scopeDepth + 1 */ | 7521a30Row pattern recognition patch (planner). |
| 1592 | 159550 | if (!isFixedLengthChildren(pattern, childIdx, scopeDepth + 1)) | 7521a30Row pattern recognition patch (planner). |
| 1593 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 1594 | - | 7521a30Row pattern recognition patch (planner). | |
| 1595 | - | /* Advance past the subgroup to its END element */ | 7521a30Row pattern recognition patch (planner). |
| 1596 | 130 | e = &pattern->elements[e->next]; | 7521a30Row pattern recognition patch (planner). |
| 1597 | 445 | while (e->depth > scopeDepth) | 7521a30Row pattern recognition patch (planner). |
| 1598 | 315 | e = &pattern->elements[e->next]; | 7521a30Row pattern recognition patch (planner). |
| 1599 | - | 7521a30Row pattern recognition patch (planner). | |
| 1600 | - | /* e is now the END at scopeDepth; check its quantifier */ | 7521a30Row pattern recognition patch (planner). |
| 1601 | 130 | Assert(RPRElemIsEnd(e) && e->depth == scopeDepth); | 7521a30Row pattern recognition patch (planner). |
| 1602 | 130 | if (e->min != e->max) | 7521a30Row pattern recognition patch (planner). |
| 1603 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 1604 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1605 | - | else | 7521a30Row pattern recognition patch (planner). |
| 1606 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1607 | - | /* ALT inside group: not supported for absorption */ | 7521a30Row pattern recognition patch (planner). |
| 1608 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 1609 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1610 | - | 7521a30Row pattern recognition patch (planner). | |
| 1611 | 4555 | Assert(e->next != RPR_ELEMIDX_INVALID); | 7521a30Row pattern recognition patch (planner). |
| 1612 | 4555 | e = &pattern->elements[e->next]; | 7521a30Row pattern recognition patch (planner). |
| 1613 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1614 | - | 7521a30Row pattern recognition patch (planner). | |
| 1615 | - | return true; | 7521a30Row pattern recognition patch (planner). |
| 1616 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1648 | 5110 | isUnboundedStart(RPRPattern *pattern, RPRElemIdx idx) | 7521a30Row pattern recognition patch (planner). |
| 1649 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1650 | 5110 | RPRPatternElement *elem = &pattern->elements[idx]; | 7521a30Row pattern recognition patch (planner). |
| 1651 | 5110 | RPRDepth startDepth = elem->depth; | 7521a30Row pattern recognition patch (planner). |
| 1652 | 5110 | RPRPatternElement *e; | 7521a30Row pattern recognition patch (planner). |
| 1653 | - | 7521a30Row pattern recognition patch (planner). | |
| 1654 | - | /* Case 1: Simple unbounded VAR at start (greedy only) */ | 7521a30Row pattern recognition patch (planner). |
| 1655 | 5110 | if (RPRElemIsVar(elem) && elem->max == RPR_QUANTITY_INF && | 7521a30Row pattern recognition patch (planner). |
| 1656 | 1270 | !RPRElemIsReluctant(elem)) | 7521a30Row pattern recognition patch (planner). |
| 1657 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1658 | - | /* Set both flags on first element */ | 7521a30Row pattern recognition patch (planner). |
| 1659 | 1190 | elem->flags |= RPR_ELEM_ABSORBABLE_BRANCH | RPR_ELEM_ABSORBABLE; | 7521a30Row pattern recognition patch (planner). |
| 1660 | 1190 | return true; | 7521a30Row pattern recognition patch (planner). |
| 1661 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1662 | - | 7521a30Row pattern recognition patch (planner). | |
| 1663 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 1664 | - | * Case 2: Unbounded GROUP with fixed-length children. Each child must | 7521a30Row pattern recognition patch (planner). |
| 1665 | - | * have min == max (recursively for nested subgroups), ensuring a fixed | 7521a30Row pattern recognition patch (planner). |
| 1666 | - | * step size per iteration so that count-dominance holds. | 7521a30Row pattern recognition patch (planner). |
| 1667 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 1668 | 3920 | if (!isFixedLengthChildren(pattern, idx, startDepth)) | 7521a30Row pattern recognition patch (planner). |
| 1669 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 1670 | - | 7521a30Row pattern recognition patch (planner). | |
| 1671 | - | /* Find the END element at startDepth - 1 */ | 7521a30Row pattern recognition patch (planner). |
| 1672 | 1220 | e = &pattern->elements[idx]; | 7521a30Row pattern recognition patch (planner). |
| 1673 | 3180 | while (e->depth >= startDepth) | 7521a30Row pattern recognition patch (planner). |
| 1674 | 1960 | e = &pattern->elements[e->next]; | 7521a30Row pattern recognition patch (planner). |
| 1675 | - | 7521a30Row pattern recognition patch (planner). | |
| 1676 | - | /* END must be unbounded greedy */ | 7521a30Row pattern recognition patch (planner). |
| 1677 | 1220 | if (e->depth == startDepth - 1 && | 7521a30Row pattern recognition patch (planner). |
| 1678 | 915 | RPRElemIsEnd(e) && e->max == RPR_QUANTITY_INF && | 7521a30Row pattern recognition patch (planner). |
| 1679 | 280 | !RPRElemIsReluctant(e)) | 7521a30Row pattern recognition patch (planner). |
| 1680 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1681 | 250 | Assert(e->jump == idx); /* END points back to first child */ | 7521a30Row pattern recognition patch (planner). |
| 1682 | - | 7521a30Row pattern recognition patch (planner). | |
| 1683 | - | /* Set ABSORBABLE_BRANCH on all children, ABSORBABLE on END only */ | 7521a30Row pattern recognition patch (planner). |
| 1684 | 955 | for (e = elem; !RPRElemIsEnd(e) || e->depth >= startDepth; | 7521a30Row pattern recognition patch (planner). |
| 1685 | 705 | e = &pattern->elements[e->next]) | 7521a30Row pattern recognition patch (planner). |
| 1686 | 705 | e->flags |= RPR_ELEM_ABSORBABLE_BRANCH; | 7521a30Row pattern recognition patch (planner). |
| 1687 | 250 | e->flags |= RPR_ELEM_ABSORBABLE_BRANCH | RPR_ELEM_ABSORBABLE; | 7521a30Row pattern recognition patch (planner). |
| 1688 | 250 | return true; | 7521a30Row pattern recognition patch (planner). |
| 1689 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1690 | - | 7521a30Row pattern recognition patch (planner). | |
| 1691 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 1692 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1708 | 5620 | computeAbsorbabilityRecursive(RPRPattern *pattern, RPRElemIdx startIdx, | 7521a30Row pattern recognition patch (planner). |
| 1709 | - | bool *hasAbsorbable) | 7521a30Row pattern recognition patch (planner). |
| 1710 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1711 | 5620 | RPRPatternElement *elem = &pattern->elements[startIdx]; | 7521a30Row pattern recognition patch (planner). |
| 1712 | - | 7521a30Row pattern recognition patch (planner). | |
| 1713 | 5620 | check_stack_depth(); | 7521a30Row pattern recognition patch (planner). |
| 1714 | - | 7521a30Row pattern recognition patch (planner). | |
| 1715 | 5620 | if (RPRElemIsAlt(elem)) | 7521a30Row pattern recognition patch (planner). |
| 1716 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1717 | - | /* ALT: recursively check each branch */ | 7521a30Row pattern recognition patch (planner). |
| 1718 | 510 | RPRElemIdx branchIdx = elem->next; | 7521a30Row pattern recognition patch (planner). |
| 1719 | 510 | RPRPatternElement *branchFirst; | 7521a30Row pattern recognition patch (planner). |
| 1720 | 510 | bool branchAbsorbable; | 7521a30Row pattern recognition patch (planner). |
| 1721 | - | 7521a30Row pattern recognition patch (planner). | |
| 1722 | 1630 | while (branchIdx != RPR_ELEMIDX_INVALID) | 7521a30Row pattern recognition patch (planner). |
| 1723 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1724 | 1145 | branchAbsorbable = false; | 7521a30Row pattern recognition patch (planner). |
| 1725 | - | 7521a30Row pattern recognition patch (planner). | |
| 1726 | 1145 | Assert(branchIdx < pattern->numElements); | 7521a30Row pattern recognition patch (planner). |
| 1727 | 1145 | branchFirst = &pattern->elements[branchIdx]; | 7521a30Row pattern recognition patch (planner). |
| 1728 | - | 7521a30Row pattern recognition patch (planner). | |
| 1729 | - | /* Stop if element is outside ALT scope (not a branch) */ | 7521a30Row pattern recognition patch (planner). |
| 1730 | 1145 | if (branchFirst->depth <= elem->depth) | 7521a30Row pattern recognition patch (planner). |
| 1731 | - | break; | 7521a30Row pattern recognition patch (planner). |
| 1732 | - | 7521a30Row pattern recognition patch (planner). | |
| 1733 | - | /* Recursively check this branch */ | 7521a30Row pattern recognition patch (planner). |
| 1734 | 1120 | computeAbsorbabilityRecursive(pattern, branchIdx, &branchAbsorbable); | 7521a30Row pattern recognition patch (planner). |
| 1735 | 1120 | if (branchAbsorbable) | 7521a30Row pattern recognition patch (planner). |
| 1736 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1737 | 220 | *hasAbsorbable = true; | 7521a30Row pattern recognition patch (planner). |
| 1738 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1739 | - | 7521a30Row pattern recognition patch (planner). | |
| 1740 | 1120 | branchIdx = branchFirst->jump; | 7521a30Row pattern recognition patch (planner). |
| 1741 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1742 | - | 7521a30Row pattern recognition patch (planner). | |
| 1743 | - | /* Mark ALT element if any branch is absorbable */ | 7521a30Row pattern recognition patch (planner). |
| 1744 | 510 | if (*hasAbsorbable) | 7521a30Row pattern recognition patch (planner). |
| 1745 | 170 | elem->flags |= RPR_ELEM_ABSORBABLE_BRANCH; | 7521a30Row pattern recognition patch (planner). |
| 1746 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1747 | 5110 | else if (RPRElemIsBegin(elem)) | 7521a30Row pattern recognition patch (planner). |
| 1748 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1749 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 1750 | - | * BEGIN: first try to treat this BEGIN's children as an unbounded | 7521a30Row pattern recognition patch (planner). |
| 1751 | - | * group directly (handles nested fixed-length groups like ((A{2} | 7521a30Row pattern recognition patch (planner). |
| 1752 | - | * B{3}){2})+). If that fails, skip to first child and recurse as | 7521a30Row pattern recognition patch (planner). |
| 1753 | - | * before. | 7521a30Row pattern recognition patch (planner). |
| 1754 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 1755 | 1895 | if (isUnboundedStart(pattern, elem->next)) | 7521a30Row pattern recognition patch (planner). |
| 1756 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1757 | 270 | *hasAbsorbable = true; | 7521a30Row pattern recognition patch (planner). |
| 1758 | 270 | elem->flags |= RPR_ELEM_ABSORBABLE_BRANCH; | 7521a30Row pattern recognition patch (planner). |
| 1759 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1760 | - | else | 7521a30Row pattern recognition patch (planner). |
| 1761 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1762 | 1625 | computeAbsorbabilityRecursive(pattern, elem->next, hasAbsorbable); | 7521a30Row pattern recognition patch (planner). |
| 1763 | - | 7521a30Row pattern recognition patch (planner). | |
| 1764 | - | /* Mark BEGIN element if contents are absorbable */ | 7521a30Row pattern recognition patch (planner). |
| 1765 | 1625 | if (*hasAbsorbable) | 7521a30Row pattern recognition patch (planner). |
| 1766 | 35 | elem->flags |= RPR_ELEM_ABSORBABLE_BRANCH; | 7521a30Row pattern recognition patch (planner). |
| 1767 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1768 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1769 | - | else | 7521a30Row pattern recognition patch (planner). |
| 1770 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1771 | - | /* Should never reach END - structural invariant of pattern parse tree */ | 9c7e5bcImprove comments, documentation, and naming for row pattern recognition |
| 1772 | 3215 | Assert(!RPRElemIsEnd(elem)); | 7521a30Row pattern recognition patch (planner). |
| 1773 | - | 7521a30Row pattern recognition patch (planner). | |
| 1774 | - | /* Non-ALT, non-BEGIN: check if unbounded start */ | 7521a30Row pattern recognition patch (planner). |
| 1775 | 3215 | if (isUnboundedStart(pattern, startIdx)) | 7521a30Row pattern recognition patch (planner). |
| 1776 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1777 | 1170 | *hasAbsorbable = true; | 7521a30Row pattern recognition patch (planner). |
| 1778 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1779 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1780 | 5620 | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1812 | 2875 | computeAbsorbability(RPRPattern *pattern) | 7521a30Row pattern recognition patch (planner). |
| 1813 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1814 | 2875 | bool hasAbsorbable = false; | 7521a30Row pattern recognition patch (planner). |
| 1815 | - | 7521a30Row pattern recognition patch (planner). | |
| 1816 | - | /* Parser always produces at least one element + FIN */ | 7521a30Row pattern recognition patch (planner). |
| 1817 | 2875 | Assert(pattern->numElements >= 2); | 7521a30Row pattern recognition patch (planner). |
| 1818 | - | 7521a30Row pattern recognition patch (planner). | |
| 1819 | - | /* Start recursion from first element */ | 7521a30Row pattern recognition patch (planner). |
| 1820 | 2875 | computeAbsorbabilityRecursive(pattern, 0, &hasAbsorbable); | 7521a30Row pattern recognition patch (planner). |
| 1821 | 2875 | pattern->isAbsorbable = hasAbsorbable; | 7521a30Row pattern recognition patch (planner). |
| 1822 | 2875 | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1829 | 11054 | rpr_volatile_func_checker(Oid funcid, void *context) | 7521a30Row pattern recognition patch (planner). |
| 1830 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1831 | 11054 | return (func_volatile(funcid) == PROVOLATILE_VOLATILE); | 7521a30Row pattern recognition patch (planner). |
| 1832 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1843 | 24 | rpr_define_errposition(int location) | 7521a30Row pattern recognition patch (planner). |
| 1844 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1845 | 24 | if (location < 0 || debug_query_string == NULL) | 7521a30Row pattern recognition patch (planner). |
| 1846 | - | return 0; | 7521a30Row pattern recognition patch (planner). |
| 1847 | 20 | return errposition(pg_mbstrlen_with_len(debug_query_string, location) + 1); | 7521a30Row pattern recognition patch (planner). |
| 1848 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1861 | 35927 | reject_volatile_in_define_walker(Node *node, void *context) | 7521a30Row pattern recognition patch (planner). |
| 1862 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1863 | 35927 | if (node == NULL) | 7521a30Row pattern recognition patch (planner). |
| 1864 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 1865 | 35842 | if (check_functions_in_node(node, rpr_volatile_func_checker, NULL)) | 7521a30Row pattern recognition patch (planner). |
| 1866 | 24 | ereport(ERROR, | 7521a30Row pattern recognition patch (planner). |
| 1867 | - | errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | 7521a30Row pattern recognition patch (planner). |
| 1868 | - | errmsg("volatile functions are not allowed in DEFINE clause"), | 7521a30Row pattern recognition patch (planner). |
| 1869 | - | rpr_define_errposition(exprLocation(node))); | 7521a30Row pattern recognition patch (planner). |
| 1870 | 35818 | if (IsA(node, NextValueExpr)) | 7521a30Row pattern recognition patch (planner). |
| 1871 | 0 | ereport(ERROR, | 7521a30Row pattern recognition patch (planner). |
UnreachableReason CONFIRMED unreachable via any SQL input.
Line 1871 (the IsA(node, NextValueExpr) -> ereport sequence-operations error) cannot fire from user SQL.
NextValueExpr nodes are synthesized ONLY by build_column_default (rewriteHandler.c:1290 for identity columns;
also tablecmds.c:7566 for ALTER TABLE column rewrites), and that output is only ever spliced into INSERT/UPDATE/COPY target-column DEFAULT positions (rewriteHandler.c:1052,1599,4745).
There is no SQL syntax that embeds a column-default/identity expression into a scalar predicate position such as a window
DEFINE condition (the DEFAULT keyword is valid only in INSERT
VALUES / UPDATE
SET targets).
A user-written nextval('seq') inside
DEFINE parses to a volatile FuncExpr (pg_proc.dat: nextval provolatile='v'), which check_functions_in_node detects, so it is rejected earlier at line 1865 with the volatile-functions error before reaching 1870-1871. Verified that check_functions_in_node deliberately ignores NextValueExpr (nodeFuncs.c:1941 comment: it carries no SQL function OID), which is exactly why the separate IsA guard exists as belt-and-suspenders.
No rewrite/view-expansion/rule path can inject a NextValueExpr into wc->defineClause, which is what validate_rpr_define_volatility (planner.c:1062) walks.
I attempted to refute the classification and could not find any reaching input.Recommended fixNo source change required. Keep the IsA(node, NextValueExpr) guard at 1870-1874 as intentional defensive code: it documents that sequence operations are disallowed in DEFINE and guards against any future path that could embed a NextValueExpr (which check_functions_in_node intentionally does not inspect). Optionally annotate the line with a brief comment noting it is currently unreachable from SQL because user nextval() parses to a volatile FuncExpr caught at line 1865, so coverage tooling can be told to ignore it. | |||
| 1872 | - | errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | 7521a30Row pattern recognition patch (planner). |
| 1873 | - | errmsg("sequence operations are not allowed in DEFINE clause"), | 7521a30Row pattern recognition patch (planner). |
| 1874 | - | rpr_define_errposition(exprLocation(node))); | 7521a30Row pattern recognition patch (planner). |
| 1875 | 35818 | return expression_tree_walker(node, reject_volatile_in_define_walker, context); | 7521a30Row pattern recognition patch (planner). |
| 1876 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1888 | 3753 | validate_rpr_define_volatility(List *defineClause) | 7521a30Row pattern recognition patch (planner). |
| 1889 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1890 | 12412 | foreach_node(TargetEntry, te, defineClause) | 4cf9108Further tidy up row pattern recognition plumbing |
| 1891 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1892 | 8683 | (void) reject_volatile_in_define_walker((Node *) te->expr, NULL); | 7521a30Row pattern recognition patch (planner). |
| 1893 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1894 | 3729 | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1911 | 3729 | buildRPRPattern(RPRPatternNode *pattern, List *defineVariableList, | 7521a30Row pattern recognition patch (planner). |
| 1912 | - | RPSkipTo rpSkipTo, int frameOptions, | 7521a30Row pattern recognition patch (planner). |
| 1913 | - | bool hasMatchStartDependent) | 7521a30Row pattern recognition patch (planner). |
| 1914 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1915 | 3729 | RPRPattern *result; | 7521a30Row pattern recognition patch (planner). |
| 1916 | 3729 | RPRPatternNode *optimized; | 7521a30Row pattern recognition patch (planner). |
| 1917 | 3729 | char *varNamesStack[RPR_VARID_MAX + 1]; | 7521a30Row pattern recognition patch (planner). |
| 1918 | 3729 | int numVars; | 7521a30Row pattern recognition patch (planner). |
| 1919 | 3729 | int numElements; | 7521a30Row pattern recognition patch (planner). |
| 1920 | 3729 | RPRDepth maxDepth; | 7521a30Row pattern recognition patch (planner). |
| 1921 | 3729 | int idx; | 7521a30Row pattern recognition patch (planner). |
| 1922 | - | 7521a30Row pattern recognition patch (planner). | |
| 1923 | - | /* Caller must check for NULL pattern before calling */ | 7521a30Row pattern recognition patch (planner). |
| 1924 | 3729 | Assert(pattern != NULL); | 7521a30Row pattern recognition patch (planner). |
| 1925 | - | /* RPR is ROWS-only: transformRPR() rejects RANGE/GROUPS up front */ | 7521a30Row pattern recognition patch (planner). |
| 1926 | 3729 | Assert(frameOptions & FRAMEOPTION_ROWS); | 7521a30Row pattern recognition patch (planner). |
| 1927 | - | 7521a30Row pattern recognition patch (planner). | |
| 1928 | - | /* Optimize the pattern tree */ | 7521a30Row pattern recognition patch (planner). |
| 1929 | 3729 | optimized = optimizeRPRPattern(copyObject(pattern)); | 7521a30Row pattern recognition patch (planner). |
| 1930 | - | 7521a30Row pattern recognition patch (planner). | |
| 1931 | - | /* Collect variable names from DEFINE clause */ | 7521a30Row pattern recognition patch (planner). |
| 1932 | 3729 | numVars = collectDefineVariables(defineVariableList, varNamesStack); | 7521a30Row pattern recognition patch (planner). |
| 1933 | - | 7521a30Row pattern recognition patch (planner). | |
| 1934 | - | /* Scan pattern: collect variables, count elements, validate limits */ | 7521a30Row pattern recognition patch (planner). |
| 1935 | 3729 | scanRPRPattern(optimized, varNamesStack, &numVars, &numElements, &maxDepth); | 7521a30Row pattern recognition patch (planner). |
| 1936 | - | 7521a30Row pattern recognition patch (planner). | |
| 1937 | - | /* Allocate result structure */ | 7521a30Row pattern recognition patch (planner). |
| 1938 | 3725 | result = makeRPRPattern(numVars, numElements, maxDepth, varNamesStack); | 7521a30Row pattern recognition patch (planner). |
| 1939 | - | 7521a30Row pattern recognition patch (planner). | |
| 1940 | - | /* Fill elements (pass 2) */ | 7521a30Row pattern recognition patch (planner). |
| 1941 | 3725 | idx = 0; | 7521a30Row pattern recognition patch (planner). |
| 1942 | 3725 | fillRPRPattern(optimized, result, &idx, 0); | 7521a30Row pattern recognition patch (planner). |
| 1943 | - | 7521a30Row pattern recognition patch (planner). | |
| 1944 | - | /* Finalize: set up next pointers, flags, and add FIN marker */ | 7521a30Row pattern recognition patch (planner). |
| 1945 | 3725 | finalizeRPRPattern(result); | 7521a30Row pattern recognition patch (planner). |
| 1946 | - | 7521a30Row pattern recognition patch (planner). | |
| 1947 | - | /* | 7521a30Row pattern recognition patch (planner). |
| 1948 | - | * Compute context absorption eligibility. Absorption requires both | 7521a30Row pattern recognition patch (planner). |
| 1949 | - | * structural absorbability and runtime conditions. Check runtime | 7521a30Row pattern recognition patch (planner). |
| 1950 | - | * conditions first to avoid unnecessary pattern analysis. | 7521a30Row pattern recognition patch (planner). |
| 1951 | - | * | 7521a30Row pattern recognition patch (planner). |
| 1952 | - | * Runtime conditions for absorption: | 7521a30Row pattern recognition patch (planner). |
| 1953 | - | * | 7521a30Row pattern recognition patch (planner). |
| 1954 | - | * 1. SKIP TO PAST LAST ROW required (not SKIP TO NEXT ROW): With NEXT | 7521a30Row pattern recognition patch (planner). |
| 1955 | - | * ROW, after each match the search resumes from the next row, so contexts | 7521a30Row pattern recognition patch (planner). |
| 1956 | - | * are immediately discarded. No redundant contexts accumulate, making | 7521a30Row pattern recognition patch (planner). |
| 1957 | - | * absorption unnecessary. | 7521a30Row pattern recognition patch (planner). |
| 1958 | - | * | 7521a30Row pattern recognition patch (planner). |
| 1959 | - | * 2. Unbounded frame end required (not ROWS with bounded end): With a | 7521a30Row pattern recognition patch (planner). |
| 1960 | - | * bounded frame (e.g., ROWS BETWEEN CURRENT ROW AND 10 FOLLOWING), | 7521a30Row pattern recognition patch (planner). |
| 1961 | - | * matches may be truncated at frame boundaries. This changes the | 7521a30Row pattern recognition patch (planner). |
| 1962 | - | * absorption semantics - older contexts don't necessarily produce longer | 7521a30Row pattern recognition patch (planner). |
| 1963 | - | * matches when frame limits apply differently to each context. | 7521a30Row pattern recognition patch (planner). |
| 1964 | - | */ | 7521a30Row pattern recognition patch (planner). |
| 1965 | 3725 | if (rpSkipTo == ST_PAST_LAST_ROW && | 7521a30Row pattern recognition patch (planner). |
| 1966 | 3115 | (frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) && | 7521a30Row pattern recognition patch (planner). |
| 1967 | - | !hasMatchStartDependent) | 7521a30Row pattern recognition patch (planner). |
| 1968 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1969 | - | /* Runtime conditions met - check structural absorbability */ | 7521a30Row pattern recognition patch (planner). |
| 1970 | 2875 | computeAbsorbability(result); | 7521a30Row pattern recognition patch (planner). |
| 1971 | - | } | 7521a30Row pattern recognition patch (planner). |
| 1972 | - | 7521a30Row pattern recognition patch (planner). | |
| 1973 | 3725 | return result; | 7521a30Row pattern recognition patch (planner). |
| 1974 | - | } | 7521a30Row pattern recognition patch (planner). |
| Line | Hits | Source | Commit |
|---|---|---|---|
| 1993 | 31542 | nav_traversal_walker(Node *node, void *ctx) | 7521a30Row pattern recognition patch (planner). |
| 1994 | - | { | 7521a30Row pattern recognition patch (planner). |
| 1995 | 31542 | if (node == NULL) | 7521a30Row pattern recognition patch (planner). |
| 1996 | - | return false; | 7521a30Row pattern recognition patch (planner). |
| 1997 | - | 7521a30Row pattern recognition patch (planner). | |
| 1998 | 31457 | if (IsA(node, RPRNavExpr)) | 7521a30Row pattern recognition patch (planner). |
| 1999 | - | { | 7521a30Row pattern recognition patch (planner). |
| 2000 | 1299 | NavTraversal *t = (NavTraversal *) ctx; | 7521a30Row pattern recognition patch (planner). |
| 2001 | - | 7521a30Row pattern recognition patch (planner). | |
| 2002 | 1299 | t->visit(t, (RPRNavExpr *) node); | 7521a30Row pattern recognition patch (planner). |
| 2003 | 1299 | return false; | 7521a30Row pattern recognition patch (planner). |
| 2004 | - | } | 7521a30Row pattern recognition patch (planner). |
| 2005 | - | 7521a30Row pattern recognition patch (planner). | |
| 2006 | 30158 | return expression_tree_walker(node, nav_traversal_walker, ctx); | 7521a30Row pattern recognition patch (planner). |
| 2007 | - | } | 7521a30Row pattern recognition patch (planner). |