diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2021-02-12 16:26:47 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2021-02-12 16:26:47 -0500 |
commit | 3a02d68a96edb54d981879b95c28fe4ba79b87f9 (patch) | |
tree | 573434159af6b115e8e647db78133b12b8193f58 | |
parent | c6cd20d91ce9b100b89997757b88a415c3e10747 (diff) | |
download | postgresql-3a02d68a96edb54d981879b95c28fe4ba79b87f9.tar.gz postgresql-3a02d68a96edb54d981879b95c28fe4ba79b87f9.zip |
Avoid divide-by-zero in regex_selectivity() with long fixed prefix.
Given a regex pattern with a very long fixed prefix (approaching 500
characters), the result of pow(FIXED_CHAR_SEL, fixed_prefix_len) can
underflow to zero. Typically the preceding selectivity calculation
would have underflowed as well, so that we compute 0/0 and get NaN.
In released branches this leads to an assertion failure later on.
That doesn't happen in HEAD, for reasons I've not explored yet,
but it's surely still a bug.
To fix, just skip the division when the pow() result is zero, so
that we'll (most likely) return a zero selectivity estimate. In
the edge cases where "sel" didn't yet underflow, perhaps this
isn't desirable, but I'm not sure that the case is worth spending
a lot of effort on. The results of regex_selectivity_sub() are
barely worth the electrons they're written on anyway :-(
Per report from Alexander Lakhin. Back-patch to all supported versions.
Discussion: https://postgr.es/m/6de0a0c3-ada9-cd0c-3e4e-2fa9964b41e3@gmail.com
-rw-r--r-- | src/backend/utils/adt/like_support.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/src/backend/utils/adt/like_support.c b/src/backend/utils/adt/like_support.c index bcfbaa1c3d1..b9144e0abb2 100644 --- a/src/backend/utils/adt/like_support.c +++ b/src/backend/utils/adt/like_support.c @@ -1442,9 +1442,18 @@ regex_selectivity(const char *patt, int pattlen, bool case_insensitive, sel *= FULL_WILDCARD_SEL; } - /* If there's a fixed prefix, discount its selectivity */ + /* + * If there's a fixed prefix, discount its selectivity. We have to be + * careful here since a very long prefix could result in pow's result + * underflowing to zero (in which case "sel" probably has as well). + */ if (fixed_prefix_len > 0) - sel /= pow(FIXED_CHAR_SEL, fixed_prefix_len); + { + double prefixsel = pow(FIXED_CHAR_SEL, fixed_prefix_len); + + if (prefixsel > 0.0) + sel /= prefixsel; + } /* Make sure result stays in range */ CLAMP_PROBABILITY(sel); |