aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-01-07 01:56:24 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-01-07 01:56:24 +0000
commit2054724c085b354f83d59611b62b47b641226e59 (patch)
treee2823b87088560218e6d06680082d92a220b6189
parent79a0a5758143a9b787069d620dae8cd52dd0601a (diff)
downloadpostgresql-2054724c085b354f83d59611b62b47b641226e59.tar.gz
postgresql-2054724c085b354f83d59611b62b47b641226e59.zip
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).
-rw-r--r--src/backend/access/nbtree/nbtsearch.c50
1 files changed, 38 insertions, 12 deletions
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index 6d9be1b0176..23b1a0027e9 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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
* like qual_ok = false.
*/
- cur = (ScanKey) DatumGetPointer(cur->sk_argument);
- Assert(cur->sk_flags & SK_ROW_MEMBER);
- if (cur->sk_flags & SK_ISNULL)
+ ScanKey subkey = (ScanKey) DatumGetPointer(cur->sk_argument);
+
+ Assert(subkey->sk_flags & SK_ROW_MEMBER);
+ if (subkey->sk_flags & SK_ISNULL)
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,
@@ -632,21 +633,46 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
* even if the row comparison is of ">" or "<" type, because the
* condition applied to all but the last row member is effectively
* ">=" 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)
{
- while (!(cur->sk_flags & SK_ROW_END))
+ bool used_all_subkeys = false;
+
+ Assert(!(subkey->sk_flags & SK_ROW_END));
+ for(;;)
{
- cur++;
- Assert(cur->sk_flags & SK_ROW_MEMBER);
- if (cur->sk_attno != keysCount + 1)
+ subkey++;
+ Assert(subkey->sk_flags & SK_ROW_MEMBER);
+ if (subkey->sk_attno != keysCount + 1)
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 */
Assert(keysCount < INDEX_MAX_KEYS);
- memcpy(scankeys + keysCount, cur, sizeof(ScanKeyData));
+ memcpy(scankeys + keysCount, subkey, sizeof(ScanKeyData));
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 */
}