summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorTomas Vondra2019-07-15 00:00:31 +0000
committerTomas Vondra2019-07-18 09:29:38 +0000
commite4deae7396f2a5576c0c8289e2bfc005ed3d6989 (patch)
treeba6b1f879b88b15f0134152be10977ef53d16a5f /src/test
parente8b6ae2130e3a95bb776708a9a7c9cb21fe8ac87 (diff)
Fix handling of NULLs in MCV items and constants
There were two issues in how the extended statistics handled NULL values in opclauses. Firstly, the code was oblivious to the possibility that Const may be NULL (constisnull=true) in which case the constvalue is undefined. We need to treat this as a mismatch, and not call the proc. Secondly, the MCV item itself may contain NULL values too - the code already did check that, and updated the match bitmap accordingly, but failed to ensure we won't call the operator procedure anyway. It did work for AND-clauses, because in that case false in the bitmap stops evaluation of further clauses. But for OR-clauses ir was not easy to get incorrect estimates or even trigger a crash. This fixes both issues by extending the existing check so that it looks at constisnull too, and making sure it skips calling the procedure. Discussion: https://postgr.es/m/8736jdhbhc.fsf%40ansel.ydns.eu
Diffstat (limited to 'src/test')
-rw-r--r--src/test/regress/expected/stats_ext.out26
-rw-r--r--src/test/regress/sql/stats_ext.sql23
2 files changed, 49 insertions, 0 deletions
diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out
index 6a070a9649d..94b8a8f8b85 100644
--- a/src/test/regress/expected/stats_ext.out
+++ b/src/test/regress/expected/stats_ext.out
@@ -619,6 +619,32 @@ SELECT m.*
0 | {1,2,3} | {f,f,f} | 1 | 1
(1 row)
+-- 2 distinct combinations with NULL values, all in the MCV list
+TRUNCATE mcv_lists;
+DROP STATISTICS mcv_lists_stats;
+INSERT INTO mcv_lists (a, b, c, d)
+ SELECT
+ (CASE WHEN mod(i,2) = 0 THEN NULL ELSE 0 END),
+ (CASE WHEN mod(i,2) = 0 THEN NULL ELSE 'x' END),
+ (CASE WHEN mod(i,2) = 0 THEN NULL ELSE 0 END),
+ (CASE WHEN mod(i,2) = 0 THEN NULL ELSE 'x' END)
+ FROM generate_series(1,5000) s(i);
+ANALYZE mcv_lists;
+SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE b = ''x'' OR d = ''x''');
+ estimated | actual
+-----------+--------
+ 3750 | 2500
+(1 row)
+
+-- create statistics
+CREATE STATISTICS mcv_lists_stats (mcv) ON b, d FROM mcv_lists;
+ANALYZE mcv_lists;
+SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE b = ''x'' OR d = ''x''');
+ estimated | actual
+-----------+--------
+ 2500 | 2500
+(1 row)
+
-- mcv with arrays
CREATE TABLE mcv_lists_arrays (
a TEXT[],
diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql
index 7a77d20446e..4bc1536727b 100644
--- a/src/test/regress/sql/stats_ext.sql
+++ b/src/test/regress/sql/stats_ext.sql
@@ -393,6 +393,29 @@ SELECT m.*
WHERE s.stxname = 'mcv_lists_stats'
AND d.stxoid = s.oid;
+-- 2 distinct combinations with NULL values, all in the MCV list
+TRUNCATE mcv_lists;
+DROP STATISTICS mcv_lists_stats;
+
+INSERT INTO mcv_lists (a, b, c, d)
+ SELECT
+ (CASE WHEN mod(i,2) = 0 THEN NULL ELSE 0 END),
+ (CASE WHEN mod(i,2) = 0 THEN NULL ELSE 'x' END),
+ (CASE WHEN mod(i,2) = 0 THEN NULL ELSE 0 END),
+ (CASE WHEN mod(i,2) = 0 THEN NULL ELSE 'x' END)
+ FROM generate_series(1,5000) s(i);
+
+ANALYZE mcv_lists;
+
+SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE b = ''x'' OR d = ''x''');
+
+-- create statistics
+CREATE STATISTICS mcv_lists_stats (mcv) ON b, d FROM mcv_lists;
+
+ANALYZE mcv_lists;
+
+SELECT * FROM check_estimated_rows('SELECT * FROM mcv_lists WHERE b = ''x'' OR d = ''x''');
+
-- mcv with arrays
CREATE TABLE mcv_lists_arrays (
a TEXT[],