mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
Fix oversight in handling of row-comparison index keys: if the row comparison
doesn't exactly match the index, we may have to change our initial positioning strategy. For example, given an index on (f1,f2,f3) and a WHERE condition "ROW(f1,f3) > ROW(2,3)", the code extracted the initial-positioning condition "f1 > 2", which is wrong ... it has to be "f1 >= 2", else some rows matching the WHERE condition may fail to be returned. Applying patch to 8.2 only --- I'll fix it in HEAD later as part of the planned index improvements (reverse-sort and NULLS FIRST/LAST work).
This commit is contained in:
parent
79a0a57581
commit
2054724c08
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.107 2006/10/04 00:29:49 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.107.2.1 2007/01/07 01:56:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -617,11 +617,12 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
|||||||
* in the first row member makes the condition unmatchable, just
|
* in the first row member makes the condition unmatchable, just
|
||||||
* like qual_ok = false.
|
* like qual_ok = false.
|
||||||
*/
|
*/
|
||||||
cur = (ScanKey) DatumGetPointer(cur->sk_argument);
|
ScanKey subkey = (ScanKey) DatumGetPointer(cur->sk_argument);
|
||||||
Assert(cur->sk_flags & SK_ROW_MEMBER);
|
|
||||||
if (cur->sk_flags & SK_ISNULL)
|
Assert(subkey->sk_flags & SK_ROW_MEMBER);
|
||||||
|
if (subkey->sk_flags & SK_ISNULL)
|
||||||
return false;
|
return false;
|
||||||
memcpy(scankeys + i, cur, sizeof(ScanKeyData));
|
memcpy(scankeys + i, subkey, sizeof(ScanKeyData));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the row comparison is the last positioning key we accepted,
|
* If the row comparison is the last positioning key we accepted,
|
||||||
@ -632,21 +633,46 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
|||||||
* even if the row comparison is of ">" or "<" type, because the
|
* even if the row comparison is of ">" or "<" type, because the
|
||||||
* condition applied to all but the last row member is effectively
|
* condition applied to all but the last row member is effectively
|
||||||
* ">=" or "<=", and so the extra keys don't break the positioning
|
* ">=" or "<=", and so the extra keys don't break the positioning
|
||||||
* scheme.
|
* scheme. But, by the same token, if we aren't able to use all
|
||||||
|
* the row members, then the part of the row comparison that we
|
||||||
|
* did use has to be treated as just a ">=" or "<=" condition,
|
||||||
|
* and so we'd better adjust strat_total accordingly.
|
||||||
*/
|
*/
|
||||||
if (i == keysCount - 1)
|
if (i == keysCount - 1)
|
||||||
{
|
{
|
||||||
while (!(cur->sk_flags & SK_ROW_END))
|
bool used_all_subkeys = false;
|
||||||
|
|
||||||
|
Assert(!(subkey->sk_flags & SK_ROW_END));
|
||||||
|
for(;;)
|
||||||
{
|
{
|
||||||
cur++;
|
subkey++;
|
||||||
Assert(cur->sk_flags & SK_ROW_MEMBER);
|
Assert(subkey->sk_flags & SK_ROW_MEMBER);
|
||||||
if (cur->sk_attno != keysCount + 1)
|
if (subkey->sk_attno != keysCount + 1)
|
||||||
break; /* out-of-sequence, can't use it */
|
break; /* out-of-sequence, can't use it */
|
||||||
if (cur->sk_flags & SK_ISNULL)
|
if (subkey->sk_strategy != cur->sk_strategy)
|
||||||
|
break; /* wrong direction, can't use it */
|
||||||
|
if (subkey->sk_flags & SK_ISNULL)
|
||||||
break; /* can't use null keys */
|
break; /* can't use null keys */
|
||||||
Assert(keysCount < INDEX_MAX_KEYS);
|
Assert(keysCount < INDEX_MAX_KEYS);
|
||||||
memcpy(scankeys + keysCount, cur, sizeof(ScanKeyData));
|
memcpy(scankeys + keysCount, subkey, sizeof(ScanKeyData));
|
||||||
keysCount++;
|
keysCount++;
|
||||||
|
if (subkey->sk_flags & SK_ROW_END)
|
||||||
|
{
|
||||||
|
used_all_subkeys = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!used_all_subkeys)
|
||||||
|
{
|
||||||
|
switch (strat_total)
|
||||||
|
{
|
||||||
|
case BTLessStrategyNumber:
|
||||||
|
strat_total = BTLessEqualStrategyNumber;
|
||||||
|
break;
|
||||||
|
case BTGreaterStrategyNumber:
|
||||||
|
strat_total = BTGreaterEqualStrategyNumber;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break; /* done with outer loop */
|
break; /* done with outer loop */
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user