src/backend/optimizer/path/allpaths.c - Coverage Report

← Back to Overview

# src/backend/optimizer/path/allpaths.c

Coverage: 18/18 lines (100.0%)
Total Lines
18
modified
Covered
18
100.0%
Uncovered
0
0.0%
Keyboard navigation
find_window_run_conditions() lines 2416-2600
Modified Lines Coverage: 1/1 lines (100.0%)

Line | Hits | Source | Commit
--- | --- | --- | ---
2416 | - | find_window_run_conditions(Query *subquery, AttrNumber attno, | -
2417 | - | WindowFunc *wfunc, OpExpr *opexpr, bool wfunc_left, | -
2418 | - | bool *keep_original, Bitmapset **run_cond_attrs) | -
2419 | - | { | -
2420 | - | Oid prosupport; | -
2421 | - | Expr *otherexpr; | -
2422 | - | SupportRequestWFuncMonotonic req; | -
2423 | - | SupportRequestWFuncMonotonic *res; | -
2424 | - | WindowClause *wclause; | -
2425 | - | List *opinfos; | -
2426 | - | OpExpr *runopexpr; | -
2427 | - | Oid runoperator; | -
2428 | - | ListCell *lc; | -
2429 | - |  | -
2430 | - | *keep_original = true; | -
2431 | - |  | -
2432 | - | while (IsA(wfunc, RelabelType)) | -
2433 | - | wfunc = (WindowFunc *) ((RelabelType *) wfunc)->arg; | -
2434 | - |  | -
2435 | - | /* we can only work with window functions */ | -
2436 | - | if (!IsA(wfunc, WindowFunc)) | -
2437 | - | return false; | -
2438 | - |  | -
2439 | - | /* can't use it if there are subplans in the WindowFunc */ | -
2440 | - | if (contain_subplans((Node *) wfunc)) | -
2441 | - | return false; | -
2442 | - |  | -
2443 | - | prosupport = get_func_support(wfunc->winfnoid); | -
2444 | - |  | -
2445 | - | /* Check if there's a support function for 'wfunc' */ | -
2446 | - | if (!OidIsValid(prosupport)) | -
2447 | - | return false; | -
2448 | - |  | -
2449 | - | /* get the Expr from the other side of the OpExpr */ | -
2450 | - | if (wfunc_left) | -
2451 | - | otherexpr = lsecond(opexpr->args); | -
2452 | - | else | -
2453 | - | otherexpr = linitial(opexpr->args); | -
2454 | - |  | -
2455 | - | /* | -
2456 | - | * The value being compared must not change during the evaluation of the | -
2457 | - | * window partition. | -
2458 | - | */ | -
2459 | - | if (!is_pseudo_constant_clause((Node *) otherexpr)) | -
2460 | - | return false; | -
2461 | - |  | -
2462 | - | /* find the window clause belonging to the window function */ | -
2463 | - | wclause = (WindowClause *) list_nth(subquery->windowClause, | -
2464 | - | wfunc->winref - 1); | -
2465 | - |  | -
2466 | - | /* | 7521a30Row pattern recognition patch (planner).
2467 | - | * If a DEFINE clause exists, we cannot push down a run condition. In the | 7521a30Row pattern recognition patch (planner).
2468 | - | * case, a window partition (or frame) is divided into multiple reduced | 7521a30Row pattern recognition patch (planner).
2469 | - | * frames and each frame should be evaluated to the end of the partition | 7521a30Row pattern recognition patch (planner).
2470 | - | * (or full frame end). This means we cannot apply the run condition | 7521a30Row pattern recognition patch (planner).
2471 | - | * optimization because it stops evaluation window functions in certain | 7521a30Row pattern recognition patch (planner).
2472 | - | * cases. | 7521a30Row pattern recognition patch (planner).
2473 | - | */ | 7521a30Row pattern recognition patch (planner).
2474 | 330 | if (wclause->defineClause != NIL) | 7521a30Row pattern recognition patch (planner).
2475 | - | return false; | 7521a30Row pattern recognition patch (planner).
2476 | - |  | 7521a30Row pattern recognition patch (planner).
2477 | - | req.type = T_SupportRequestWFuncMonotonic; | -
2478 | - | req.window_func = wfunc; | -
2479 | - | req.window_clause = wclause; | -
2480 | - |  | -
2481 | - | /* call the support function */ | -
2482 | - | res = (SupportRequestWFuncMonotonic *) | -
2483 | - | DatumGetPointer(OidFunctionCall1(prosupport, | -
2484 | - | PointerGetDatum(&req))); | -
2485 | - |  | -
2486 | - | /* | -
2487 | - | * Nothing to do if the function is neither monotonically increasing nor | -
2488 | - | * monotonically decreasing. | -
2489 | - | */ | -
2490 | - | if (res == NULL || res->monotonic == MONOTONICFUNC_NONE) | -
2491 | - | return false; | -
2492 | - |  | -
2493 | - | runopexpr = NULL; | -
2494 | - | runoperator = InvalidOid; | -
2495 | - | opinfos = get_op_index_interpretation(opexpr->opno); | -
2496 | - |  | -
2497 | - | foreach(lc, opinfos) | -
2498 | - | { | -
2499 | - | OpIndexInterpretation *opinfo = (OpIndexInterpretation *) lfirst(lc); | -
2500 | - | CompareType cmptype = opinfo->cmptype; | -
2501 | - |  | -
2502 | - | /* handle < / <= */ | -
2503 | - | if (cmptype == COMPARE_LT || cmptype == COMPARE_LE) | -
2504 | - | { | -
2505 | - | /* | -
2506 | - | * < / <= is supported for monotonically increasing functions in | -
2507 | - | * the form <wfunc> op <pseudoconst> and <pseudoconst> op <wfunc> | -
2508 | - | * for monotonically decreasing functions. | -
2509 | - | */ | -
2510 | - | if ((wfunc_left && (res->monotonic & MONOTONICFUNC_INCREASING)) || | -
2511 | - | (!wfunc_left && (res->monotonic & MONOTONICFUNC_DECREASING))) | -
2512 | - | { | -
2513 | - | *keep_original = false; | -
2514 | - | runopexpr = opexpr; | -
2515 | - | runoperator = opexpr->opno; | -
2516 | - | } | -
2517 | - | break; | -
2518 | - | } | -
2519 | - | /* handle > / >= */ | -
2520 | - | else if (cmptype == COMPARE_GT || cmptype == COMPARE_GE) | -
2521 | - | { | -
2522 | - | /* | -
2523 | - | * > / >= is supported for monotonically decreasing functions in | -
2524 | - | * the form <wfunc> op <pseudoconst> and <pseudoconst> op <wfunc> | -
2525 | - | * for monotonically increasing functions. | -
2526 | - | */ | -
2527 | - | if ((wfunc_left && (res->monotonic & MONOTONICFUNC_DECREASING)) || | -
2528 | - | (!wfunc_left && (res->monotonic & MONOTONICFUNC_INCREASING))) | -
2529 | - | { | -
2530 | - | *keep_original = false; | -
2531 | - | runopexpr = opexpr; | -
2532 | - | runoperator = opexpr->opno; | -
2533 | - | } | -
2534 | - | break; | -
2535 | - | } | -
2536 | - | /* handle = */ | -
2537 | - | else if (cmptype == COMPARE_EQ) | -
2538 | - | { | -
2539 | - | CompareType newcmptype; | -
2540 | - |  | -
2541 | - | /* | -
2542 | - | * When both monotonically increasing and decreasing then the | -
2543 | - | * return value of the window function will be the same each time. | -
2544 | - | * We can simply use 'opexpr' as the run condition without | -
2545 | - | * modifying it. | -
2546 | - | */ | -
2547 | - | if ((res->monotonic & MONOTONICFUNC_BOTH) == MONOTONICFUNC_BOTH) | -
2548 | - | { | -
2549 | - | *keep_original = false; | -
2550 | - | runopexpr = opexpr; | -
2551 | - | runoperator = opexpr->opno; | -
2552 | - | break; | -
2553 | - | } | -
2554 | - |  | -
2555 | - | /* | -
2556 | - | * When monotonically increasing we make a qual with <wfunc> <= | -
2557 | - | * <value> or <value> >= <wfunc> in order to filter out values | -
2558 | - | * which are above the value in the equality condition. For | -
2559 | - | * monotonically decreasing functions we want to filter values | -
2560 | - | * below the value in the equality condition. | -
2561 | - | */ | -
2562 | - | if (res->monotonic & MONOTONICFUNC_INCREASING) | -
2563 | - | newcmptype = wfunc_left ? COMPARE_LE : COMPARE_GE; | -
2564 | - | else | -
2565 | - | newcmptype = wfunc_left ? COMPARE_GE : COMPARE_LE; | -
2566 | - |  | -
2567 | - | /* We must keep the original equality qual */ | -
2568 | - | *keep_original = true; | -
2569 | - | runopexpr = opexpr; | -
2570 | - |  | -
2571 | - | /* determine the operator to use for the WindowFuncRunCondition */ | -
2572 | - | runoperator = get_opfamily_member_for_cmptype(opinfo->opfamily_id, | -
2573 | - | opinfo->oplefttype, | -
2574 | - | opinfo->oprighttype, | -
2575 | - | newcmptype); | -
2576 | - | break; | -
2577 | - | } | -
2578 | - | } | -
2579 | - |  | -
2580 | - | if (runopexpr != NULL) | -
2581 | - | { | -
2582 | - | WindowFuncRunCondition *wfuncrc; | -
2583 | - |  | -
2584 | - | wfuncrc = makeNode(WindowFuncRunCondition); | -
2585 | - | wfuncrc->opno = runoperator; | -
2586 | - | wfuncrc->inputcollid = runopexpr->inputcollid; | -
2587 | - | wfuncrc->wfunc_left = wfunc_left; | -
2588 | - | wfuncrc->arg = copyObject(otherexpr); | -
2589 | - |  | -
2590 | - | wfunc->runCondition = lappend(wfunc->runCondition, wfuncrc); | -
2591 | - |  | -
2592 | - | /* record that this attno was used in a run condition */ | -
2593 | - | *run_cond_attrs = bms_add_member(*run_cond_attrs, | -
2594 | - | attno - FirstLowInvalidHeapAttributeNumber); | -
2595 | - | return true; | -
2596 | - | } | -
2597 | - |  | -
2598 | - | /* unsupported OpExpr */ | -
2599 | - | return false; | -
2600 | - | } | -

remove_unused_subquery_outputs() lines 4657-4835
Modified Lines Coverage: 17/17 lines (100.0%)

Line | Hits | Source | Commit
--- | --- | --- | ---
4657 | - | remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel, | -
4658 | - | Bitmapset *extra_used_attrs) | -
4659 | - | { | -
4660 | - | Bitmapset *attrs_used; | -
4661 | - | ListCell *lc; | -
4662 | - |  | -
4663 | - | /* | -
4664 | - | * Just point directly to extra_used_attrs. No need to bms_copy as none of | -
4665 | - | * the current callers use the Bitmapset after calling this function. | -
4666 | - | */ | -
4667 | - | attrs_used = extra_used_attrs; | -
4668 | - |  | -
4669 | - | /* | -
4670 | - | * Do nothing if subquery has UNION/INTERSECT/EXCEPT: in principle we | -
4671 | - | * could update all the child SELECTs' tlists, but it seems not worth the | -
4672 | - | * trouble presently. | -
4673 | - | */ | -
4674 | - | if (subquery->setOperations) | -
4675 | - | return; | -
4676 | - |  | -
4677 | - | /* | -
4678 | - | * If subquery has regular DISTINCT (not DISTINCT ON), we're wasting our | -
4679 | - | * time: all its output columns must be used in the distinctClause. | -
4680 | - | */ | -
4681 | - | if (subquery->distinctClause && !subquery->hasDistinctOn) | -
4682 | - | return; | -
4683 | - |  | -
4684 | - | /* | -
4685 | - | * Collect a bitmap of all the output column numbers used by the upper | -
4686 | - | * query. | -
4687 | - | * | -
4688 | - | * Add all the attributes needed for joins or final output. Note: we must | -
4689 | - | * look at rel's targetlist, not the attr_needed data, because attr_needed | -
4690 | - | * isn't computed for inheritance child rels, cf set_append_rel_size(). | -
4691 | - | * (XXX might be worth changing that sometime.) | -
4692 | - | */ | -
4693 | - | pull_varattnos((Node *) rel->reltarget->exprs, rel->relid, &attrs_used); | -
4694 | - |  | -
4695 | - | /* Add all the attributes used by un-pushed-down restriction clauses. */ | -
4696 | - | foreach(lc, rel->baserestrictinfo) | -
4697 | - | { | -
4698 | - | RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc); | -
4699 | - |  | -
4700 | - | pull_varattnos((Node *) rinfo->clause, rel->relid, &attrs_used); | -
4701 | - | } | -
4702 | - |  | -
4703 | - | /* | -
4704 | - | * If there's a whole-row reference to the subquery, we can't remove | -
4705 | - | * anything. | -
4706 | - | */ | -
4707 | - | if (bms_is_member(0 - FirstLowInvalidHeapAttributeNumber, attrs_used)) | -
4708 | - | return; | -
4709 | - |  | -
4710 | - | /* | -
4711 | - | * Run through the tlist and zap entries we don't need. It's okay to | -
4712 | - | * modify the tlist items in-place because set_subquery_pathlist made a | -
4713 | - | * copy of the subquery. | -
4714 | - | */ | -
4715 | - | foreach(lc, subquery->targetList) | -
4716 | - | { | -
4717 | - | TargetEntry *tle = (TargetEntry *) lfirst(lc); | -
4718 | - | Node *texpr = (Node *) tle->expr; | -
4719 | - |  | -
4720 | - | /* | -
4721 | - | * If it has a sortgroupref number, it's used in some sort/group | -
4722 | - | * clause so we'd better not remove it. Also, don't remove any | -
4723 | - | * resjunk columns, since their reason for being has nothing to do | -
4724 | - | * with anybody reading the subquery's output. (It's likely that | -
4725 | - | * resjunk columns in a sub-SELECT would always have ressortgroupref | -
4726 | - | * set, but even if they don't, it seems imprudent to remove them.) | -
4727 | - | */ | -
4728 | - | if (tle->ressortgroupref || tle->resjunk) | -
4729 | - | continue; | -
4730 | - |  | -
4731 | - | /* | -
4732 | - | * If it's used by the upper query, we can't remove it. | -
4733 | - | */ | -
4734 | - | if (bms_is_member(tle->resno - FirstLowInvalidHeapAttributeNumber, | -
4735 | - | attrs_used)) | -
4736 | - | continue; | -
4737 | - |  | -
4738 | - | /* | -
4739 | - | * If it contains a set-returning function, we can't remove it since | -
4740 | - | * that could change the number of rows returned by the subquery. | -
4741 | - | */ | -
4742 | - | if (subquery->hasTargetSRFs && | -
4743 | - | expression_returns_set(texpr)) | -
4744 | - | continue; | -
4745 | - |  | -
4746 | - | /* | -
4747 | - | * If it contains volatile functions, we daren't remove it for fear | -
4748 | - | * that the user is expecting their side-effects to happen. | -
4749 | - | */ | -
4750 | - | if (contain_volatile_functions(texpr)) | -
4751 | - | continue; | -
4752 | - |  | -
4753 | - | /* | 7521a30Row pattern recognition patch (planner).
4754 | - | * If any RPR (Row Pattern Recognition) window clause references this | 7521a30Row pattern recognition patch (planner).
4755 | - | * column in its DEFINE clause, don't remove it. The DEFINE | 7521a30Row pattern recognition patch (planner).
4756 | - | * expression needs these columns in the tuplestore slot for pattern | 7521a30Row pattern recognition patch (planner).
4757 | - | * matching evaluation, even if the outer query doesn't reference | 7521a30Row pattern recognition patch (planner).
4758 | - | * them. | 7521a30Row pattern recognition patch (planner).
4759 | - | */ | 7521a30Row pattern recognition patch (planner).
4760 | 27223 | if (IsA(texpr, Var)) | 7521a30Row pattern recognition patch (planner).
4761 | - | { | 7521a30Row pattern recognition patch (planner).
4762 | - | Var *var = (Var *) texpr; | 7521a30Row pattern recognition patch (planner).
4763 | - | bool needed_by_define = false; | 7521a30Row pattern recognition patch (planner).
4764 | - |  | 7521a30Row pattern recognition patch (planner).
4765 | 12762 | foreach_node(WindowClause, wc, subquery->windowClause) | 7521a30Row pattern recognition patch (planner).
4766 | - | { | 7521a30Row pattern recognition patch (planner).
4767 | 55 | if (wc->defineClause != NIL) | 7521a30Row pattern recognition patch (planner).
4768 | - | { | 7521a30Row pattern recognition patch (planner).
4769 | 50 | List *vars = pull_var_clause((Node *) wc->defineClause, 0); | 7521a30Row pattern recognition patch (planner).
4770 | - |  | 7521a30Row pattern recognition patch (planner).
4771 | 80 | foreach_node(Var, dvar, vars) | 7521a30Row pattern recognition patch (planner).
4772 | - | { | 7521a30Row pattern recognition patch (planner).
4773 | - |  | 7521a30Row pattern recognition patch (planner).
4774 | - | /* | 7521a30Row pattern recognition patch (planner).
4775 | - | * Match varno as well as varattno: a Var pulled from | 7521a30Row pattern recognition patch (planner).
4776 | - | * a DEFINE clause can share an attribute number with | 7521a30Row pattern recognition patch (planner).
4777 | - | * an unrelated output column of a different relation, | 7521a30Row pattern recognition patch (planner).
4778 | - | * which would otherwise be over-retained. Checking | 7521a30Row pattern recognition patch (planner).
4779 | - | * varlevelsup is just paranoia, since outer | 7521a30Row pattern recognition patch (planner).
4780 | - | * references in DEFINE are rejected during parse | 7521a30Row pattern recognition patch (planner).
4781 | - | * analysis. | 7521a30Row pattern recognition patch (planner).
4782 | - | */ | 7521a30Row pattern recognition patch (planner).
4783 | 60 | if (dvar->varno == var->varno && | 7521a30Row pattern recognition patch (planner).
4784 | 55 | dvar->varattno == var->varattno && | 7521a30Row pattern recognition patch (planner).
4785 | 30 | dvar->varlevelsup == var->varlevelsup) | 7521a30Row pattern recognition patch (planner).
4786 | - | { | 7521a30Row pattern recognition patch (planner).
4787 | - | needed_by_define = true; | 7521a30Row pattern recognition patch (planner).
4788 | - | break; | 7521a30Row pattern recognition patch (planner).
4789 | - | } | 7521a30Row pattern recognition patch (planner).
4790 | - | } | 7521a30Row pattern recognition patch (planner).
4791 | 50 | list_free(vars); | 7521a30Row pattern recognition patch (planner).
4792 | 50 | if (needed_by_define) | 7521a30Row pattern recognition patch (planner).
4793 | - | break; | 7521a30Row pattern recognition patch (planner).
4794 | - | } | 7521a30Row pattern recognition patch (planner).
4795 | - | } | 7521a30Row pattern recognition patch (planner).
4796 | 12737 | if (needed_by_define) | 7521a30Row pattern recognition patch (planner).
4797 | 30 | continue; | 7521a30Row pattern recognition patch (planner).
4798 | - | } | 7521a30Row pattern recognition patch (planner).
4799 | - |  | 7521a30Row pattern recognition patch (planner).
4800 | - | /* | 7521a30Row pattern recognition patch (planner).
4801 | - | * If it's a window function referencing a window clause with RPR, | 7521a30Row pattern recognition patch (planner).
4802 | - | * don't remove it. Even when the window function result is unused by | 7521a30Row pattern recognition patch (planner).
4803 | - | * the outer query, the RPR pattern matching (frame reduction via | 7521a30Row pattern recognition patch (planner).
4804 | - | * DEFINE/PATTERN) must still execute. Replacing this with NULL would | 7521a30Row pattern recognition patch (planner).
4805 | - | * leave no active window functions for the WindowClause, causing the | 7521a30Row pattern recognition patch (planner).
4806 | - | * planner to omit the WindowAgg node entirely. | 7521a30Row pattern recognition patch (planner).
4807 | - | */ | 7521a30Row pattern recognition patch (planner).
4808 | 27193 | if (IsA(texpr, WindowFunc)) | 7521a30Row pattern recognition patch (planner).
4809 | - | { | 7521a30Row pattern recognition patch (planner).
4810 | - | bool is_rpr = false; | b848408Tidy up row pattern recognition plumbing
4811 | - | WindowFunc *wfunc = (WindowFunc *) texpr; | 7521a30Row pattern recognition patch (planner).
4812 | - |  | 7521a30Row pattern recognition patch (planner).
4813 | 35 | foreach_node(WindowClause, wc, subquery->windowClause) | b848408Tidy up row pattern recognition plumbing
4814 | - | { | 7521a30Row pattern recognition patch (planner).
4815 | 30 | if (wc->winref == wfunc->winref && wc->defineClause != NIL) | b848408Tidy up row pattern recognition plumbing
4816 | - | { | 7521a30Row pattern recognition patch (planner).
4817 | - | is_rpr = true; | b848408Tidy up row pattern recognition plumbing
4818 | - | break; | 7521a30Row pattern recognition patch (planner).
4819 | - | } | 7521a30Row pattern recognition patch (planner).
4820 | - | } | 7521a30Row pattern recognition patch (planner).
4821 | - |  | b848408Tidy up row pattern recognition plumbing
4822 | 30 | if (is_rpr) | b848408Tidy up row pattern recognition plumbing
4823 | 25 | continue; | 7521a30Row pattern recognition patch (planner).
4824 | - | } | 7521a30Row pattern recognition patch (planner).
4825 | - |  | 7521a30Row pattern recognition patch (planner).
4826 | - | /* | -
4827 | - | * OK, we don't need it. Replace the expression with a NULL constant. | -
4828 | - | * Preserve the exposed type of the expression, in case something | -
4829 | - | * looks at the rowtype of the subquery's result. | -
4830 | - | */ | -
4831 | - | tle->expr = (Expr *) makeNullConst(exprType(texpr), | -
4832 | - | exprTypmod(texpr), | -
4833 | - | exprCollation(texpr)); | -
4834 | - | } | -
4835 | - | } | -