|
8 | 8 | * Portions Copyright (c) 1994, Regents of the University of California
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.101 2006/01/23 22:31:40 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.102 2006/01/25 20:29:23 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -551,6 +551,10 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
551 | 551 | * one we use --- by definition, they are either redundant or
|
552 | 552 | * contradictory.
|
553 | 553 | *
|
| 554 | + * In this loop, row-comparison keys are treated the same as keys on their |
| 555 | + * first (leftmost) columns. We'll add on lower-order columns of the row |
| 556 | + * comparison below, if possible. |
| 557 | + * |
554 | 558 | * The selected scan keys (at most one per index column) are remembered by
|
555 | 559 | * storing their addresses into the local startKeys[] array.
|
556 | 560 | *----------
|
@@ -657,44 +661,91 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
657 | 661 | {
|
658 | 662 | ScanKeycur=startKeys[i];
|
659 | 663 |
|
660 |
| -/* |
661 |
| - * _bt_preprocess_keys disallows it, but it's place to add some code |
662 |
| - * later |
663 |
| - */ |
664 |
| -if (cur->sk_flags&SK_ISNULL) |
665 |
| -elog(ERROR,"btree doesn't support is(not)null, yet"); |
| 664 | +Assert(cur->sk_attno==i+1); |
666 | 665 |
|
667 |
| -/* |
668 |
| - * If scankey operator is of default subtype, we can use the cached |
669 |
| - * comparison procedure; otherwise gotta look it up in the catalogs. |
670 |
| - */ |
671 |
| -if (cur->sk_subtype==InvalidOid) |
| 666 | +if (cur->sk_flags&SK_ROW_HEADER) |
672 | 667 | {
|
673 |
| -FmgrInfo*procinfo; |
674 |
| - |
675 |
| -procinfo=index_getprocinfo(rel,i+1,BTORDER_PROC); |
676 |
| -ScanKeyEntryInitializeWithInfo(scankeys+i, |
677 |
| -cur->sk_flags, |
678 |
| -i+1, |
679 |
| -InvalidStrategy, |
680 |
| -InvalidOid, |
681 |
| -procinfo, |
682 |
| -cur->sk_argument); |
| 668 | +/* |
| 669 | + * Row comparison header: look to the first row member instead. |
| 670 | + * |
| 671 | + * The member scankeys are already in insertion format (ie, they |
| 672 | + * have sk_func = 3-way-comparison function), but we have to |
| 673 | + * watch out for nulls, which _bt_preprocess_keys didn't check. |
| 674 | + * A null in the first row member makes the condition unmatchable, |
| 675 | + * just like qual_ok = false. |
| 676 | + */ |
| 677 | +cur= (ScanKey)DatumGetPointer(cur->sk_argument); |
| 678 | +Assert(cur->sk_flags&SK_ROW_MEMBER); |
| 679 | +if (cur->sk_flags&SK_ISNULL) |
| 680 | +return false; |
| 681 | +memcpy(scankeys+i,cur,sizeof(ScanKeyData)); |
| 682 | +/* |
| 683 | + * If the row comparison is the last positioning key we accepted, |
| 684 | + * try to add additional keys from the lower-order row members. |
| 685 | + * (If we accepted independent conditions on additional index |
| 686 | + * columns, we use those instead --- doesn't seem worth trying to |
| 687 | + * determine which is more restrictive.) Note that this is OK |
| 688 | + * even if the row comparison is of ">" or "<" type, because the |
| 689 | + * condition applied to all but the last row member is effectively |
| 690 | + * ">=" or "<=", and so the extra keys don't break the positioning |
| 691 | + * scheme. |
| 692 | + */ |
| 693 | +if (i==keysCount-1) |
| 694 | +{ |
| 695 | +while (!(cur->sk_flags&SK_ROW_END)) |
| 696 | +{ |
| 697 | +cur++; |
| 698 | +Assert(cur->sk_flags&SK_ROW_MEMBER); |
| 699 | +if (cur->sk_attno!=keysCount+1) |
| 700 | +break;/* out-of-sequence, can't use it */ |
| 701 | +if (cur->sk_flags&SK_ISNULL) |
| 702 | +break;/* can't use null keys */ |
| 703 | +Assert(keysCount<INDEX_MAX_KEYS); |
| 704 | +memcpy(scankeys+keysCount,cur,sizeof(ScanKeyData)); |
| 705 | +keysCount++; |
| 706 | +} |
| 707 | +break;/* done with outer loop */ |
| 708 | +} |
683 | 709 | }
|
684 | 710 | else
|
685 | 711 | {
|
686 |
| -RegProcedurecmp_proc; |
687 |
| - |
688 |
| -cmp_proc=get_opclass_proc(rel->rd_indclass->values[i], |
689 |
| -cur->sk_subtype, |
690 |
| -BTORDER_PROC); |
691 |
| -ScanKeyEntryInitialize(scankeys+i, |
692 |
| -cur->sk_flags, |
693 |
| -i+1, |
694 |
| -InvalidStrategy, |
695 |
| -cur->sk_subtype, |
696 |
| -cmp_proc, |
697 |
| -cur->sk_argument); |
| 712 | +/* |
| 713 | + * Ordinary comparison key. Transform the search-style scan key |
| 714 | + * to an insertion scan key by replacing the sk_func with the |
| 715 | + * appropriate btree comparison function. |
| 716 | + * |
| 717 | + * If scankey operator is of default subtype, we can use the |
| 718 | + * cached comparison function; otherwise gotta look it up in the |
| 719 | + * catalogs. |
| 720 | + */ |
| 721 | +if (cur->sk_subtype==InvalidOid) |
| 722 | +{ |
| 723 | +FmgrInfo*procinfo; |
| 724 | + |
| 725 | +procinfo=index_getprocinfo(rel,cur->sk_attno,BTORDER_PROC); |
| 726 | +ScanKeyEntryInitializeWithInfo(scankeys+i, |
| 727 | +cur->sk_flags, |
| 728 | +cur->sk_attno, |
| 729 | +InvalidStrategy, |
| 730 | +InvalidOid, |
| 731 | +procinfo, |
| 732 | +cur->sk_argument); |
| 733 | +} |
| 734 | +else |
| 735 | +{ |
| 736 | +RegProcedurecmp_proc; |
| 737 | + |
| 738 | +cmp_proc=get_opclass_proc(rel->rd_indclass->values[i], |
| 739 | +cur->sk_subtype, |
| 740 | +BTORDER_PROC); |
| 741 | +ScanKeyEntryInitialize(scankeys+i, |
| 742 | +cur->sk_flags, |
| 743 | +cur->sk_attno, |
| 744 | +InvalidStrategy, |
| 745 | +cur->sk_subtype, |
| 746 | +cmp_proc, |
| 747 | +cur->sk_argument); |
| 748 | +} |
698 | 749 | }
|
699 | 750 | }
|
700 | 751 |
|
|