2 * contrib/btree_gin/btree_gin.c
25 * Our opclasses use the same strategy numbers as btree (1-5) for same-type
26 * comparison operators. For cross-type comparison operators, the
27 * low 4 bits of our strategy numbers are the btree strategy number,
28 * and the upper bits are a code for the right-hand-side data type.
30 #define BTGIN_GET_BTREE_STRATEGY(strat) ((strat) & 0x0F)
31 #define BTGIN_GET_RHS_TYPE_CODE(strat) ((strat) >> 4)
33/* extra data passed from gin_btree_extract_query to gin_btree_compare_prefix */
47/*** GIN support functions shared by all datatypes ***/
56 /* Ensure that values stored in the index are not toasted */
68 const bool *rhs_is_varlena,
79 bool *ptr_partialmatch = (
bool *)
palloc(
sizeof(
bool));
84 * Extract the btree strategy code and the RHS data type code from the
85 * given strategy number.
91 * Detoast the comparison datum. This isn't necessary for correctness,
92 * but it can save repeat detoastings within the comparison function.
94 if (rhs_is_varlena[rhs_code])
97 /* Prep single comparison key with possible partial-match flag */
99 *partialmatch = ptr_partialmatch;
100 *ptr_partialmatch =
false;
103 * For BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, and
104 * BTEqualStrategyNumber we want to start the index scan at the supplied
105 * query datum, and work forward. For BTLessStrategyNumber and
106 * BTLessEqualStrategyNumber, we need to start at the leftmost key, and
107 * work forward until the supplied query datum (which we'll send along
108 * inside the QueryInfo structure). Use partial match rules except for
109 * BTEqualStrategyNumber without a conversion function. (If there is a
110 * conversion function, comparison to the entry value is not trustworthy.)
116 entries[0] = leftmostvalue();
117 *ptr_partialmatch =
true;
121 *ptr_partialmatch =
true;
124 /* If we have a conversion function, apply it */
125 if (cvt_fns && cvt_fns[rhs_code])
127 entries[0] = (*cvt_fns[rhs_code]) (datum);
128 *ptr_partialmatch =
true;
134 elog(
ERROR,
"unrecognized strategy number: %d", strategy);
137 /* Fill "extra" data */
138 data->strategy = strategy;
139 data->orig_datum = datum;
140 data->entry_datum = entries[0];
141 data->typecmp = cmp_fns[rhs_code];
158 * partial_key is only an approximation to the real comparison value,
159 * especially if it's a leftmost value. We can get an accurate answer by
160 * doing a possibly-cross-type comparison to the real comparison value.
161 * (Note that partial_key and key are of the indexed datatype while
162 * orig_datum is of the query operator's RHS datatype.)
164 * But just to be sure that things are what we expect, let's assert that
165 * partial_key is indeed what gin_btree_extract_query reported, so that
166 * we'll notice if anyone ever changes the core code in a way that breaks
178 * Convert the comparison result to the correct thing for the search
179 * operator strategy. When dealing with cross-type comparisons, an
180 * imprecise entry datum could lead GIN to start the scan just before the
181 * first possible match, so we must continue the scan if the current index
182 * entry doesn't satisfy the search condition for >= and > cases. But if
183 * that happens in an = search we can stop, because an imprecise entry
184 * datum means that the search value is unrepresentable in the indexed
185 * data type, so that there will be no exact matches.
190 /* If original datum > indexed one then return match */
194 res = 1;
/* end scan */
197 /* If original datum >= indexed one then return match */
201 res = 1;
/* end scan */
204 /* If original datum = indexed one then return match */
205 /* See above about why we can end scan when cmp < 0 */
209 res = 1;
/* end scan */
212 /* If original datum <= indexed one then return match */
216 res = -1;
/* keep scanning */
219 /* If original datum < indexed one then return match */
223 res = -1;
/* keep scanning */
226 elog(
ERROR,
"unrecognized strategy number: %d",
244/*** GIN_SUPPORT macro defines the datatype specific functions ***/
246 #define GIN_SUPPORT(type, leftmostvalue, is_varlena, cvtfns, cmpfns) \
247PG_FUNCTION_INFO_V1(gin_extract_value_##type); \
249gin_extract_value_##type(PG_FUNCTION_ARGS) \
251 return gin_btree_extract_value(fcinfo, is_varlena[0]); \
253PG_FUNCTION_INFO_V1(gin_extract_query_##type); \
255gin_extract_query_##type(PG_FUNCTION_ARGS) \
257 return gin_btree_extract_query(fcinfo, \
258 leftmostvalue, is_varlena, \
261PG_FUNCTION_INFO_V1(gin_compare_prefix_##type); \
263gin_compare_prefix_##type(PG_FUNCTION_ARGS) \
265 return gin_btree_compare_prefix(fcinfo); \
269/*** Datatype specifications ***/
271/* Function to produce the least possible value of the indexed datatype */
279 * For cross-type support, we must provide conversion functions that produce
280 * a Datum of the indexed datatype, since GIN requires the "entry" datums to
281 * be of that type. If an exact conversion is not possible, produce a value
282 * that will lead GIN to find the first index entry that is greater than
283 * or equal to the actual comparison value. (But rounding down is OK, so
284 * sometimes we might find an index entry that's just less than the
287 * For integer values, it's sufficient to clamp the input to be in-range.
289 * Note: for out-of-range input values, we could in theory detect that the
290 * search condition matches all or none of the index, and avoid a useless
291 * index descent in the latter case. Such searches are probably rare though,
292 * so we don't contort this code enough to do that.
315 * RHS-type-is-varlena flags, conversion and comparison function arrays,
316 * indexed by high bits of the operator strategy number. A NULL in the
317 * conversion function array indicates that no conversion is needed, which
318 * will always be the case for the zero'th entry. Note that the cross-type
319 * comparison functions should be the ones with the indexed datatype second.
322{
false,
false,
false};
357{
false,
false,
false};
390{
false,
false,
false};
413 * Assume that ordinary C conversion will produce a usable result.
414 * (Compare dtof(), which raises error conditions that we don't need.)
415 * Note that for inputs that aren't exactly representable as float4, it
416 * doesn't matter whether the conversion rounds up or down. That might
417 * cause us to scan a few index entries that we'll reject as not matching,
418 * but we won't miss any that should match.
502 /* We can ignore the overflow result, since result is useful as-is */
514 /* We can ignore the overflow result, since result is useful as-is */
519{
false,
false,
false};
537 /* We can ignore the overflow result, since result is useful as-is */
549 /* We can ignore the overflow result, since result is useful as-is */
554{
false,
false,
false};
584 v->
zone = -24 * 3600;
/* XXX is that true? */
611 /* We can ignore the overflow result, since result is useful as-is */
623 /* We can ignore the overflow result, since result is useful as-is */
628{
false,
false,
false};
800 * Numeric type hasn't a real left-most value, so we use PointerGetDatum(NULL)
801 * (*not* a SQL NULL) to represent that. We can get away with that because
802 * the value returned by our leftmostvalue function will never be stored in
803 * the index nor passed to anything except our compare and prefix-comparison
804 * functions. The same trick could be used for other pass-by-reference types.
807 #define NUMERIC_IS_LEFTMOST(x) ((x) == NULL)
851 * Use a similar trick to that used for numeric for enums, since we don't
852 * actually know the leftmost value of any enum without knowing the concrete
853 * type, so we use a dummy leftmost value of InvalidOid.
855 * Note that we use CallerFInfoFunctionCall2 here so that enum_cmp
856 * gets a valid fn_extra to work with. Unlike most other type comparison
857 * routines it needs it, so we can't use DirectFunctionCall2.
860 #define ENUM_IS_LEFTMOST(x) ((x) == InvalidOid)
909 * palloc0 will create the UUID with all zeroes:
910 * "00000000-0000-0000-0000-000000000000"
941 * Truncate oversize input. We're assuming this will produce a result
942 * considered less than the original. That could be a bad assumption in
943 * some collations, but fortunately an index on "name" is generally going
944 * to use C collation.
Datum numeric_cmp(PG_FUNCTION_ARGS)
Datum timestamp_cmp_timestamptz(PG_FUNCTION_ARGS)
Datum timestamp_cmp(PG_FUNCTION_ARGS)
TimestampTz timestamp2timestamptz_opt_overflow(Timestamp timestamp, int *overflow)
Datum timestamptz_cmp_timestamp(PG_FUNCTION_ARGS)
Datum interval_cmp(PG_FUNCTION_ARGS)
Timestamp timestamptz2timestamp_opt_overflow(TimestampTz timestamp, int *overflow)
static const PGFunction bytea_cmp_fns[]
static Datum leftmostvalue_oid(void)
static const PGFunction char_cmp_fns[]
static const btree_gin_convert_function int8_cvt_fns[]
static const PGFunction int8_cmp_fns[]
static const btree_gin_convert_function int2_cvt_fns[]
static const PGFunction macaddr_cmp_fns[]
Datum gin_numeric_cmp(PG_FUNCTION_ARGS)
static Datum leftmostvalue_timestamp(void)
static const bool text_rhs_is_varlena[]
static Datum cvt_int2_int8(Datum input)
static const PGFunction varbit_cmp_fns[]
static const bool time_rhs_is_varlena[]
static Datum cvt_int8_int2(Datum input)
static Datum leftmostvalue_int4(void)
static const PGFunction oid_cmp_fns[]
static const bool int4_rhs_is_varlena[]
static const btree_gin_convert_function text_cvt_fns[]
static const bool timestamptz_rhs_is_varlena[]
static Datum leftmostvalue_varbit(void)
static const PGFunction timestamp_cmp_fns[]
static const btree_gin_convert_function timestamptz_cvt_fns[]
static const PGFunction uuid_cmp_fns[]
static const PGFunction interval_cmp_fns[]
static Datum leftmostvalue_float8(void)
static Datum leftmostvalue_time(void)
Datum(* btree_gin_leftmost_function)(void)
static const PGFunction time_cmp_fns[]
#define BTGIN_GET_BTREE_STRATEGY(strat)
static const bool uuid_rhs_is_varlena[]
static Datum leftmostvalue_int2(void)
static const bool name_rhs_is_varlena[]
Datum gin_enum_cmp(PG_FUNCTION_ARGS)
static const PGFunction cidr_cmp_fns[]
static const PGFunction numeric_cmp_fns[]
static const PGFunction float4_cmp_fns[]
static const PGFunction timestamptz_cmp_fns[]
static Datum gin_btree_extract_query(FunctionCallInfo fcinfo, btree_gin_leftmost_function leftmostvalue, const bool *rhs_is_varlena, const btree_gin_convert_function *cvt_fns, const PGFunction *cmp_fns)
#define BTGIN_GET_RHS_TYPE_CODE(strat)
static const bool interval_rhs_is_varlena[]
static const PGFunction name_cmp_fns[]
static const bool bit_rhs_is_varlena[]
static const bool timetz_rhs_is_varlena[]
static const bool float8_rhs_is_varlena[]
PG_MODULE_MAGIC_EXT(.name="btree_gin",.version=PG_VERSION)
static const PGFunction enum_cmp_fns[]
static Datum leftmostvalue_macaddr8(void)
static Datum cvt_int8_int4(Datum input)
static const bool inet_rhs_is_varlena[]
static Datum cvt_timestamptz_timestamp(Datum input)
static const PGFunction date_cmp_fns[]
static Datum leftmostvalue_text(void)
static const bool date_rhs_is_varlena[]
static const PGFunction int2_cmp_fns[]
struct QueryInfo QueryInfo
static const bool oid_rhs_is_varlena[]
static const bool macaddr8_rhs_is_varlena[]
static Datum cvt_date_timestamptz(Datum input)
static Datum leftmostvalue_enum(void)
static Datum leftmostvalue_bool(void)
#define NUMERIC_IS_LEFTMOST(x)
static const btree_gin_convert_function float4_cvt_fns[]
static Datum cvt_timestamp_timestamptz(Datum input)
static Datum leftmostvalue_interval(void)
static const PGFunction bit_cmp_fns[]
static Datum leftmostvalue_float4(void)
static Datum leftmostvalue_name(void)
static const bool float4_rhs_is_varlena[]
static const bool macaddr_rhs_is_varlena[]
static const bool numeric_rhs_is_varlena[]
static Datum leftmostvalue_inet(void)
static const btree_gin_convert_function name_cvt_fns[]
static Datum cvt_text_name(Datum input)
static const btree_gin_convert_function int4_cvt_fns[]
static const btree_gin_convert_function float8_cvt_fns[]
static const bool bool_rhs_is_varlena[]
static Datum cvt_timestamptz_date(Datum input)
static Datum cvt_date_timestamp(Datum input)
static const bool char_rhs_is_varlena[]
Datum(* btree_gin_convert_function)(Datum input)
static Datum cvt_timestamp_date(Datum input)
static const bool cidr_rhs_is_varlena[]
static Datum leftmostvalue_char(void)
static const PGFunction float8_cmp_fns[]
static Datum cvt_int4_int2(Datum input)
static const PGFunction bpchar_cmp_fns[]
static Datum leftmostvalue_uuid(void)
#define GIN_SUPPORT(type, leftmostvalue, is_varlena, cvtfns, cmpfns)
static Datum leftmostvalue_macaddr(void)
Datum gin_btree_consistent(PG_FUNCTION_ARGS)
static Datum leftmostvalue_timetz(void)
#define ENUM_IS_LEFTMOST(x)
static Datum leftmostvalue_money(void)
static const bool int2_rhs_is_varlena[]
static Datum leftmostvalue_numeric(void)
static const PGFunction inet_cmp_fns[]
static const btree_gin_convert_function date_cvt_fns[]
static const PGFunction macaddr8_cmp_fns[]
static Datum cvt_int2_int4(Datum input)
static const bool enum_rhs_is_varlena[]
static const PGFunction money_cmp_fns[]
static Datum gin_btree_compare_prefix(FunctionCallInfo fcinfo)
static const bool timestamp_rhs_is_varlena[]
static Datum gin_btree_extract_value(FunctionCallInfo fcinfo, bool is_varlena)
static Datum leftmostvalue_int8(void)
static Datum cvt_float4_float8(Datum input)
static const PGFunction text_cmp_fns[]
static Datum cvt_name_text(Datum input)
static const bool varbit_rhs_is_varlena[]
static Datum leftmostvalue_date(void)
static const bool bytea_rhs_is_varlena[]
PG_FUNCTION_INFO_V1(gin_btree_consistent)
static const PGFunction bool_cmp_fns[]
static Datum leftmostvalue_bit(void)
static const bool int8_rhs_is_varlena[]
static const PGFunction timetz_cmp_fns[]
static Datum cvt_float8_float4(Datum input)
static const btree_gin_convert_function timestamp_cvt_fns[]
static const bool money_rhs_is_varlena[]
static const bool bpchar_rhs_is_varlena[]
static const PGFunction int4_cmp_fns[]
static Datum cvt_int4_int8(Datum input)
Datum byteacmp(PG_FUNCTION_ARGS)
#define PG_USED_FOR_ASSERTS_ONLY
Datum cash_cmp(PG_FUNCTION_ARGS)
#define INTERVAL_NOBEGIN(i)
DateADT timestamp2date_opt_overflow(Timestamp timestamp, int *overflow)
Datum date_cmp(PG_FUNCTION_ARGS)
Datum time_cmp(PG_FUNCTION_ARGS)
Datum timetz_cmp(PG_FUNCTION_ARGS)
Datum date_cmp_timestamp(PG_FUNCTION_ARGS)
TimestampTz date2timestamptz_opt_overflow(DateADT dateVal, int *overflow)
Datum timestamptz_cmp_date(PG_FUNCTION_ARGS)
Datum date_cmp_timestamptz(PG_FUNCTION_ARGS)
DateADT timestamptz2date_opt_overflow(TimestampTz timestamp, int *overflow)
Timestamp date2timestamp_opt_overflow(DateADT dateVal, int *overflow)
Datum timestamp_cmp_date(PG_FUNCTION_ARGS)
static Datum DateADTGetDatum(DateADT X)
static DateADT DatumGetDateADT(Datum X)
static Datum TimeTzADTPGetDatum(const TimeTzADT *X)
static Datum TimeADTGetDatum(TimeADT X)
Datum enum_cmp(PG_FUNCTION_ARGS)
Datum btfloat4cmp(PG_FUNCTION_ARGS)
Datum btfloat84cmp(PG_FUNCTION_ARGS)
Datum btfloat8cmp(PG_FUNCTION_ARGS)
Datum btfloat48cmp(PG_FUNCTION_ARGS)
static float4 get_float4_infinity(void)
static float8 get_float8_infinity(void)
Datum CallerFInfoFunctionCall2(PGFunction func, FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
#define DirectFunctionCall2(func, arg1, arg2)
#define DatumGetTextPP(X)
#define PG_GETARG_POINTER(n)
#define DirectFunctionCall1(func, arg1)
#define PG_GETARG_DATUM(n)
#define PG_GETARG_UINT16(n)
#define PG_DETOAST_DATUM(datum)
#define PG_RETURN_INT32(x)
Datum(* PGFunction)(FunctionCallInfo fcinfo)
#define DirectFunctionCall3(func, arg1, arg2, arg3)
#define PG_RETURN_POINTER(x)
#define PG_GET_COLLATION()
#define PG_RETURN_BOOL(x)
Assert(PointerIsAligned(start, uint64))
Datum macaddr8_cmp(PG_FUNCTION_ARGS)
Datum macaddr_cmp(PG_FUNCTION_ARGS)
int pg_mbcliplen(const char *mbstr, int len, int limit)
void * palloc0(Size size)
Datum btnamecmp(PG_FUNCTION_ARGS)
Datum btint4cmp(PG_FUNCTION_ARGS)
Datum btboolcmp(PG_FUNCTION_ARGS)
Datum btint2cmp(PG_FUNCTION_ARGS)
Datum btint24cmp(PG_FUNCTION_ARGS)
Datum btoidcmp(PG_FUNCTION_ARGS)
Datum btint84cmp(PG_FUNCTION_ARGS)
Datum btcharcmp(PG_FUNCTION_ARGS)
Datum btint82cmp(PG_FUNCTION_ARGS)
Datum btint48cmp(PG_FUNCTION_ARGS)
Datum btint8cmp(PG_FUNCTION_ARGS)
Datum btint42cmp(PG_FUNCTION_ARGS)
Datum btint28cmp(PG_FUNCTION_ARGS)
Datum inet_in(PG_FUNCTION_ARGS)
Datum network_cmp(PG_FUNCTION_ARGS)
struct NumericData * Numeric
static Datum NumericGetDatum(Numeric X)
static Datum Int64GetDatum(int64 X)
static int64 DatumGetInt64(Datum X)
static Datum PointerGetDatum(const void *X)
static Name DatumGetName(Datum X)
static Datum Float4GetDatum(float4 X)
static float4 DatumGetFloat4(Datum X)
static Datum Int16GetDatum(int16 X)
static Datum BoolGetDatum(bool X)
static float8 DatumGetFloat8(Datum X)
static Datum ObjectIdGetDatum(Oid X)
static Datum NameGetDatum(const NameData *X)
static Datum Float8GetDatum(float8 X)
static Datum CStringGetDatum(const char *X)
static Datum Int32GetDatum(int32 X)
static int16 DatumGetInt16(Datum X)
static int32 DatumGetInt32(Datum X)
static Datum CharGetDatum(char X)
static int cmp(const chr *x, const chr *y, size_t len)
#define BTGreaterStrategyNumber
#define BTLessStrategyNumber
#define BTEqualStrategyNumber
#define BTLessEqualStrategyNumber
#define BTGreaterEqualStrategyNumber
static Datum MacaddrPGetDatum(const macaddr *X)
static Datum Macaddr8PGetDatum(const macaddr8 *X)
static Datum TimestampTzGetDatum(TimestampTz X)
static Datum TimestampGetDatum(Timestamp X)
static Datum IntervalPGetDatum(const Interval *X)
static Timestamp DatumGetTimestamp(Datum X)
static TimestampTz DatumGetTimestampTz(Datum X)
Datum uuid_cmp(PG_FUNCTION_ARGS)
static Datum UUIDPGetDatum(const pg_uuid_t *X)
static Size VARSIZE_ANY_EXHDR(const void *PTR)
static char * VARDATA_ANY(const void *PTR)
Datum bitcmp(PG_FUNCTION_ARGS)
Datum bit(PG_FUNCTION_ARGS)
Datum varbit(PG_FUNCTION_ARGS)
Datum bit_in(PG_FUNCTION_ARGS)
Datum varbit_in(PG_FUNCTION_ARGS)
Datum bpchar(PG_FUNCTION_ARGS)
Datum bpcharcmp(PG_FUNCTION_ARGS)
text * cstring_to_text_with_len(const char *s, int len)
text * cstring_to_text(const char *s)
Datum bttextnamecmp(PG_FUNCTION_ARGS)
Datum btnametextcmp(PG_FUNCTION_ARGS)
Datum bttextcmp(PG_FUNCTION_ARGS)