On Wed, Mar 25, 2026 at 5:27 PM Corey Huinker <[email protected]>
wrote:
> The MonotonicFunction enum seems like a good pattern to follow here.
>>>
>>
>> Learning about the existence of that now
>>
>> typedef enum MonotonicFunction
>> {
>> MONOTONICFUNC_NONE = 0,
>> MONOTONICFUNC_INCREASING = (1 << 0),
>> MONOTONICFUNC_DECREASING = (1 << 1),
>> MONOTONICFUNC_BOTH = MONOTONICFUNC_INCREASING | MONOTONICFUNC_DECREASING,
>> } MonotonicFunction;
>>
>> So, BOTH means that the function is both increasing and decreasing, thus
>> it is constant.
>> Simply replacing the SLOPE_* by the corresponding MONOTONICFUNC_* does
>> the job.
>> But now using an enum we will have 4 bytes per argument.
>>
>
> Sorry, I wasn't suggesting that you use MonotonicFunction outright, only
> that you follow it's pattern (make an enum, if you're needing specific bit
> patterns do it this way, etc. We often use enums as a way for switch
> statements to warn us when we're missing values.
>
No worries, that was easy as the values coincided.
>> So, how would this work with a function like left() with a positive 2nd
>>> param (assuming specified collation matches the index)?
>>>
>> That would require a separate prosupport function, it would have to do
>> some extra work, checking if the second argument is a positive constant at
>> planning time.
>> I'm happy to do that if there is interest, but I would keep after this.
>>
>>
>>> I'm also curious if NULLS FIRST/LAST will throw this off.
>>>
>>
>> All that this will do is, when considering index scans, check if the
>> requested order
>> matches the index order. And whether we have to do a backwards or
>> forwards scan.
>>
>
> What I meant was will we need a custom function to inspect parameters such
> that we *do* try the index optimization on substr(foo,x,..) if and only if
> x = 1?
>
What I would do in this case is
if(x is constant and x > 0) {
return {INCREASING, BOTH, NONE}
}else{
return {NONE, BOTH, NONE}
}
It almost seems like what we need is "does f(x) preserve the leading sort
> bits of x, and reduce the trailing bits to ties?"
>
Yes, this is definitely the most common case, the few exceptions are there
for completeness, but I don't believe people will want to order by e.g.
atan(x) very often.
Is there a specialized nulls first/last sort or does it use a generic sort?
>>
>
> No, it just fed into my wondering about situations where the ordering of
> f(x) would be modified away from the ordering of x.
>
There is one caveat, my current approach for nulls first/last is valid only
if f(NULL) is NULL
> Oh, one other thing I am curious if any other reviewers like/dislike the
>
> static const Slope pattern[2] = {SLOPE_ASC, SLOPE_DESC};
>
> pattern. I haven't seen that one done before, and I'm wondering if we need
> some comments to explain how it works so that people don't start looking
> for the pfree that they'll never find.
>
OK, adding this
+ req.expr = (Node *) expr;
+ /* prosupport function sets req.slopes to a static
+ * pointer, no pfree is required.
+ */
+ req.slopes = NULL;