PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
nbtpreprocesskeys.c File Reference
#include "postgres.h"
#include "access/nbtree.h"
#include "lib/qunique.h"
#include "utils/array.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
Include dependency graph for nbtpreprocesskeys.c:

Go to the source code of this file.

Data Structures

struct  BTScanKeyPreproc
 
struct  BTSortArrayContext
 

Typedefs

typedef struct BTScanKeyPreproc BTScanKeyPreproc
 
typedef struct BTSortArrayContext BTSortArrayContext
 

Functions

static bool _bt_fix_scankey_strategy (ScanKey skey, int16 *indoption)
 
static void _bt_mark_scankey_required (ScanKey skey)
 
static bool _bt_compare_scankey_args (IndexScanDesc scan, ScanKey op, ScanKey leftarg, ScanKey rightarg, BTArrayKeyInfo *array, FmgrInfo *orderproc, bool *result)
 
static bool _bt_compare_array_scankey_args (IndexScanDesc scan, ScanKey arraysk, ScanKey skey, FmgrInfo *orderproc, BTArrayKeyInfo *array, bool *qual_ok)
 
static bool _bt_saoparray_shrink (IndexScanDesc scan, ScanKey arraysk, ScanKey skey, FmgrInfo *orderproc, BTArrayKeyInfo *array, bool *qual_ok)
 
static bool _bt_skiparray_shrink (IndexScanDesc scan, ScanKey skey, BTArrayKeyInfo *array, bool *qual_ok)
 
static void _bt_skiparray_strat_adjust (IndexScanDesc scan, ScanKey arraysk, BTArrayKeyInfo *array)
 
static void _bt_skiparray_strat_decrement (IndexScanDesc scan, ScanKey arraysk, BTArrayKeyInfo *array)
 
static void _bt_skiparray_strat_increment (IndexScanDesc scan, ScanKey arraysk, BTArrayKeyInfo *array)
 
static ScanKey _bt_preprocess_array_keys (IndexScanDesc scan, int *new_numberOfKeys)
 
static void _bt_preprocess_array_keys_final (IndexScanDesc scan, int *keyDataMap)
 
static int _bt_num_array_keys (IndexScanDesc scan, Oid *skip_eq_ops_out, int *numSkipArrayKeys_out)
 
static Datum _bt_find_extreme_element (IndexScanDesc scan, ScanKey skey, Oid elemtype, StrategyNumber strat, Datum *elems, int nelems)
 
static void _bt_setup_array_cmp (IndexScanDesc scan, ScanKey skey, Oid elemtype, FmgrInfo *orderproc, FmgrInfo **sortprocp)
 
static int _bt_sort_array_elements (ScanKey skey, FmgrInfo *sortproc, bool reverse, Datum *elems, int nelems)
 
static bool _bt_merge_arrays (IndexScanDesc scan, ScanKey skey, FmgrInfo *sortproc, bool reverse, Oid origelemtype, Oid nextelemtype, Datum *elems_orig, int *nelems_orig, Datum *elems_next, int nelems_next)
 
static int _bt_compare_array_elements (const void *a, const void *b, void *arg)
 
void _bt_preprocess_keys (IndexScanDesc scan)
 

Typedef Documentation

◆ BTScanKeyPreproc

◆ BTSortArrayContext

Function Documentation

◆ _bt_compare_array_elements()

static int _bt_compare_array_elements ( const void *  a,
const void *  b,
void *  arg 
)
static

Definition at line 2513 of file nbtpreprocesskeys.c.

2514{
2515 Datum da = *((const Datum *) a);
2516 Datum db = *((const Datum *) b);
2518 int32 compare;
2519
2521 cxt->collation,
2522 da, db));
2523 if (cxt->reverse)
2525 return compare;
2526}
#define INVERT_COMPARE_RESULT(var)
Definition: c.h:1077
int32_t int32
Definition: c.h:498
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1149
static int compare(const void *arg1, const void *arg2)
Definition: geqo_pool.c:145
int b
Definition: isn.c:74
int a
Definition: isn.c:73
void * arg
uintptr_t Datum
Definition: postgres.h:69
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:207

References a, arg, b, BTSortArrayContext::collation, compare(), DatumGetInt32(), FunctionCall2Coll(), INVERT_COMPARE_RESULT, BTSortArrayContext::reverse, and BTSortArrayContext::sortproc.

Referenced by _bt_merge_arrays(), and _bt_sort_array_elements().

◆ _bt_compare_array_scankey_args()

static bool _bt_compare_array_scankey_args ( IndexScanDesc  scan,
ScanKey  arraysk,
ScanKey  skey,
FmgrInfo orderproc,
BTArrayKeyInfo array,
bool *  qual_ok 
)
static

Definition at line 1055 of file nbtpreprocesskeys.c.

1058{
1059 Assert(arraysk->sk_attno == skey->sk_attno);
1061 Assert((arraysk->sk_flags & SK_SEARCHARRAY) &&
1063 /* don't expect to have to deal with NULLs/row comparison scan keys */
1065 Assert(!(skey->sk_flags & SK_SEARCHARRAY) ||
1067
1068 /*
1069 * Just call the appropriate helper function based on whether it's a SAOP
1070 * array or a skip array. Both helpers will set *qual_ok in passing.
1071 */
1072 if (array->num_elems != -1)
1073 return _bt_saoparray_shrink(scan, arraysk, skey, orderproc, array,
1074 qual_ok);
1075 else
1076 return _bt_skiparray_shrink(scan, skey, array, qual_ok);
1077}
Assert(PointerIsAligned(start, uint64))
static bool _bt_saoparray_shrink(IndexScanDesc scan, ScanKey arraysk, ScanKey skey, FmgrInfo *orderproc, BTArrayKeyInfo *array, bool *qual_ok)
static bool _bt_skiparray_shrink(IndexScanDesc scan, ScanKey skey, BTArrayKeyInfo *array, bool *qual_ok)
#define SK_ROW_HEADER
Definition: skey.h:117
#define SK_SEARCHARRAY
Definition: skey.h:120
#define SK_ROW_MEMBER
Definition: skey.h:118
#define SK_ISNULL
Definition: skey.h:115
#define BTEqualStrategyNumber
Definition: stratnum.h:31
int sk_flags
Definition: skey.h:66
StrategyNumber sk_strategy
Definition: skey.h:68
AttrNumber sk_attno
Definition: skey.h:67

References _bt_saoparray_shrink(), _bt_skiparray_shrink(), Assert(), BTEqualStrategyNumber, BTArrayKeyInfo::num_elems, ScanKeyData::sk_attno, ScanKeyData::sk_flags, SK_ISNULL, SK_ROW_HEADER, SK_ROW_MEMBER, SK_SEARCHARRAY, and ScanKeyData::sk_strategy.

Referenced by _bt_compare_scankey_args().

◆ _bt_compare_scankey_args()

static bool _bt_compare_scankey_args ( IndexScanDesc  scan,
ScanKey  op,
ScanKey  leftarg,
ScanKey  rightarg,
BTArrayKeyInfo array,
FmgrInfo orderproc,
bool *  result 
)
static

Definition at line 837 of file nbtpreprocesskeys.c.

841{
842 Relation rel = scan->indexRelation;
843 Oid lefttype,
844 righttype,
845 optype,
846 opcintype,
847 cmp_op;
848 StrategyNumber strat;
849
850 Assert(!((leftarg->sk_flags | rightarg->sk_flags) &
852
853 /*
854 * First, deal with cases where one or both args are NULL. This should
855 * only happen when the scankeys represent IS NULL/NOT NULL conditions.
856 */
857 if ((leftarg->sk_flags | rightarg->sk_flags) & SK_ISNULL)
858 {
859 bool leftnull,
860 rightnull;
861
862 /* Handle skip array comparison with IS NOT NULL scan key */
863 if ((leftarg->sk_flags | rightarg->sk_flags) & SK_BT_SKIP)
864 {
865 /* Shouldn't generate skip array in presence of IS NULL key */
866 Assert(!((leftarg->sk_flags | rightarg->sk_flags) & SK_SEARCHNULL));
867 Assert((leftarg->sk_flags | rightarg->sk_flags) & SK_SEARCHNOTNULL);
868
869 /* Skip array will have no NULL element/IS NULL scan key */
870 Assert(array->num_elems == -1);
871 array->null_elem = false;
872
873 /* IS NOT NULL key (could be leftarg or rightarg) now redundant */
874 *result = true;
875 return true;
876 }
877
878 if (leftarg->sk_flags & SK_ISNULL)
879 {
881 leftnull = true;
882 }
883 else
884 leftnull = false;
885 if (rightarg->sk_flags & SK_ISNULL)
886 {
888 rightnull = true;
889 }
890 else
891 rightnull = false;
892
893 /*
894 * We treat NULL as either greater than or less than all other values.
895 * Since true > false, the tests below work correctly for NULLS LAST
896 * logic. If the index is NULLS FIRST, we need to flip the strategy.
897 */
898 strat = op->sk_strategy;
899 if (op->sk_flags & SK_BT_NULLS_FIRST)
900 strat = BTCommuteStrategyNumber(strat);
901
902 switch (strat)
903 {
905 *result = (leftnull < rightnull);
906 break;
908 *result = (leftnull <= rightnull);
909 break;
911 *result = (leftnull == rightnull);
912 break;
914 *result = (leftnull >= rightnull);
915 break;
917 *result = (leftnull > rightnull);
918 break;
919 default:
920 elog(ERROR, "unrecognized StrategyNumber: %d", (int) strat);
921 *result = false; /* keep compiler quiet */
922 break;
923 }
924 return true;
925 }
926
927 /*
928 * If either leftarg or rightarg are equality-type array scankeys, we need
929 * specialized handling (since by now we know that IS NULL wasn't used)
930 */
931 if (array)
932 {
933 bool leftarray,
934 rightarray;
935
936 leftarray = ((leftarg->sk_flags & SK_SEARCHARRAY) &&
938 rightarray = ((rightarg->sk_flags & SK_SEARCHARRAY) &&
940
941 /*
942 * _bt_preprocess_array_keys is responsible for merging together array
943 * scan keys, and will do so whenever the opfamily has the required
944 * cross-type support. If it failed to do that, we handle it just
945 * like the case where we can't make the comparison ourselves.
946 */
947 if (leftarray && rightarray)
948 {
949 /* Can't make the comparison */
950 *result = false; /* suppress compiler warnings */
951 Assert(!((leftarg->sk_flags | rightarg->sk_flags) & SK_BT_SKIP));
952 return false;
953 }
954
955 /*
956 * Otherwise we need to determine if either one of leftarg or rightarg
957 * uses an array, then pass this through to a dedicated helper
958 * function.
959 */
960 if (leftarray)
961 return _bt_compare_array_scankey_args(scan, leftarg, rightarg,
962 orderproc, array, result);
963 else if (rightarray)
964 return _bt_compare_array_scankey_args(scan, rightarg, leftarg,
965 orderproc, array, result);
966
967 /* FALL THRU */
968 }
969
970 /*
971 * The opfamily we need to worry about is identified by the index column.
972 */
973 Assert(leftarg->sk_attno == rightarg->sk_attno);
974
975 opcintype = rel->rd_opcintype[leftarg->sk_attno - 1];
976
977 /*
978 * Determine the actual datatypes of the ScanKey arguments. We have to
979 * support the convention that sk_subtype == InvalidOid means the opclass
980 * input type; this is a hack to simplify life for ScanKeyInit().
981 */
982 lefttype = leftarg->sk_subtype;
983 if (lefttype == InvalidOid)
984 lefttype = opcintype;
985 righttype = rightarg->sk_subtype;
986 if (righttype == InvalidOid)
987 righttype = opcintype;
988 optype = op->sk_subtype;
989 if (optype == InvalidOid)
990 optype = opcintype;
991
992 /*
993 * If leftarg and rightarg match the types expected for the "op" scankey,
994 * we can use its already-looked-up comparison function.
995 */
996 if (lefttype == opcintype && righttype == optype)
997 {
999 op->sk_collation,
1000 leftarg->sk_argument,
1001 rightarg->sk_argument));
1002 return true;
1003 }
1004
1005 /*
1006 * Otherwise, we need to go to the syscache to find the appropriate
1007 * operator. (This cannot result in infinite recursion, since no
1008 * indexscan initiated by syscache lookup will use cross-data-type
1009 * operators.)
1010 *
1011 * If the sk_strategy was flipped by _bt_fix_scankey_strategy, we have to
1012 * un-flip it to get the correct opfamily member.
1013 */
1014 strat = op->sk_strategy;
1015 if (op->sk_flags & SK_BT_DESC)
1016 strat = BTCommuteStrategyNumber(strat);
1017
1018 cmp_op = get_opfamily_member(rel->rd_opfamily[leftarg->sk_attno - 1],
1019 lefttype,
1020 righttype,
1021 strat);
1022 if (OidIsValid(cmp_op))
1023 {
1024 RegProcedure cmp_proc = get_opcode(cmp_op);
1025
1026 if (RegProcedureIsValid(cmp_proc))
1027 {
1028 *result = DatumGetBool(OidFunctionCall2Coll(cmp_proc,
1029 op->sk_collation,
1030 leftarg->sk_argument,
1031 rightarg->sk_argument));
1032 return true;
1033 }
1034 }
1035
1036 /* Can't make the comparison */
1037 *result = false; /* suppress compiler warnings */
1038 return false;
1039}
#define RegProcedureIsValid(p)
Definition: c.h:748
regproc RegProcedure
Definition: c.h:621
#define OidIsValid(objectId)
Definition: c.h:746
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
Datum OidFunctionCall2Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1421
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1425
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:167
static bool _bt_compare_array_scankey_args(IndexScanDesc scan, ScanKey arraysk, ScanKey skey, FmgrInfo *orderproc, BTArrayKeyInfo *array, bool *qual_ok)
#define SK_BT_SKIP
Definition: nbtree.h:1136
#define SK_BT_NULLS_FIRST
Definition: nbtree.h:1147
#define SK_BT_DESC
Definition: nbtree.h:1146
#define BTCommuteStrategyNumber(strat)
Definition: nbtree.h:686
static bool DatumGetBool(Datum X)
Definition: postgres.h:95
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
#define SK_SEARCHNOTNULL
Definition: skey.h:122
#define SK_SEARCHNULL
Definition: skey.h:121
uint16 StrategyNumber
Definition: stratnum.h:22
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define BTLessStrategyNumber
Definition: stratnum.h:29
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
bool null_elem
Definition: nbtree.h:1047
Relation indexRelation
Definition: relscan.h:137
Oid * rd_opcintype
Definition: rel.h:208
Oid * rd_opfamily
Definition: rel.h:207
Datum sk_argument
Definition: skey.h:72
FmgrInfo sk_func
Definition: skey.h:71
Oid sk_subtype
Definition: skey.h:69
Oid sk_collation
Definition: skey.h:70

References _bt_compare_array_scankey_args(), Assert(), BTCommuteStrategyNumber, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, DatumGetBool(), elog, ERROR, FunctionCall2Coll(), get_opcode(), get_opfamily_member(), IndexScanDescData::indexRelation, InvalidOid, BTArrayKeyInfo::null_elem, BTArrayKeyInfo::num_elems, OidFunctionCall2Coll(), OidIsValid, RelationData::rd_opcintype, RelationData::rd_opfamily, RegProcedureIsValid, ScanKeyData::sk_argument, ScanKeyData::sk_attno, SK_BT_DESC, SK_BT_NULLS_FIRST, SK_BT_SKIP, ScanKeyData::sk_collation, ScanKeyData::sk_flags, ScanKeyData::sk_func, SK_ISNULL, SK_ROW_HEADER, SK_ROW_MEMBER, SK_SEARCHARRAY, SK_SEARCHNOTNULL, SK_SEARCHNULL, ScanKeyData::sk_strategy, and ScanKeyData::sk_subtype.

Referenced by _bt_preprocess_keys(), and _bt_skiparray_shrink().

◆ _bt_find_extreme_element()

static Datum _bt_find_extreme_element ( IndexScanDesc  scan,
ScanKey  skey,
Oid  elemtype,
StrategyNumber  strat,
Datum elems,
int  nelems 
)
static

Definition at line 2248 of file nbtpreprocesskeys.c.

2251{
2252 Relation rel = scan->indexRelation;
2253 Oid cmp_op;
2254 RegProcedure cmp_proc;
2255 FmgrInfo flinfo;
2256 Datum result;
2257 int i;
2258
2259 /*
2260 * Look up the appropriate comparison operator in the opfamily.
2261 *
2262 * Note: it's possible that this would fail, if the opfamily is
2263 * incomplete, but it seems quite unlikely that an opfamily would omit
2264 * non-cross-type comparison operators for any datatype that it supports
2265 * at all.
2266 */
2268 Assert(OidIsValid(elemtype));
2269 cmp_op = get_opfamily_member(rel->rd_opfamily[skey->sk_attno - 1],
2270 elemtype,
2271 elemtype,
2272 strat);
2273 if (!OidIsValid(cmp_op))
2274 elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
2275 strat, elemtype, elemtype,
2276 rel->rd_opfamily[skey->sk_attno - 1]);
2277 cmp_proc = get_opcode(cmp_op);
2278 if (!RegProcedureIsValid(cmp_proc))
2279 elog(ERROR, "missing oprcode for operator %u", cmp_op);
2280
2281 fmgr_info(cmp_proc, &flinfo);
2282
2283 Assert(nelems > 0);
2284 result = elems[0];
2285 for (i = 1; i < nelems; i++)
2286 {
2287 if (DatumGetBool(FunctionCall2Coll(&flinfo,
2288 skey->sk_collation,
2289 elems[i],
2290 result)))
2291 result = elems[i];
2292 }
2293
2294 return result;
2295}
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
int i
Definition: isn.c:77
Definition: fmgr.h:57

References Assert(), BTEqualStrategyNumber, DatumGetBool(), elog, ERROR, fmgr_info(), FunctionCall2Coll(), get_opcode(), get_opfamily_member(), i, IndexScanDescData::indexRelation, OidIsValid, RelationData::rd_opfamily, RegProcedureIsValid, ScanKeyData::sk_attno, ScanKeyData::sk_collation, and ScanKeyData::sk_strategy.

Referenced by _bt_preprocess_array_keys().

◆ _bt_fix_scankey_strategy()

static bool _bt_fix_scankey_strategy ( ScanKey  skey,
int16 indoption 
)
static

Definition at line 651 of file nbtpreprocesskeys.c.

652{
653 int addflags;
654
655 addflags = indoption[skey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;
656
657 /*
658 * We treat all btree operators as strict (even if they're not so marked
659 * in pg_proc). This means that it is impossible for an operator condition
660 * with a NULL comparison constant to succeed, and we can reject it right
661 * away.
662 *
663 * However, we now also support "x IS NULL" clauses as search conditions,
664 * so in that case keep going. The planner has not filled in any
665 * particular strategy in this case, so set it to BTEqualStrategyNumber
666 * --- we can treat IS NULL as an equality operator for purposes of search
667 * strategy.
668 *
669 * Likewise, "x IS NOT NULL" is supported. We treat that as either "less
670 * than NULL" in a NULLS LAST index, or "greater than NULL" in a NULLS
671 * FIRST index.
672 *
673 * Note: someday we might have to fill in sk_collation from the index
674 * column's collation. At the moment this is a non-issue because we'll
675 * never actually call the comparison operator on a NULL.
676 */
677 if (skey->sk_flags & SK_ISNULL)
678 {
679 /* SK_ISNULL shouldn't be set in a row header scankey */
680 Assert(!(skey->sk_flags & SK_ROW_HEADER));
681
682 /* Set indoption flags in scankey (might be done already) */
683 skey->sk_flags |= addflags;
684
685 /* Set correct strategy for IS NULL or NOT NULL search */
686 if (skey->sk_flags & SK_SEARCHNULL)
687 {
689 skey->sk_subtype = InvalidOid;
690 skey->sk_collation = InvalidOid;
691 }
692 else if (skey->sk_flags & SK_SEARCHNOTNULL)
693 {
694 if (skey->sk_flags & SK_BT_NULLS_FIRST)
696 else
698 skey->sk_subtype = InvalidOid;
699 skey->sk_collation = InvalidOid;
700 }
701 else
702 {
703 /* regular qual, so it cannot be satisfied */
704 return false;
705 }
706
707 /* Needn't do the rest */
708 return true;
709 }
710
711 /* Adjust strategy for DESC, if we didn't already */
712 if ((addflags & SK_BT_DESC) && !(skey->sk_flags & SK_BT_DESC))
714 skey->sk_flags |= addflags;
715
716 /* If it's a row header, fix row member flags and strategies similarly */
717 if (skey->sk_flags & SK_ROW_HEADER)
718 {
719 ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
720
721 if (subkey->sk_flags & SK_ISNULL)
722 {
723 /* First row member is NULL, so RowCompare is unsatisfiable */
724 Assert(subkey->sk_flags & SK_ROW_MEMBER);
725 return false;
726 }
727
728 for (;;)
729 {
730 Assert(subkey->sk_flags & SK_ROW_MEMBER);
731 addflags = indoption[subkey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;
732 if ((addflags & SK_BT_DESC) && !(subkey->sk_flags & SK_BT_DESC))
734 subkey->sk_flags |= addflags;
735 if (subkey->sk_flags & SK_ROW_END)
736 break;
737 subkey++;
738 }
739 }
740
741 return true;
742}
#define SK_BT_INDOPTION_SHIFT
Definition: nbtree.h:1145
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
#define SK_ROW_END
Definition: skey.h:119
ScanKeyData * ScanKey
Definition: skey.h:75

References Assert(), BTCommuteStrategyNumber, BTEqualStrategyNumber, BTGreaterStrategyNumber, BTLessStrategyNumber, DatumGetPointer(), InvalidOid, ScanKeyData::sk_argument, ScanKeyData::sk_attno, SK_BT_DESC, SK_BT_INDOPTION_SHIFT, SK_BT_NULLS_FIRST, ScanKeyData::sk_collation, ScanKeyData::sk_flags, SK_ISNULL, SK_ROW_END, SK_ROW_HEADER, SK_ROW_MEMBER, SK_SEARCHNOTNULL, SK_SEARCHNULL, ScanKeyData::sk_strategy, and ScanKeyData::sk_subtype.

Referenced by _bt_preprocess_keys().

◆ _bt_mark_scankey_required()

static void _bt_mark_scankey_required ( ScanKey  skey)
static

Definition at line 760 of file nbtpreprocesskeys.c.

761{
762 int addflags;
763
764 switch (skey->sk_strategy)
765 {
768 addflags = SK_BT_REQFWD;
769 break;
771 addflags = SK_BT_REQFWD | SK_BT_REQBKWD;
772 break;
775 addflags = SK_BT_REQBKWD;
776 break;
777 default:
778 elog(ERROR, "unrecognized StrategyNumber: %d",
779 (int) skey->sk_strategy);
780 addflags = 0; /* keep compiler quiet */
781 break;
782 }
783
784 skey->sk_flags |= addflags;
785
786 if (skey->sk_flags & SK_ROW_HEADER)
787 {
788 ScanKey subkey = (ScanKey) DatumGetPointer(skey->sk_argument);
789
790 /* First subkey should be same column/operator as the header */
791 Assert(subkey->sk_flags & SK_ROW_MEMBER);
792 Assert(subkey->sk_attno == skey->sk_attno);
793 Assert(subkey->sk_strategy == skey->sk_strategy);
794 subkey->sk_flags |= addflags;
795 }
796}
#define SK_BT_REQBKWD
Definition: nbtree.h:1135
#define SK_BT_REQFWD
Definition: nbtree.h:1134

References Assert(), BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, DatumGetPointer(), elog, ERROR, ScanKeyData::sk_argument, ScanKeyData::sk_attno, SK_BT_REQBKWD, SK_BT_REQFWD, ScanKeyData::sk_flags, SK_ROW_HEADER, SK_ROW_MEMBER, and ScanKeyData::sk_strategy.

Referenced by _bt_preprocess_keys().

◆ _bt_merge_arrays()

static bool _bt_merge_arrays ( IndexScanDesc  scan,
ScanKey  skey,
FmgrInfo sortproc,
bool  reverse,
Oid  origelemtype,
Oid  nextelemtype,
Datum elems_orig,
int *  nelems_orig,
Datum elems_next,
int  nelems_next 
)
static

Definition at line 2445 of file nbtpreprocesskeys.c.

2449{
2450 Relation rel = scan->indexRelation;
2451 BTScanOpaque so = (BTScanOpaque) scan->opaque;
2453 int nelems_orig_start = *nelems_orig,
2454 nelems_orig_merged = 0;
2455 FmgrInfo *mergeproc = sortproc;
2456 FmgrInfo crosstypeproc;
2457
2459 Assert(OidIsValid(origelemtype) && OidIsValid(nextelemtype));
2460
2461 if (origelemtype != nextelemtype)
2462 {
2463 RegProcedure cmp_proc;
2464
2465 /*
2466 * Cross-array-element-type merging is required, so can't just reuse
2467 * sortproc when merging
2468 */
2469 cmp_proc = get_opfamily_proc(rel->rd_opfamily[skey->sk_attno - 1],
2470 origelemtype, nextelemtype, BTORDER_PROC);
2471 if (!RegProcedureIsValid(cmp_proc))
2472 {
2473 /* Can't make the required comparisons */
2474 return false;
2475 }
2476
2477 /* We have all we need to determine redundancy/contradictoriness */
2478 mergeproc = &crosstypeproc;
2479 fmgr_info_cxt(cmp_proc, mergeproc, so->arrayContext);
2480 }
2481
2482 cxt.sortproc = mergeproc;
2483 cxt.collation = skey->sk_collation;
2484 cxt.reverse = reverse;
2485
2486 for (int i = 0, j = 0; i < nelems_orig_start && j < nelems_next;)
2487 {
2488 Datum *oelem = elems_orig + i,
2489 *nelem = elems_next + j;
2490 int res = _bt_compare_array_elements(oelem, nelem, &cxt);
2491
2492 if (res == 0)
2493 {
2494 elems_orig[nelems_orig_merged++] = *oelem;
2495 i++;
2496 j++;
2497 }
2498 else if (res < 0)
2499 i++;
2500 else /* res > 0 */
2501 j++;
2502 }
2503
2504 *nelems_orig = nelems_orig_merged;
2505
2506 return true;
2507}
void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
Definition: fmgr.c:137
int j
Definition: isn.c:78
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:888
static int _bt_compare_array_elements(const void *a, const void *b, void *arg)
#define BTORDER_PROC
Definition: nbtree.h:717
BTScanOpaqueData * BTScanOpaque
Definition: nbtree.h:1096
MemoryContext arrayContext
Definition: nbtree.h:1068

References _bt_compare_array_elements(), BTScanOpaqueData::arrayContext, Assert(), BTEqualStrategyNumber, BTORDER_PROC, fmgr_info_cxt(), get_opfamily_proc(), i, IndexScanDescData::indexRelation, j, OidIsValid, IndexScanDescData::opaque, RelationData::rd_opfamily, RegProcedureIsValid, ScanKeyData::sk_attno, ScanKeyData::sk_collation, and ScanKeyData::sk_strategy.

Referenced by _bt_preprocess_array_keys().

◆ _bt_num_array_keys()

static int _bt_num_array_keys ( IndexScanDesc  scan,
Oid skip_eq_ops_out,
int *  numSkipArrayKeys_out 
)
static

Definition at line 2082 of file nbtpreprocesskeys.c.

2084{
2085 Relation rel = scan->indexRelation;
2086 AttrNumber attno_skip = 1,
2087 attno_inkey = 1;
2088 bool attno_has_equal = false,
2089 attno_has_rowcompare = false;
2090 int numSAOPArrayKeys,
2091 numSkipArrayKeys,
2092 prev_numSkipArrayKeys;
2093
2094 Assert(scan->numberOfKeys);
2095
2096 /* Initial pass over input scan keys counts the number of SAOP arrays */
2097 numSAOPArrayKeys = 0;
2098 *numSkipArrayKeys_out = prev_numSkipArrayKeys = numSkipArrayKeys = 0;
2099 for (int i = 0; i < scan->numberOfKeys; i++)
2100 {
2101 ScanKey inkey = scan->keyData + i;
2102
2103 if (inkey->sk_flags & SK_SEARCHARRAY)
2104 numSAOPArrayKeys++;
2105 }
2106
2107#ifdef DEBUG_DISABLE_SKIP_SCAN
2108 /* don't attempt to add skip arrays */
2109 return numSAOPArrayKeys;
2110#endif
2111
2112 for (int i = 0;; i++)
2113 {
2114 ScanKey inkey = scan->keyData + i;
2115
2116 /*
2117 * Backfill skip arrays for any wholly omitted attributes prior to
2118 * attno_inkey
2119 */
2120 while (attno_skip < attno_inkey)
2121 {
2122 Oid opfamily = rel->rd_opfamily[attno_skip - 1];
2123 Oid opcintype = rel->rd_opcintype[attno_skip - 1];
2124
2125 /* Look up input opclass's equality operator (might fail) */
2126 skip_eq_ops_out[attno_skip - 1] =
2127 get_opfamily_member(opfamily, opcintype, opcintype,
2129 if (!OidIsValid(skip_eq_ops_out[attno_skip - 1]))
2130 {
2131 /*
2132 * Cannot generate a skip array for this or later attributes
2133 * (input opclass lacks an equality strategy operator)
2134 */
2135 *numSkipArrayKeys_out = prev_numSkipArrayKeys;
2136 return numSAOPArrayKeys + prev_numSkipArrayKeys;
2137 }
2138
2139 /* plan on adding a backfill skip array for this attribute */
2140 numSkipArrayKeys++;
2141 attno_skip++;
2142 }
2143
2144 prev_numSkipArrayKeys = numSkipArrayKeys;
2145
2146 /*
2147 * Stop once past the final input scan key. We deliberately never add
2148 * a skip array for the last input scan key's attribute -- even when
2149 * there are only inequality keys on that attribute.
2150 */
2151 if (i == scan->numberOfKeys)
2152 break;
2153
2154 /*
2155 * Later preprocessing steps cannot merge a RowCompare into a skip
2156 * array, so stop adding skip arrays once we see one. (Note that we
2157 * can backfill skip arrays before a RowCompare, which will allow keys
2158 * up to and including the RowCompare to be marked required.)
2159 *
2160 * Skip arrays work by maintaining a current array element value,
2161 * which anchors lower-order keys via an implied equality constraint.
2162 * This is incompatible with the current nbtree row comparison design,
2163 * which compares all columns together, as an indivisible group.
2164 * Alternative designs that can be used alongside skip arrays are
2165 * possible, but it's not clear that they're really worth pursuing.
2166 *
2167 * A RowCompare qual "(a, b, c) > (10, 'foo', 42)" is equivalent to
2168 * "(a=10 AND b='foo' AND c>42) OR (a=10 AND b>'foo') OR (a>10)".
2169 * Decomposing this RowCompare into these 3 disjuncts allows each
2170 * disjunct to be executed as a separate "single value" index scan.
2171 * That'll give all 3 scans the ability to add skip arrays in the
2172 * usual way (when there are any scalar keys after the RowCompare).
2173 * Under this scheme, a qual "(a, b, c) > (10, 'foo', 42) AND d = 99"
2174 * performs 3 separate scans, each of which can mark keys up to and
2175 * including its "d = 99" key as required to continue the scan.
2176 */
2177 if (attno_has_rowcompare)
2178 break;
2179
2180 /*
2181 * Now consider next attno_inkey (or keep going if this is an
2182 * additional scan key against the same attribute)
2183 */
2184 if (attno_inkey < inkey->sk_attno)
2185 {
2186 /*
2187 * Now add skip array for previous scan key's attribute, though
2188 * only if the attribute has no equality strategy scan keys
2189 */
2190 if (attno_has_equal)
2191 {
2192 /* Attributes with an = key must have InvalidOid eq_op set */
2193 skip_eq_ops_out[attno_skip - 1] = InvalidOid;
2194 }
2195 else
2196 {
2197 Oid opfamily = rel->rd_opfamily[attno_skip - 1];
2198 Oid opcintype = rel->rd_opcintype[attno_skip - 1];
2199
2200 /* Look up input opclass's equality operator (might fail) */
2201 skip_eq_ops_out[attno_skip - 1] =
2202 get_opfamily_member(opfamily, opcintype, opcintype,
2204
2205 if (!OidIsValid(skip_eq_ops_out[attno_skip - 1]))
2206 {
2207 /*
2208 * Input opclass lacks an equality strategy operator, so
2209 * don't generate a skip array that definitely won't work
2210 */
2211 break;
2212 }
2213
2214 /* plan on adding a backfill skip array for this attribute */
2215 numSkipArrayKeys++;
2216 }
2217
2218 /* Set things up for this new attribute */
2219 attno_skip++;
2220 attno_inkey = inkey->sk_attno;
2221 attno_has_equal = false;
2222 }
2223
2224 /*
2225 * Track if this attribute's scan keys include any equality strategy
2226 * scan keys (IS NULL keys count as equality keys here). Also track
2227 * if it has any RowCompare keys.
2228 */
2229 if (inkey->sk_strategy == BTEqualStrategyNumber ||
2230 (inkey->sk_flags & SK_SEARCHNULL))
2231 attno_has_equal = true;
2232 if (inkey->sk_flags & SK_ROW_HEADER)
2233 attno_has_rowcompare = true;
2234 }
2235
2236 *numSkipArrayKeys_out = numSkipArrayKeys;
2237 return numSAOPArrayKeys + numSkipArrayKeys;
2238}
int16 AttrNumber
Definition: attnum.h:21
struct ScanKeyData * keyData
Definition: relscan.h:141

References Assert(), BTEqualStrategyNumber, get_opfamily_member(), i, IndexScanDescData::indexRelation, InvalidOid, IndexScanDescData::keyData, IndexScanDescData::numberOfKeys, OidIsValid, RelationData::rd_opcintype, RelationData::rd_opfamily, ScanKeyData::sk_attno, ScanKeyData::sk_flags, SK_ROW_HEADER, SK_SEARCHARRAY, SK_SEARCHNULL, and ScanKeyData::sk_strategy.

Referenced by _bt_preprocess_array_keys().

◆ _bt_preprocess_array_keys()

static ScanKey _bt_preprocess_array_keys ( IndexScanDesc  scan,
int *  new_numberOfKeys 
)
static

Definition at line 1514 of file nbtpreprocesskeys.c.

1515{
1516 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1517 Relation rel = scan->indexRelation;
1518 int16 *indoption = rel->rd_indoption;
1519 Oid skip_eq_ops[INDEX_MAX_KEYS];
1520 int numArrayKeys,
1521 numSkipArrayKeys,
1522 numArrayKeyData;
1523 AttrNumber attno_skip = 1;
1524 int origarrayatt = InvalidAttrNumber,
1525 origarraykey = -1;
1526 Oid origelemtype = InvalidOid;
1527 MemoryContext oldContext;
1528 ScanKey arrayKeyData; /* modified copy of scan->keyData */
1529
1530 /*
1531 * Check the number of input array keys within scan->keyData[] input keys
1532 * (also checks if we should add extra skip arrays based on input keys)
1533 */
1534 numArrayKeys = _bt_num_array_keys(scan, skip_eq_ops, &numSkipArrayKeys);
1535
1536 /* Quit if nothing to do. */
1537 if (numArrayKeys == 0)
1538 return NULL;
1539
1540 /*
1541 * Estimated final size of arrayKeyData[] array we'll return to our caller
1542 * is the size of the original scan->keyData[] input array, plus space for
1543 * any additional skip array scan keys we'll need to generate below
1544 */
1545 numArrayKeyData = scan->numberOfKeys + numSkipArrayKeys;
1546
1547 /*
1548 * Make a scan-lifespan context to hold array-associated data, or reset it
1549 * if we already have one from a previous rescan cycle.
1550 */
1551 if (so->arrayContext == NULL)
1553 "BTree array context",
1555 else
1557
1558 oldContext = MemoryContextSwitchTo(so->arrayContext);
1559
1560 /* Create output scan keys in the workspace context */
1561 arrayKeyData = (ScanKey) palloc(numArrayKeyData * sizeof(ScanKeyData));
1562
1563 /* Allocate space for per-array data in the workspace context */
1564 so->skipScan = (numSkipArrayKeys > 0);
1565 so->arrayKeys = (BTArrayKeyInfo *) palloc(numArrayKeys * sizeof(BTArrayKeyInfo));
1566
1567 /* Allocate space for ORDER procs used to help _bt_checkkeys */
1568 so->orderProcs = (FmgrInfo *) palloc(numArrayKeyData * sizeof(FmgrInfo));
1569
1570 numArrayKeys = 0;
1571 numArrayKeyData = 0;
1572 for (int input_ikey = 0; input_ikey < scan->numberOfKeys; input_ikey++)
1573 {
1574 ScanKey inkey = scan->keyData + input_ikey,
1575 cur;
1576 FmgrInfo sortproc;
1577 FmgrInfo *sortprocp = &sortproc;
1578 Oid elemtype;
1579 bool reverse;
1580 ArrayType *arrayval;
1581 int16 elmlen;
1582 bool elmbyval;
1583 char elmalign;
1584 int num_elems;
1585 Datum *elem_values;
1586 bool *elem_nulls;
1587 int num_nonnulls;
1588
1589 /* set up next output scan key */
1590 cur = &arrayKeyData[numArrayKeyData];
1591
1592 /* Backfill skip arrays for attrs < or <= input key's attr? */
1593 while (numSkipArrayKeys && attno_skip <= inkey->sk_attno)
1594 {
1595 Oid opfamily = rel->rd_opfamily[attno_skip - 1];
1596 Oid opcintype = rel->rd_opcintype[attno_skip - 1];
1597 Oid collation = rel->rd_indcollation[attno_skip - 1];
1598 Oid eq_op = skip_eq_ops[attno_skip - 1];
1599 CompactAttribute *attr;
1600 RegProcedure cmp_proc;
1601
1602 if (!OidIsValid(eq_op))
1603 {
1604 /*
1605 * Attribute already has an = input key, so don't output a
1606 * skip array for attno_skip. Just copy attribute's = input
1607 * key into arrayKeyData[] once outside this inner loop.
1608 *
1609 * Note: When we get here there must be a later attribute that
1610 * lacks an equality input key, and still needs a skip array
1611 * (if there wasn't then numSkipArrayKeys would be 0 by now).
1612 */
1613 Assert(attno_skip == inkey->sk_attno);
1614 /* inkey can't be last input key to be marked required: */
1615 Assert(input_ikey < scan->numberOfKeys - 1);
1616#if 0
1617 /* Could be a redundant input scan key, so can't do this: */
1619 (inkey->sk_flags & SK_SEARCHNULL));
1620#endif
1621
1622 attno_skip++;
1623 break;
1624 }
1625
1626 cmp_proc = get_opcode(eq_op);
1627 if (!RegProcedureIsValid(cmp_proc))
1628 elog(ERROR, "missing oprcode for skipping equals operator %u", eq_op);
1629
1631 SK_SEARCHARRAY | SK_BT_SKIP, /* flags */
1632 attno_skip, /* skipped att number */
1633 BTEqualStrategyNumber, /* equality strategy */
1634 InvalidOid, /* opclass input subtype */
1635 collation, /* index column's collation */
1636 cmp_proc, /* equality operator's proc */
1637 (Datum) 0); /* constant */
1638
1639 /* Initialize generic BTArrayKeyInfo fields */
1640 so->arrayKeys[numArrayKeys].scan_key = numArrayKeyData;
1641 so->arrayKeys[numArrayKeys].num_elems = -1;
1642
1643 /* Initialize skip array specific BTArrayKeyInfo fields */
1644 attr = TupleDescCompactAttr(RelationGetDescr(rel), attno_skip - 1);
1645 reverse = (indoption[attno_skip - 1] & INDOPTION_DESC) != 0;
1646 so->arrayKeys[numArrayKeys].attlen = attr->attlen;
1647 so->arrayKeys[numArrayKeys].attbyval = attr->attbyval;
1648 so->arrayKeys[numArrayKeys].null_elem = true; /* for now */
1649 so->arrayKeys[numArrayKeys].sksup =
1650 PrepareSkipSupportFromOpclass(opfamily, opcintype, reverse);
1651 so->arrayKeys[numArrayKeys].low_compare = NULL; /* for now */
1652 so->arrayKeys[numArrayKeys].high_compare = NULL; /* for now */
1653
1654 /*
1655 * We'll need a 3-way ORDER proc. Set that up now.
1656 */
1657 _bt_setup_array_cmp(scan, cur, opcintype,
1658 &so->orderProcs[numArrayKeyData], NULL);
1659
1660 numArrayKeys++;
1661 numArrayKeyData++; /* keep this scan key/array */
1662
1663 /* set up next output scan key */
1664 cur = &arrayKeyData[numArrayKeyData];
1665
1666 /* remember having output this skip array and scan key */
1667 numSkipArrayKeys--;
1668 attno_skip++;
1669 }
1670
1671 /*
1672 * Provisionally copy scan key into arrayKeyData[] array we'll return
1673 * to _bt_preprocess_keys caller
1674 */
1675 *cur = *inkey;
1676
1677 if (!(cur->sk_flags & SK_SEARCHARRAY))
1678 {
1679 numArrayKeyData++; /* keep this non-array scan key */
1680 continue;
1681 }
1682
1683 /*
1684 * Process SAOP array scan key
1685 */
1687
1688 /* If array is null as a whole, the scan qual is unsatisfiable */
1689 if (cur->sk_flags & SK_ISNULL)
1690 {
1691 so->qual_ok = false;
1692 break;
1693 }
1694
1695 /*
1696 * Deconstruct the array into elements
1697 */
1698 arrayval = DatumGetArrayTypeP(cur->sk_argument);
1699 /* We could cache this data, but not clear it's worth it */
1701 &elmlen, &elmbyval, &elmalign);
1702 deconstruct_array(arrayval,
1703 ARR_ELEMTYPE(arrayval),
1704 elmlen, elmbyval, elmalign,
1705 &elem_values, &elem_nulls, &num_elems);
1706
1707 /*
1708 * Compress out any null elements. We can ignore them since we assume
1709 * all btree operators are strict.
1710 */
1711 num_nonnulls = 0;
1712 for (int j = 0; j < num_elems; j++)
1713 {
1714 if (!elem_nulls[j])
1715 elem_values[num_nonnulls++] = elem_values[j];
1716 }
1717
1718 /* We could pfree(elem_nulls) now, but not worth the cycles */
1719
1720 /* If there's no non-nulls, the scan qual is unsatisfiable */
1721 if (num_nonnulls == 0)
1722 {
1723 so->qual_ok = false;
1724 break;
1725 }
1726
1727 /*
1728 * Determine the nominal datatype of the array elements. We have to
1729 * support the convention that sk_subtype == InvalidOid means the
1730 * opclass input type; this is a hack to simplify life for
1731 * ScanKeyInit().
1732 */
1733 elemtype = cur->sk_subtype;
1734 if (elemtype == InvalidOid)
1735 elemtype = rel->rd_opcintype[cur->sk_attno - 1];
1736
1737 /*
1738 * If the comparison operator is not equality, then the array qual
1739 * degenerates to a simple comparison against the smallest or largest
1740 * non-null array element, as appropriate.
1741 */
1742 switch (cur->sk_strategy)
1743 {
1746 cur->sk_argument =
1747 _bt_find_extreme_element(scan, cur, elemtype,
1749 elem_values, num_nonnulls);
1750 numArrayKeyData++; /* keep this transformed scan key */
1751 continue;
1753 /* proceed with rest of loop */
1754 break;
1757 cur->sk_argument =
1758 _bt_find_extreme_element(scan, cur, elemtype,
1760 elem_values, num_nonnulls);
1761 numArrayKeyData++; /* keep this transformed scan key */
1762 continue;
1763 default:
1764 elog(ERROR, "unrecognized StrategyNumber: %d",
1765 (int) cur->sk_strategy);
1766 break;
1767 }
1768
1769 /*
1770 * We'll need a 3-way ORDER proc to perform binary searches for the
1771 * next matching array element. Set that up now.
1772 *
1773 * Array scan keys with cross-type equality operators will require a
1774 * separate same-type ORDER proc for sorting their array. Otherwise,
1775 * sortproc just points to the same proc used during binary searches.
1776 */
1777 _bt_setup_array_cmp(scan, cur, elemtype,
1778 &so->orderProcs[numArrayKeyData], &sortprocp);
1779
1780 /*
1781 * Sort the non-null elements and eliminate any duplicates. We must
1782 * sort in the same ordering used by the index column, so that the
1783 * arrays can be advanced in lockstep with the scan's progress through
1784 * the index's key space.
1785 */
1786 reverse = (indoption[cur->sk_attno - 1] & INDOPTION_DESC) != 0;
1787 num_elems = _bt_sort_array_elements(cur, sortprocp, reverse,
1788 elem_values, num_nonnulls);
1789
1790 if (origarrayatt == cur->sk_attno)
1791 {
1792 BTArrayKeyInfo *orig = &so->arrayKeys[origarraykey];
1793
1794 /*
1795 * This array scan key is redundant with a previous equality
1796 * operator array scan key. Merge the two arrays together to
1797 * eliminate contradictory non-intersecting elements (or try to).
1798 *
1799 * We merge this next array back into attribute's original array.
1800 */
1801 Assert(arrayKeyData[orig->scan_key].sk_attno == cur->sk_attno);
1802 Assert(arrayKeyData[orig->scan_key].sk_collation ==
1803 cur->sk_collation);
1804 if (_bt_merge_arrays(scan, cur, sortprocp, reverse,
1805 origelemtype, elemtype,
1806 orig->elem_values, &orig->num_elems,
1807 elem_values, num_elems))
1808 {
1809 /* Successfully eliminated this array */
1810 pfree(elem_values);
1811
1812 /*
1813 * If no intersecting elements remain in the original array,
1814 * the scan qual is unsatisfiable
1815 */
1816 if (orig->num_elems == 0)
1817 {
1818 so->qual_ok = false;
1819 break;
1820 }
1821
1822 /* Throw away this scan key/array */
1823 continue;
1824 }
1825
1826 /*
1827 * Unable to merge this array with previous array due to a lack of
1828 * suitable cross-type opfamily support. Will need to keep both
1829 * scan keys/arrays.
1830 */
1831 }
1832 else
1833 {
1834 /*
1835 * This array is the first for current index attribute.
1836 *
1837 * If it turns out to not be the last array (that is, if the next
1838 * array is redundantly applied to this same index attribute),
1839 * we'll then treat this array as the attribute's "original" array
1840 * when merging.
1841 */
1842 origarrayatt = cur->sk_attno;
1843 origarraykey = numArrayKeys;
1844 origelemtype = elemtype;
1845 }
1846
1847 /* Initialize generic BTArrayKeyInfo fields */
1848 so->arrayKeys[numArrayKeys].scan_key = numArrayKeyData;
1849 so->arrayKeys[numArrayKeys].num_elems = num_elems;
1850
1851 /* Initialize SAOP array specific BTArrayKeyInfo fields */
1852 so->arrayKeys[numArrayKeys].elem_values = elem_values;
1853 so->arrayKeys[numArrayKeys].cur_elem = -1; /* i.e. invalid */
1854
1855 numArrayKeys++;
1856 numArrayKeyData++; /* keep this scan key/array */
1857 }
1858
1859 Assert(numSkipArrayKeys == 0 || !so->qual_ok);
1860
1861 /* Set final number of equality-type array keys */
1862 so->numArrayKeys = numArrayKeys;
1863 /* Set number of scan keys in arrayKeyData[] */
1864 *new_numberOfKeys = numArrayKeyData;
1865
1866 MemoryContextSwitchTo(oldContext);
1867
1868 return arrayKeyData;
1869}
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3631
#define InvalidAttrNumber
Definition: attnum.h:23
int16_t int16
Definition: c.h:497
struct cursor * cur
Definition: ecpg.c:29
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2411
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:414
void pfree(void *pointer)
Definition: mcxt.c:2152
void * palloc(Size size)
Definition: mcxt.c:1945
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
#define AllocSetContextCreate
Definition: memutils.h:149
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:190
static bool _bt_merge_arrays(IndexScanDesc scan, ScanKey skey, FmgrInfo *sortproc, bool reverse, Oid origelemtype, Oid nextelemtype, Datum *elems_orig, int *nelems_orig, Datum *elems_next, int nelems_next)
static int _bt_num_array_keys(IndexScanDesc scan, Oid *skip_eq_ops_out, int *numSkipArrayKeys_out)
static Datum _bt_find_extreme_element(IndexScanDesc scan, ScanKey skey, Oid elemtype, StrategyNumber strat, Datum *elems, int nelems)
static void _bt_setup_array_cmp(IndexScanDesc scan, ScanKey skey, Oid elemtype, FmgrInfo *orderproc, FmgrInfo **sortprocp)
static int _bt_sort_array_elements(ScanKey skey, FmgrInfo *sortproc, bool reverse, Datum *elems, int nelems)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define INDEX_MAX_KEYS
#define RelationGetDescr(relation)
Definition: rel.h:542
void ScanKeyEntryInitialize(ScanKey entry, int flags, AttrNumber attributeNumber, StrategyNumber strategy, Oid subtype, Oid collation, RegProcedure procedure, Datum argument)
Definition: scankey.c:32
SkipSupport PrepareSkipSupportFromOpclass(Oid opfamily, Oid opcintype, bool reverse)
Definition: skipsupport.c:30
bool attbyval
Definition: nbtree.h:1046
Datum * elem_values
Definition: nbtree.h:1041
ScanKey high_compare
Definition: nbtree.h:1050
ScanKey low_compare
Definition: nbtree.h:1049
SkipSupport sksup
Definition: nbtree.h:1048
int16 attlen
Definition: nbtree.h:1045
BTArrayKeyInfo * arrayKeys
Definition: nbtree.h:1066
FmgrInfo * orderProcs
Definition: nbtree.h:1067
int16 attlen
Definition: tupdesc.h:71
int16 * rd_indoption
Definition: rel.h:211
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:175

References _bt_find_extreme_element(), _bt_merge_arrays(), _bt_num_array_keys(), _bt_setup_array_cmp(), _bt_sort_array_elements(), ALLOCSET_SMALL_SIZES, AllocSetContextCreate, ARR_ELEMTYPE, BTScanOpaqueData::arrayContext, BTScanOpaqueData::arrayKeys, Assert(), BTArrayKeyInfo::attbyval, CompactAttribute::attbyval, BTArrayKeyInfo::attlen, CompactAttribute::attlen, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, cur, BTArrayKeyInfo::cur_elem, CurrentMemoryContext, DatumGetArrayTypeP, deconstruct_array(), BTArrayKeyInfo::elem_values, elog, ERROR, get_opcode(), get_typlenbyvalalign(), BTArrayKeyInfo::high_compare, INDEX_MAX_KEYS, IndexScanDescData::indexRelation, InvalidAttrNumber, InvalidOid, j, IndexScanDescData::keyData, BTArrayKeyInfo::low_compare, MemoryContextReset(), MemoryContextSwitchTo(), BTArrayKeyInfo::null_elem, BTArrayKeyInfo::num_elems, BTScanOpaqueData::numArrayKeys, IndexScanDescData::numberOfKeys, OidIsValid, IndexScanDescData::opaque, BTScanOpaqueData::orderProcs, palloc(), pfree(), PrepareSkipSupportFromOpclass(), BTScanOpaqueData::qual_ok, RelationData::rd_indoption, RegProcedureIsValid, RelationGetDescr, BTArrayKeyInfo::scan_key, ScanKeyEntryInitialize(), ScanKeyData::sk_attno, SK_BT_SKIP, ScanKeyData::sk_flags, SK_ISNULL, SK_ROW_HEADER, SK_SEARCHARRAY, SK_SEARCHNOTNULL, SK_SEARCHNULL, ScanKeyData::sk_strategy, BTScanOpaqueData::skipScan, BTArrayKeyInfo::sksup, and TupleDescCompactAttr().

Referenced by _bt_preprocess_keys().

◆ _bt_preprocess_array_keys_final()

static void _bt_preprocess_array_keys_final ( IndexScanDesc  scan,
int *  keyDataMap 
)
static

Definition at line 1894 of file nbtpreprocesskeys.c.

1895{
1896 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1897 Relation rel = scan->indexRelation;
1898 int arrayidx = 0;
1899 int last_equal_output_ikey PG_USED_FOR_ASSERTS_ONLY = -1;
1900
1901 Assert(so->qual_ok);
1902
1903 /*
1904 * Nothing for us to do when _bt_preprocess_array_keys only had to deal
1905 * with array inequalities
1906 */
1907 if (so->numArrayKeys == 0)
1908 return;
1909
1910 for (int output_ikey = 0; output_ikey < so->numberOfKeys; output_ikey++)
1911 {
1912 ScanKey outkey = so->keyData + output_ikey;
1913 int input_ikey;
1914 bool found PG_USED_FOR_ASSERTS_ONLY = false;
1915
1917
1918 if (outkey->sk_strategy != BTEqualStrategyNumber)
1919 continue;
1920
1921 input_ikey = keyDataMap[output_ikey];
1922
1923 Assert(last_equal_output_ikey < output_ikey);
1924 Assert(last_equal_output_ikey < input_ikey);
1925 last_equal_output_ikey = output_ikey;
1926
1927 /*
1928 * We're lazy about looking up ORDER procs for non-array keys, since
1929 * not all input keys become output keys. Take care of it now.
1930 */
1931 if (!(outkey->sk_flags & SK_SEARCHARRAY))
1932 {
1933 Oid elemtype;
1934
1935 /* No need for an ORDER proc given an IS NULL scan key */
1936 if (outkey->sk_flags & SK_SEARCHNULL)
1937 continue;
1938
1939 /*
1940 * A non-required scan key doesn't need an ORDER proc, either
1941 * (unless it's associated with an array, which this one isn't)
1942 */
1943 if (!(outkey->sk_flags & SK_BT_REQFWD))
1944 continue;
1945
1946 elemtype = outkey->sk_subtype;
1947 if (elemtype == InvalidOid)
1948 elemtype = rel->rd_opcintype[outkey->sk_attno - 1];
1949
1950 _bt_setup_array_cmp(scan, outkey, elemtype,
1951 &so->orderProcs[output_ikey], NULL);
1952 continue;
1953 }
1954
1955 /*
1956 * Reorder existing array scan key so->orderProcs[] entries.
1957 *
1958 * Doing this in-place is safe because preprocessing is required to
1959 * output all equality strategy scan keys in original input order
1960 * (among each group of entries against the same index attribute).
1961 * This is also the order that the arrays themselves appear in.
1962 */
1963 so->orderProcs[output_ikey] = so->orderProcs[input_ikey];
1964
1965 /* Fix-up array->scan_key references for arrays */
1966 for (; arrayidx < so->numArrayKeys; arrayidx++)
1967 {
1968 BTArrayKeyInfo *array = &so->arrayKeys[arrayidx];
1969
1970 /*
1971 * All skip arrays must be marked required, and final column can
1972 * never have a skip array
1973 */
1974 Assert(array->num_elems > 0 || array->num_elems == -1);
1975 Assert(array->num_elems != -1 || outkey->sk_flags & SK_BT_REQFWD);
1976 Assert(array->num_elems != -1 ||
1978
1979 if (array->scan_key == input_ikey)
1980 {
1981 /* found it */
1982 array->scan_key = output_ikey;
1983 found = true;
1984
1985 /*
1986 * Transform array scan keys that have exactly 1 element
1987 * remaining (following all prior preprocessing) into
1988 * equivalent non-array scan keys.
1989 */
1990 if (array->num_elems == 1)
1991 {
1992 outkey->sk_flags &= ~SK_SEARCHARRAY;
1993 outkey->sk_argument = array->elem_values[0];
1994 so->numArrayKeys--;
1995
1996 /* If we're out of array keys, we can quit right away */
1997 if (so->numArrayKeys == 0)
1998 return;
1999
2000 /* Shift other arrays forward */
2001 memmove(array, array + 1,
2002 sizeof(BTArrayKeyInfo) *
2003 (so->numArrayKeys - arrayidx));
2004
2005 /*
2006 * Don't increment arrayidx (there was an entry that was
2007 * just shifted forward to the offset at arrayidx, which
2008 * will still need to be matched)
2009 */
2010 }
2011 else
2012 {
2013 /*
2014 * Any skip array low_compare and high_compare scan keys
2015 * are now final. Transform the array's > low_compare key
2016 * into a >= key (and < high_compare keys into a <= key).
2017 */
2018 if (array->num_elems == -1 && array->sksup &&
2019 !array->null_elem)
2020 _bt_skiparray_strat_adjust(scan, outkey, array);
2021
2022 /* Match found, so done with this array */
2023 arrayidx++;
2024 }
2025
2026 break;
2027 }
2028 }
2029
2030 Assert(found);
2031 }
2032
2033 /*
2034 * Parallel index scans require space in shared memory to store the
2035 * current array elements (for arrays kept by preprocessing) to schedule
2036 * the next primitive index scan. The underlying structure is protected
2037 * using an LWLock, so defensively limit its size. In practice this can
2038 * only affect parallel scans that use an incomplete opfamily.
2039 */
2040 if (scan->parallel_scan && so->numArrayKeys > INDEX_MAX_KEYS)
2041 ereport(ERROR,
2042 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2043 errmsg_internal("number of array scan keys left by preprocessing (%d) exceeds the maximum allowed by parallel btree index scans (%d)",
2045}
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:224
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1158
int errcode(int sqlerrcode)
Definition: elog.c:854
#define ereport(elevel,...)
Definition: elog.h:149
static void _bt_skiparray_strat_adjust(IndexScanDesc scan, ScanKey arraysk, BTArrayKeyInfo *array)
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:535
#define InvalidStrategy
Definition: stratnum.h:24
ScanKey keyData
Definition: nbtree.h:1058
struct ParallelIndexScanDescData * parallel_scan
Definition: relscan.h:191

References _bt_setup_array_cmp(), _bt_skiparray_strat_adjust(), BTScanOpaqueData::arrayKeys, Assert(), BTEqualStrategyNumber, BTArrayKeyInfo::elem_values, ereport, errcode(), errmsg_internal(), ERROR, INDEX_MAX_KEYS, IndexScanDescData::indexRelation, IndexRelationGetNumberOfKeyAttributes, InvalidOid, InvalidStrategy, BTScanOpaqueData::keyData, BTArrayKeyInfo::null_elem, BTArrayKeyInfo::num_elems, BTScanOpaqueData::numArrayKeys, BTScanOpaqueData::numberOfKeys, IndexScanDescData::opaque, BTScanOpaqueData::orderProcs, IndexScanDescData::parallel_scan, PG_USED_FOR_ASSERTS_ONLY, BTScanOpaqueData::qual_ok, BTArrayKeyInfo::scan_key, ScanKeyData::sk_argument, ScanKeyData::sk_attno, SK_BT_REQFWD, ScanKeyData::sk_flags, SK_SEARCHARRAY, SK_SEARCHNULL, ScanKeyData::sk_strategy, ScanKeyData::sk_subtype, and BTArrayKeyInfo::sksup.

Referenced by _bt_preprocess_keys().

◆ _bt_preprocess_keys()

void _bt_preprocess_keys ( IndexScanDesc  scan)

Definition at line 182 of file nbtpreprocesskeys.c.

183{
184 BTScanOpaque so = (BTScanOpaque) scan->opaque;
185 int numberOfKeys = scan->numberOfKeys;
186 int16 *indoption = scan->indexRelation->rd_indoption;
187 int new_numberOfKeys;
188 int numberOfEqualCols;
189 ScanKey inkeys;
191 bool test_result;
192 AttrNumber attno;
193 ScanKey arrayKeyData;
194 int *keyDataMap = NULL;
195 int arrayidx = 0;
196
197 if (so->numberOfKeys > 0)
198 {
199 /*
200 * Only need to do preprocessing once per btrescan, at most. All
201 * calls after the first are handled as no-ops.
202 */
203 return;
204 }
205
206 /* initialize result variables */
207 so->qual_ok = true;
208 so->numberOfKeys = 0;
209
210 if (numberOfKeys < 1)
211 return; /* done if qual-less scan */
212
213 /* If any keys are SK_SEARCHARRAY type, set up array-key info */
214 arrayKeyData = _bt_preprocess_array_keys(scan, &numberOfKeys);
215 if (!so->qual_ok)
216 {
217 /* unmatchable array, so give up */
218 return;
219 }
220
221 /*
222 * Treat arrayKeyData[] (a partially preprocessed copy of scan->keyData[])
223 * as our input if _bt_preprocess_array_keys just allocated it, else just
224 * use scan->keyData[]
225 */
226 if (arrayKeyData)
227 {
228 inkeys = arrayKeyData;
229
230 /* Also maintain keyDataMap for remapping so->orderProcs[] later */
231 keyDataMap = MemoryContextAlloc(so->arrayContext,
232 numberOfKeys * sizeof(int));
233
234 /*
235 * Also enlarge output array when it might otherwise not have room for
236 * a skip array's scan key
237 */
238 if (numberOfKeys > scan->numberOfKeys)
239 so->keyData = repalloc(so->keyData,
240 numberOfKeys * sizeof(ScanKeyData));
241 }
242 else
243 inkeys = scan->keyData;
244
245 /* we check that input keys are correctly ordered */
246 if (inkeys[0].sk_attno < 1)
247 elog(ERROR, "btree index keys must be ordered by attribute");
248
249 /* We can short-circuit most of the work if there's just one key */
250 if (numberOfKeys == 1)
251 {
252 /* Apply indoption to scankey (might change sk_strategy!) */
253 if (!_bt_fix_scankey_strategy(&inkeys[0], indoption))
254 so->qual_ok = false;
255 memcpy(&so->keyData[0], &inkeys[0], sizeof(ScanKeyData));
256 so->numberOfKeys = 1;
257 /* We can mark the qual as required if it's for first index col */
258 if (inkeys[0].sk_attno == 1)
260 if (arrayKeyData)
261 {
262 /*
263 * Don't call _bt_preprocess_array_keys_final in this fast path
264 * (we'll miss out on the single value array transformation, but
265 * that's not nearly as important when there's only one scan key)
266 */
269 (so->arrayKeys[0].scan_key == 0 &&
270 !(so->keyData[0].sk_flags & SK_BT_SKIP) &&
271 OidIsValid(so->orderProcs[0].fn_oid)));
272 }
273
274 return;
275 }
276
277 /*
278 * Otherwise, do the full set of pushups.
279 */
280 new_numberOfKeys = 0;
281 numberOfEqualCols = 0;
282
283 /*
284 * Initialize for processing of keys for attr 1.
285 *
286 * xform[i] points to the currently best scan key of strategy type i+1; it
287 * is NULL if we haven't yet found such a key for this attr.
288 */
289 attno = 1;
290 memset(xform, 0, sizeof(xform));
291
292 /*
293 * Loop iterates from 0 to numberOfKeys inclusive; we use the last pass to
294 * handle after-last-key processing. Actual exit from the loop is at the
295 * "break" statement below.
296 */
297 for (int i = 0;; i++)
298 {
299 ScanKey inkey = inkeys + i;
300 int j;
301
302 if (i < numberOfKeys)
303 {
304 /* Apply indoption to scankey (might change sk_strategy!) */
305 if (!_bt_fix_scankey_strategy(inkey, indoption))
306 {
307 /* NULL can't be matched, so give up */
308 so->qual_ok = false;
309 return;
310 }
311 }
312
313 /*
314 * If we are at the end of the keys for a particular attr, finish up
315 * processing and emit the cleaned-up keys.
316 */
317 if (i == numberOfKeys || inkey->sk_attno != attno)
318 {
319 int priorNumberOfEqualCols = numberOfEqualCols;
320
321 /* check input keys are correctly ordered */
322 if (i < numberOfKeys && inkey->sk_attno < attno)
323 elog(ERROR, "btree index keys must be ordered by attribute");
324
325 /*
326 * If = has been specified, all other keys can be eliminated as
327 * redundant. Note that this is no less true if the = key is
328 * SEARCHARRAY; the only real difference is that the inequality
329 * key _becomes_ redundant by making _bt_compare_scankey_args
330 * eliminate the subset of elements that won't need to be matched
331 * (with SAOP arrays and skip arrays alike).
332 *
333 * If we have a case like "key = 1 AND key > 2", we set qual_ok to
334 * false and abandon further processing. We'll do the same thing
335 * given a case like "key IN (0, 1) AND key > 2".
336 *
337 * We also have to deal with the case of "key IS NULL", which is
338 * unsatisfiable in combination with any other index condition. By
339 * the time we get here, that's been classified as an equality
340 * check, and we've rejected any combination of it with a regular
341 * equality condition; but not with other types of conditions.
342 */
343 if (xform[BTEqualStrategyNumber - 1].inkey)
344 {
345 ScanKey eq = xform[BTEqualStrategyNumber - 1].inkey;
346 BTArrayKeyInfo *array = NULL;
347 FmgrInfo *orderproc = NULL;
348
349 if (arrayKeyData && (eq->sk_flags & SK_SEARCHARRAY))
350 {
351 int eq_in_ikey,
352 eq_arrayidx;
353
354 eq_in_ikey = xform[BTEqualStrategyNumber - 1].inkeyi;
355 eq_arrayidx = xform[BTEqualStrategyNumber - 1].arrayidx;
356 array = &so->arrayKeys[eq_arrayidx - 1];
357 orderproc = so->orderProcs + eq_in_ikey;
358
359 Assert(array->scan_key == eq_in_ikey);
360 Assert(OidIsValid(orderproc->fn_oid));
361 }
362
363 for (j = BTMaxStrategyNumber; --j >= 0;)
364 {
365 ScanKey chk = xform[j].inkey;
366
367 if (!chk || j == (BTEqualStrategyNumber - 1))
368 continue;
369
370 if (eq->sk_flags & SK_SEARCHNULL)
371 {
372 /* IS NULL is contradictory to anything else */
373 so->qual_ok = false;
374 return;
375 }
376
377 if (_bt_compare_scankey_args(scan, chk, eq, chk,
378 array, orderproc,
379 &test_result))
380 {
381 if (!test_result)
382 {
383 /* keys proven mutually contradictory */
384 so->qual_ok = false;
385 return;
386 }
387 /* else discard the redundant non-equality key */
388 xform[j].inkey = NULL;
389 xform[j].inkeyi = -1;
390 }
391 /* else, cannot determine redundancy, keep both keys */
392 }
393 /* track number of attrs for which we have "=" keys */
394 numberOfEqualCols++;
395 }
396
397 /* try to keep only one of <, <= */
398 if (xform[BTLessStrategyNumber - 1].inkey &&
399 xform[BTLessEqualStrategyNumber - 1].inkey)
400 {
401 ScanKey lt = xform[BTLessStrategyNumber - 1].inkey;
402 ScanKey le = xform[BTLessEqualStrategyNumber - 1].inkey;
403
404 if (_bt_compare_scankey_args(scan, le, lt, le, NULL, NULL,
405 &test_result))
406 {
407 if (test_result)
408 xform[BTLessEqualStrategyNumber - 1].inkey = NULL;
409 else
410 xform[BTLessStrategyNumber - 1].inkey = NULL;
411 }
412 }
413
414 /* try to keep only one of >, >= */
415 if (xform[BTGreaterStrategyNumber - 1].inkey &&
416 xform[BTGreaterEqualStrategyNumber - 1].inkey)
417 {
418 ScanKey gt = xform[BTGreaterStrategyNumber - 1].inkey;
419 ScanKey ge = xform[BTGreaterEqualStrategyNumber - 1].inkey;
420
421 if (_bt_compare_scankey_args(scan, ge, gt, ge, NULL, NULL,
422 &test_result))
423 {
424 if (test_result)
425 xform[BTGreaterEqualStrategyNumber - 1].inkey = NULL;
426 else
427 xform[BTGreaterStrategyNumber - 1].inkey = NULL;
428 }
429 }
430
431 /*
432 * Emit the cleaned-up keys into the so->keyData[] array, and then
433 * mark them if they are required. They are required (possibly
434 * only in one direction) if all attrs before this one had "=".
435 *
436 * In practice we'll rarely output non-required scan keys here;
437 * typically, _bt_preprocess_array_keys has already added "=" keys
438 * sufficient to form an unbroken series of "=" constraints on all
439 * attrs prior to the attr from the final scan->keyData[] key.
440 */
441 for (j = BTMaxStrategyNumber; --j >= 0;)
442 {
443 if (xform[j].inkey)
444 {
445 ScanKey outkey = &so->keyData[new_numberOfKeys++];
446
447 memcpy(outkey, xform[j].inkey, sizeof(ScanKeyData));
448 if (arrayKeyData)
449 keyDataMap[new_numberOfKeys - 1] = xform[j].inkeyi;
450 if (priorNumberOfEqualCols == attno - 1)
452 }
453 }
454
455 /*
456 * Exit loop here if done.
457 */
458 if (i == numberOfKeys)
459 break;
460
461 /* Re-initialize for new attno */
462 attno = inkey->sk_attno;
463 memset(xform, 0, sizeof(xform));
464 }
465
466 /* check strategy this key's operator corresponds to */
467 j = inkey->sk_strategy - 1;
468
469 /* if row comparison, push it directly to the output array */
470 if (inkey->sk_flags & SK_ROW_HEADER)
471 {
472 ScanKey outkey = &so->keyData[new_numberOfKeys++];
473
474 memcpy(outkey, inkey, sizeof(ScanKeyData));
475 if (arrayKeyData)
476 keyDataMap[new_numberOfKeys - 1] = i;
477 if (numberOfEqualCols == attno - 1)
479
480 /*
481 * We don't support RowCompare using equality; such a qual would
482 * mess up the numberOfEqualCols tracking.
483 */
485 continue;
486 }
487
488 if (inkey->sk_strategy == BTEqualStrategyNumber &&
489 (inkey->sk_flags & SK_SEARCHARRAY))
490 {
491 /* must track how input scan keys map to arrays */
492 Assert(arrayKeyData);
493 arrayidx++;
494 }
495
496 /*
497 * have we seen a scan key for this same attribute and using this same
498 * operator strategy before now?
499 */
500 if (xform[j].inkey == NULL)
501 {
502 /* nope, so this scan key wins by default (at least for now) */
503 xform[j].inkey = inkey;
504 xform[j].inkeyi = i;
505 xform[j].arrayidx = arrayidx;
506 }
507 else
508 {
509 FmgrInfo *orderproc = NULL;
510 BTArrayKeyInfo *array = NULL;
511
512 /*
513 * Seen one of these before, so keep only the more restrictive key
514 * if possible
515 */
516 if (j == (BTEqualStrategyNumber - 1) && arrayKeyData)
517 {
518 /*
519 * Have to set up array keys
520 */
521 if (inkey->sk_flags & SK_SEARCHARRAY)
522 {
523 array = &so->arrayKeys[arrayidx - 1];
524 orderproc = so->orderProcs + i;
525
526 Assert(array->scan_key == i);
527 Assert(OidIsValid(orderproc->fn_oid));
528 Assert(!(inkey->sk_flags & SK_BT_SKIP));
529 }
530 else if (xform[j].inkey->sk_flags & SK_SEARCHARRAY)
531 {
532 array = &so->arrayKeys[xform[j].arrayidx - 1];
533 orderproc = so->orderProcs + xform[j].inkeyi;
534
535 Assert(array->scan_key == xform[j].inkeyi);
536 Assert(OidIsValid(orderproc->fn_oid));
537 Assert(!(xform[j].inkey->sk_flags & SK_BT_SKIP));
538 }
539
540 /*
541 * Both scan keys might have arrays, in which case we'll
542 * arbitrarily pass only one of the arrays. That won't
543 * matter, since _bt_compare_scankey_args is aware that two
544 * SEARCHARRAY scan keys mean that _bt_preprocess_array_keys
545 * failed to eliminate redundant arrays through array merging.
546 * _bt_compare_scankey_args just returns false when it sees
547 * this; it won't even try to examine either array.
548 */
549 }
550
551 if (_bt_compare_scankey_args(scan, inkey, inkey, xform[j].inkey,
552 array, orderproc, &test_result))
553 {
554 /* Have all we need to determine redundancy */
555 if (test_result)
556 {
557 /*
558 * New key is more restrictive, and so replaces old key...
559 */
560 if (j != (BTEqualStrategyNumber - 1) ||
561 !(xform[j].inkey->sk_flags & SK_SEARCHARRAY))
562 {
563 xform[j].inkey = inkey;
564 xform[j].inkeyi = i;
565 xform[j].arrayidx = arrayidx;
566 }
567 else
568 {
569 /*
570 * ...unless we have to keep the old key because it's
571 * an array that rendered the new key redundant. We
572 * need to make sure that we don't throw away an array
573 * scan key. _bt_preprocess_array_keys_final expects
574 * us to keep all of the arrays that weren't already
575 * eliminated by _bt_preprocess_array_keys earlier on.
576 */
577 Assert(!(inkey->sk_flags & SK_SEARCHARRAY));
578 }
579 }
580 else if (j == (BTEqualStrategyNumber - 1))
581 {
582 /* key == a && key == b, but a != b */
583 so->qual_ok = false;
584 return;
585 }
586 /* else old key is more restrictive, keep it */
587 }
588 else
589 {
590 /*
591 * We can't determine which key is more restrictive. Push
592 * xform[j] directly to the output array, then set xform[j] to
593 * the new scan key.
594 *
595 * Note: We do things this way around so that our arrays are
596 * always in the same order as their corresponding scan keys,
597 * even with incomplete opfamilies. _bt_advance_array_keys
598 * depends on this.
599 */
600 ScanKey outkey = &so->keyData[new_numberOfKeys++];
601
602 memcpy(outkey, xform[j].inkey, sizeof(ScanKeyData));
603 if (arrayKeyData)
604 keyDataMap[new_numberOfKeys - 1] = xform[j].inkeyi;
605 if (numberOfEqualCols == attno - 1)
607 xform[j].inkey = inkey;
608 xform[j].inkeyi = i;
609 xform[j].arrayidx = arrayidx;
610 }
611 }
612 }
613
614 so->numberOfKeys = new_numberOfKeys;
615
616 /*
617 * Now that we've built a temporary mapping from so->keyData[] (output
618 * scan keys) to arrayKeyData[] (our input scan keys), fix array->scan_key
619 * references. Also consolidate the so->orderProcs[] array such that it
620 * can be subscripted using so->keyData[]-wise offsets.
621 */
622 if (arrayKeyData)
623 _bt_preprocess_array_keys_final(scan, keyDataMap);
624
625 /* Could pfree arrayKeyData/keyDataMap now, but not worth the cycles */
626}
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1260
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:2172
static bool _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption)
static void _bt_mark_scankey_required(ScanKey skey)
static ScanKey _bt_preprocess_array_keys(IndexScanDesc scan, int *new_numberOfKeys)
static void _bt_preprocess_array_keys_final(IndexScanDesc scan, int *keyDataMap)
static bool _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op, ScanKey leftarg, ScanKey rightarg, BTArrayKeyInfo *array, FmgrInfo *orderproc, bool *result)
#define BTMaxStrategyNumber
Definition: stratnum.h:35
Oid fn_oid
Definition: fmgr.h:59

References _bt_compare_scankey_args(), _bt_fix_scankey_strategy(), _bt_mark_scankey_required(), _bt_preprocess_array_keys(), _bt_preprocess_array_keys_final(), BTScanOpaqueData::arrayContext, BTScanOpaqueData::arrayKeys, Assert(), BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, BTMaxStrategyNumber, elog, ERROR, FmgrInfo::fn_oid, i, if(), IndexScanDescData::indexRelation, j, BTScanOpaqueData::keyData, IndexScanDescData::keyData, MemoryContextAlloc(), BTScanOpaqueData::numberOfKeys, IndexScanDescData::numberOfKeys, OidIsValid, IndexScanDescData::opaque, BTScanOpaqueData::orderProcs, BTScanOpaqueData::qual_ok, RelationData::rd_indoption, repalloc(), BTArrayKeyInfo::scan_key, ScanKeyData::sk_attno, SK_BT_SKIP, ScanKeyData::sk_flags, SK_ROW_HEADER, SK_SEARCHARRAY, SK_SEARCHNULL, and ScanKeyData::sk_strategy.

Referenced by _bt_first().

◆ _bt_saoparray_shrink()

static bool _bt_saoparray_shrink ( IndexScanDesc  scan,
ScanKey  arraysk,
ScanKey  skey,
FmgrInfo orderproc,
BTArrayKeyInfo array,
bool *  qual_ok 
)
static

Definition at line 1093 of file nbtpreprocesskeys.c.

1095{
1096 Relation rel = scan->indexRelation;
1097 Oid opcintype = rel->rd_opcintype[arraysk->sk_attno - 1];
1098 int cmpresult = 0,
1099 cmpexact = 0,
1100 matchelem,
1101 new_nelems = 0;
1102 FmgrInfo crosstypeproc;
1103 FmgrInfo *orderprocp = orderproc;
1104
1105 Assert(array->num_elems > 0);
1106 Assert(!(arraysk->sk_flags & SK_BT_SKIP));
1107
1108 /*
1109 * _bt_binsrch_array_skey searches an array for the entry best matching a
1110 * datum of opclass input type for the index's attribute (on-disk type).
1111 * We can reuse the array's ORDER proc whenever the non-array scan key's
1112 * type is a match for the corresponding attribute's input opclass type.
1113 * Otherwise, we have to do another ORDER proc lookup so that our call to
1114 * _bt_binsrch_array_skey applies the correct comparator.
1115 *
1116 * Note: we have to support the convention that sk_subtype == InvalidOid
1117 * means the opclass input type; this is a hack to simplify life for
1118 * ScanKeyInit().
1119 */
1120 if (skey->sk_subtype != opcintype && skey->sk_subtype != InvalidOid)
1121 {
1122 RegProcedure cmp_proc;
1123 Oid arraysk_elemtype;
1124
1125 /*
1126 * Need an ORDER proc lookup to detect redundancy/contradictoriness
1127 * with this pair of scankeys.
1128 *
1129 * Scalar scan key's argument will be passed to _bt_compare_array_skey
1130 * as its tupdatum/lefthand argument (rhs arg is for array elements).
1131 */
1132 arraysk_elemtype = arraysk->sk_subtype;
1133 if (arraysk_elemtype == InvalidOid)
1134 arraysk_elemtype = rel->rd_opcintype[arraysk->sk_attno - 1];
1135 cmp_proc = get_opfamily_proc(rel->rd_opfamily[arraysk->sk_attno - 1],
1136 skey->sk_subtype, arraysk_elemtype,
1137 BTORDER_PROC);
1138 if (!RegProcedureIsValid(cmp_proc))
1139 {
1140 /* Can't make the comparison */
1141 *qual_ok = false; /* suppress compiler warnings */
1142 return false;
1143 }
1144
1145 /* We have all we need to determine redundancy/contradictoriness */
1146 orderprocp = &crosstypeproc;
1147 fmgr_info(cmp_proc, orderprocp);
1148 }
1149
1150 matchelem = _bt_binsrch_array_skey(orderprocp, false,
1152 skey->sk_argument, false, array,
1153 arraysk, &cmpresult);
1154
1155 switch (skey->sk_strategy)
1156 {
1158 cmpexact = 1; /* exclude exact match, if any */
1159 /* FALL THRU */
1161 if (cmpresult >= cmpexact)
1162 matchelem++;
1163 /* Resize, keeping elements from the start of the array */
1164 new_nelems = matchelem;
1165 break;
1167 if (cmpresult != 0)
1168 {
1169 /* qual is unsatisfiable */
1170 new_nelems = 0;
1171 }
1172 else
1173 {
1174 /* Shift matching element to the start of the array, resize */
1175 array->elem_values[0] = array->elem_values[matchelem];
1176 new_nelems = 1;
1177 }
1178 break;
1180 cmpexact = 1; /* include exact match, if any */
1181 /* FALL THRU */
1183 if (cmpresult >= cmpexact)
1184 matchelem++;
1185 /* Shift matching elements to the start of the array, resize */
1186 new_nelems = array->num_elems - matchelem;
1187 memmove(array->elem_values, array->elem_values + matchelem,
1188 sizeof(Datum) * new_nelems);
1189 break;
1190 default:
1191 elog(ERROR, "unrecognized StrategyNumber: %d",
1192 (int) skey->sk_strategy);
1193 break;
1194 }
1195
1196 Assert(new_nelems >= 0);
1197 Assert(new_nelems <= array->num_elems);
1198
1199 array->num_elems = new_nelems;
1200 *qual_ok = new_nelems > 0;
1201
1202 return true;
1203}
int _bt_binsrch_array_skey(FmgrInfo *orderproc, bool cur_elem_trig, ScanDirection dir, Datum tupdatum, bool tupnull, BTArrayKeyInfo *array, ScanKey cur, int32 *set_elem_result)
Definition: nbtutils.c:287
@ NoMovementScanDirection
Definition: sdir.h:27

References _bt_binsrch_array_skey(), Assert(), BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, BTORDER_PROC, BTArrayKeyInfo::elem_values, elog, ERROR, fmgr_info(), get_opfamily_proc(), IndexScanDescData::indexRelation, InvalidOid, NoMovementScanDirection, BTArrayKeyInfo::num_elems, RelationData::rd_opcintype, RelationData::rd_opfamily, RegProcedureIsValid, ScanKeyData::sk_argument, ScanKeyData::sk_attno, SK_BT_SKIP, ScanKeyData::sk_flags, ScanKeyData::sk_strategy, and ScanKeyData::sk_subtype.

Referenced by _bt_compare_array_scankey_args().

◆ _bt_setup_array_cmp()

static void _bt_setup_array_cmp ( IndexScanDesc  scan,
ScanKey  skey,
Oid  elemtype,
FmgrInfo orderproc,
FmgrInfo **  sortprocp 
)
static

Definition at line 2321 of file nbtpreprocesskeys.c.

2323{
2324 BTScanOpaque so = (BTScanOpaque) scan->opaque;
2325 Relation rel = scan->indexRelation;
2326 RegProcedure cmp_proc;
2327 Oid opcintype = rel->rd_opcintype[skey->sk_attno - 1];
2328
2330 Assert(OidIsValid(elemtype));
2331
2332 /*
2333 * If scankey operator is not a cross-type comparison, we can use the
2334 * cached comparison function; otherwise gotta look it up in the catalogs
2335 */
2336 if (elemtype == opcintype)
2337 {
2338 /* Set same-type ORDER procs for caller */
2339 *orderproc = *index_getprocinfo(rel, skey->sk_attno, BTORDER_PROC);
2340 if (sortprocp)
2341 *sortprocp = orderproc;
2342
2343 return;
2344 }
2345
2346 /*
2347 * Look up the appropriate cross-type comparison function in the opfamily.
2348 *
2349 * Use the opclass input type as the left hand arg type, and the array
2350 * element type as the right hand arg type (since binary searches use an
2351 * index tuple's attribute value to search for a matching array element).
2352 *
2353 * Note: it's possible that this would fail, if the opfamily is
2354 * incomplete, but only in cases where it's quite likely that _bt_first
2355 * would fail in just the same way (had we not failed before it could).
2356 */
2357 cmp_proc = get_opfamily_proc(rel->rd_opfamily[skey->sk_attno - 1],
2358 opcintype, elemtype, BTORDER_PROC);
2359 if (!RegProcedureIsValid(cmp_proc))
2360 elog(ERROR, "missing support function %d(%u,%u) for attribute %d of index \"%s\"",
2361 BTORDER_PROC, opcintype, elemtype, skey->sk_attno,
2363
2364 /* Set cross-type ORDER proc for caller */
2365 fmgr_info_cxt(cmp_proc, orderproc, so->arrayContext);
2366
2367 /* Done if caller doesn't actually have an array they'll need to sort */
2368 if (!sortprocp)
2369 return;
2370
2371 /*
2372 * Look up the appropriate same-type comparison function in the opfamily.
2373 *
2374 * Note: it's possible that this would fail, if the opfamily is
2375 * incomplete, but it seems quite unlikely that an opfamily would omit
2376 * non-cross-type comparison procs for any datatype that it supports at
2377 * all.
2378 */
2379 cmp_proc = get_opfamily_proc(rel->rd_opfamily[skey->sk_attno - 1],
2380 elemtype, elemtype, BTORDER_PROC);
2381 if (!RegProcedureIsValid(cmp_proc))
2382 elog(ERROR, "missing support function %d(%u,%u) for attribute %d of index \"%s\"",
2383 BTORDER_PROC, elemtype, elemtype,
2384 skey->sk_attno, RelationGetRelationName(rel));
2385
2386 /* Set same-type ORDER proc for caller */
2387 fmgr_info_cxt(cmp_proc, *sortprocp, so->arrayContext);
2388}
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:907
#define RelationGetRelationName(relation)
Definition: rel.h:550

References BTScanOpaqueData::arrayContext, Assert(), BTEqualStrategyNumber, BTORDER_PROC, elog, ERROR, fmgr_info_cxt(), get_opfamily_proc(), index_getprocinfo(), IndexScanDescData::indexRelation, OidIsValid, IndexScanDescData::opaque, RelationData::rd_opcintype, RegProcedureIsValid, RelationGetRelationName, ScanKeyData::sk_attno, and ScanKeyData::sk_strategy.

Referenced by _bt_preprocess_array_keys(), and _bt_preprocess_array_keys_final().

◆ _bt_skiparray_shrink()

static bool _bt_skiparray_shrink ( IndexScanDesc  scan,
ScanKey  skey,
BTArrayKeyInfo array,
bool *  qual_ok 
)
static

Definition at line 1218 of file nbtpreprocesskeys.c.

1220{
1221 bool test_result;
1222
1223 Assert(array->num_elems == -1);
1224
1225 /*
1226 * Array's index attribute will be constrained by a strict operator/key.
1227 * Array must not "contain a NULL element" (i.e. the scan must not apply
1228 * "IS NULL" qual when it reaches the end of the index that stores NULLs).
1229 */
1230 array->null_elem = false;
1231 *qual_ok = true;
1232
1233 /*
1234 * Consider if we should treat caller's scalar scan key as the skip
1235 * array's high_compare or low_compare.
1236 *
1237 * In general the current array element must either be a copy of a value
1238 * taken from an index tuple, or a derivative value generated by opclass's
1239 * skip support function. That way the scan can always safely assume that
1240 * it's okay to use the only-input-opclass-type proc from so->orderProcs[]
1241 * (they can be cross-type with SAOP arrays, but never with skip arrays).
1242 *
1243 * This approach is enabled by MINVAL/MAXVAL sentinel key markings, which
1244 * can be thought of as representing either the lowest or highest matching
1245 * array element (excluding the NULL element, where applicable, though as
1246 * just discussed it isn't applicable to this range skip array anyway).
1247 * Array keys marked MINVAL/MAXVAL never have a valid datum in their
1248 * sk_argument field. The scan directly applies the array's low_compare
1249 * key when it encounters MINVAL in the array key proper (just as it
1250 * applies high_compare when it sees MAXVAL set in the array key proper).
1251 * The scan must never use the array's so->orderProcs[] proc against
1252 * low_compare's/high_compare's sk_argument, either (so->orderProcs[] is
1253 * only intended to be used with rhs datums from the array proper/index).
1254 */
1255 switch (skey->sk_strategy)
1256 {
1259 if (array->high_compare)
1260 {
1261 /* replace existing high_compare with caller's key? */
1262 if (!_bt_compare_scankey_args(scan, array->high_compare, skey,
1263 array->high_compare, NULL, NULL,
1264 &test_result))
1265 return false; /* can't determine more restrictive key */
1266
1267 if (!test_result)
1268 return true; /* no, just discard caller's key */
1269
1270 /* yes, replace existing high_compare with caller's key */
1271 }
1272
1273 /* caller's key becomes skip array's high_compare */
1274 array->high_compare = skey;
1275 break;
1278 if (array->low_compare)
1279 {
1280 /* replace existing low_compare with caller's key? */
1281 if (!_bt_compare_scankey_args(scan, array->low_compare, skey,
1282 array->low_compare, NULL, NULL,
1283 &test_result))
1284 return false; /* can't determine more restrictive key */
1285
1286 if (!test_result)
1287 return true; /* no, just discard caller's key */
1288
1289 /* yes, replace existing low_compare with caller's key */
1290 }
1291
1292 /* caller's key becomes skip array's low_compare */
1293 array->low_compare = skey;
1294 break;
1296 default:
1297 elog(ERROR, "unrecognized StrategyNumber: %d",
1298 (int) skey->sk_strategy);
1299 break;
1300 }
1301
1302 return true;
1303}

References _bt_compare_scankey_args(), Assert(), BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, elog, ERROR, BTArrayKeyInfo::high_compare, BTArrayKeyInfo::low_compare, BTArrayKeyInfo::null_elem, BTArrayKeyInfo::num_elems, and ScanKeyData::sk_strategy.

Referenced by _bt_compare_array_scankey_args().

◆ _bt_skiparray_strat_adjust()

static void _bt_skiparray_strat_adjust ( IndexScanDesc  scan,
ScanKey  arraysk,
BTArrayKeyInfo array 
)
static

Definition at line 1340 of file nbtpreprocesskeys.c.

1342{
1343 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1344 MemoryContext oldContext;
1345
1346 /*
1347 * Called last among all preprocessing steps, when the skip array's final
1348 * low_compare and high_compare have both been chosen
1349 */
1350 Assert(arraysk->sk_flags & SK_BT_SKIP);
1351 Assert(array->num_elems == -1 && !array->null_elem && array->sksup);
1352
1353 oldContext = MemoryContextSwitchTo(so->arrayContext);
1354
1355 if (array->high_compare &&
1357 _bt_skiparray_strat_decrement(scan, arraysk, array);
1358
1359 if (array->low_compare &&
1361 _bt_skiparray_strat_increment(scan, arraysk, array);
1362
1363 MemoryContextSwitchTo(oldContext);
1364}
static void _bt_skiparray_strat_increment(IndexScanDesc scan, ScanKey arraysk, BTArrayKeyInfo *array)
static void _bt_skiparray_strat_decrement(IndexScanDesc scan, ScanKey arraysk, BTArrayKeyInfo *array)

References _bt_skiparray_strat_decrement(), _bt_skiparray_strat_increment(), BTScanOpaqueData::arrayContext, Assert(), BTGreaterStrategyNumber, BTLessStrategyNumber, BTArrayKeyInfo::high_compare, BTArrayKeyInfo::low_compare, MemoryContextSwitchTo(), BTArrayKeyInfo::null_elem, BTArrayKeyInfo::num_elems, IndexScanDescData::opaque, SK_BT_SKIP, ScanKeyData::sk_flags, ScanKeyData::sk_strategy, and BTArrayKeyInfo::sksup.

Referenced by _bt_preprocess_array_keys_final().

◆ _bt_skiparray_strat_decrement()

static void _bt_skiparray_strat_decrement ( IndexScanDesc  scan,
ScanKey  arraysk,
BTArrayKeyInfo array 
)
static

Definition at line 1370 of file nbtpreprocesskeys.c.

1372{
1373 Relation rel = scan->indexRelation;
1374 Oid opfamily = rel->rd_opfamily[arraysk->sk_attno - 1],
1375 opcintype = rel->rd_opcintype[arraysk->sk_attno - 1],
1376 leop;
1377 RegProcedure cmp_proc;
1378 ScanKey high_compare = array->high_compare;
1379 Datum orig_sk_argument = high_compare->sk_argument,
1380 new_sk_argument;
1381 bool uflow;
1382
1383 Assert(high_compare->sk_strategy == BTLessStrategyNumber);
1384
1385 /*
1386 * Only perform the transformation when the operator type matches the
1387 * index attribute's input opclass type
1388 */
1389 if (high_compare->sk_subtype != opcintype &&
1390 high_compare->sk_subtype != InvalidOid)
1391 return;
1392
1393 /* Decrement, handling underflow by marking the qual unsatisfiable */
1394 new_sk_argument = array->sksup->decrement(rel, orig_sk_argument, &uflow);
1395 if (uflow)
1396 {
1397 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1398
1399 so->qual_ok = false;
1400 return;
1401 }
1402
1403 /* Look up <= operator (might fail) */
1404 leop = get_opfamily_member(opfamily, opcintype, opcintype,
1406 if (!OidIsValid(leop))
1407 return;
1408 cmp_proc = get_opcode(leop);
1409 if (RegProcedureIsValid(cmp_proc))
1410 {
1411 /* Transform < high_compare key into <= key */
1412 fmgr_info(cmp_proc, &high_compare->sk_func);
1413 high_compare->sk_argument = new_sk_argument;
1414 high_compare->sk_strategy = BTLessEqualStrategyNumber;
1415 }
1416}
SkipSupportIncDec decrement
Definition: skipsupport.h:91

References Assert(), BTLessEqualStrategyNumber, BTLessStrategyNumber, SkipSupportData::decrement, fmgr_info(), get_opcode(), get_opfamily_member(), BTArrayKeyInfo::high_compare, IndexScanDescData::indexRelation, InvalidOid, OidIsValid, IndexScanDescData::opaque, BTScanOpaqueData::qual_ok, RelationData::rd_opcintype, RelationData::rd_opfamily, RegProcedureIsValid, ScanKeyData::sk_argument, ScanKeyData::sk_attno, ScanKeyData::sk_func, ScanKeyData::sk_strategy, ScanKeyData::sk_subtype, and BTArrayKeyInfo::sksup.

Referenced by _bt_skiparray_strat_adjust().

◆ _bt_skiparray_strat_increment()

static void _bt_skiparray_strat_increment ( IndexScanDesc  scan,
ScanKey  arraysk,
BTArrayKeyInfo array 
)
static

Definition at line 1422 of file nbtpreprocesskeys.c.

1424{
1425 Relation rel = scan->indexRelation;
1426 Oid opfamily = rel->rd_opfamily[arraysk->sk_attno - 1],
1427 opcintype = rel->rd_opcintype[arraysk->sk_attno - 1],
1428 geop;
1429 RegProcedure cmp_proc;
1430 ScanKey low_compare = array->low_compare;
1431 Datum orig_sk_argument = low_compare->sk_argument,
1432 new_sk_argument;
1433 bool oflow;
1434
1436
1437 /*
1438 * Only perform the transformation when the operator type matches the
1439 * index attribute's input opclass type
1440 */
1441 if (low_compare->sk_subtype != opcintype &&
1442 low_compare->sk_subtype != InvalidOid)
1443 return;
1444
1445 /* Increment, handling overflow by marking the qual unsatisfiable */
1446 new_sk_argument = array->sksup->increment(rel, orig_sk_argument, &oflow);
1447 if (oflow)
1448 {
1449 BTScanOpaque so = (BTScanOpaque) scan->opaque;
1450
1451 so->qual_ok = false;
1452 return;
1453 }
1454
1455 /* Look up >= operator (might fail) */
1456 geop = get_opfamily_member(opfamily, opcintype, opcintype,
1458 if (!OidIsValid(geop))
1459 return;
1460 cmp_proc = get_opcode(geop);
1461 if (RegProcedureIsValid(cmp_proc))
1462 {
1463 /* Transform > low_compare key into >= key */
1464 fmgr_info(cmp_proc, &low_compare->sk_func);
1465 low_compare->sk_argument = new_sk_argument;
1467 }
1468}
SkipSupportIncDec increment
Definition: skipsupport.h:92

References Assert(), BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, fmgr_info(), get_opcode(), get_opfamily_member(), SkipSupportData::increment, IndexScanDescData::indexRelation, InvalidOid, BTArrayKeyInfo::low_compare, OidIsValid, IndexScanDescData::opaque, BTScanOpaqueData::qual_ok, RelationData::rd_opcintype, RelationData::rd_opfamily, RegProcedureIsValid, ScanKeyData::sk_argument, ScanKeyData::sk_attno, ScanKeyData::sk_func, ScanKeyData::sk_strategy, ScanKeyData::sk_subtype, and BTArrayKeyInfo::sksup.

Referenced by _bt_skiparray_strat_adjust().

◆ _bt_sort_array_elements()

static int _bt_sort_array_elements ( ScanKey  skey,
FmgrInfo sortproc,
bool  reverse,
Datum elems,
int  nelems 
)
static

Definition at line 2401 of file nbtpreprocesskeys.c.

2403{
2405
2406 if (nelems <= 1)
2407 return nelems; /* no work to do */
2408
2409 /* Sort the array elements */
2410 cxt.sortproc = sortproc;
2411 cxt.collation = skey->sk_collation;
2412 cxt.reverse = reverse;
2413 qsort_arg(elems, nelems, sizeof(Datum),
2415
2416 /* Now scan the sorted elements and remove duplicates */
2417 return qunique_arg(elems, nelems, sizeof(Datum),
2419}
void qsort_arg(void *base, size_t nel, size_t elsize, qsort_arg_comparator cmp, void *arg)
static size_t qunique_arg(void *array, size_t elements, size_t width, int(*compare)(const void *, const void *, void *), void *arg)
Definition: qunique.h:46

References _bt_compare_array_elements(), BTSortArrayContext::collation, qsort_arg(), qunique_arg(), BTSortArrayContext::reverse, ScanKeyData::sk_collation, and BTSortArrayContext::sortproc.

Referenced by _bt_preprocess_array_keys().