mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-28 02:27:19 +02:00
Fix CLUSTER tuplesorts on abbreviated expressions.
CLUSTER sort won't use the datum1 SortTuple field when clustering against an index whose leading key is an expression. This makes it unsafe to use the abbreviated keys optimization, which was missed by the logic that sets up SortSupport state. Affected tuplesorts output tuples in a completely bogus order as a result (the wrong SortSupport based comparator was used for the leading attribute). This issue is similar to the bug fixed on the master branch by recent commitcc58eecc5d
. But it's a far older issue, that dates back to the introduction of the abbreviated keys optimization by commit4ea51cdfe8
. Backpatch to all supported versions. Author: Peter Geoghegan <pg@bowt.ie> Author: Thomas Munro <thomas.munro@gmail.com> Discussion: https://postgr.es/m/CA+hUKG+bA+bmwD36_oDxAoLrCwZjVtST2fqe=b4=qZcmU7u89A@mail.gmail.com Backpatch: 10-
This commit is contained in:
parent
33fe55c06b
commit
5487585e37
@ -884,6 +884,7 @@ tuplesort_begin_cluster(TupleDesc tupDesc,
|
|||||||
{
|
{
|
||||||
Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
|
Tuplesortstate *state = tuplesort_begin_common(workMem, coordinate,
|
||||||
randomAccess);
|
randomAccess);
|
||||||
|
AttrNumber leading;
|
||||||
BTScanInsert indexScanKey;
|
BTScanInsert indexScanKey;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
int i;
|
int i;
|
||||||
@ -916,6 +917,7 @@ tuplesort_begin_cluster(TupleDesc tupDesc,
|
|||||||
state->abbrevNext = 10;
|
state->abbrevNext = 10;
|
||||||
|
|
||||||
state->indexInfo = BuildIndexInfo(indexRel);
|
state->indexInfo = BuildIndexInfo(indexRel);
|
||||||
|
leading = state->indexInfo->ii_IndexAttrNumbers[0];
|
||||||
|
|
||||||
state->tupDesc = tupDesc; /* assume we need not copy tupDesc */
|
state->tupDesc = tupDesc; /* assume we need not copy tupDesc */
|
||||||
|
|
||||||
@ -954,7 +956,7 @@ tuplesort_begin_cluster(TupleDesc tupDesc,
|
|||||||
(scanKey->sk_flags & SK_BT_NULLS_FIRST) != 0;
|
(scanKey->sk_flags & SK_BT_NULLS_FIRST) != 0;
|
||||||
sortKey->ssup_attno = scanKey->sk_attno;
|
sortKey->ssup_attno = scanKey->sk_attno;
|
||||||
/* Convey if abbreviation optimization is applicable in principle */
|
/* Convey if abbreviation optimization is applicable in principle */
|
||||||
sortKey->abbreviate = (i == 0);
|
sortKey->abbreviate = (i == 0 && leading != 0);
|
||||||
|
|
||||||
AssertState(sortKey->ssup_attno != 0);
|
AssertState(sortKey->ssup_attno != 0);
|
||||||
|
|
||||||
|
@ -506,6 +506,13 @@ SELECT * FROM clstr_expression WHERE -a = -3 ORDER BY -a, b;
|
|||||||
COMMIT;
|
COMMIT;
|
||||||
-- and after clustering on clstr_expression_minus_a
|
-- and after clustering on clstr_expression_minus_a
|
||||||
CLUSTER clstr_expression USING clstr_expression_minus_a;
|
CLUSTER clstr_expression USING clstr_expression_minus_a;
|
||||||
|
WITH rows AS
|
||||||
|
(SELECT ctid, lag(a) OVER (ORDER BY ctid) AS la, a FROM clstr_expression)
|
||||||
|
SELECT * FROM rows WHERE la < a;
|
||||||
|
ctid | la | a
|
||||||
|
------+----+---
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SET LOCAL enable_seqscan = false;
|
SET LOCAL enable_seqscan = false;
|
||||||
EXPLAIN (COSTS OFF) SELECT * FROM clstr_expression WHERE upper(b) = 'PREFIX3';
|
EXPLAIN (COSTS OFF) SELECT * FROM clstr_expression WHERE upper(b) = 'PREFIX3';
|
||||||
@ -540,6 +547,13 @@ SELECT * FROM clstr_expression WHERE -a = -3 ORDER BY -a, b;
|
|||||||
COMMIT;
|
COMMIT;
|
||||||
-- and after clustering on clstr_expression_upper_b
|
-- and after clustering on clstr_expression_upper_b
|
||||||
CLUSTER clstr_expression USING clstr_expression_upper_b;
|
CLUSTER clstr_expression USING clstr_expression_upper_b;
|
||||||
|
WITH rows AS
|
||||||
|
(SELECT ctid, lag(b) OVER (ORDER BY ctid) AS lb, b FROM clstr_expression)
|
||||||
|
SELECT * FROM rows WHERE upper(lb) > upper(b);
|
||||||
|
ctid | lb | b
|
||||||
|
------+----+---
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SET LOCAL enable_seqscan = false;
|
SET LOCAL enable_seqscan = false;
|
||||||
EXPLAIN (COSTS OFF) SELECT * FROM clstr_expression WHERE upper(b) = 'PREFIX3';
|
EXPLAIN (COSTS OFF) SELECT * FROM clstr_expression WHERE upper(b) = 'PREFIX3';
|
||||||
|
@ -239,6 +239,9 @@ COMMIT;
|
|||||||
|
|
||||||
-- and after clustering on clstr_expression_minus_a
|
-- and after clustering on clstr_expression_minus_a
|
||||||
CLUSTER clstr_expression USING clstr_expression_minus_a;
|
CLUSTER clstr_expression USING clstr_expression_minus_a;
|
||||||
|
WITH rows AS
|
||||||
|
(SELECT ctid, lag(a) OVER (ORDER BY ctid) AS la, a FROM clstr_expression)
|
||||||
|
SELECT * FROM rows WHERE la < a;
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SET LOCAL enable_seqscan = false;
|
SET LOCAL enable_seqscan = false;
|
||||||
EXPLAIN (COSTS OFF) SELECT * FROM clstr_expression WHERE upper(b) = 'PREFIX3';
|
EXPLAIN (COSTS OFF) SELECT * FROM clstr_expression WHERE upper(b) = 'PREFIX3';
|
||||||
@ -249,6 +252,9 @@ COMMIT;
|
|||||||
|
|
||||||
-- and after clustering on clstr_expression_upper_b
|
-- and after clustering on clstr_expression_upper_b
|
||||||
CLUSTER clstr_expression USING clstr_expression_upper_b;
|
CLUSTER clstr_expression USING clstr_expression_upper_b;
|
||||||
|
WITH rows AS
|
||||||
|
(SELECT ctid, lag(b) OVER (ORDER BY ctid) AS lb, b FROM clstr_expression)
|
||||||
|
SELECT * FROM rows WHERE upper(lb) > upper(b);
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SET LOCAL enable_seqscan = false;
|
SET LOCAL enable_seqscan = false;
|
||||||
EXPLAIN (COSTS OFF) SELECT * FROM clstr_expression WHERE upper(b) = 'PREFIX3';
|
EXPLAIN (COSTS OFF) SELECT * FROM clstr_expression WHERE upper(b) = 'PREFIX3';
|
||||||
|
Loading…
Reference in New Issue
Block a user