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

Commitd758d97

Browse files
committed
Fix assorted partition pruning bugs
match_clause_to_partition_key failed to consider COERCION_PATH_ARRAYCOERCEcases in scalar-op-array expressions, so it was possible to crash theserver easily. To handle this case properly (ie. prune partitions) wewould need to run a bit of executor code during planning. Maybe it canbe improved, but for now let's just not crash. Add a test case thatused to trigger the crash.Author: Michaël Paquiermatch_clause_to_partition_key failed to indicate that operators thatdon't have a commutator in a btree opclass are unsupported. It ispossible for this to cause a crash later if such an operator is used ina scalar-op-array expression. Add a test case that used to the crash.Author: Amit LangoteOne caller of gen_partprune_steps_internal inmatch_clause_to_partition_key was too optimistic about the former neverreturning an empty step list. Rid it of its innocence. (Having fixedthe bug above, I no longer know how to exploit this, so no test case forit, but it remained a bug.) Revise code flow a little bit, forsuccintness.Author: Álvaro HerreraReported-by: Marina PolyakovaReviewed-by: Michaël PaquierReviewed-by: Amit LangoteReviewed-by: Álvaro HerreraDiscussion:https://postgr.es/m/ff8f9bfa485ff961d6bb43e54120485b@postgrespro.ru
1 parent35361ee commitd758d97

File tree

3 files changed

+106
-32
lines changed

3 files changed

+106
-32
lines changed

‎src/backend/partitioning/partprune.c

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -573,8 +573,9 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
573573
* For BoolExpr clauses, we recursively generate steps for each argument, and
574574
* return a PartitionPruneStepCombine of their results.
575575
*
576-
* The generated steps are added to the context's steps list. Each step is
577-
* assigned a step identifier, unique even across recursive calls.
576+
* The return value is a list of the steps generated, which are also added to
577+
* the context's steps list. Each step is assigned a step identifier, unique
578+
* even across recursive calls.
578579
*
579580
* If we find clauses that are mutually contradictory, or a pseudoconstant
580581
* clause that contains false, we set *contradictory to true and return NIL
@@ -1601,6 +1602,7 @@ match_clause_to_partition_key(RelOptInfo *rel,
16011602
List*elem_exprs,
16021603
*elem_clauses;
16031604
ListCell*lc1;
1605+
boolcontradictory;
16041606

16051607
if (IsA(leftop,RelabelType))
16061608
leftop= ((RelabelType*)leftop)->arg;
@@ -1619,7 +1621,7 @@ match_clause_to_partition_key(RelOptInfo *rel,
16191621
* Only allow strict operators. This will guarantee nulls are
16201622
* filtered.
16211623
*/
1622-
if (!op_strict(saop->opno))
1624+
if (!op_strict(saop_op))
16231625
returnPARTCLAUSE_UNSUPPORTED;
16241626

16251627
/* Useless if the array has any volatile functions. */
@@ -1652,6 +1654,8 @@ match_clause_to_partition_key(RelOptInfo *rel,
16521654
if (strategy!=BTEqualStrategyNumber)
16531655
returnPARTCLAUSE_UNSUPPORTED;
16541656
}
1657+
else
1658+
returnPARTCLAUSE_UNSUPPORTED;/* no useful negator */
16551659
}
16561660

16571661
/*
@@ -1692,7 +1696,7 @@ match_clause_to_partition_key(RelOptInfo *rel,
16921696
elem_exprs=lappend(elem_exprs,elem_expr);
16931697
}
16941698
}
1695-
else
1699+
elseif (IsA(rightop,ArrayExpr))
16961700
{
16971701
ArrayExpr*arrexpr=castNode(ArrayExpr,rightop);
16981702

@@ -1706,6 +1710,11 @@ match_clause_to_partition_key(RelOptInfo *rel,
17061710

17071711
elem_exprs=arrexpr->elements;
17081712
}
1713+
else
1714+
{
1715+
/* Give up on any other clause types. */
1716+
returnPARTCLAUSE_UNSUPPORTED;
1717+
}
17091718

17101719
/*
17111720
* Now generate a list of clauses, one for each array element, of the
@@ -1724,36 +1733,21 @@ match_clause_to_partition_key(RelOptInfo *rel,
17241733
}
17251734

17261735
/*
1727-
*Build a combine step as if for an OR clause or addtheclauses to
1728-
*the endofthe list that's being processed currently.
1736+
*If we have an ANY clause and multiple elements, first turnthelist
1737+
* ofclauses into an OR expression.
17291738
*/
17301739
if (saop->useOr&&list_length(elem_clauses)>1)
1731-
{
1732-
Expr*orexpr;
1733-
boolcontradictory;
1734-
1735-
orexpr=makeBoolExpr(OR_EXPR,elem_clauses,-1);
1736-
*clause_steps=
1737-
gen_partprune_steps_internal(context,rel,list_make1(orexpr),
1738-
&contradictory);
1739-
if (contradictory)
1740-
returnPARTCLAUSE_MATCH_CONTRADICT;
1741-
1742-
Assert(list_length(*clause_steps)==1);
1743-
returnPARTCLAUSE_MATCH_STEPS;
1744-
}
1745-
else
1746-
{
1747-
boolcontradictory;
1748-
1749-
*clause_steps=
1750-
gen_partprune_steps_internal(context,rel,elem_clauses,
1751-
&contradictory);
1752-
if (contradictory)
1753-
returnPARTCLAUSE_MATCH_CONTRADICT;
1754-
Assert(list_length(*clause_steps) >=1);
1755-
returnPARTCLAUSE_MATCH_STEPS;
1756-
}
1740+
elem_clauses=list_make1(makeBoolExpr(OR_EXPR,elem_clauses,-1));
1741+
1742+
/* Finally, generate steps */
1743+
*clause_steps=
1744+
gen_partprune_steps_internal(context,rel,elem_clauses,
1745+
&contradictory);
1746+
if (contradictory)
1747+
returnPARTCLAUSE_MATCH_CONTRADICT;
1748+
elseif (*clause_steps==NIL)
1749+
returnPARTCLAUSE_UNSUPPORTED;/* step generation failed */
1750+
returnPARTCLAUSE_MATCH_STEPS;
17571751
}
17581752
elseif (IsA(clause,NullTest))
17591753
{

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

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,72 @@ explain (costs off) select * from boolpart where a is not unknown;
10731073
Filter: (a IS NOT UNKNOWN)
10741074
(7 rows)
10751075

1076+
-- test scalar-to-array operators
1077+
create table coercepart (a varchar) partition by list (a);
1078+
create table coercepart_ab partition of coercepart for values in ('ab');
1079+
create table coercepart_bc partition of coercepart for values in ('bc');
1080+
create table coercepart_cd partition of coercepart for values in ('cd');
1081+
explain (costs off) select * from coercepart where a in ('ab', to_char(125, '999'));
1082+
QUERY PLAN
1083+
------------------------------------------------------------------------------------------------------------------------------
1084+
Append
1085+
-> Seq Scan on coercepart_ab
1086+
Filter: ((a)::text = ANY ((ARRAY['ab'::character varying, (to_char(125, '999'::text))::character varying])::text[]))
1087+
-> Seq Scan on coercepart_bc
1088+
Filter: ((a)::text = ANY ((ARRAY['ab'::character varying, (to_char(125, '999'::text))::character varying])::text[]))
1089+
-> Seq Scan on coercepart_cd
1090+
Filter: ((a)::text = ANY ((ARRAY['ab'::character varying, (to_char(125, '999'::text))::character varying])::text[]))
1091+
(7 rows)
1092+
1093+
explain (costs off) select * from coercepart where a ~ any ('{ab}');
1094+
QUERY PLAN
1095+
----------------------------------------------------
1096+
Append
1097+
-> Seq Scan on coercepart_ab
1098+
Filter: ((a)::text ~ ANY ('{ab}'::text[]))
1099+
-> Seq Scan on coercepart_bc
1100+
Filter: ((a)::text ~ ANY ('{ab}'::text[]))
1101+
-> Seq Scan on coercepart_cd
1102+
Filter: ((a)::text ~ ANY ('{ab}'::text[]))
1103+
(7 rows)
1104+
1105+
explain (costs off) select * from coercepart where a !~ all ('{ab}');
1106+
QUERY PLAN
1107+
-----------------------------------------------------
1108+
Append
1109+
-> Seq Scan on coercepart_ab
1110+
Filter: ((a)::text !~ ALL ('{ab}'::text[]))
1111+
-> Seq Scan on coercepart_bc
1112+
Filter: ((a)::text !~ ALL ('{ab}'::text[]))
1113+
-> Seq Scan on coercepart_cd
1114+
Filter: ((a)::text !~ ALL ('{ab}'::text[]))
1115+
(7 rows)
1116+
1117+
explain (costs off) select * from coercepart where a ~ any ('{ab,bc}');
1118+
QUERY PLAN
1119+
-------------------------------------------------------
1120+
Append
1121+
-> Seq Scan on coercepart_ab
1122+
Filter: ((a)::text ~ ANY ('{ab,bc}'::text[]))
1123+
-> Seq Scan on coercepart_bc
1124+
Filter: ((a)::text ~ ANY ('{ab,bc}'::text[]))
1125+
-> Seq Scan on coercepart_cd
1126+
Filter: ((a)::text ~ ANY ('{ab,bc}'::text[]))
1127+
(7 rows)
1128+
1129+
explain (costs off) select * from coercepart where a !~ all ('{ab,bc}');
1130+
QUERY PLAN
1131+
--------------------------------------------------------
1132+
Append
1133+
-> Seq Scan on coercepart_ab
1134+
Filter: ((a)::text !~ ALL ('{ab,bc}'::text[]))
1135+
-> Seq Scan on coercepart_bc
1136+
Filter: ((a)::text !~ ALL ('{ab,bc}'::text[]))
1137+
-> Seq Scan on coercepart_cd
1138+
Filter: ((a)::text !~ ALL ('{ab,bc}'::text[]))
1139+
(7 rows)
1140+
1141+
drop table coercepart;
10761142
--
10771143
-- some more cases
10781144
--

‎src/test/regress/sql/partition_prune.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,20 @@ explain (costs off) select * from boolpart where a is not true and a is not fals
152152
explain (costs off)select*from boolpartwhere a is unknown;
153153
explain (costs off)select*from boolpartwhere a is not unknown;
154154

155+
-- test scalar-to-array operators
156+
createtablecoercepart (avarchar) partition by list (a);
157+
createtablecoercepart_ab partition of coercepart forvaluesin ('ab');
158+
createtablecoercepart_bc partition of coercepart forvaluesin ('bc');
159+
createtablecoercepart_cd partition of coercepart forvaluesin ('cd');
160+
161+
explain (costs off)select*from coercepartwhere ain ('ab', to_char(125,'999'));
162+
explain (costs off)select*from coercepartwhere a ~ any ('{ab}');
163+
explain (costs off)select*from coercepartwhere a !~ all ('{ab}');
164+
explain (costs off)select*from coercepartwhere a ~ any ('{ab,bc}');
165+
explain (costs off)select*from coercepartwhere a !~ all ('{ab,bc}');
166+
167+
droptable coercepart;
168+
155169
--
156170
-- some more cases
157171
--

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp