Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 79a3ab1

Browse files
author
Etsuro Fujita
committed
Fix yet another issue with step generation in partition pruning.
Commit 13838740f fixed some issues with step generation in partition pruning, but there was yet another one: get_steps_using_prefix() assumes that clauses in the passed-in prefix list are sorted in ascending order of their partition key numbers, but the caller failed to ensure this for range partitioning, which led to an assertion failure in debug builds. Adjust the caller function to arrange the clauses in the prefix list in the required order for range partitioning. Back-patch to v11, like the previous commit. Patch by me, reviewed by Amit Langote. Discussion: https://postgr.es/m/CAPmGK16jkXiFG0YqMbU66wte-oJTfW6D1HaNvQf%3D%2B5o9%3Dm55wQ%40mail.gmail.com
1 parent be9bdab commit 79a3ab1

File tree

3 files changed

+96
-57
lines changed

3 files changed

+96
-57
lines changed

src/backend/partitioning/partprune.c

Lines changed: 81 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,7 +1362,6 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
13621362
List *eq_clauses = btree_clauses[BTEqualStrategyNumber];
13631363
List *le_clauses = btree_clauses[BTLessEqualStrategyNumber];
13641364
List *ge_clauses = btree_clauses[BTGreaterEqualStrategyNumber];
1365-
bool pk_has_clauses[PARTITION_MAX_KEYS];
13661365
int strat;
13671366

13681367
/*
@@ -1382,10 +1381,15 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
13821381
foreach(lc, btree_clauses[strat])
13831382
{
13841383
PartClauseInfo *pc = lfirst(lc);
1384+
ListCell *eq_start;
1385+
ListCell *le_start;
1386+
ListCell *ge_start;
13851387
ListCell *lc1;
13861388
List *prefix = NIL;
13871389
List *pc_steps;
13881390
bool prefix_valid = true;
1391+
bool pk_has_clauses;
1392+
int keyno;
13891393

13901394
/*
13911395
* If this is a clause for the first partition key,
@@ -1410,79 +1414,96 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
14101414
continue;
14111415
}
14121416

1413-
/* (Re-)initialize the pk_has_clauses array */
1414-
Assert(pc->keyno > 0);
1415-
for (i = 0; i < pc->keyno; i++)
1416-
pk_has_clauses[i] = false;
1417+
eq_start = list_head(eq_clauses);
1418+
le_start = list_head(le_clauses);
1419+
ge_start = list_head(ge_clauses);
14171420

14181421
/*
1419-
* Expressions from = clauses can always be in the
1420-
* prefix, provided they're from an earlier key.
1422+
* We arrange clauses into prefix in ascending order
1423+
* of their partition key numbers.
14211424
*/
1422-
foreach(lc1, eq_clauses)
1425+
for (keyno = 0; keyno < pc->keyno; keyno++)
14231426
{
1424-
PartClauseInfo *eqpc = lfirst(lc1);
1427+
pk_has_clauses = false;
14251428

1426-
if (eqpc->keyno == pc->keyno)
1427-
break;
1428-
if (eqpc->keyno < pc->keyno)
1429+
/*
1430+
* Expressions from = clauses can always be in the
1431+
* prefix, provided they're from an earlier key.
1432+
*/
1433+
for_each_cell(lc1, eq_clauses, eq_start)
14291434
{
1430-
prefix = lappend(prefix, eqpc);
1431-
pk_has_clauses[eqpc->keyno] = true;
1432-
}
1433-
}
1435+
PartClauseInfo *eqpc = lfirst(lc1);
14341436

1435-
/*
1436-
* If we're generating steps for </<= strategy, we can
1437-
* add other <= clauses to the prefix, provided
1438-
* they're from an earlier key.
1439-
*/
1440-
if (strat == BTLessStrategyNumber ||
1441-
strat == BTLessEqualStrategyNumber)
1442-
{
1443-
foreach(lc1, le_clauses)
1444-
{
1445-
PartClauseInfo *lepc = lfirst(lc1);
1446-
1447-
if (lepc->keyno == pc->keyno)
1437+
if (eqpc->keyno == keyno)
1438+
{
1439+
prefix = lappend(prefix, eqpc);
1440+
pk_has_clauses = true;
1441+
}
1442+
else
1443+
{
1444+
Assert(eqpc->keyno > keyno);
14481445
break;
1449-
if (lepc->keyno < pc->keyno)
1446+
}
1447+
}
1448+
eq_start = lc1;
1449+
1450+
/*
1451+
* If we're generating steps for </<= strategy, we
1452+
* can add other <= clauses to the prefix,
1453+
* provided they're from an earlier key.
1454+
*/
1455+
if (strat == BTLessStrategyNumber ||
1456+
strat == BTLessEqualStrategyNumber)
1457+
{
1458+
for_each_cell(lc1, le_clauses, le_start)
14501459
{
1451-
prefix = lappend(prefix, lepc);
1452-
pk_has_clauses[lepc->keyno] = true;
1460+
PartClauseInfo *lepc = lfirst(lc1);
1461+
1462+
if (lepc->keyno == keyno)
1463+
{
1464+
prefix = lappend(prefix, lepc);
1465+
pk_has_clauses = true;
1466+
}
1467+
else
1468+
{
1469+
Assert(lepc->keyno > keyno);
1470+
break;
1471+
}
14531472
}
1473+
le_start = lc1;
14541474
}
1455-
}
14561475

1457-
/*
1458-
* If we're generating steps for >/>= strategy, we can
1459-
* add other >= clauses to the prefix, provided
1460-
* they're from an earlier key.
1461-
*/
1462-
if (strat == BTGreaterStrategyNumber ||
1463-
strat == BTGreaterEqualStrategyNumber)
1464-
{
1465-
foreach(lc1, ge_clauses)
1476+
/*
1477+
* If we're generating steps for >/>= strategy, we
1478+
* can add other >= clauses to the prefix,
1479+
* provided they're from an earlier key.
1480+
*/
1481+
if (strat == BTGreaterStrategyNumber ||
1482+
strat == BTGreaterEqualStrategyNumber)
14661483
{
1467-
PartClauseInfo *gepc = lfirst(lc1);
1468-
1469-
if (gepc->keyno == pc->keyno)
1470-
break;
1471-
if (gepc->keyno < pc->keyno)
1484+
for_each_cell(lc1, ge_clauses, ge_start)
14721485
{
1473-
prefix = lappend(prefix, gepc);
1474-
pk_has_clauses[gepc->keyno] = true;
1486+
PartClauseInfo *gepc = lfirst(lc1);
1487+
1488+
if (gepc->keyno == keyno)
1489+
{
1490+
prefix = lappend(prefix, gepc);
1491+
pk_has_clauses = true;
1492+
}
1493+
else
1494+
{
1495+
Assert(gepc->keyno > keyno);
1496+
break;
1497+
}
14751498
}
1499+
ge_start = lc1;
14761500
}
1477-
}
14781501

1479-
/*
1480-
* Check whether every earlier partition key has at
1481-
* least one clause.
1482-
*/
1483-
for (i = 0; i < pc->keyno; i++)
1484-
{
1485-
if (!pk_has_clauses[i])
1502+
/*
1503+
* If this key has no clauses, prefix is not valid
1504+
* anymore.
1505+
*/
1506+
if (!pk_has_clauses)
14861507
{
14871508
prefix_valid = false;
14881509
break;
@@ -2241,6 +2262,9 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context,
22412262
* non-NULL, but they must ensure that prefix contains at least one clause
22422263
* for each of the partition keys other than those specified in step_nullkeys
22432264
* and step_lastkeyno.
2265+
*
2266+
* For both cases, callers must also ensure that clauses in prefix are sorted
2267+
* in ascending order of their partition key numbers.
22442268
*/
22452269
static List *
22462270
get_steps_using_prefix(GeneratePruningStepsContext *context,

src/test/regress/expected/partition_prune.out

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3711,6 +3711,16 @@ explain (costs off) select * from rp_prefix_test3 where a >= 1 and b >= 1 and b
37113711
Filter: ((a >= 1) AND (b >= 1) AND (b >= 2) AND (c >= 2) AND (d >= 0))
37123712
(2 rows)
37133713

3714+
-- Test that get_steps_using_prefix() handles a prefix that contains multiple
3715+
-- clauses for the partition key b (ie, b >= 1 and b = 2) (This also tests
3716+
-- that the caller arranges clauses in that prefix in the required order)
3717+
explain (costs off) select * from rp_prefix_test3 where a >= 1 and b >= 1 and b = 2 and c = 2 and d >= 0;
3718+
QUERY PLAN
3719+
------------------------------------------------------------------------
3720+
Seq Scan on rp_prefix_test3_p2 rp_prefix_test3
3721+
Filter: ((a >= 1) AND (b >= 1) AND (d >= 0) AND (b = 2) AND (c = 2))
3722+
(2 rows)
3723+
37143724
create table hp_prefix_test (a int, b int, c int, d int) partition by hash (a part_test_int4_ops, b part_test_int4_ops, c part_test_int4_ops, d part_test_int4_ops);
37153725
create table hp_prefix_test_p1 partition of hp_prefix_test for values with (modulus 2, remainder 0);
37163726
create table hp_prefix_test_p2 partition of hp_prefix_test for values with (modulus 2, remainder 1);

src/test/regress/sql/partition_prune.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,11 @@ create table rp_prefix_test3_p2 partition of rp_prefix_test3 for values from (2,
10801080
-- clauses for the partition key b (ie, b >= 1 and b >= 2)
10811081
explain (costs off) select * from rp_prefix_test3 where a >= 1 and b >= 1 and b >= 2 and c >= 2 and d >= 0;
10821082

1083+
-- Test that get_steps_using_prefix() handles a prefix that contains multiple
1084+
-- clauses for the partition key b (ie, b >= 1 and b = 2) (This also tests
1085+
-- that the caller arranges clauses in that prefix in the required order)
1086+
explain (costs off) select * from rp_prefix_test3 where a >= 1 and b >= 1 and b = 2 and c = 2 and d >= 0;
1087+
10831088
create table hp_prefix_test (a int, b int, c int, d int) partition by hash (a part_test_int4_ops, b part_test_int4_ops, c part_test_int4_ops, d part_test_int4_ops);
10841089
create table hp_prefix_test_p1 partition of hp_prefix_test for values with (modulus 2, remainder 0);
10851090
create table hp_prefix_test_p2 partition of hp_prefix_test for values with (modulus 2, remainder 1);

0 commit comments

Comments
 (0)