]> granicus.if.org Git - postgresql/commitdiff
Fix oversight in handling of row-comparison index keys: if the row comparison
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 7 Jan 2007 01:56:24 +0000 (01:56 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 7 Jan 2007 01:56:24 +0000 (01:56 +0000)
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).

src/backend/access/nbtree/nbtsearch.c

index 6d9be1b0176636f17f90792eacb5df206914eb63..23b1a0027e9987713acdaa92ff4adaba9ff8dd03 100644 (file)
@@ -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 */
                        }