LCOV - code coverage report
Current view: top level - contrib/btree_gist - btree_utils_var.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 84.4 % 262 221
Test Date: 2026-07-03 19:57:34 Functions: 95.0 % 20 19
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 70.6 % 119 84

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * contrib/btree_gist/btree_utils_var.c
       3                 :             :  *
       4                 :             :  * Common routines for btree_gist code working with varlena indexed data types.
       5                 :             :  */
       6                 :             : #include "postgres.h"
       7                 :             : 
       8                 :             : #include <limits.h>
       9                 :             : #include <float.h>
      10                 :             : 
      11                 :             : #include "btree_gist.h"
      12                 :             : #include "btree_utils_var.h"
      13                 :             : #include "utils/rel.h"
      14                 :             : #include "varatt.h"
      15                 :             : 
      16                 :             : /* used for key sorting */
      17                 :             : typedef struct
      18                 :             : {
      19                 :             :     int         i;
      20                 :             :     GBT_VARKEY *t;
      21                 :             : } Vsrt;
      22                 :             : 
      23                 :             : typedef struct
      24                 :             : {
      25                 :             :     const gbtree_vinfo *tinfo;
      26                 :             :     Oid         collation;
      27                 :             :     FmgrInfo   *flinfo;
      28                 :             : } gbt_vsrt_arg;
      29                 :             : 
      30                 :             : 
      31                 :          11 : PG_FUNCTION_INFO_V1(gbt_var_decompress);
      32                 :          11 : PG_FUNCTION_INFO_V1(gbt_var_fetch);
      33                 :             : 
      34                 :             : 
      35                 :             : Datum
      36                 :       63263 : gbt_var_decompress(PG_FUNCTION_ARGS)
      37                 :             : {
      38                 :       63263 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
      39                 :       63263 :     GBT_VARKEY *key = (GBT_VARKEY *) PG_DETOAST_DATUM(entry->key);
      40                 :             : 
      41                 :             :     /* We only need a new GISTENTRY if detoasting did something */
      42         [ +  + ]:       63263 :     if (key != (GBT_VARKEY *) DatumGetPointer(entry->key))
      43                 :             :     {
      44                 :       63233 :         GISTENTRY  *retval = palloc_object(GISTENTRY);
      45                 :             : 
      46                 :       63233 :         gistentryinit(*retval, PointerGetDatum(key),
      47                 :             :                       entry->rel, entry->page,
      48                 :             :                       entry->offset, false);
      49                 :             : 
      50                 :       63233 :         PG_RETURN_POINTER(retval);
      51                 :             :     }
      52                 :             : 
      53                 :          30 :     PG_RETURN_POINTER(entry);
      54                 :             : }
      55                 :             : 
      56                 :             : /*
      57                 :             :  * Extract a "readable" representation of a GBT_VARKEY, containing direct
      58                 :             :  * pointers to the contained lower and upper datums.
      59                 :             :  */
      60                 :             : GBT_VARKEY_R
      61                 :      309993 : gbt_var_key_readable(const GBT_VARKEY *k)
      62                 :             : {
      63                 :             :     GBT_VARKEY_R r;
      64                 :             : 
      65                 :      309993 :     r.lower = (bytea *) &(((char *) k)[VARHDRSZ]);
      66         [ +  + ]:      309993 :     if (VARSIZE(k) > (VARHDRSZ + (VARSIZE(r.lower))))
      67                 :       55980 :         r.upper = (bytea *) &(((char *) k)[VARHDRSZ + INTALIGN(VARSIZE(r.lower))]);
      68                 :             :     else
      69                 :      254013 :         r.upper = r.lower;
      70                 :      309993 :     return r;
      71                 :             : }
      72                 :             : 
      73                 :             : 
      74                 :             : /*
      75                 :             :  * Create a leaf-entry to store in the index, from a single Datum.
      76                 :             :  */
      77                 :             : static GBT_VARKEY *
      78                 :        8265 : gbt_var_key_from_datum(const varlena *u)
      79                 :             : {
      80                 :        8265 :     int32       lowersize = VARSIZE(u);
      81                 :             :     GBT_VARKEY *r;
      82                 :             : 
      83                 :        8265 :     r = (GBT_VARKEY *) palloc(lowersize + VARHDRSZ);
      84                 :        8265 :     memcpy(VARDATA(r), u, lowersize);
      85                 :        8265 :     SET_VARSIZE(r, lowersize + VARHDRSZ);
      86                 :             : 
      87                 :        8265 :     return r;
      88                 :             : }
      89                 :             : 
      90                 :             : /*
      91                 :             :  * Create a key entry to store in the index, from lower and upper bound.
      92                 :             :  *
      93                 :             :  * This code assumes that none of the types we work with require more
      94                 :             :  * than INTALIGN alignment.
      95                 :             :  */
      96                 :             : GBT_VARKEY *
      97                 :       22333 : gbt_var_key_copy(const GBT_VARKEY_R *u)
      98                 :             : {
      99                 :       22333 :     int32       lowersize = VARSIZE(u->lower);
     100                 :       22333 :     int32       uppersize = VARSIZE(u->upper);
     101                 :             :     GBT_VARKEY *r;
     102                 :             : 
     103                 :       22333 :     r = (GBT_VARKEY *) palloc0(INTALIGN(lowersize) + uppersize + VARHDRSZ);
     104                 :       22333 :     memcpy(VARDATA(r), u->lower, lowersize);
     105                 :       22333 :     memcpy(VARDATA(r) + INTALIGN(lowersize), u->upper, uppersize);
     106                 :       22333 :     SET_VARSIZE(r, INTALIGN(lowersize) + uppersize + VARHDRSZ);
     107                 :             : 
     108                 :       22333 :     return r;
     109                 :             : }
     110                 :             : 
     111                 :             : /*
     112                 :             :  * Convert a GBT_VARKEY in leaf form to a GBT_VARKEY in internal form.
     113                 :             :  * No-op if the data type doesn't require a transformation.
     114                 :             :  */
     115                 :             : static GBT_VARKEY *
     116                 :       47000 : gbt_var_leaf2node(GBT_VARKEY *leaf, const gbtree_vinfo *tinfo, FmgrInfo *flinfo)
     117                 :             : {
     118         [ +  + ]:       47000 :     if (tinfo->f_l2n)
     119                 :        3598 :         return tinfo->f_l2n(leaf, flinfo);
     120                 :             :     else
     121                 :       43402 :         return leaf;
     122                 :             : }
     123                 :             : 
     124                 :             : 
     125                 :             : /*
     126                 :             :  * returns the common prefix length of a node key
     127                 :             :  *
     128                 :             :  * This is not used for any cases where the underlying type is character data
     129                 :             :  * (except in gbt_var_penalty, where it doesn't matter since we're just making
     130                 :             :  * an estimated correction not constructing a truncated string).  If it were,
     131                 :             :  * we'd need to be careful not to truncate in the middle of a multibyte
     132                 :             :  * character.
     133                 :             :  */
     134                 :             : static int32
     135                 :          25 : gbt_var_node_cp_len(const GBT_VARKEY *node, const gbtree_vinfo *tinfo)
     136                 :             : {
     137                 :          25 :     GBT_VARKEY_R r = gbt_var_key_readable(node);
     138                 :          25 :     int32       i = 0;
     139                 :          25 :     int32       t1len = VARSIZE(r.lower) - VARHDRSZ;
     140                 :          25 :     int32       t2len = VARSIZE(r.upper) - VARHDRSZ;
     141                 :          25 :     int32       ml = Min(t1len, t2len);
     142                 :          25 :     char       *p1 = VARDATA(r.lower);
     143                 :          25 :     char       *p2 = VARDATA(r.upper);
     144                 :             : 
     145         [ +  + ]:          25 :     if (ml == 0)
     146                 :           4 :         return 0;
     147                 :             : 
     148         [ +  - ]:          21 :     while (i < ml)
     149                 :             :     {
     150         [ +  - ]:          21 :         if (*p1 != *p2)
     151                 :          21 :             return i;
     152                 :           0 :         p1++;
     153                 :           0 :         p2++;
     154                 :           0 :         i++;
     155                 :             :     }
     156                 :           0 :     return ml;                  /* lower == upper */
     157                 :             : }
     158                 :             : 
     159                 :             : 
     160                 :             : /*
     161                 :             :  * returns true if query matches prefix up to the length of the prefix
     162                 :             :  *
     163                 :             :  * We need this to avoid edge-case problems when the "prefix" is a truncated
     164                 :             :  * datum; see discussion in btree_utils_var.h.
     165                 :             :  */
     166                 :             : static bool
     167                 :          26 : gbt_bytea_pf_match(const bytea *pf, const bytea *query, const gbtree_vinfo *tinfo)
     168                 :             : {
     169                 :          26 :     bool        out = false;
     170                 :          26 :     int32       qlen = VARSIZE(query) - VARHDRSZ;
     171                 :          26 :     int32       nlen = VARSIZE(pf) - VARHDRSZ;
     172                 :             : 
     173         [ +  - ]:          26 :     if (nlen <= qlen)
     174                 :             :     {
     175                 :          26 :         char       *q = VARDATA(query);
     176                 :          26 :         char       *n = VARDATA(pf);
     177                 :             : 
     178                 :          26 :         out = (memcmp(q, n, nlen) == 0);
     179                 :             :     }
     180                 :             : 
     181                 :          26 :     return out;
     182                 :             : }
     183                 :             : 
     184                 :             : 
     185                 :             : /*
     186                 :             :  * returns true if query matches node according to common-prefix rule
     187                 :             :  *
     188                 :             :  * If the data type is truncatable, then a shortened upper bound must be
     189                 :             :  * considered to include all values that match it up to its own length,
     190                 :             :  * even though longer values would normally be considered larger.
     191                 :             :  * We don't need to check the lower bound though: shortening it just
     192                 :             :  * makes it even smaller.
     193                 :             :  */
     194                 :             : static bool
     195                 :          86 : gbt_var_node_pf_match(const GBT_VARKEY_R *node, const bytea *query, const gbtree_vinfo *tinfo)
     196                 :             : {
     197   [ +  +  +  + ]:         112 :     return (tinfo->trnc &&
     198                 :          26 :             gbt_bytea_pf_match(node->upper, query, tinfo));
     199                 :             : }
     200                 :             : 
     201                 :             : 
     202                 :             : /*
     203                 :             :  * truncates / compresses the node key
     204                 :             :  *
     205                 :             :  * cpf_length is the common prefix length of the lower and upper values.
     206                 :             :  * We truncate to that plus one byte, so that the node represents a range
     207                 :             :  * of leaf values but doesn't have undue specificity.
     208                 :             :  */
     209                 :             : static GBT_VARKEY *
     210                 :          25 : gbt_var_node_truncate(const GBT_VARKEY *node, int32 cpf_length, const gbtree_vinfo *tinfo)
     211                 :             : {
     212                 :             :     GBT_VARKEY *out;
     213                 :          25 :     GBT_VARKEY_R r = gbt_var_key_readable(node);
     214                 :          25 :     int32       len1 = VARSIZE(r.lower) - VARHDRSZ;
     215                 :          25 :     int32       len2 = VARSIZE(r.upper) - VARHDRSZ;
     216                 :             :     int32       si;
     217                 :             :     char       *out2;
     218                 :             : 
     219                 :          25 :     len1 = Min(len1, (cpf_length + 1));
     220                 :          25 :     len2 = Min(len2, (cpf_length + 1));
     221                 :             : 
     222                 :          25 :     si = 2 * VARHDRSZ + INTALIGN(len1 + VARHDRSZ) + len2;
     223                 :          25 :     out = (GBT_VARKEY *) palloc0(si);
     224                 :          25 :     SET_VARSIZE(out, si);
     225                 :             : 
     226                 :          25 :     memcpy(VARDATA(out), r.lower, len1 + VARHDRSZ);
     227                 :          25 :     SET_VARSIZE(VARDATA(out), len1 + VARHDRSZ);
     228                 :             : 
     229                 :          25 :     out2 = VARDATA(out) + INTALIGN(len1 + VARHDRSZ);
     230                 :          25 :     memcpy(out2, r.upper, len2 + VARHDRSZ);
     231                 :          25 :     SET_VARSIZE(out2, len2 + VARHDRSZ);
     232                 :             : 
     233                 :          25 :     return out;
     234                 :             : }
     235                 :             : 
     236                 :             : 
     237                 :             : 
     238                 :             : void
     239                 :       31382 : gbt_var_bin_union(Datum *u, GBT_VARKEY *e, Oid collation,
     240                 :             :                   const gbtree_vinfo *tinfo, FmgrInfo *flinfo)
     241                 :             : {
     242                 :       31382 :     GBT_VARKEY_R eo = gbt_var_key_readable(e);
     243                 :             :     GBT_VARKEY_R nr;
     244                 :             : 
     245         [ +  + ]:       31382 :     if (eo.lower == eo.upper)   /* if leaf, convert to internal form */
     246                 :             :     {
     247                 :             :         GBT_VARKEY *tmp;
     248                 :             : 
     249                 :       28976 :         tmp = gbt_var_leaf2node(e, tinfo, flinfo);
     250         [ +  + ]:       28976 :         if (tmp != e)
     251                 :        1198 :             eo = gbt_var_key_readable(tmp);
     252                 :             :     }
     253                 :             : 
     254         [ +  + ]:       31382 :     if (DatumGetPointer(*u))
     255                 :             :     {
     256                 :       31280 :         GBT_VARKEY_R ro = gbt_var_key_readable((GBT_VARKEY *) DatumGetPointer(*u));
     257                 :       31280 :         bool        update = false;
     258                 :             : 
     259                 :       31280 :         nr.lower = ro.lower;
     260                 :       31280 :         nr.upper = ro.upper;
     261                 :             : 
     262         [ +  + ]:       31280 :         if (tinfo->f_cmp(ro.lower, eo.lower, collation, flinfo) > 0)
     263                 :             :         {
     264                 :          16 :             nr.lower = eo.lower;
     265                 :          16 :             update = true;
     266                 :             :         }
     267                 :             : 
     268         [ +  + ]:       31280 :         if (tinfo->f_cmp(ro.upper, eo.upper, collation, flinfo) < 0)
     269                 :             :         {
     270                 :       13258 :             nr.upper = eo.upper;
     271                 :       13258 :             update = true;
     272                 :             :         }
     273                 :             : 
     274         [ +  + ]:       31280 :         if (update)
     275                 :       13274 :             *u = PointerGetDatum(gbt_var_key_copy(&nr));
     276                 :             :     }
     277                 :             :     else
     278                 :             :     {
     279                 :         102 :         nr.lower = eo.lower;
     280                 :         102 :         nr.upper = eo.upper;
     281                 :         102 :         *u = PointerGetDatum(gbt_var_key_copy(&nr));
     282                 :             :     }
     283                 :       31382 : }
     284                 :             : 
     285                 :             : 
     286                 :             : GISTENTRY *
     287                 :        8346 : gbt_var_compress(GISTENTRY *entry, const gbtree_vinfo *tinfo)
     288                 :             : {
     289                 :             :     GISTENTRY  *retval;
     290                 :             : 
     291         [ +  + ]:        8346 :     if (entry->leafkey)
     292                 :             :     {
     293                 :        8265 :         varlena    *leaf = PG_DETOAST_DATUM(entry->key);
     294                 :             :         GBT_VARKEY *r;
     295                 :             : 
     296                 :        8265 :         r = gbt_var_key_from_datum(leaf);
     297                 :             : 
     298                 :        8265 :         retval = palloc_object(GISTENTRY);
     299                 :        8265 :         gistentryinit(*retval, PointerGetDatum(r),
     300                 :             :                       entry->rel, entry->page,
     301                 :             :                       entry->offset, true);
     302                 :             :     }
     303                 :             :     else
     304                 :          81 :         retval = entry;
     305                 :             : 
     306                 :        8346 :     return retval;
     307                 :             : }
     308                 :             : 
     309                 :             : 
     310                 :             : Datum
     311                 :       14982 : gbt_var_fetch(PG_FUNCTION_ARGS)
     312                 :             : {
     313                 :       14982 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     314                 :       14982 :     GBT_VARKEY *key = (GBT_VARKEY *) PG_DETOAST_DATUM(entry->key);
     315                 :       14982 :     GBT_VARKEY_R r = gbt_var_key_readable(key);
     316                 :             :     GISTENTRY  *retval;
     317                 :             : 
     318                 :       14982 :     retval = palloc_object(GISTENTRY);
     319                 :       14982 :     gistentryinit(*retval, PointerGetDatum(r.lower),
     320                 :             :                   entry->rel, entry->page,
     321                 :             :                   entry->offset, true);
     322                 :             : 
     323                 :       14982 :     PG_RETURN_POINTER(retval);
     324                 :             : }
     325                 :             : 
     326                 :             : 
     327                 :             : GBT_VARKEY *
     328                 :        1865 : gbt_var_union(const GistEntryVector *entryvec, int32 *size, Oid collation,
     329                 :             :               const gbtree_vinfo *tinfo, FmgrInfo *flinfo)
     330                 :             : {
     331                 :        1865 :     int         i = 0,
     332                 :        1865 :                 numranges = entryvec->n;
     333                 :             :     GBT_VARKEY *cur;
     334                 :             :     Datum       out;
     335                 :             :     GBT_VARKEY_R rk;
     336                 :             : 
     337                 :        1865 :     *size = sizeof(GBT_VARKEY);
     338                 :             : 
     339                 :        1865 :     cur = (GBT_VARKEY *) DatumGetPointer(entryvec->vector[0].key);
     340                 :        1865 :     rk = gbt_var_key_readable(cur);
     341                 :        1865 :     out = PointerGetDatum(gbt_var_key_copy(&rk));
     342                 :             : 
     343         [ +  + ]:       11729 :     for (i = 1; i < numranges; i++)
     344                 :             :     {
     345                 :        9864 :         cur = (GBT_VARKEY *) DatumGetPointer(entryvec->vector[i].key);
     346                 :        9864 :         gbt_var_bin_union(&out, cur, collation, tinfo, flinfo);
     347                 :             :     }
     348                 :             : 
     349                 :             : 
     350                 :             :     /* Truncate (=compress) key */
     351         [ +  + ]:        1865 :     if (tinfo->trnc)
     352                 :             :     {
     353                 :             :         int32       plen;
     354                 :             :         GBT_VARKEY *trc;
     355                 :             : 
     356                 :           3 :         plen = gbt_var_node_cp_len((GBT_VARKEY *) DatumGetPointer(out), tinfo);
     357                 :           3 :         trc = gbt_var_node_truncate((GBT_VARKEY *) DatumGetPointer(out), plen + 1, tinfo);
     358                 :             : 
     359                 :           3 :         out = PointerGetDatum(trc);
     360                 :             :     }
     361                 :             : 
     362                 :        1865 :     return ((GBT_VARKEY *) DatumGetPointer(out));
     363                 :             : }
     364                 :             : 
     365                 :             : 
     366                 :             : bool
     367                 :        1814 : gbt_var_same(Datum d1, Datum d2, Oid collation,
     368                 :             :              const gbtree_vinfo *tinfo, FmgrInfo *flinfo)
     369                 :             : {
     370                 :        1814 :     GBT_VARKEY *t1 = (GBT_VARKEY *) DatumGetPointer(d1);
     371                 :        1814 :     GBT_VARKEY *t2 = (GBT_VARKEY *) DatumGetPointer(d2);
     372                 :             :     GBT_VARKEY_R r1,
     373                 :             :                 r2;
     374                 :             : 
     375                 :        1814 :     r1 = gbt_var_key_readable(t1);
     376                 :        1814 :     r2 = gbt_var_key_readable(t2);
     377                 :             : 
     378   [ +  -  +  - ]:        3628 :     return (tinfo->f_cmp(r1.lower, r2.lower, collation, flinfo) == 0 &&
     379                 :        1814 :             tinfo->f_cmp(r1.upper, r2.upper, collation, flinfo) == 0);
     380                 :             : }
     381                 :             : 
     382                 :             : 
     383                 :             : float *
     384                 :           0 : gbt_var_penalty(float *res, const GISTENTRY *o, const GISTENTRY *n,
     385                 :             :                 Oid collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo)
     386                 :             : {
     387                 :           0 :     GBT_VARKEY *orge = (GBT_VARKEY *) DatumGetPointer(o->key);
     388                 :           0 :     GBT_VARKEY *newe = (GBT_VARKEY *) DatumGetPointer(n->key);
     389                 :             :     GBT_VARKEY_R ok,
     390                 :             :                 nk;
     391                 :             : 
     392                 :           0 :     *res = 0.0;
     393                 :             : 
     394                 :           0 :     nk = gbt_var_key_readable(newe);
     395         [ #  # ]:           0 :     if (nk.lower == nk.upper)   /* if leaf, convert to internal form */
     396                 :             :     {
     397                 :             :         GBT_VARKEY *tmp;
     398                 :             : 
     399                 :           0 :         tmp = gbt_var_leaf2node(newe, tinfo, flinfo);
     400         [ #  # ]:           0 :         if (tmp != newe)
     401                 :           0 :             nk = gbt_var_key_readable(tmp);
     402                 :             :     }
     403                 :           0 :     ok = gbt_var_key_readable(orge);
     404                 :             : 
     405   [ #  #  #  # ]:           0 :     if ((VARSIZE(ok.lower) - VARHDRSZ) == 0 && (VARSIZE(ok.upper) - VARHDRSZ) == 0)
     406                 :           0 :         *res = 0.0;
     407   [ #  #  #  #  :           0 :     else if (!((tinfo->f_cmp(nk.lower, ok.lower, collation, flinfo) >= 0 ||
                   #  # ]
     408                 :           0 :                 gbt_bytea_pf_match(ok.lower, nk.lower, tinfo)) &&
     409         [ #  # ]:           0 :                (tinfo->f_cmp(nk.upper, ok.upper, collation, flinfo) <= 0 ||
     410                 :           0 :                 gbt_bytea_pf_match(ok.upper, nk.upper, tinfo))))
     411                 :             :     {
     412                 :           0 :         Datum       d = PointerGetDatum(0);
     413                 :             :         double      dres;
     414                 :             :         int32       ol,
     415                 :             :                     ul;
     416                 :             : 
     417                 :           0 :         gbt_var_bin_union(&d, orge, collation, tinfo, flinfo);
     418                 :           0 :         ol = gbt_var_node_cp_len((GBT_VARKEY *) DatumGetPointer(d), tinfo);
     419                 :           0 :         gbt_var_bin_union(&d, newe, collation, tinfo, flinfo);
     420                 :           0 :         ul = gbt_var_node_cp_len((GBT_VARKEY *) DatumGetPointer(d), tinfo);
     421                 :             : 
     422         [ #  # ]:           0 :         if (ul < ol)
     423                 :             :         {
     424                 :           0 :             dres = (ol - ul);   /* reduction of common prefix len */
     425                 :             :         }
     426                 :             :         else
     427                 :             :         {
     428                 :           0 :             GBT_VARKEY_R uk = gbt_var_key_readable((GBT_VARKEY *) DatumGetPointer(d));
     429                 :             :             unsigned char tmp[4];
     430                 :             : 
     431         [ #  # ]:           0 :             tmp[0] = (unsigned char) (((VARSIZE(ok.lower) - VARHDRSZ) <= ul) ? 0 : (VARDATA(ok.lower)[ul]));
     432         [ #  # ]:           0 :             tmp[1] = (unsigned char) (((VARSIZE(uk.lower) - VARHDRSZ) <= ul) ? 0 : (VARDATA(uk.lower)[ul]));
     433         [ #  # ]:           0 :             tmp[2] = (unsigned char) (((VARSIZE(ok.upper) - VARHDRSZ) <= ul) ? 0 : (VARDATA(ok.upper)[ul]));
     434         [ #  # ]:           0 :             tmp[3] = (unsigned char) (((VARSIZE(uk.upper) - VARHDRSZ) <= ul) ? 0 : (VARDATA(uk.upper)[ul]));
     435                 :           0 :             dres = abs(tmp[0] - tmp[1]) + abs(tmp[3] - tmp[2]);
     436                 :           0 :             dres /= 256.0;
     437                 :             :         }
     438                 :             : 
     439                 :           0 :         *res += FLT_MIN;
     440                 :           0 :         *res += (float) (dres / ((double) (ol + 1)));
     441                 :           0 :         *res *= (FLT_MAX / (o->rel->rd_att->natts + 1));
     442                 :             :     }
     443                 :             : 
     444                 :           0 :     return res;
     445                 :             : }
     446                 :             : 
     447                 :             : 
     448                 :             : static int
     449                 :       17987 : gbt_vsrt_cmp(const void *a, const void *b, void *arg)
     450                 :             : {
     451                 :       17987 :     GBT_VARKEY_R ar = gbt_var_key_readable(((const Vsrt *) a)->t);
     452                 :       17987 :     GBT_VARKEY_R br = gbt_var_key_readable(((const Vsrt *) b)->t);
     453                 :       17987 :     const gbt_vsrt_arg *varg = (const gbt_vsrt_arg *) arg;
     454                 :             :     int         res;
     455                 :             : 
     456                 :       17987 :     res = varg->tinfo->f_cmp(ar.lower, br.lower, varg->collation, varg->flinfo);
     457         [ +  + ]:       17987 :     if (res == 0)
     458                 :        7632 :         return varg->tinfo->f_cmp(ar.upper, br.upper, varg->collation, varg->flinfo);
     459                 :             : 
     460                 :       10355 :     return res;
     461                 :             : }
     462                 :             : 
     463                 :             : GIST_SPLITVEC *
     464                 :          51 : gbt_var_picksplit(const GistEntryVector *entryvec, GIST_SPLITVEC *v,
     465                 :             :                   Oid collation, const gbtree_vinfo *tinfo, FmgrInfo *flinfo)
     466                 :             : {
     467                 :             :     OffsetNumber i,
     468                 :          51 :                 maxoff = entryvec->n - 1;
     469                 :             :     Vsrt       *arr;
     470                 :          51 :     int         svcntr = 0,
     471                 :             :                 nbytes;
     472                 :             :     char       *cur;
     473                 :          51 :     GBT_VARKEY **sv = NULL;
     474                 :             :     gbt_vsrt_arg varg;
     475                 :             : 
     476                 :          51 :     arr = palloc_array(Vsrt, maxoff + 1);
     477                 :          51 :     nbytes = (maxoff + 2) * sizeof(OffsetNumber);
     478                 :          51 :     v->spl_left = (OffsetNumber *) palloc(nbytes);
     479                 :          51 :     v->spl_right = (OffsetNumber *) palloc(nbytes);
     480                 :          51 :     v->spl_ldatum = PointerGetDatum(0);
     481                 :          51 :     v->spl_rdatum = PointerGetDatum(0);
     482                 :          51 :     v->spl_nleft = 0;
     483                 :          51 :     v->spl_nright = 0;
     484                 :             : 
     485                 :          51 :     sv = palloc_array(GBT_VARKEY *, maxoff + 1);
     486                 :             : 
     487                 :             :     /* Sort entries */
     488                 :             : 
     489         [ +  + ]:       18075 :     for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
     490                 :             :     {
     491                 :             :         GBT_VARKEY_R ro;
     492                 :             : 
     493                 :       18024 :         cur = (char *) DatumGetPointer(entryvec->vector[i].key);
     494                 :       18024 :         ro = gbt_var_key_readable((GBT_VARKEY *) cur);
     495         [ +  - ]:       18024 :         if (ro.lower == ro.upper)   /* leaf */
     496                 :             :         {
     497                 :       18024 :             sv[svcntr] = gbt_var_leaf2node((GBT_VARKEY *) cur, tinfo, flinfo);
     498                 :       18024 :             arr[i].t = sv[svcntr];
     499         [ +  + ]:       18024 :             if (sv[svcntr] != (GBT_VARKEY *) cur)
     500                 :        2400 :                 svcntr++;
     501                 :             :         }
     502                 :             :         else
     503                 :           0 :             arr[i].t = (GBT_VARKEY *) cur;
     504                 :       18024 :         arr[i].i = i;
     505                 :             :     }
     506                 :             : 
     507                 :             :     /* sort */
     508                 :          51 :     varg.tinfo = tinfo;
     509                 :          51 :     varg.collation = collation;
     510                 :          51 :     varg.flinfo = flinfo;
     511                 :          51 :     qsort_arg(&arr[FirstOffsetNumber],
     512                 :             :               maxoff - FirstOffsetNumber + 1,
     513                 :             :               sizeof(Vsrt),
     514                 :             :               gbt_vsrt_cmp,
     515                 :             :               &varg);
     516                 :             : 
     517                 :             :     /* We do simply create two parts */
     518                 :             : 
     519         [ +  + ]:       18075 :     for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
     520                 :             :     {
     521         [ +  + ]:       18024 :         if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
     522                 :             :         {
     523                 :        9008 :             gbt_var_bin_union(&v->spl_ldatum, arr[i].t, collation, tinfo, flinfo);
     524                 :        9008 :             v->spl_left[v->spl_nleft] = arr[i].i;
     525                 :        9008 :             v->spl_nleft++;
     526                 :             :         }
     527                 :             :         else
     528                 :             :         {
     529                 :        9016 :             gbt_var_bin_union(&v->spl_rdatum, arr[i].t, collation, tinfo, flinfo);
     530                 :        9016 :             v->spl_right[v->spl_nright] = arr[i].i;
     531                 :        9016 :             v->spl_nright++;
     532                 :             :         }
     533                 :             :     }
     534                 :             : 
     535                 :             :     /* Truncate (=compress) key */
     536         [ +  + ]:          51 :     if (tinfo->trnc)
     537                 :             :     {
     538                 :          11 :         int32       ll = gbt_var_node_cp_len((GBT_VARKEY *) DatumGetPointer(v->spl_ldatum), tinfo);
     539                 :          11 :         int32       lr = gbt_var_node_cp_len((GBT_VARKEY *) DatumGetPointer(v->spl_rdatum), tinfo);
     540                 :             :         GBT_VARKEY *dl;
     541                 :             :         GBT_VARKEY *dr;
     542                 :             : 
     543                 :          11 :         ll = Max(ll, lr);
     544                 :          11 :         ll++;
     545                 :             : 
     546                 :          11 :         dl = gbt_var_node_truncate((GBT_VARKEY *) DatumGetPointer(v->spl_ldatum), ll, tinfo);
     547                 :          11 :         dr = gbt_var_node_truncate((GBT_VARKEY *) DatumGetPointer(v->spl_rdatum), ll, tinfo);
     548                 :          11 :         v->spl_ldatum = PointerGetDatum(dl);
     549                 :          11 :         v->spl_rdatum = PointerGetDatum(dr);
     550                 :             :     }
     551                 :             : 
     552                 :          51 :     return v;
     553                 :             : }
     554                 :             : 
     555                 :             : 
     556                 :             : /*
     557                 :             :  * The GiST consistent method
     558                 :             :  */
     559                 :             : bool
     560                 :       23680 : gbt_var_consistent(const GBT_VARKEY_R *key,
     561                 :             :                    const void *query,
     562                 :             :                    StrategyNumber strategy,
     563                 :             :                    Oid collation,
     564                 :             :                    bool is_leaf,
     565                 :             :                    const gbtree_vinfo *tinfo,
     566                 :             :                    FmgrInfo *flinfo)
     567                 :             : {
     568                 :             :     bool        retval;
     569                 :             : 
     570                 :             :     /*
     571                 :             :      * On leaf pages we directly apply the check "key->lower OP query"; we
     572                 :             :      * need not consider key->upper since it will be equal to key->lower.
     573                 :             :      *
     574                 :             :      * On internal pages we mostly need to check "is lower bound below query?"
     575                 :             :      * and/or "is upper bound above query?", where we must allow equality in
     576                 :             :      * both cases.  When checking against the upper bound we have to allow a
     577                 :             :      * gbt_var_node_pf_match too.
     578                 :             :      *
     579                 :             :      * Remember that f_cmp is for internal pages, f_eq etc for leaf pages.
     580                 :             :      */
     581                 :             : #define lower_is_below_query() \
     582                 :             :     (tinfo->f_cmp(key->lower, query, collation, flinfo) <= 0)
     583                 :             : #define upper_is_above_query() \
     584                 :             :     (tinfo->f_cmp(key->upper, query, collation, flinfo) >= 0 || \
     585                 :             :      gbt_var_node_pf_match(key, query, tinfo))
     586                 :             : 
     587   [ +  +  +  +  :       23680 :     switch (strategy)
                +  +  - ]
     588                 :             :     {
     589                 :        5708 :         case BTLessEqualStrategyNumber:
     590         [ +  + ]:        5708 :             if (is_leaf)
     591                 :        5639 :                 retval = tinfo->f_le(key->lower, query, collation, flinfo);
     592                 :             :             else
     593                 :          69 :                 retval = lower_is_below_query();
     594                 :        5708 :             break;
     595                 :        5615 :         case BTLessStrategyNumber:
     596         [ +  + ]:        5615 :             if (is_leaf)
     597                 :        5560 :                 retval = tinfo->f_lt(key->lower, query, collation, flinfo);
     598                 :             :             else
     599                 :          55 :                 retval = lower_is_below_query();
     600                 :        5615 :             break;
     601                 :        2197 :         case BTEqualStrategyNumber:
     602         [ +  + ]:        2197 :             if (is_leaf)
     603                 :        2130 :                 retval = tinfo->f_eq(key->lower, query, collation, flinfo);
     604                 :             :             else
     605   [ +  +  +  +  :          67 :                 retval = lower_is_below_query() && upper_is_above_query();
                   +  + ]
     606                 :        2197 :             break;
     607                 :        4978 :         case BTGreaterStrategyNumber:
     608         [ +  + ]:        4978 :             if (is_leaf)
     609                 :        4917 :                 retval = tinfo->f_gt(key->lower, query, collation, flinfo);
     610                 :             :             else
     611   [ +  +  +  + ]:          61 :                 retval = upper_is_above_query();
     612                 :        4978 :             break;
     613                 :        5171 :         case BTGreaterEqualStrategyNumber:
     614         [ +  + ]:        5171 :             if (is_leaf)
     615                 :        5095 :                 retval = tinfo->f_ge(key->lower, query, collation, flinfo);
     616                 :             :             else
     617   [ +  +  +  + ]:          76 :                 retval = upper_is_above_query();
     618                 :        5171 :             break;
     619                 :          11 :         case BtreeGistNotEqualStrategyNumber:
     620         [ +  + ]:          11 :             if (is_leaf)
     621                 :           9 :                 retval = !(tinfo->f_eq(key->lower, query, collation, flinfo));
     622                 :             :             else
     623                 :             :             {
     624                 :             :                 /*
     625                 :             :                  * If the upper/lower bounds are equal and not truncated, then
     626                 :             :                  * all entries below this node must have exactly that value.
     627                 :             :                  * So we can avoid descending if the query equals both bounds.
     628                 :             :                  * In all other cases, we must descend.
     629                 :             :                  */
     630   [ +  -  +  + ]:           5 :                 retval = tinfo->trnc ||
     631         [ +  - ]:           3 :                     !(tinfo->f_cmp(key->lower, query, collation, flinfo) == 0 &&
     632                 :           1 :                       tinfo->f_cmp(key->upper, query, collation, flinfo) == 0);
     633                 :             :             }
     634                 :          11 :             break;
     635                 :           0 :         default:
     636                 :           0 :             retval = false;
     637                 :             :     }
     638                 :             : 
     639                 :             : #undef lower_is_below_query
     640                 :             : #undef upper_is_above_query
     641                 :             : 
     642                 :       23680 :     return retval;
     643                 :             : }
        

Generated by: LCOV version 2.0-1