postgres.git / summary / log / commit / refs
commit 0347470b31c139aa4f1d366fbdb85f32b7f82ad0
Author: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri Feb 12 21:26:47 2021 +0000
First released in: 14.0, 9.6.22, 10.17, 11.12, 12.7, 13.3
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
src/backend/utils/adt/like_support.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/backend/utils/adt/like_support.c b/src/backend/utils/adt/like_support.c
index 6465c9edcc3..822a234df36 100644
--- a/src/backend/utils/adt/like_support.c
+++ b/src/backend/utils/adt/like_support.c
@@ -1424,9 +1424,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);
[parent: 5b2945ec0a39]