@@ -19,14 +19,18 @@ PG_MODULE_MAGIC_EXT(
19
19
.version = PG_VERSION
20
20
);
21
21
22
+ /* extra data passed from gin_btree_extract_query to gin_btree_compare_prefix */
22
23
typedef struct QueryInfo
23
24
{
24
- StrategyNumber strategy ;
25
- Datum datum ;
26
- bool is_varlena ;
27
- Datum ( * typecmp ) ( FunctionCallInfo );
25
+ StrategyNumber strategy ; /* operator strategy number */
26
+ Datum orig_datum ; /* original query (comparison) datum */
27
+ Datum entry_datum ; /* datum we reported as the entry value */
28
+ PGFunction typecmp ; /* appropriate btree comparison function */
28
29
} QueryInfo ;
29
30
31
+ typedef Datum (* btree_gin_leftmost_function ) (void );
32
+
33
+
30
34
/*** GIN support functions shared by all datatypes ***/
31
35
32
36
static Datum
@@ -36,6 +40,7 @@ gin_btree_extract_value(FunctionCallInfo fcinfo, bool is_varlena)
36
40
int32 * nentries = (int32 * ) PG_GETARG_POINTER (1 );
37
41
Datum * entries = (Datum * ) palloc (sizeof (Datum ));
38
42
43
+ /* Ensure that values stored in the index are not toasted */
39
44
if (is_varlena )
40
45
datum = PointerGetDatum (PG_DETOAST_DATUM (datum ));
41
46
entries [0 ] = datum ;
@@ -44,19 +49,11 @@ gin_btree_extract_value(FunctionCallInfo fcinfo, bool is_varlena)
44
49
PG_RETURN_POINTER (entries );
45
50
}
46
51
47
- /*
48
- * For BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, and
49
- * BTEqualStrategyNumber we want to start the index scan at the
50
- * supplied query datum, and work forward. For BTLessStrategyNumber
51
- * and BTLessEqualStrategyNumber, we need to start at the leftmost
52
- * key, and work forward until the supplied query datum (which must be
53
- * sent along inside the QueryInfo structure).
54
- */
55
52
static Datum
56
53
gin_btree_extract_query (FunctionCallInfo fcinfo ,
57
54
bool is_varlena ,
58
- Datum ( * leftmostvalue ) ( void ) ,
59
- Datum ( * typecmp ) ( FunctionCallInfo ) )
55
+ btree_gin_leftmost_function leftmostvalue ,
56
+ PGFunction typecmp )
60
57
{
61
58
Datum datum = PG_GETARG_DATUM (0 );
62
59
int32 * nentries = (int32 * ) PG_GETARG_POINTER (1 );
@@ -65,20 +62,29 @@ gin_btree_extract_query(FunctionCallInfo fcinfo,
65
62
Pointer * * extra_data = (Pointer * * ) PG_GETARG_POINTER (4 );
66
63
Datum * entries = (Datum * ) palloc (sizeof (Datum ));
67
64
QueryInfo * data = (QueryInfo * ) palloc (sizeof (QueryInfo ));
68
- bool * ptr_partialmatch ;
65
+ bool * ptr_partialmatch = ( bool * ) palloc ( sizeof ( bool )) ;
69
66
70
- * nentries = 1 ;
71
- ptr_partialmatch = * partialmatch = (bool * ) palloc (sizeof (bool ));
72
- * ptr_partialmatch = false;
67
+ /*
68
+ * Detoast the comparison datum. This isn't necessary for correctness,
69
+ * but it can save repeat detoastings within the comparison function.
70
+ */
73
71
if (is_varlena )
74
72
datum = PointerGetDatum (PG_DETOAST_DATUM (datum ));
75
- data -> strategy = strategy ;
76
- data -> datum = datum ;
77
- data -> is_varlena = is_varlena ;
78
- data -> typecmp = typecmp ;
79
- * extra_data = (Pointer * ) palloc (sizeof (Pointer ));
80
- * * extra_data = (Pointer ) data ;
81
73
74
+ /* Prep single comparison key with possible partial-match flag */
75
+ * nentries = 1 ;
76
+ * partialmatch = ptr_partialmatch ;
77
+ * ptr_partialmatch = false;
78
+
79
+ /*
80
+ * For BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, and
81
+ * BTEqualStrategyNumber we want to start the index scan at the supplied
82
+ * query datum, and work forward. For BTLessStrategyNumber and
83
+ * BTLessEqualStrategyNumber, we need to start at the leftmost key, and
84
+ * work forward until the supplied query datum (which we'll send along
85
+ * inside the QueryInfo structure). Use partial match rules except for
86
+ * BTEqualStrategyNumber.
87
+ */
82
88
switch (strategy )
83
89
{
84
90
case BTLessStrategyNumber :
@@ -97,30 +103,42 @@ gin_btree_extract_query(FunctionCallInfo fcinfo,
97
103
elog (ERROR , "unrecognized strategy number: %d" , strategy );
98
104
}
99
105
106
+ /* Fill "extra" data */
107
+ data -> strategy = strategy ;
108
+ data -> orig_datum = datum ;
109
+ data -> entry_datum = entries [0 ];
110
+ data -> typecmp = typecmp ;
111
+ * extra_data = (Pointer * ) palloc (sizeof (Pointer ));
112
+ * * extra_data = (Pointer ) data ;
113
+
100
114
PG_RETURN_POINTER (entries );
101
115
}
102
116
103
- /*
104
- * Datum a is a value from extract_query method and for BTLess*
105
- * strategy it is a left-most value. So, use original datum from QueryInfo
106
- * to decide to stop scanning or not. Datum b is always from index.
107
- */
108
117
static Datum
109
118
gin_btree_compare_prefix (FunctionCallInfo fcinfo )
110
119
{
111
- Datum a = PG_GETARG_DATUM (0 );
112
- Datum b = PG_GETARG_DATUM (1 );
120
+ Datum partial_key PG_USED_FOR_ASSERTS_ONLY = PG_GETARG_DATUM (0 );
121
+ Datum key = PG_GETARG_DATUM (1 );
113
122
QueryInfo * data = (QueryInfo * ) PG_GETARG_POINTER (3 );
114
123
int32 res ,
115
124
cmp ;
116
125
126
+ /*
127
+ * partial_key is only an approximation to the real comparison value,
128
+ * especially if it's a leftmost value. We can get an accurate answer by
129
+ * doing a possibly-cross-type comparison to the real comparison value.
130
+ * But just to be sure that things are what we expect, let's assert that
131
+ * partial_key is indeed what gin_btree_extract_query reported, so that
132
+ * we'll notice if anyone ever changes the core code in a way that breaks
133
+ * our assumptions.
134
+ */
135
+ Assert (partial_key == data -> entry_datum );
136
+
117
137
cmp = DatumGetInt32 (CallerFInfoFunctionCall2 (data -> typecmp ,
118
138
fcinfo -> flinfo ,
119
139
PG_GET_COLLATION (),
120
- (data -> strategy == BTLessStrategyNumber ||
121
- data -> strategy == BTLessEqualStrategyNumber )
122
- ? data -> datum : a ,
123
- b ));
140
+ data -> orig_datum ,
141
+ key ));
124
142
125
143
switch (data -> strategy )
126
144
{
@@ -152,7 +170,7 @@ gin_btree_compare_prefix(FunctionCallInfo fcinfo)
152
170
res = 1 ;
153
171
break ;
154
172
case BTGreaterStrategyNumber :
155
- /* If original datum <= indexed one then return match */
173
+ /* If original datum < indexed one then return match */
156
174
/* If original datum == indexed one then continue scan */
157
175
if (cmp < 0 )
158
176
res = 0 ;
0 commit comments