LCOV - code coverage report
Current view: top level - contrib/btree_gin - btree_gin.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 310 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 218 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * contrib/btree_gin/btree_gin.c
       3              :  */
       4              : #include "postgres.h"
       5              : 
       6              : #include <limits.h>
       7              : 
       8              : #include "access/stratnum.h"
       9              : #include "mb/pg_wchar.h"
      10              : #include "nodes/miscnodes.h"
      11              : #include "utils/builtins.h"
      12              : #include "utils/date.h"
      13              : #include "utils/float.h"
      14              : #include "utils/inet.h"
      15              : #include "utils/numeric.h"
      16              : #include "utils/timestamp.h"
      17              : #include "utils/uuid.h"
      18              : #include "varatt.h"
      19              : 
      20            0 : PG_MODULE_MAGIC_EXT(
      21              :                                         .name = "btree_gin",
      22              :                                         .version = PG_VERSION
      23              : );
      24              : 
      25              : /*
      26              :  * Our opclasses use the same strategy numbers as btree (1-5) for same-type
      27              :  * comparison operators.  For cross-type comparison operators, the
      28              :  * low 4 bits of our strategy numbers are the btree strategy number,
      29              :  * and the upper bits are a code for the right-hand-side data type.
      30              :  */
      31              : #define BTGIN_GET_BTREE_STRATEGY(strat)         ((strat) & 0x0F)
      32              : #define BTGIN_GET_RHS_TYPE_CODE(strat)          ((strat) >> 4)
      33              : 
      34              : /* extra data passed from gin_btree_extract_query to gin_btree_compare_prefix */
      35              : typedef struct QueryInfo
      36              : {
      37              :         StrategyNumber strategy;        /* operator strategy number */
      38              :         Datum           orig_datum;             /* original query (comparison) datum */
      39              :         Datum           entry_datum;    /* datum we reported as the entry value */
      40              :         PGFunction      typecmp;                /* appropriate btree comparison function */
      41              : } QueryInfo;
      42              : 
      43              : typedef Datum (*btree_gin_convert_function) (Datum input);
      44              : 
      45              : typedef Datum (*btree_gin_leftmost_function) (void);
      46              : 
      47              : 
      48              : /*** GIN support functions shared by all datatypes ***/
      49              : 
      50              : static Datum
      51            0 : gin_btree_extract_value(FunctionCallInfo fcinfo, bool is_varlena)
      52              : {
      53            0 :         Datum           datum = PG_GETARG_DATUM(0);
      54            0 :         int32      *nentries = (int32 *) PG_GETARG_POINTER(1);
      55            0 :         Datum      *entries = palloc_object(Datum);
      56              : 
      57              :         /* Ensure that values stored in the index are not toasted */
      58            0 :         if (is_varlena)
      59            0 :                 datum = PointerGetDatum(PG_DETOAST_DATUM(datum));
      60            0 :         entries[0] = datum;
      61            0 :         *nentries = 1;
      62              : 
      63            0 :         PG_RETURN_POINTER(entries);
      64            0 : }
      65              : 
      66              : static Datum
      67            0 : gin_btree_extract_query(FunctionCallInfo fcinfo,
      68              :                                                 btree_gin_leftmost_function leftmostvalue,
      69              :                                                 const bool *rhs_is_varlena,
      70              :                                                 const btree_gin_convert_function *cvt_fns,
      71              :                                                 const PGFunction *cmp_fns)
      72              : {
      73            0 :         Datum           datum = PG_GETARG_DATUM(0);
      74            0 :         int32      *nentries = (int32 *) PG_GETARG_POINTER(1);
      75            0 :         StrategyNumber strategy = PG_GETARG_UINT16(2);
      76            0 :         bool      **partialmatch = (bool **) PG_GETARG_POINTER(3);
      77            0 :         Pointer   **extra_data = (Pointer **) PG_GETARG_POINTER(4);
      78            0 :         Datum      *entries = palloc_object(Datum);
      79            0 :         QueryInfo  *data = palloc_object(QueryInfo);
      80            0 :         bool       *ptr_partialmatch = palloc_object(bool);
      81            0 :         int                     btree_strat,
      82              :                                 rhs_code;
      83              : 
      84              :         /*
      85              :          * Extract the btree strategy code and the RHS data type code from the
      86              :          * given strategy number.
      87              :          */
      88            0 :         btree_strat = BTGIN_GET_BTREE_STRATEGY(strategy);
      89            0 :         rhs_code = BTGIN_GET_RHS_TYPE_CODE(strategy);
      90              : 
      91              :         /*
      92              :          * Detoast the comparison datum.  This isn't necessary for correctness,
      93              :          * but it can save repeat detoastings within the comparison function.
      94              :          */
      95            0 :         if (rhs_is_varlena[rhs_code])
      96            0 :                 datum = PointerGetDatum(PG_DETOAST_DATUM(datum));
      97              : 
      98              :         /* Prep single comparison key with possible partial-match flag */
      99            0 :         *nentries = 1;
     100            0 :         *partialmatch = ptr_partialmatch;
     101            0 :         *ptr_partialmatch = false;
     102              : 
     103              :         /*
     104              :          * For BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, and
     105              :          * BTEqualStrategyNumber we want to start the index scan at the supplied
     106              :          * query datum, and work forward.  For BTLessStrategyNumber and
     107              :          * BTLessEqualStrategyNumber, we need to start at the leftmost key, and
     108              :          * work forward until the supplied query datum (which we'll send along
     109              :          * inside the QueryInfo structure).  Use partial match rules except for
     110              :          * BTEqualStrategyNumber without a conversion function.  (If there is a
     111              :          * conversion function, comparison to the entry value is not trustworthy.)
     112              :          */
     113            0 :         switch (btree_strat)
     114              :         {
     115              :                 case BTLessStrategyNumber:
     116              :                 case BTLessEqualStrategyNumber:
     117            0 :                         entries[0] = leftmostvalue();
     118            0 :                         *ptr_partialmatch = true;
     119            0 :                         break;
     120              :                 case BTGreaterEqualStrategyNumber:
     121              :                 case BTGreaterStrategyNumber:
     122            0 :                         *ptr_partialmatch = true;
     123              :                         /* FALLTHROUGH */
     124              :                 case BTEqualStrategyNumber:
     125              :                         /* If we have a conversion function, apply it */
     126            0 :                         if (cvt_fns && cvt_fns[rhs_code])
     127              :                         {
     128            0 :                                 entries[0] = (*cvt_fns[rhs_code]) (datum);
     129            0 :                                 *ptr_partialmatch = true;
     130            0 :                         }
     131              :                         else
     132            0 :                                 entries[0] = datum;
     133            0 :                         break;
     134              :                 default:
     135            0 :                         elog(ERROR, "unrecognized strategy number: %d", strategy);
     136            0 :         }
     137              : 
     138              :         /* Fill "extra" data */
     139            0 :         data->strategy = strategy;
     140            0 :         data->orig_datum = datum;
     141            0 :         data->entry_datum = entries[0];
     142            0 :         data->typecmp = cmp_fns[rhs_code];
     143            0 :         *extra_data = palloc_object(Pointer);
     144            0 :         **extra_data = (Pointer) data;
     145              : 
     146            0 :         PG_RETURN_POINTER(entries);
     147            0 : }
     148              : 
     149              : static Datum
     150            0 : gin_btree_compare_prefix(FunctionCallInfo fcinfo)
     151              : {
     152            0 :         Datum           partial_key PG_USED_FOR_ASSERTS_ONLY = PG_GETARG_DATUM(0);
     153            0 :         Datum           key = PG_GETARG_DATUM(1);
     154            0 :         QueryInfo  *data = (QueryInfo *) PG_GETARG_POINTER(3);
     155            0 :         int32           res,
     156              :                                 cmp;
     157              : 
     158              :         /*
     159              :          * partial_key is only an approximation to the real comparison value,
     160              :          * especially if it's a leftmost value.  We can get an accurate answer by
     161              :          * doing a possibly-cross-type comparison to the real comparison value.
     162              :          * (Note that partial_key and key are of the indexed datatype while
     163              :          * orig_datum is of the query operator's RHS datatype.)
     164              :          *
     165              :          * But just to be sure that things are what we expect, let's assert that
     166              :          * partial_key is indeed what gin_btree_extract_query reported, so that
     167              :          * we'll notice if anyone ever changes the core code in a way that breaks
     168              :          * our assumptions.
     169              :          */
     170            0 :         Assert(partial_key == data->entry_datum);
     171              : 
     172            0 :         cmp = DatumGetInt32(CallerFInfoFunctionCall2(data->typecmp,
     173            0 :                                                                                                  fcinfo->flinfo,
     174            0 :                                                                                                  PG_GET_COLLATION(),
     175            0 :                                                                                                  data->orig_datum,
     176            0 :                                                                                                  key));
     177              : 
     178              :         /*
     179              :          * Convert the comparison result to the correct thing for the search
     180              :          * operator strategy.  When dealing with cross-type comparisons, an
     181              :          * imprecise entry datum could lead GIN to start the scan just before the
     182              :          * first possible match, so we must continue the scan if the current index
     183              :          * entry doesn't satisfy the search condition for >= and > cases.  But if
     184              :          * that happens in an = search we can stop, because an imprecise entry
     185              :          * datum means that the search value is unrepresentable in the indexed
     186              :          * data type, so that there will be no exact matches.
     187              :          */
     188            0 :         switch (BTGIN_GET_BTREE_STRATEGY(data->strategy))
     189              :         {
     190              :                 case BTLessStrategyNumber:
     191              :                         /* If original datum > indexed one then return match */
     192            0 :                         if (cmp > 0)
     193            0 :                                 res = 0;
     194              :                         else
     195            0 :                                 res = 1;                /* end scan */
     196            0 :                         break;
     197              :                 case BTLessEqualStrategyNumber:
     198              :                         /* If original datum >= indexed one then return match */
     199            0 :                         if (cmp >= 0)
     200            0 :                                 res = 0;
     201              :                         else
     202            0 :                                 res = 1;                /* end scan */
     203            0 :                         break;
     204              :                 case BTEqualStrategyNumber:
     205              :                         /* If original datum = indexed one then return match */
     206              :                         /* See above about why we can end scan when cmp < 0 */
     207            0 :                         if (cmp == 0)
     208            0 :                                 res = 0;
     209              :                         else
     210            0 :                                 res = 1;                /* end scan */
     211            0 :                         break;
     212              :                 case BTGreaterEqualStrategyNumber:
     213              :                         /* If original datum <= indexed one then return match */
     214            0 :                         if (cmp <= 0)
     215            0 :                                 res = 0;
     216              :                         else
     217            0 :                                 res = -1;               /* keep scanning */
     218            0 :                         break;
     219              :                 case BTGreaterStrategyNumber:
     220              :                         /* If original datum < indexed one then return match */
     221            0 :                         if (cmp < 0)
     222            0 :                                 res = 0;
     223              :                         else
     224            0 :                                 res = -1;               /* keep scanning */
     225            0 :                         break;
     226              :                 default:
     227            0 :                         elog(ERROR, "unrecognized strategy number: %d",
     228              :                                  data->strategy);
     229            0 :                         res = 0;
     230            0 :         }
     231              : 
     232            0 :         PG_RETURN_INT32(res);
     233            0 : }
     234              : 
     235            0 : PG_FUNCTION_INFO_V1(gin_btree_consistent);
     236              : Datum
     237            0 : gin_btree_consistent(PG_FUNCTION_ARGS)
     238              : {
     239            0 :         bool       *recheck = (bool *) PG_GETARG_POINTER(5);
     240              : 
     241            0 :         *recheck = false;
     242            0 :         PG_RETURN_BOOL(true);
     243            0 : }
     244              : 
     245              : /*** GIN_SUPPORT macro defines the datatype specific functions ***/
     246              : 
     247              : #define GIN_SUPPORT(type, leftmostvalue, is_varlena, cvtfns, cmpfns)            \
     248              : PG_FUNCTION_INFO_V1(gin_extract_value_##type);                                                          \
     249              : Datum                                                                                                                                           \
     250              : gin_extract_value_##type(PG_FUNCTION_ARGS)                                                                      \
     251              : {                                                                                                                                                       \
     252              :         return gin_btree_extract_value(fcinfo, is_varlena[0]);                                  \
     253              : }       \
     254              : PG_FUNCTION_INFO_V1(gin_extract_query_##type);                                                          \
     255              : Datum                                                                                                                                           \
     256              : gin_extract_query_##type(PG_FUNCTION_ARGS)                                                                      \
     257              : {                                                                                                                                                       \
     258              :         return gin_btree_extract_query(fcinfo,                                                                  \
     259              :                                                                    leftmostvalue, is_varlena,                           \
     260              :                                                                    cvtfns, cmpfns);                                                     \
     261              : }       \
     262              : PG_FUNCTION_INFO_V1(gin_compare_prefix_##type);                                                         \
     263              : Datum                                                                                                                                           \
     264              : gin_compare_prefix_##type(PG_FUNCTION_ARGS)                                                                     \
     265              : {                                                                                                                                                       \
     266              :         return gin_btree_compare_prefix(fcinfo);                                                                \
     267              : }
     268              : 
     269              : 
     270              : /*** Datatype specifications ***/
     271              : 
     272              : /* Function to produce the least possible value of the indexed datatype */
     273              : static Datum
     274            0 : leftmostvalue_int2(void)
     275              : {
     276            0 :         return Int16GetDatum(SHRT_MIN);
     277              : }
     278              : 
     279              : /*
     280              :  * For cross-type support, we must provide conversion functions that produce
     281              :  * a Datum of the indexed datatype, since GIN requires the "entry" datums to
     282              :  * be of that type.  If an exact conversion is not possible, produce a value
     283              :  * that will lead GIN to find the first index entry that is greater than
     284              :  * or equal to the actual comparison value.  (But rounding down is OK, so
     285              :  * sometimes we might find an index entry that's just less than the
     286              :  * comparison value.)
     287              :  *
     288              :  * For integer values, it's sufficient to clamp the input to be in-range.
     289              :  *
     290              :  * Note: for out-of-range input values, we could in theory detect that the
     291              :  * search condition matches all or none of the index, and avoid a useless
     292              :  * index descent in the latter case.  Such searches are probably rare though,
     293              :  * so we don't contort this code enough to do that.
     294              :  */
     295              : static Datum
     296            0 : cvt_int4_int2(Datum input)
     297              : {
     298            0 :         int32           val = DatumGetInt32(input);
     299              : 
     300            0 :         val = Max(val, SHRT_MIN);
     301            0 :         val = Min(val, SHRT_MAX);
     302            0 :         return Int16GetDatum((int16) val);
     303            0 : }
     304              : 
     305              : static Datum
     306            0 : cvt_int8_int2(Datum input)
     307              : {
     308            0 :         int64           val = DatumGetInt64(input);
     309              : 
     310            0 :         val = Max(val, SHRT_MIN);
     311            0 :         val = Min(val, SHRT_MAX);
     312            0 :         return Int16GetDatum((int16) val);
     313            0 : }
     314              : 
     315              : /*
     316              :  * RHS-type-is-varlena flags, conversion and comparison function arrays,
     317              :  * indexed by high bits of the operator strategy number.  A NULL in the
     318              :  * conversion function array indicates that no conversion is needed, which
     319              :  * will always be the case for the zero'th entry.  Note that the cross-type
     320              :  * comparison functions should be the ones with the indexed datatype second.
     321              :  */
     322              : static const bool int2_rhs_is_varlena[] =
     323              : {false, false, false};
     324              : 
     325              : static const btree_gin_convert_function int2_cvt_fns[] =
     326              : {NULL, cvt_int4_int2, cvt_int8_int2};
     327              : 
     328              : static const PGFunction int2_cmp_fns[] =
     329              : {btint2cmp, btint42cmp, btint82cmp};
     330              : 
     331            0 : GIN_SUPPORT(int2, leftmostvalue_int2, int2_rhs_is_varlena, int2_cvt_fns, int2_cmp_fns)
     332              : 
     333              : static Datum
     334            0 : leftmostvalue_int4(void)
     335              : {
     336            0 :         return Int32GetDatum(INT_MIN);
     337              : }
     338              : 
     339              : static Datum
     340            0 : cvt_int2_int4(Datum input)
     341              : {
     342            0 :         int16           val = DatumGetInt16(input);
     343              : 
     344            0 :         return Int32GetDatum((int32) val);
     345            0 : }
     346              : 
     347              : static Datum
     348            0 : cvt_int8_int4(Datum input)
     349              : {
     350            0 :         int64           val = DatumGetInt64(input);
     351              : 
     352            0 :         val = Max(val, INT_MIN);
     353            0 :         val = Min(val, INT_MAX);
     354            0 :         return Int32GetDatum((int32) val);
     355            0 : }
     356              : 
     357              : static const bool int4_rhs_is_varlena[] =
     358              : {false, false, false};
     359              : 
     360              : static const btree_gin_convert_function int4_cvt_fns[] =
     361              : {NULL, cvt_int2_int4, cvt_int8_int4};
     362              : 
     363              : static const PGFunction int4_cmp_fns[] =
     364              : {btint4cmp, btint24cmp, btint84cmp};
     365              : 
     366            0 : GIN_SUPPORT(int4, leftmostvalue_int4, int4_rhs_is_varlena, int4_cvt_fns, int4_cmp_fns)
     367              : 
     368              : static Datum
     369            0 : leftmostvalue_int8(void)
     370              : {
     371            0 :         return Int64GetDatum(PG_INT64_MIN);
     372              : }
     373              : 
     374              : static Datum
     375            0 : cvt_int2_int8(Datum input)
     376              : {
     377            0 :         int16           val = DatumGetInt16(input);
     378              : 
     379            0 :         return Int64GetDatum((int64) val);
     380            0 : }
     381              : 
     382              : static Datum
     383            0 : cvt_int4_int8(Datum input)
     384              : {
     385            0 :         int32           val = DatumGetInt32(input);
     386              : 
     387            0 :         return Int64GetDatum((int64) val);
     388            0 : }
     389              : 
     390              : static const bool int8_rhs_is_varlena[] =
     391              : {false, false, false};
     392              : 
     393              : static const btree_gin_convert_function int8_cvt_fns[] =
     394              : {NULL, cvt_int2_int8, cvt_int4_int8};
     395              : 
     396              : static const PGFunction int8_cmp_fns[] =
     397              : {btint8cmp, btint28cmp, btint48cmp};
     398              : 
     399            0 : GIN_SUPPORT(int8, leftmostvalue_int8, int8_rhs_is_varlena, int8_cvt_fns, int8_cmp_fns)
     400              : 
     401              : static Datum
     402            0 : leftmostvalue_float4(void)
     403              : {
     404            0 :         return Float4GetDatum(-get_float4_infinity());
     405              : }
     406              : 
     407              : static Datum
     408            0 : cvt_float8_float4(Datum input)
     409              : {
     410            0 :         float8          val = DatumGetFloat8(input);
     411            0 :         float4          result;
     412              : 
     413              :         /*
     414              :          * Assume that ordinary C conversion will produce a usable result.
     415              :          * (Compare dtof(), which raises error conditions that we don't need.)
     416              :          * Note that for inputs that aren't exactly representable as float4, it
     417              :          * doesn't matter whether the conversion rounds up or down.  That might
     418              :          * cause us to scan a few index entries that we'll reject as not matching,
     419              :          * but we won't miss any that should match.
     420              :          */
     421            0 :         result = (float4) val;
     422            0 :         return Float4GetDatum(result);
     423            0 : }
     424              : 
     425              : static const bool float4_rhs_is_varlena[] =
     426              : {false, false};
     427              : 
     428              : static const btree_gin_convert_function float4_cvt_fns[] =
     429              : {NULL, cvt_float8_float4};
     430              : 
     431              : static const PGFunction float4_cmp_fns[] =
     432              : {btfloat4cmp, btfloat84cmp};
     433              : 
     434            0 : GIN_SUPPORT(float4, leftmostvalue_float4, float4_rhs_is_varlena, float4_cvt_fns, float4_cmp_fns)
     435              : 
     436              : static Datum
     437            0 : leftmostvalue_float8(void)
     438              : {
     439            0 :         return Float8GetDatum(-get_float8_infinity());
     440              : }
     441              : 
     442              : static Datum
     443            0 : cvt_float4_float8(Datum input)
     444              : {
     445            0 :         float4          val = DatumGetFloat4(input);
     446              : 
     447            0 :         return Float8GetDatum((float8) val);
     448            0 : }
     449              : 
     450              : static const bool float8_rhs_is_varlena[] =
     451              : {false, false};
     452              : 
     453              : static const btree_gin_convert_function float8_cvt_fns[] =
     454              : {NULL, cvt_float4_float8};
     455              : 
     456              : static const PGFunction float8_cmp_fns[] =
     457              : {btfloat8cmp, btfloat48cmp};
     458              : 
     459            0 : GIN_SUPPORT(float8, leftmostvalue_float8, float8_rhs_is_varlena, float8_cvt_fns, float8_cmp_fns)
     460              : 
     461              : static Datum
     462            0 : leftmostvalue_money(void)
     463              : {
     464            0 :         return Int64GetDatum(PG_INT64_MIN);
     465              : }
     466              : 
     467              : static const bool money_rhs_is_varlena[] =
     468              : {false};
     469              : 
     470              : static const PGFunction money_cmp_fns[] =
     471              : {cash_cmp};
     472              : 
     473            0 : GIN_SUPPORT(money, leftmostvalue_money, money_rhs_is_varlena, NULL, money_cmp_fns)
     474              : 
     475              : static Datum
     476            0 : leftmostvalue_oid(void)
     477              : {
     478            0 :         return ObjectIdGetDatum(0);
     479              : }
     480              : 
     481              : static const bool oid_rhs_is_varlena[] =
     482              : {false};
     483              : 
     484              : static const PGFunction oid_cmp_fns[] =
     485              : {btoidcmp};
     486              : 
     487            0 : GIN_SUPPORT(oid, leftmostvalue_oid, oid_rhs_is_varlena, NULL, oid_cmp_fns)
     488              : 
     489              : static Datum
     490            0 : leftmostvalue_timestamp(void)
     491              : {
     492            0 :         return TimestampGetDatum(DT_NOBEGIN);
     493              : }
     494              : 
     495              : static Datum
     496            0 : cvt_date_timestamp(Datum input)
     497              : {
     498            0 :         DateADT         val = DatumGetDateADT(input);
     499            0 :         Timestamp       result;
     500            0 :         ErrorSaveContext escontext = {T_ErrorSaveContext};
     501              : 
     502            0 :         result = date2timestamp_safe(val, (Node *) &escontext);
     503              :         /* We can ignore errors, since result is useful as-is */
     504            0 :         return TimestampGetDatum(result);
     505            0 : }
     506              : 
     507              : static Datum
     508            0 : cvt_timestamptz_timestamp(Datum input)
     509              : {
     510            0 :         TimestampTz val = DatumGetTimestampTz(input);
     511            0 :         ErrorSaveContext escontext = {T_ErrorSaveContext};
     512            0 :         Timestamp       result;
     513              : 
     514            0 :         result = timestamptz2timestamp_safe(val, (Node *) &escontext);
     515              :         /* We can ignore errors, since result is useful as-is */
     516            0 :         return TimestampGetDatum(result);
     517            0 : }
     518              : 
     519              : static const bool timestamp_rhs_is_varlena[] =
     520              : {false, false, false};
     521              : 
     522              : static const btree_gin_convert_function timestamp_cvt_fns[] =
     523              : {NULL, cvt_date_timestamp, cvt_timestamptz_timestamp};
     524              : 
     525              : static const PGFunction timestamp_cmp_fns[] =
     526              : {timestamp_cmp, date_cmp_timestamp, timestamptz_cmp_timestamp};
     527              : 
     528            0 : GIN_SUPPORT(timestamp, leftmostvalue_timestamp, timestamp_rhs_is_varlena, timestamp_cvt_fns, timestamp_cmp_fns)
     529              : 
     530              : static Datum
     531            0 : cvt_date_timestamptz(Datum input)
     532              : {
     533            0 :         DateADT         val = DatumGetDateADT(input);
     534            0 :         ErrorSaveContext escontext = {T_ErrorSaveContext};
     535            0 :         TimestampTz result;
     536              : 
     537            0 :         result = date2timestamptz_safe(val, (Node *) &escontext);
     538              :         /* We can ignore errors, since result is useful as-is */
     539            0 :         return TimestampTzGetDatum(result);
     540            0 : }
     541              : 
     542              : static Datum
     543            0 : cvt_timestamp_timestamptz(Datum input)
     544              : {
     545            0 :         Timestamp       val = DatumGetTimestamp(input);
     546            0 :         ErrorSaveContext escontext = {T_ErrorSaveContext};
     547            0 :         TimestampTz result;
     548              : 
     549            0 :         result = timestamp2timestamptz_safe(val, (Node *) &escontext);
     550              :         /* We can ignore errors, since result is useful as-is */
     551            0 :         return TimestampTzGetDatum(result);
     552            0 : }
     553              : 
     554              : static const bool timestamptz_rhs_is_varlena[] =
     555              : {false, false, false};
     556              : 
     557              : static const btree_gin_convert_function timestamptz_cvt_fns[] =
     558              : {NULL, cvt_date_timestamptz, cvt_timestamp_timestamptz};
     559              : 
     560              : static const PGFunction timestamptz_cmp_fns[] =
     561              : {timestamp_cmp, date_cmp_timestamptz, timestamp_cmp_timestamptz};
     562              : 
     563            0 : GIN_SUPPORT(timestamptz, leftmostvalue_timestamp, timestamptz_rhs_is_varlena, timestamptz_cvt_fns, timestamptz_cmp_fns)
     564              : 
     565              : static Datum
     566            0 : leftmostvalue_time(void)
     567              : {
     568            0 :         return TimeADTGetDatum(0);
     569              : }
     570              : 
     571              : static const bool time_rhs_is_varlena[] =
     572              : {false};
     573              : 
     574              : static const PGFunction time_cmp_fns[] =
     575              : {time_cmp};
     576              : 
     577            0 : GIN_SUPPORT(time, leftmostvalue_time, time_rhs_is_varlena, NULL, time_cmp_fns)
     578              : 
     579              : static Datum
     580            0 : leftmostvalue_timetz(void)
     581              : {
     582            0 :         TimeTzADT  *v = palloc_object(TimeTzADT);
     583              : 
     584            0 :         v->time = 0;
     585            0 :         v->zone = -24 * 3600;                /* XXX is that true? */
     586              : 
     587            0 :         return TimeTzADTPGetDatum(v);
     588            0 : }
     589              : 
     590              : static const bool timetz_rhs_is_varlena[] =
     591              : {false};
     592              : 
     593              : static const PGFunction timetz_cmp_fns[] =
     594              : {timetz_cmp};
     595              : 
     596            0 : GIN_SUPPORT(timetz, leftmostvalue_timetz, timetz_rhs_is_varlena, NULL, timetz_cmp_fns)
     597              : 
     598              : static Datum
     599            0 : leftmostvalue_date(void)
     600              : {
     601            0 :         return DateADTGetDatum(DATEVAL_NOBEGIN);
     602              : }
     603              : 
     604              : static Datum
     605            0 : cvt_timestamp_date(Datum input)
     606              : {
     607            0 :         Timestamp       val = DatumGetTimestamp(input);
     608            0 :         ErrorSaveContext escontext = {T_ErrorSaveContext};
     609            0 :         DateADT         result;
     610              : 
     611            0 :         result = timestamp2date_safe(val, (Node *) &escontext);
     612              :         /* We can ignore errors, since result is useful as-is */
     613            0 :         return DateADTGetDatum(result);
     614            0 : }
     615              : 
     616              : static Datum
     617            0 : cvt_timestamptz_date(Datum input)
     618              : {
     619            0 :         TimestampTz val = DatumGetTimestampTz(input);
     620            0 :         ErrorSaveContext escontext = {T_ErrorSaveContext};
     621            0 :         DateADT         result;
     622              : 
     623            0 :         result = timestamptz2date_safe(val, (Node *) &escontext);
     624              :         /* We can ignore errors, since result is useful as-is */
     625            0 :         return DateADTGetDatum(result);
     626            0 : }
     627              : 
     628              : static const bool date_rhs_is_varlena[] =
     629              : {false, false, false};
     630              : 
     631              : static const btree_gin_convert_function date_cvt_fns[] =
     632              : {NULL, cvt_timestamp_date, cvt_timestamptz_date};
     633              : 
     634              : static const PGFunction date_cmp_fns[] =
     635              : {date_cmp, timestamp_cmp_date, timestamptz_cmp_date};
     636              : 
     637            0 : GIN_SUPPORT(date, leftmostvalue_date, date_rhs_is_varlena, date_cvt_fns, date_cmp_fns)
     638              : 
     639              : static Datum
     640            0 : leftmostvalue_interval(void)
     641              : {
     642            0 :         Interval   *v = palloc_object(Interval);
     643              : 
     644            0 :         INTERVAL_NOBEGIN(v);
     645              : 
     646            0 :         return IntervalPGetDatum(v);
     647            0 : }
     648              : 
     649              : static const bool interval_rhs_is_varlena[] =
     650              : {false};
     651              : 
     652              : static const PGFunction interval_cmp_fns[] =
     653              : {interval_cmp};
     654              : 
     655            0 : GIN_SUPPORT(interval, leftmostvalue_interval, interval_rhs_is_varlena, NULL, interval_cmp_fns)
     656              : 
     657              : static Datum
     658            0 : leftmostvalue_macaddr(void)
     659              : {
     660            0 :         macaddr    *v = palloc0_object(macaddr);
     661              : 
     662            0 :         return MacaddrPGetDatum(v);
     663            0 : }
     664              : 
     665              : static const bool macaddr_rhs_is_varlena[] =
     666              : {false};
     667              : 
     668              : static const PGFunction macaddr_cmp_fns[] =
     669              : {macaddr_cmp};
     670              : 
     671            0 : GIN_SUPPORT(macaddr, leftmostvalue_macaddr, macaddr_rhs_is_varlena, NULL, macaddr_cmp_fns)
     672              : 
     673              : static Datum
     674            0 : leftmostvalue_macaddr8(void)
     675              : {
     676            0 :         macaddr8   *v = palloc0_object(macaddr8);
     677              : 
     678            0 :         return Macaddr8PGetDatum(v);
     679            0 : }
     680              : 
     681              : static const bool macaddr8_rhs_is_varlena[] =
     682              : {false};
     683              : 
     684              : static const PGFunction macaddr8_cmp_fns[] =
     685              : {macaddr8_cmp};
     686              : 
     687            0 : GIN_SUPPORT(macaddr8, leftmostvalue_macaddr8, macaddr8_rhs_is_varlena, NULL, macaddr8_cmp_fns)
     688              : 
     689              : static Datum
     690            0 : leftmostvalue_inet(void)
     691              : {
     692            0 :         return DirectFunctionCall1(inet_in, CStringGetDatum("0.0.0.0/0"));
     693              : }
     694              : 
     695              : static const bool inet_rhs_is_varlena[] =
     696              : {true};
     697              : 
     698              : static const PGFunction inet_cmp_fns[] =
     699              : {network_cmp};
     700              : 
     701            0 : GIN_SUPPORT(inet, leftmostvalue_inet, inet_rhs_is_varlena, NULL, inet_cmp_fns)
     702              : 
     703              : static const bool cidr_rhs_is_varlena[] =
     704              : {true};
     705              : 
     706              : static const PGFunction cidr_cmp_fns[] =
     707              : {network_cmp};
     708              : 
     709            0 : GIN_SUPPORT(cidr, leftmostvalue_inet, cidr_rhs_is_varlena, NULL, cidr_cmp_fns)
     710              : 
     711              : static Datum
     712            0 : leftmostvalue_text(void)
     713              : {
     714            0 :         return PointerGetDatum(cstring_to_text_with_len("", 0));
     715              : }
     716              : 
     717              : static Datum
     718            0 : cvt_name_text(Datum input)
     719              : {
     720            0 :         Name            val = DatumGetName(input);
     721              : 
     722            0 :         return PointerGetDatum(cstring_to_text(NameStr(*val)));
     723            0 : }
     724              : 
     725              : static const bool text_rhs_is_varlena[] =
     726              : {true, false};
     727              : 
     728              : static const btree_gin_convert_function text_cvt_fns[] =
     729              : {NULL, cvt_name_text};
     730              : 
     731              : static const PGFunction text_cmp_fns[] =
     732              : {bttextcmp, btnametextcmp};
     733              : 
     734            0 : GIN_SUPPORT(text, leftmostvalue_text, text_rhs_is_varlena, text_cvt_fns, text_cmp_fns)
     735              : 
     736              : static const bool bpchar_rhs_is_varlena[] =
     737              : {true};
     738              : 
     739              : static const PGFunction bpchar_cmp_fns[] =
     740              : {bpcharcmp};
     741              : 
     742            0 : GIN_SUPPORT(bpchar, leftmostvalue_text, bpchar_rhs_is_varlena, NULL, bpchar_cmp_fns)
     743              : 
     744              : static Datum
     745            0 : leftmostvalue_char(void)
     746              : {
     747            0 :         return CharGetDatum(0);
     748              : }
     749              : 
     750              : static const bool char_rhs_is_varlena[] =
     751              : {false};
     752              : 
     753              : static const PGFunction char_cmp_fns[] =
     754              : {btcharcmp};
     755              : 
     756            0 : GIN_SUPPORT(char, leftmostvalue_char, char_rhs_is_varlena, NULL, char_cmp_fns)
     757              : 
     758              : static const bool bytea_rhs_is_varlena[] =
     759              : {true};
     760              : 
     761              : static const PGFunction bytea_cmp_fns[] =
     762              : {byteacmp};
     763              : 
     764            0 : GIN_SUPPORT(bytea, leftmostvalue_text, bytea_rhs_is_varlena, NULL, bytea_cmp_fns)
     765              : 
     766              : static Datum
     767            0 : leftmostvalue_bit(void)
     768              : {
     769            0 :         return DirectFunctionCall3(bit_in,
     770              :                                                            CStringGetDatum(""),
     771              :                                                            ObjectIdGetDatum(0),
     772              :                                                            Int32GetDatum(-1));
     773              : }
     774              : 
     775              : static const bool bit_rhs_is_varlena[] =
     776              : {true};
     777              : 
     778              : static const PGFunction bit_cmp_fns[] =
     779              : {bitcmp};
     780              : 
     781            0 : GIN_SUPPORT(bit, leftmostvalue_bit, bit_rhs_is_varlena, NULL, bit_cmp_fns)
     782              : 
     783              : static Datum
     784            0 : leftmostvalue_varbit(void)
     785              : {
     786            0 :         return DirectFunctionCall3(varbit_in,
     787              :                                                            CStringGetDatum(""),
     788              :                                                            ObjectIdGetDatum(0),
     789              :                                                            Int32GetDatum(-1));
     790              : }
     791              : 
     792              : static const bool varbit_rhs_is_varlena[] =
     793              : {true};
     794              : 
     795              : static const PGFunction varbit_cmp_fns[] =
     796              : {bitcmp};
     797              : 
     798            0 : GIN_SUPPORT(varbit, leftmostvalue_varbit, varbit_rhs_is_varlena, NULL, varbit_cmp_fns)
     799              : 
     800              : /*
     801              :  * Numeric type hasn't a real left-most value, so we use PointerGetDatum(NULL)
     802              :  * (*not* a SQL NULL) to represent that.  We can get away with that because
     803              :  * the value returned by our leftmostvalue function will never be stored in
     804              :  * the index nor passed to anything except our compare and prefix-comparison
     805              :  * functions.  The same trick could be used for other pass-by-reference types.
     806              :  */
     807              : 
     808              : #define NUMERIC_IS_LEFTMOST(x)  ((x) == NULL)
     809              : 
     810            0 : PG_FUNCTION_INFO_V1(gin_numeric_cmp);
     811              : 
     812              : Datum
     813            0 : gin_numeric_cmp(PG_FUNCTION_ARGS)
     814              : {
     815            0 :         Numeric         a = (Numeric) PG_GETARG_POINTER(0);
     816            0 :         Numeric         b = (Numeric) PG_GETARG_POINTER(1);
     817            0 :         int                     res = 0;
     818              : 
     819            0 :         if (NUMERIC_IS_LEFTMOST(a))
     820              :         {
     821            0 :                 res = (NUMERIC_IS_LEFTMOST(b)) ? 0 : -1;
     822            0 :         }
     823            0 :         else if (NUMERIC_IS_LEFTMOST(b))
     824              :         {
     825            0 :                 res = 1;
     826            0 :         }
     827              :         else
     828              :         {
     829            0 :                 res = DatumGetInt32(DirectFunctionCall2(numeric_cmp,
     830              :                                                                                                 NumericGetDatum(a),
     831              :                                                                                                 NumericGetDatum(b)));
     832              :         }
     833              : 
     834            0 :         PG_RETURN_INT32(res);
     835            0 : }
     836              : 
     837              : static Datum
     838            0 : leftmostvalue_numeric(void)
     839              : {
     840            0 :         return PointerGetDatum(NULL);
     841              : }
     842              : 
     843              : static const bool numeric_rhs_is_varlena[] =
     844              : {true};
     845              : 
     846              : static const PGFunction numeric_cmp_fns[] =
     847              : {gin_numeric_cmp};
     848              : 
     849            0 : GIN_SUPPORT(numeric, leftmostvalue_numeric, numeric_rhs_is_varlena, NULL, numeric_cmp_fns)
     850              : 
     851              : /*
     852              :  * Use a similar trick to that used for numeric for enums, since we don't
     853              :  * actually know the leftmost value of any enum without knowing the concrete
     854              :  * type, so we use a dummy leftmost value of InvalidOid.
     855              :  *
     856              :  * Note that we use CallerFInfoFunctionCall2 here so that enum_cmp
     857              :  * gets a valid fn_extra to work with. Unlike most other type comparison
     858              :  * routines it needs it, so we can't use DirectFunctionCall2.
     859              :  */
     860              : 
     861              : #define ENUM_IS_LEFTMOST(x) ((x) == InvalidOid)
     862              : 
     863            0 : PG_FUNCTION_INFO_V1(gin_enum_cmp);
     864              : 
     865              : Datum
     866            0 : gin_enum_cmp(PG_FUNCTION_ARGS)
     867              : {
     868            0 :         Oid                     a = PG_GETARG_OID(0);
     869            0 :         Oid                     b = PG_GETARG_OID(1);
     870            0 :         int                     res = 0;
     871              : 
     872            0 :         if (ENUM_IS_LEFTMOST(a))
     873              :         {
     874            0 :                 res = (ENUM_IS_LEFTMOST(b)) ? 0 : -1;
     875            0 :         }
     876            0 :         else if (ENUM_IS_LEFTMOST(b))
     877              :         {
     878            0 :                 res = 1;
     879            0 :         }
     880              :         else
     881              :         {
     882            0 :                 res = DatumGetInt32(CallerFInfoFunctionCall2(enum_cmp,
     883            0 :                                                                                                          fcinfo->flinfo,
     884            0 :                                                                                                          PG_GET_COLLATION(),
     885            0 :                                                                                                          ObjectIdGetDatum(a),
     886            0 :                                                                                                          ObjectIdGetDatum(b)));
     887              :         }
     888              : 
     889            0 :         PG_RETURN_INT32(res);
     890            0 : }
     891              : 
     892              : static Datum
     893            0 : leftmostvalue_enum(void)
     894              : {
     895            0 :         return ObjectIdGetDatum(InvalidOid);
     896              : }
     897              : 
     898              : static const bool enum_rhs_is_varlena[] =
     899              : {false};
     900              : 
     901              : static const PGFunction enum_cmp_fns[] =
     902              : {gin_enum_cmp};
     903              : 
     904            0 : GIN_SUPPORT(anyenum, leftmostvalue_enum, enum_rhs_is_varlena, NULL, enum_cmp_fns)
     905              : 
     906              : static Datum
     907            0 : leftmostvalue_uuid(void)
     908              : {
     909              :         /*
     910              :          * palloc0 will create the UUID with all zeroes:
     911              :          * "00000000-0000-0000-0000-000000000000"
     912              :          */
     913            0 :         pg_uuid_t  *retval = palloc0_object(pg_uuid_t);
     914              : 
     915            0 :         return UUIDPGetDatum(retval);
     916            0 : }
     917              : 
     918              : static const bool uuid_rhs_is_varlena[] =
     919              : {false};
     920              : 
     921              : static const PGFunction uuid_cmp_fns[] =
     922              : {uuid_cmp};
     923              : 
     924            0 : GIN_SUPPORT(uuid, leftmostvalue_uuid, uuid_rhs_is_varlena, NULL, uuid_cmp_fns)
     925              : 
     926              : static Datum
     927            0 : leftmostvalue_name(void)
     928              : {
     929            0 :         NameData   *result = (NameData *) palloc0(NAMEDATALEN);
     930              : 
     931            0 :         return NameGetDatum(result);
     932            0 : }
     933              : 
     934              : static Datum
     935            0 : cvt_text_name(Datum input)
     936              : {
     937            0 :         text       *val = DatumGetTextPP(input);
     938            0 :         NameData   *result = (NameData *) palloc0(NAMEDATALEN);
     939            0 :         int                     len = VARSIZE_ANY_EXHDR(val);
     940              : 
     941              :         /*
     942              :          * Truncate oversize input.  We're assuming this will produce a result
     943              :          * considered less than the original.  That could be a bad assumption in
     944              :          * some collations, but fortunately an index on "name" is generally going
     945              :          * to use C collation.
     946              :          */
     947            0 :         if (len >= NAMEDATALEN)
     948            0 :                 len = pg_mbcliplen(VARDATA_ANY(val), len, NAMEDATALEN - 1);
     949              : 
     950            0 :         memcpy(NameStr(*result), VARDATA_ANY(val), len);
     951              : 
     952            0 :         return NameGetDatum(result);
     953            0 : }
     954              : 
     955              : static const bool name_rhs_is_varlena[] =
     956              : {false, true};
     957              : 
     958              : static const btree_gin_convert_function name_cvt_fns[] =
     959              : {NULL, cvt_text_name};
     960              : 
     961              : static const PGFunction name_cmp_fns[] =
     962              : {btnamecmp, bttextnamecmp};
     963              : 
     964            0 : GIN_SUPPORT(name, leftmostvalue_name, name_rhs_is_varlena, name_cvt_fns, name_cmp_fns)
     965              : 
     966              : static Datum
     967            0 : leftmostvalue_bool(void)
     968              : {
     969            0 :         return BoolGetDatum(false);
     970              : }
     971              : 
     972              : static const bool bool_rhs_is_varlena[] =
     973              : {false};
     974              : 
     975              : static const PGFunction bool_cmp_fns[] =
     976              : {btboolcmp};
     977              : 
     978            0 : GIN_SUPPORT(bool, leftmostvalue_bool, bool_rhs_is_varlena, NULL, bool_cmp_fns)
        

Generated by: LCOV version 2.3.2-1