Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3fe2fc6

Browse files
committed
Fix handling of bare boolean expressions in mcv_get_match_bitmap.
Since v14, the extended stats machinery will try to estimate forotherwise-unsupported boolean expressions if they match an expressionavailable from an extended stats object. mcv.c did not get the memoabout this, and would spit up with "unknown clause type". Fortunatelythe case is easy to handle, since we can expect the expression yieldsboolean.While here, replace some not-terribly-on-point assertions withsimpler runtime tests for lookup failure. That seems appropriateso that we get an elog not a crash if we somehow get to the newit-should-be-a-bool-expression code with a subexpression thatdoesn't match any stats column.Per report from Danny Shemesh. Thanks to Justin Pryzby forpreliminary investigation.Discussion:https://postgr.es/m/CAFZC=QqD6=27wQPOW1pbRa98KPyuyn+7cL_Ay_Ck-roZV84vHg@mail.gmail.com
1 parentea6c916 commit3fe2fc6

File tree

3 files changed

+60
-27
lines changed

3 files changed

+60
-27
lines changed

‎src/backend/statistics/mcv.c

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,13 +1531,13 @@ pg_mcv_list_send(PG_FUNCTION_ARGS)
15311531
/*
15321532
* match the attribute/expression to a dimension of the statistic
15331533
*
1534-
*Match theattribute/expression tostatistics dimension. Optionally
1535-
*determine the collation.
1534+
*Returns thezero-based index of the matchingstatistics dimension.
1535+
*Optionally determines the collation.
15361536
*/
15371537
staticint
15381538
mcv_match_expression(Node*expr,Bitmapset*keys,List*exprs,Oid*collid)
15391539
{
1540-
intidx=-1;
1540+
intidx;
15411541

15421542
if (IsA(expr,Var))
15431543
{
@@ -1549,20 +1549,19 @@ mcv_match_expression(Node *expr, Bitmapset *keys, List *exprs, Oid *collid)
15491549

15501550
idx=bms_member_index(keys,var->varattno);
15511551

1552-
/* make sure the index is valid */
1553-
Assert((idx >=0)&& (idx <=bms_num_members(keys)));
1552+
if (idx<0)
1553+
elog(ERROR,"variable not found in statistics object");
15541554
}
15551555
else
15561556
{
1557+
/* expression - lookup in stats expressions */
15571558
ListCell*lc;
15581559

1559-
/* expressions are stored after the simple columns */
1560-
idx=bms_num_members(keys);
1561-
15621560
if (collid)
15631561
*collid=exprCollation(expr);
15641562

1565-
/* expression - lookup in stats expressions */
1563+
/* expressions are stored after the simple columns */
1564+
idx=bms_num_members(keys);
15661565
foreach(lc,exprs)
15671566
{
15681567
Node*stat_expr= (Node*)lfirst(lc);
@@ -1573,13 +1572,10 @@ mcv_match_expression(Node *expr, Bitmapset *keys, List *exprs, Oid *collid)
15731572
idx++;
15741573
}
15751574

1576-
/* make sure the index is valid */
1577-
Assert((idx >=bms_num_members(keys))&&
1578-
(idx <=bms_num_members(keys)+list_length(exprs)));
1575+
if (lc==NULL)
1576+
elog(ERROR,"expression not found in statistics object");
15791577
}
15801578

1581-
Assert((idx >=0)&& (idx<bms_num_members(keys)+list_length(exprs)));
1582-
15831579
returnidx;
15841580
}
15851581

@@ -1659,8 +1655,6 @@ mcv_get_match_bitmap(PlannerInfo *root, List *clauses,
16591655
/* match the attribute/expression to a dimension of the statistic */
16601656
idx=mcv_match_expression(clause_expr,keys,exprs,&collid);
16611657

1662-
Assert((idx >=0)&& (idx<bms_num_members(keys)+list_length(exprs)));
1663-
16641658
/*
16651659
* Walk through the MCV items and evaluate the current clause. We
16661660
* can skip items that were already ruled out, and terminate if
@@ -1944,7 +1938,30 @@ mcv_get_match_bitmap(PlannerInfo *root, List *clauses,
19441938
}
19451939
}
19461940
else
1947-
elog(ERROR,"unknown clause type: %d",clause->type);
1941+
{
1942+
/* Otherwise, it must be a bare boolean-returning expression */
1943+
intidx;
1944+
1945+
/* match the expression to a dimension of the statistic */
1946+
idx=mcv_match_expression(clause,keys,exprs,NULL);
1947+
1948+
/*
1949+
* Walk through the MCV items and evaluate the current clause. We
1950+
* can skip items that were already ruled out, and terminate if
1951+
* there are no remaining MCV items that might possibly match.
1952+
*/
1953+
for (i=0;i<mcvlist->nitems;i++)
1954+
{
1955+
boolmatch;
1956+
MCVItem*item=&mcvlist->items[i];
1957+
1958+
/* "match" just means it's bool TRUE */
1959+
match= !item->isnull[idx]&&DatumGetBool(item->values[idx]);
1960+
1961+
/* now, update the match bitmap, depending on OR/AND type */
1962+
matches[i]=RESULT_MERGE(matches[i],is_or,match);
1963+
}
1964+
}
19481965
}
19491966

19501967
returnmatches;

‎src/test/regress/expected/stats_ext.out

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,14 +260,23 @@ SELECT stxkind FROM pg_statistic_ext WHERE stxname = 'ab1_exprstat_3';
260260
CREATE STATISTICS ab1_exprstat_4 ON date_trunc('day', d) FROM ab1;
261261
-- date_trunc on timestamp is immutable
262262
CREATE STATISTICS ab1_exprstat_5 ON date_trunc('day', c) FROM ab1;
263+
-- check use of a boolean-returning expression
264+
CREATE STATISTICS ab1_exprstat_6 ON
265+
(case a when 1 then true else false end), b FROM ab1;
263266
-- insert some data and run analyze, to test that these cases build properly
264267
INSERT INTO ab1
265-
SELECT
266-
generate_series(1,10),
267-
generate_series(1,10),
268-
generate_series('2020-10-01'::timestamp, '2020-10-10'::timestamp, interval '1 day'),
269-
generate_series('2020-10-01'::timestamptz, '2020-10-10'::timestamptz, interval '1 day');
268+
SELECT x / 10, x / 3,
269+
'2020-10-01'::timestamp + x * interval '1 day',
270+
'2020-10-01'::timestamptz + x * interval '1 day'
271+
FROM generate_series(1, 100) x;
270272
ANALYZE ab1;
273+
-- apply some stats
274+
SELECT * FROM check_estimated_rows('SELECT * FROM ab1 WHERE (case a when 1 then true else false end) AND b=2');
275+
estimated | actual
276+
-----------+--------
277+
1 | 0
278+
(1 row)
279+
271280
DROP TABLE ab1;
272281
-- Verify supported object types for extended statistics
273282
CREATE schema tststats;

‎src/test/regress/sql/stats_ext.sql

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,21 @@ CREATE STATISTICS ab1_exprstat_4 ON date_trunc('day', d) FROM ab1;
164164
-- date_trunc on timestamp is immutable
165165
CREATE STATISTICS ab1_exprstat_5ON date_trunc('day', c)FROM ab1;
166166

167+
-- check use of a boolean-returning expression
168+
CREATE STATISTICS ab1_exprstat_6ON
169+
(case a when1 then true else false end), bFROM ab1;
170+
167171
-- insert some data and run analyze, to test that these cases build properly
168172
INSERT INTO ab1
169-
SELECT
170-
generate_series(1,10),
171-
generate_series(1,10),
172-
generate_series('2020-10-01'::timestamp,'2020-10-10'::timestamp, interval'1 day'),
173-
generate_series('2020-10-01'::timestamptz,'2020-10-10'::timestamptz, interval'1 day');
173+
SELECT x/10, x/3,
174+
'2020-10-01'::timestamp+ x* interval'1 day',
175+
'2020-10-01'::timestamptz+ x* interval'1 day'
176+
FROM generate_series(1,100) x;
174177
ANALYZE ab1;
178+
179+
-- apply some stats
180+
SELECT*FROM check_estimated_rows('SELECT * FROM ab1 WHERE (case a when 1 then true else false end) AND b=2');
181+
175182
DROPTABLE ab1;
176183

177184
-- Verify supported object types for extended statistics

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp