LCOV - code coverage report
Current view: top level - contrib/ltree - ltree_gist.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 93.5 % 383 358
Test Date: 2026-07-19 22:15:42 Functions: 93.9 % 33 31
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 58.1 % 485 282

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * GiST support for ltree
       3                 :             :  * Teodor Sigaev <teodor@stack.net>
       4                 :             :  * contrib/ltree/ltree_gist.c
       5                 :             :  */
       6                 :             : #include "postgres.h"
       7                 :             : 
       8                 :             : #include "access/gist.h"
       9                 :             : #include "access/reloptions.h"
      10                 :             : #include "access/stratnum.h"
      11                 :             : #include "crc32.h"
      12                 :             : #include "ltree.h"
      13                 :             : #include "utils/array.h"
      14                 :             : 
      15                 :             : #define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
      16                 :             : #define ISEQ(a,b)   ( (a)->numlevel == (b)->numlevel && ltree_compare(a,b)==0 )
      17                 :             : 
      18                 :           2 : PG_FUNCTION_INFO_V1(ltree_gist_in);
      19                 :           2 : PG_FUNCTION_INFO_V1(ltree_gist_out);
      20                 :             : 
      21                 :             : Datum
      22                 :           0 : ltree_gist_in(PG_FUNCTION_ARGS)
      23                 :             : {
      24         [ #  # ]:           0 :     ereport(ERROR,
      25                 :             :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
      26                 :             :              errmsg("cannot accept a value of type %s", "ltree_gist")));
      27                 :             : 
      28                 :             :     PG_RETURN_VOID();           /* keep compiler quiet */
      29                 :             : }
      30                 :             : 
      31                 :             : Datum
      32                 :           0 : ltree_gist_out(PG_FUNCTION_ARGS)
      33                 :             : {
      34         [ #  # ]:           0 :     ereport(ERROR,
      35                 :             :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
      36                 :             :              errmsg("cannot display a value of type %s", "ltree_gist")));
      37                 :             : 
      38                 :             :     PG_RETURN_VOID();           /* keep compiler quiet */
      39                 :             : }
      40                 :             : 
      41                 :             : ltree_gist *
      42                 :       16571 : ltree_gist_alloc(bool isalltrue, BITVECP sign, int siglen,
      43                 :             :                  ltree *left, ltree *right)
      44                 :             : {
      45   [ +  -  +  + ]:       21852 :     int32       size = LTG_HDRSIZE + (isalltrue ? 0 : siglen) +
      46         [ +  + ]:        5281 :         (left ? VARSIZE(left) + (right ? VARSIZE(right) : 0) : 0);
      47                 :       16571 :     ltree_gist *result = palloc(size);
      48                 :             : 
      49                 :       16571 :     SET_VARSIZE(result, size);
      50                 :             : 
      51         [ +  + ]:       16571 :     if (siglen)
      52                 :             :     {
      53                 :       14559 :         result->flag = 0;
      54                 :             : 
      55         [ -  + ]:       14559 :         if (isalltrue)
      56                 :           0 :             result->flag |= LTG_ALLTRUE;
      57         [ +  + ]:       14559 :         else if (sign)
      58                 :        5039 :             memcpy(LTG_SIGN(result), sign, siglen);
      59                 :             :         else
      60                 :        9520 :             memset(LTG_SIGN(result), 0, siglen);
      61                 :             : 
      62         [ +  + ]:       14559 :         if (left)
      63                 :             :         {
      64         [ +  - ]:        3269 :             memcpy(LTG_LNODE(result, siglen), left, VARSIZE(left));
      65                 :             : 
      66   [ +  -  +  -  :        3269 :             if (!right || left == right || ISEQ(left, right))
             +  +  -  + ]
      67                 :           0 :                 result->flag |= LTG_NORIGHT;
      68                 :             :             else
      69   [ -  +  -  -  :        3269 :                 memcpy(LTG_RNODE(result, siglen), right, VARSIZE(right));
             +  -  +  - ]
      70                 :             :         }
      71                 :             :     }
      72                 :             :     else
      73                 :             :     {
      74                 :             :         Assert(left);
      75                 :        2012 :         result->flag = LTG_ONENODE;
      76                 :        2012 :         memcpy(LTG_NODE(result), left, VARSIZE(left));
      77                 :             :     }
      78                 :             : 
      79                 :       16571 :     return result;
      80                 :             : }
      81                 :             : 
      82                 :           3 : PG_FUNCTION_INFO_V1(ltree_compress);
      83                 :           3 : PG_FUNCTION_INFO_V1(ltree_decompress);
      84                 :           3 : PG_FUNCTION_INFO_V1(ltree_same);
      85                 :           3 : PG_FUNCTION_INFO_V1(ltree_union);
      86                 :           3 : PG_FUNCTION_INFO_V1(ltree_penalty);
      87                 :           3 : PG_FUNCTION_INFO_V1(ltree_picksplit);
      88                 :           3 : PG_FUNCTION_INFO_V1(ltree_consistent);
      89                 :           3 : PG_FUNCTION_INFO_V1(ltree_gist_options);
      90                 :             : 
      91                 :             : #define GETENTRY(vec,pos) ((ltree_gist *) DatumGetPointer((vec)->vector[(pos)].key))
      92                 :             : 
      93                 :             : Datum
      94                 :        2111 : ltree_compress(PG_FUNCTION_ARGS)
      95                 :             : {
      96                 :        2111 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
      97                 :        2111 :     GISTENTRY  *retval = entry;
      98                 :             : 
      99         [ +  + ]:        2111 :     if (entry->leafkey)
     100                 :             :     {                           /* ltree */
     101                 :        2012 :         ltree      *val = DatumGetLtreeP(entry->key);
     102                 :        2012 :         ltree_gist *key = ltree_gist_alloc(false, NULL, 0, val, 0);
     103                 :             : 
     104                 :        2012 :         retval = palloc_object(GISTENTRY);
     105                 :        2012 :         gistentryinit(*retval, PointerGetDatum(key),
     106                 :             :                       entry->rel, entry->page,
     107                 :             :                       entry->offset, false);
     108                 :             :     }
     109                 :        2111 :     PG_RETURN_POINTER(retval);
     110                 :             : }
     111                 :             : 
     112                 :             : Datum
     113                 :       97112 : ltree_decompress(PG_FUNCTION_ARGS)
     114                 :             : {
     115                 :       97112 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     116                 :       97112 :     ltree_gist *key = (ltree_gist *) PG_DETOAST_DATUM(entry->key);
     117                 :             : 
     118         [ -  + ]:       97112 :     if (PointerGetDatum(key) != entry->key)
     119                 :             :     {
     120                 :           0 :         GISTENTRY  *retval = palloc_object(GISTENTRY);
     121                 :             : 
     122                 :           0 :         gistentryinit(*retval, PointerGetDatum(key),
     123                 :             :                       entry->rel, entry->page,
     124                 :             :                       entry->offset, false);
     125                 :           0 :         PG_RETURN_POINTER(retval);
     126                 :             :     }
     127                 :       97112 :     PG_RETURN_POINTER(entry);
     128                 :             : }
     129                 :             : 
     130                 :             : Datum
     131                 :        3199 : ltree_same(PG_FUNCTION_ARGS)
     132                 :             : {
     133                 :        3199 :     ltree_gist *a = (ltree_gist *) PG_GETARG_POINTER(0);
     134                 :        3199 :     ltree_gist *b = (ltree_gist *) PG_GETARG_POINTER(1);
     135                 :        3199 :     bool       *result = (bool *) PG_GETARG_POINTER(2);
     136         [ +  - ]:        3199 :     int         siglen = LTREE_GET_SIGLEN();
     137                 :             : 
     138                 :        3199 :     *result = false;
     139         [ -  + ]:        3199 :     if (LTG_ISONENODE(a) != LTG_ISONENODE(b))
     140                 :           0 :         PG_RETURN_POINTER(result);
     141                 :             : 
     142         [ -  + ]:        3199 :     if (LTG_ISONENODE(a))
     143   [ #  #  #  # ]:           0 :         *result = ISEQ(LTG_NODE(a), LTG_NODE(b));
     144                 :             :     else
     145                 :             :     {
     146                 :             :         int32       i;
     147                 :        3199 :         BITVECP     sa = LTG_SIGN(a),
     148                 :        3199 :                     sb = LTG_SIGN(b);
     149                 :             : 
     150         [ -  + ]:        3199 :         if (LTG_ISALLTRUE(a) != LTG_ISALLTRUE(b))
     151                 :           0 :             PG_RETURN_POINTER(result);
     152                 :             : 
     153   [ +  -  +  -  :        3199 :         if (!ISEQ(LTG_LNODE(a, siglen), LTG_LNODE(b, siglen)))
          +  +  +  -  +  
                -  -  + ]
     154                 :          10 :             PG_RETURN_POINTER(result);
     155   [ -  +  -  -  :        3189 :         if (!ISEQ(LTG_RNODE(a, siglen), LTG_RNODE(b, siglen)))
          +  -  +  -  -  
          +  -  -  +  -  
          +  -  +  +  -  
          +  -  -  +  -  
          +  -  -  +  -  
          -  +  -  +  -  
                   +  + ]
     156                 :          17 :             PG_RETURN_POINTER(result);
     157                 :             : 
     158                 :        3172 :         *result = true;
     159         [ +  - ]:        3172 :         if (!LTG_ISALLTRUE(a))
     160                 :             :         {
     161         [ +  + ]:     4598632 :             LOOPBYTE(siglen)
     162                 :             :             {
     163         [ +  + ]:     4595462 :                 if (sa[i] != sb[i])
     164                 :             :                 {
     165                 :           2 :                     *result = false;
     166                 :           2 :                     break;
     167                 :             :                 }
     168                 :             :             }
     169                 :             :         }
     170                 :             :     }
     171                 :             : 
     172                 :        3172 :     PG_RETURN_POINTER(result);
     173                 :             : }
     174                 :             : 
     175                 :             : static void
     176                 :        5867 : hashing(BITVECP sign, ltree *t, int siglen)
     177                 :             : {
     178                 :        5867 :     int         tlen = t->numlevel;
     179                 :        5867 :     ltree_level *cur = LTREE_FIRST(t);
     180                 :             :     int         hash;
     181                 :             : 
     182         [ +  + ]:       44351 :     while (tlen > 0)
     183                 :             :     {
     184                 :       38484 :         hash = ltree_crc32_sz(cur->name, cur->len);
     185                 :       38484 :         HASH(sign, hash, siglen);
     186                 :       38484 :         cur = LEVEL_NEXT(cur);
     187                 :       38484 :         tlen--;
     188                 :             :     }
     189                 :        5867 : }
     190                 :             : 
     191                 :             : Datum
     192                 :        3199 : ltree_union(PG_FUNCTION_ARGS)
     193                 :             : {
     194                 :        3199 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     195                 :        3199 :     int        *size = (int *) PG_GETARG_POINTER(1);
     196         [ +  - ]:        3199 :     int         siglen = LTREE_GET_SIGLEN();
     197                 :        3199 :     BITVECP     base = palloc0(siglen);
     198                 :             :     int32       i,
     199                 :             :                 j;
     200                 :             :     ltree_gist *result,
     201                 :             :                *cur;
     202                 :        3199 :     ltree      *left = NULL,
     203                 :        3199 :                *right = NULL,
     204                 :             :                *curtree;
     205                 :        3199 :     bool        isalltrue = false;
     206                 :             : 
     207         [ +  + ]:        9597 :     for (j = 0; j < entryvec->n; j++)
     208                 :             :     {
     209                 :        6398 :         cur = GETENTRY(entryvec, j);
     210         [ +  + ]:        6398 :         if (LTG_ISONENODE(cur))
     211                 :             :         {
     212                 :        3199 :             curtree = LTG_NODE(cur);
     213                 :        3199 :             hashing(base, curtree, siglen);
     214   [ +  -  +  + ]:        3199 :             if (!left || ltree_compare(left, curtree) > 0)
     215                 :          10 :                 left = curtree;
     216   [ +  -  +  + ]:        3199 :             if (!right || ltree_compare(right, curtree) < 0)
     217                 :          17 :                 right = curtree;
     218                 :             :         }
     219                 :             :         else
     220                 :             :         {
     221   [ +  -  -  + ]:        3199 :             if (isalltrue || LTG_ISALLTRUE(cur))
     222                 :           0 :                 isalltrue = true;
     223                 :             :             else
     224                 :             :             {
     225                 :        3199 :                 BITVECP     sc = LTG_SIGN(cur);
     226                 :             : 
     227         [ +  + ]:     4641399 :                 LOOPBYTE(siglen)
     228                 :     4638200 :                     ((unsigned char *) base)[i] |= sc[i];
     229                 :             :             }
     230                 :             : 
     231         [ +  - ]:        3199 :             curtree = LTG_LNODE(cur, siglen);
     232   [ -  +  -  - ]:        3199 :             if (!left || ltree_compare(left, curtree) > 0)
     233                 :        3199 :                 left = curtree;
     234   [ -  +  -  -  :        3199 :             curtree = LTG_RNODE(cur, siglen);
             +  -  +  - ]
     235   [ -  +  -  - ]:        3199 :             if (!right || ltree_compare(right, curtree) < 0)
     236                 :        3199 :                 right = curtree;
     237                 :             :         }
     238                 :             :     }
     239                 :             : 
     240         [ +  - ]:        3199 :     if (isalltrue == false)
     241                 :             :     {
     242                 :        3199 :         isalltrue = true;
     243         [ +  - ]:        3199 :         LOOPBYTE(siglen)
     244                 :             :         {
     245         [ +  - ]:        3199 :             if (((unsigned char *) base)[i] != 0xff)
     246                 :             :             {
     247                 :        3199 :                 isalltrue = false;
     248                 :        3199 :                 break;
     249                 :             :             }
     250                 :             :         }
     251                 :             :     }
     252                 :             : 
     253                 :        3199 :     result = ltree_gist_alloc(isalltrue, base, siglen, left, right);
     254                 :             : 
     255                 :        3199 :     *size = VARSIZE(result);
     256                 :             : 
     257                 :        3199 :     PG_RETURN_POINTER(result);
     258                 :             : }
     259                 :             : 
     260                 :             : Datum
     261                 :        9609 : ltree_penalty(PG_FUNCTION_ARGS)
     262                 :             : {
     263                 :        9609 :     ltree_gist *origval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
     264                 :        9609 :     ltree_gist *newval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
     265                 :        9609 :     float      *penalty = (float *) PG_GETARG_POINTER(2);
     266         [ +  - ]:        9609 :     int         siglen = LTREE_GET_SIGLEN();
     267                 :             :     float       cmpr,
     268                 :             :                 cmpl;
     269                 :             : 
     270   [ +  -  -  -  :        9609 :     cmpl = ltree_compare_distance(LTG_GETLNODE(origval, siglen), LTG_GETLNODE(newval, siglen));
             -  +  +  - ]
     271   [ -  +  -  +  :        9609 :     cmpr = ltree_compare_distance(LTG_GETRNODE(newval, siglen), LTG_GETRNODE(origval, siglen));
          -  -  +  -  +  
          -  +  -  -  -  
          -  -  -  -  -  
                      - ]
     272                 :             : 
     273   [ +  +  +  + ]:        9609 :     *penalty = Max(cmpl, 0) + Max(cmpr, 0);
     274                 :             : 
     275                 :        9609 :     PG_RETURN_POINTER(penalty);
     276                 :             : }
     277                 :             : 
     278                 :             : /* used for sorting */
     279                 :             : typedef struct rix
     280                 :             : {
     281                 :             :     int         index;
     282                 :             :     ltree      *r;
     283                 :             : } RIX;
     284                 :             : 
     285                 :             : static int
     286                 :       18989 : treekey_cmp(const void *a, const void *b)
     287                 :             : {
     288                 :       37978 :     return ltree_compare(((const RIX *) a)->r,
     289                 :       18989 :                          ((const RIX *) b)->r);
     290                 :             : }
     291                 :             : 
     292                 :             : 
     293                 :             : Datum
     294                 :          35 : ltree_picksplit(PG_FUNCTION_ARGS)
     295                 :             : {
     296                 :          35 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     297                 :          35 :     GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
     298         [ +  - ]:          35 :     int         siglen = LTREE_GET_SIGLEN();
     299                 :             :     OffsetNumber j;
     300                 :             :     int32       i;
     301                 :             :     RIX        *array;
     302                 :             :     OffsetNumber maxoff;
     303                 :             :     int         nbytes;
     304                 :             :     ltree      *lu_l,
     305                 :             :                *lu_r,
     306                 :             :                *ru_l,
     307                 :             :                *ru_r;
     308                 :             :     ltree_gist *lu,
     309                 :             :                *ru;
     310                 :          35 :     BITVECP     ls = palloc0(siglen),
     311                 :          35 :                 rs = palloc0(siglen);
     312                 :          35 :     bool        lisat = false,
     313                 :          35 :                 risat = false;
     314                 :             : 
     315                 :          35 :     maxoff = entryvec->n - 1;
     316                 :          35 :     nbytes = (maxoff + 2) * sizeof(OffsetNumber);
     317                 :          35 :     v->spl_left = (OffsetNumber *) palloc(nbytes);
     318                 :          35 :     v->spl_right = (OffsetNumber *) palloc(nbytes);
     319                 :          35 :     v->spl_nleft = 0;
     320                 :          35 :     v->spl_nright = 0;
     321                 :          35 :     array = palloc_array(RIX, maxoff + 1);
     322                 :             : 
     323                 :             :     /* copy the data into RIXes, and sort the RIXes */
     324         [ +  + ]:        2727 :     for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
     325                 :             :     {
     326                 :        2692 :         array[j].index = j;
     327                 :        2692 :         lu = GETENTRY(entryvec, j); /* use as tmp val */
     328   [ +  +  +  - ]:        2692 :         array[j].r = LTG_GETLNODE(lu, siglen);
     329                 :             :     }
     330                 :             : 
     331                 :          35 :     qsort(&array[FirstOffsetNumber], maxoff - FirstOffsetNumber + 1,
     332                 :             :           sizeof(RIX), treekey_cmp);
     333                 :             : 
     334                 :          35 :     lu_l = lu_r = ru_l = ru_r = NULL;
     335         [ +  + ]:        2727 :     for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
     336                 :             :     {
     337                 :        2692 :         lu = GETENTRY(entryvec, array[j].index);    /* use as tmp val */
     338         [ +  + ]:        2692 :         if (j <= (maxoff - FirstOffsetNumber + 1) / 2)
     339                 :             :         {
     340                 :        1339 :             v->spl_left[v->spl_nleft] = array[j].index;
     341                 :        1339 :             v->spl_nleft++;
     342   [ +  +  +  +  :        1339 :             if (lu_r == NULL || ltree_compare(LTG_GETRNODE(lu, siglen), lu_r) > 0)
          -  +  -  -  +  
             -  +  -  +  
                      + ]
     343   [ +  +  -  +  :        1338 :                 lu_r = LTG_GETRNODE(lu, siglen);
          -  -  +  -  +  
                      - ]
     344         [ +  + ]:        1339 :             if (LTG_ISONENODE(lu))
     345                 :        1327 :                 hashing(ls, LTG_NODE(lu), siglen);
     346                 :             :             else
     347                 :             :             {
     348   [ +  -  -  + ]:          12 :                 if (lisat || LTG_ISALLTRUE(lu))
     349                 :           0 :                     lisat = true;
     350                 :             :                 else
     351                 :             :                 {
     352                 :          12 :                     BITVECP     sc = LTG_SIGN(lu);
     353                 :             : 
     354         [ +  + ]:       24300 :                     LOOPBYTE(siglen)
     355                 :       24288 :                         ((unsigned char *) ls)[i] |= sc[i];
     356                 :             :                 }
     357                 :             :             }
     358                 :             :         }
     359                 :             :         else
     360                 :             :         {
     361                 :        1353 :             v->spl_right[v->spl_nright] = array[j].index;
     362                 :        1353 :             v->spl_nright++;
     363   [ +  +  +  +  :        1353 :             if (ru_r == NULL || ltree_compare(LTG_GETRNODE(lu, siglen), ru_r) > 0)
          -  +  -  -  +  
             -  +  -  +  
                      + ]
     364   [ +  +  -  +  :        1352 :                 ru_r = LTG_GETRNODE(lu, siglen);
          -  -  +  -  +  
                      - ]
     365         [ +  + ]:        1353 :             if (LTG_ISONENODE(lu))
     366                 :        1341 :                 hashing(rs, LTG_NODE(lu), siglen);
     367                 :             :             else
     368                 :             :             {
     369   [ +  -  -  + ]:          12 :                 if (risat || LTG_ISALLTRUE(lu))
     370                 :           0 :                     risat = true;
     371                 :             :                 else
     372                 :             :                 {
     373                 :          12 :                     BITVECP     sc = LTG_SIGN(lu);
     374                 :             : 
     375         [ +  + ]:       24300 :                     LOOPBYTE(siglen)
     376                 :       24288 :                         ((unsigned char *) rs)[i] |= sc[i];
     377                 :             :                 }
     378                 :             :             }
     379                 :             :         }
     380                 :             :     }
     381                 :             : 
     382         [ +  - ]:          35 :     if (lisat == false)
     383                 :             :     {
     384                 :          35 :         lisat = true;
     385         [ +  - ]:          35 :         LOOPBYTE(siglen)
     386                 :             :         {
     387         [ +  - ]:          35 :             if (((unsigned char *) ls)[i] != 0xff)
     388                 :             :             {
     389                 :          35 :                 lisat = false;
     390                 :          35 :                 break;
     391                 :             :             }
     392                 :             :         }
     393                 :             :     }
     394                 :             : 
     395         [ +  - ]:          35 :     if (risat == false)
     396                 :             :     {
     397                 :          35 :         risat = true;
     398         [ +  - ]:          35 :         LOOPBYTE(siglen)
     399                 :             :         {
     400         [ +  - ]:          35 :             if (((unsigned char *) rs)[i] != 0xff)
     401                 :             :             {
     402                 :          35 :                 risat = false;
     403                 :          35 :                 break;
     404                 :             :             }
     405                 :             :         }
     406                 :             :     }
     407                 :             : 
     408   [ +  +  +  - ]:          35 :     lu_l = LTG_GETLNODE(GETENTRY(entryvec, array[FirstOffsetNumber].index), siglen);
     409                 :          35 :     lu = ltree_gist_alloc(lisat, ls, siglen, lu_l, lu_r);
     410                 :             : 
     411   [ +  +  +  - ]:          35 :     ru_l = LTG_GETLNODE(GETENTRY(entryvec, array[1 + ((maxoff - FirstOffsetNumber + 1) / 2)].index), siglen);
     412                 :          35 :     ru = ltree_gist_alloc(risat, rs, siglen, ru_l, ru_r);
     413                 :             : 
     414                 :          35 :     pfree(ls);
     415                 :          35 :     pfree(rs);
     416                 :             : 
     417                 :          35 :     v->spl_ldatum = PointerGetDatum(lu);
     418                 :          35 :     v->spl_rdatum = PointerGetDatum(ru);
     419                 :             : 
     420                 :          35 :     PG_RETURN_POINTER(v);
     421                 :             : }
     422                 :             : 
     423                 :             : static bool
     424                 :          24 : gist_isparent(ltree_gist *key, ltree *query, int siglen)
     425                 :             : {
     426                 :          24 :     int32       numlevel = query->numlevel;
     427                 :             :     int         i;
     428                 :             : 
     429         [ +  + ]:         104 :     for (i = query->numlevel; i >= 0; i--)
     430                 :             :     {
     431                 :          84 :         query->numlevel = i;
     432   [ -  +  +  -  :          88 :         if (ltree_compare(query, LTG_GETLNODE(key, siglen)) >= 0 &&
             +  +  +  - ]
     433   [ -  +  -  +  :           4 :             ltree_compare(query, LTG_GETRNODE(key, siglen)) <= 0)
          -  -  +  -  +  
                      - ]
     434                 :             :         {
     435                 :           4 :             query->numlevel = numlevel;
     436                 :           4 :             return true;
     437                 :             :         }
     438                 :             :     }
     439                 :             : 
     440                 :          20 :     query->numlevel = numlevel;
     441                 :          20 :     return false;
     442                 :             : }
     443                 :             : 
     444                 :             : static ltree *
     445                 :          48 : copy_ltree(ltree *src)
     446                 :             : {
     447                 :          48 :     ltree      *dst = (ltree *) palloc0(VARSIZE(src));
     448                 :             : 
     449                 :          48 :     memcpy(dst, src, VARSIZE(src));
     450                 :          48 :     return dst;
     451                 :             : }
     452                 :             : 
     453                 :             : static bool
     454                 :          24 : gist_ischild(ltree_gist *key, ltree *query, int siglen)
     455                 :             : {
     456   [ -  +  +  - ]:          24 :     ltree      *left = copy_ltree(LTG_GETLNODE(key, siglen));
     457   [ -  +  -  +  :          24 :     ltree      *right = copy_ltree(LTG_GETRNODE(key, siglen));
          -  -  +  -  +  
                      - ]
     458                 :          24 :     bool        res = true;
     459                 :             : 
     460         [ +  + ]:          24 :     if (left->numlevel > query->numlevel)
     461                 :          15 :         left->numlevel = query->numlevel;
     462                 :             : 
     463         [ +  + ]:          24 :     if (ltree_compare(query, left) < 0)
     464                 :          20 :         res = false;
     465                 :             : 
     466         [ +  + ]:          24 :     if (right->numlevel > query->numlevel)
     467                 :          22 :         right->numlevel = query->numlevel;
     468                 :             : 
     469   [ +  +  -  + ]:          24 :     if (res && ltree_compare(query, right) > 0)
     470                 :           0 :         res = false;
     471                 :             : 
     472                 :          24 :     pfree(left);
     473                 :          24 :     pfree(right);
     474                 :             : 
     475                 :          24 :     return res;
     476                 :             : }
     477                 :             : 
     478                 :             : static bool
     479                 :         210 : gist_qe(ltree_gist *key, lquery *query, int siglen)
     480                 :             : {
     481                 :         210 :     lquery_level *curq = LQUERY_FIRST(query);
     482                 :         210 :     BITVECP     sign = LTG_SIGN(key);
     483                 :         210 :     int         qlen = query->numlevel;
     484                 :             : 
     485         [ -  + ]:         210 :     if (LTG_ISALLTRUE(key))
     486                 :           0 :         return true;
     487                 :             : 
     488         [ +  + ]:         825 :     while (qlen > 0)
     489                 :             :     {
     490   [ +  +  +  - ]:         615 :         if (curq->numvar && LQL_CANLOOKSIGN(curq))
     491                 :             :         {
     492                 :         405 :             bool        isexist = false;
     493                 :         405 :             int         vlen = curq->numvar;
     494                 :         405 :             lquery_variant *curv = LQL_FIRST(curq);
     495                 :             : 
     496         [ +  - ]:         405 :             while (vlen > 0)
     497                 :             :             {
     498         [ +  - ]:         405 :                 if (GETBIT(sign, HASHVAL(curv->val, siglen)))
     499                 :             :                 {
     500                 :         405 :                     isexist = true;
     501                 :         405 :                     break;
     502                 :             :                 }
     503                 :           0 :                 curv = LVAR_NEXT(curv);
     504                 :           0 :                 vlen--;
     505                 :             :             }
     506         [ -  + ]:         405 :             if (!isexist)
     507                 :           0 :                 return false;
     508                 :             :         }
     509                 :             : 
     510                 :         615 :         curq = LQL_NEXT(curq);
     511                 :         615 :         qlen--;
     512                 :             :     }
     513                 :             : 
     514                 :         210 :     return true;
     515                 :             : }
     516                 :             : 
     517                 :             : static int
     518                 :         272 : gist_tqcmp(ltree *t, lquery *q)
     519                 :             : {
     520                 :         272 :     ltree_level *al = LTREE_FIRST(t);
     521                 :         272 :     lquery_level *ql = LQUERY_FIRST(q);
     522                 :             :     lquery_variant *bl;
     523                 :         272 :     int         an = t->numlevel;
     524                 :         272 :     int         bn = q->firstgood;
     525                 :         272 :     int         res = 0;
     526                 :             : 
     527   [ +  +  +  + ]:         320 :     while (an > 0 && bn > 0)
     528                 :             :     {
     529                 :         254 :         bl = LQL_FIRST(ql);
     530         [ +  + ]:         254 :         if ((res = memcmp(al->name, bl->name, Min(al->len, bl->len))) == 0)
     531                 :             :         {
     532         [ +  + ]:          83 :             if (al->len != bl->len)
     533                 :          35 :                 return al->len - bl->len;
     534                 :             :         }
     535                 :             :         else
     536                 :         171 :             return res;
     537                 :          48 :         an--;
     538                 :          48 :         bn--;
     539                 :          48 :         al = LEVEL_NEXT(al);
     540                 :          48 :         ql = LQL_NEXT(ql);
     541                 :             :     }
     542                 :             : 
     543                 :          66 :     return Min(t->numlevel, q->firstgood) - q->firstgood;
     544                 :             : }
     545                 :             : 
     546                 :             : static bool
     547                 :         210 : gist_between(ltree_gist *key, lquery *query, int siglen)
     548                 :             : {
     549         [ +  + ]:         210 :     if (query->firstgood == 0)
     550                 :          39 :         return true;
     551                 :             : 
     552   [ -  +  +  -  :         171 :     if (gist_tqcmp(LTG_GETLNODE(key, siglen), query) > 0)
                   +  + ]
     553                 :          70 :         return false;
     554                 :             : 
     555   [ -  +  -  +  :         101 :     if (gist_tqcmp(LTG_GETRNODE(key, siglen), query) < 0)
          -  -  +  -  +  
                -  +  + ]
     556                 :          45 :         return false;
     557                 :             : 
     558                 :          56 :     return true;
     559                 :             : }
     560                 :             : 
     561                 :             : typedef struct LtreeSignature
     562                 :             : {
     563                 :             :     BITVECP     sign;
     564                 :             :     int         siglen;
     565                 :             : } LtreeSignature;
     566                 :             : 
     567                 :             : static bool
     568                 :          78 : checkcondition_bit(void *cxt, ITEM *val)
     569                 :             : {
     570                 :          78 :     LtreeSignature *sig = cxt;
     571                 :             : 
     572         [ +  - ]:          78 :     return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(sig->sign, HASHVAL(val->val, sig->siglen)) : true;
     573                 :             : }
     574                 :             : 
     575                 :             : static bool
     576                 :          39 : gist_qtxt(ltree_gist *key, ltxtquery *query, int siglen)
     577                 :             : {
     578                 :             :     LtreeSignature sig;
     579                 :             : 
     580         [ -  + ]:          39 :     if (LTG_ISALLTRUE(key))
     581                 :           0 :         return true;
     582                 :             : 
     583                 :          39 :     sig.sign = LTG_SIGN(key);
     584                 :          39 :     sig.siglen = siglen;
     585                 :             : 
     586                 :          39 :     return ltree_execute(GETQUERY(query),
     587                 :             :                          &sig, false,
     588                 :             :                          checkcondition_bit);
     589                 :             : }
     590                 :             : 
     591                 :             : static bool
     592                 :          32 : arrq_cons(ltree_gist *key, ArrayType *_query, int siglen)
     593                 :             : {
     594         [ -  + ]:          32 :     lquery     *query = (lquery *) ARR_DATA_PTR(_query);
     595                 :          32 :     int         num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
     596                 :             : 
     597         [ -  + ]:          32 :     if (ARR_NDIM(_query) > 1)
     598         [ #  # ]:           0 :         ereport(ERROR,
     599                 :             :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     600                 :             :                  errmsg("array must be one-dimensional")));
     601         [ -  + ]:          32 :     if (array_contains_nulls(_query))
     602         [ #  # ]:           0 :         ereport(ERROR,
     603                 :             :                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     604                 :             :                  errmsg("array must not contain nulls")));
     605                 :             : 
     606         [ +  + ]:          70 :     while (num > 0)
     607                 :             :     {
     608   [ +  -  +  + ]:          51 :         if (gist_qe(key, query, siglen) && gist_between(key, query, siglen))
     609                 :          13 :             return true;
     610                 :          38 :         num--;
     611                 :          38 :         query = NEXTVAL(query);
     612                 :             :     }
     613                 :          19 :     return false;
     614                 :             : }
     615                 :             : 
     616                 :             : Datum
     617                 :        9713 : ltree_consistent(PG_FUNCTION_ARGS)
     618                 :             : {
     619                 :        9713 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     620                 :        9713 :     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     621                 :             : #ifdef NOT_USED
     622                 :             :     Oid         subtype = PG_GETARG_OID(3);
     623                 :             : #endif
     624                 :        9713 :     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
     625         [ +  - ]:        9713 :     int         siglen = LTREE_GET_SIGLEN();
     626                 :        9713 :     ltree_gist *key = (ltree_gist *) DatumGetPointer(entry->key);
     627                 :        9713 :     void       *query = NULL;
     628                 :        9713 :     bool        res = false;
     629                 :             : 
     630                 :             :     /* All cases served by this function are exact */
     631                 :        9713 :     *recheck = false;
     632                 :             : 
     633   [ +  +  +  +  :        9713 :     switch (strategy)
          +  +  +  +  +  
                   +  - ]
     634                 :             :     {
     635                 :         301 :         case BTLessStrategyNumber:
     636                 :         301 :             query = PG_GETARG_LTREE_P(1);
     637                 :         301 :             res = (GIST_LEAF(entry)) ?
     638                 :         285 :                 (ltree_compare((ltree *) query, LTG_NODE(key)) > 0)
     639                 :             :                 :
     640   [ +  +  -  +  :         586 :                 (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0);
                   +  - ]
     641                 :         301 :             break;
     642                 :         301 :         case BTLessEqualStrategyNumber:
     643                 :         301 :             query = PG_GETARG_LTREE_P(1);
     644   [ +  +  +  - ]:         301 :             res = (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0);
     645                 :         301 :             break;
     646                 :         282 :         case BTEqualStrategyNumber:
     647                 :         282 :             query = PG_GETARG_LTREE_P(1);
     648         [ +  + ]:         282 :             if (GIST_LEAF(entry))
     649                 :         258 :                 res = (ltree_compare((ltree *) query, LTG_NODE(key)) == 0);
     650                 :             :             else
     651   [ -  +  +  - ]:          48 :                 res = (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0
     652   [ +  +  +  + ]:          32 :                        &&
     653   [ -  +  -  +  :           8 :                        ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0);
          -  -  +  -  +  
                      - ]
     654                 :         282 :             break;
     655                 :         940 :         case BTGreaterEqualStrategyNumber:
     656                 :         940 :             query = PG_GETARG_LTREE_P(1);
     657   [ +  +  -  +  :         940 :             res = (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0);
          -  -  +  -  +  
                      - ]
     658                 :         940 :             break;
     659                 :         940 :         case BTGreaterStrategyNumber:
     660                 :         940 :             query = PG_GETARG_LTREE_P(1);
     661                 :         940 :             res = (GIST_LEAF(entry)) ?
     662   [ +  -  -  -  :         924 :                 (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) < 0)
          -  -  -  -  -  
                      - ]
     663                 :             :                 :
     664   [ +  +  -  +  :        1864 :                 (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0);
          -  +  -  -  +  
                -  +  - ]
     665                 :         940 :             break;
     666                 :         189 :         case 10:
     667                 :         189 :             query = PG_GETARG_LTREE_P_COPY(1);
     668                 :         189 :             res = (GIST_LEAF(entry)) ?
     669                 :         165 :                 inner_isparent((ltree *) query, LTG_NODE(key))
     670                 :             :                 :
     671         [ +  + ]:         354 :                 gist_isparent(key, (ltree *) query, siglen);
     672                 :         189 :             break;
     673                 :         189 :         case 11:
     674                 :         189 :             query = PG_GETARG_LTREE_P(1);
     675                 :         189 :             res = (GIST_LEAF(entry)) ?
     676                 :         165 :                 inner_isparent(LTG_NODE(key), (ltree *) query)
     677                 :             :                 :
     678         [ +  + ]:         354 :                 gist_ischild(key, (ltree *) query, siglen);
     679                 :         189 :             break;
     680                 :        3950 :         case 12:
     681                 :             :         case 13:
     682                 :        3950 :             query = PG_GETARG_LQUERY_P(1);
     683         [ +  + ]:        3950 :             if (GIST_LEAF(entry))
     684                 :        3791 :                 res = DatumGetBool(DirectFunctionCall2(ltq_regex,
     685                 :             :                                                        PointerGetDatum(LTG_NODE(key)),
     686                 :             :                                                        PointerGetDatum((lquery *) query)
     687                 :             :                                                        ));
     688                 :             :             else
     689   [ +  -  +  + ]:         318 :                 res = (gist_qe(key, (lquery *) query, siglen) &&
     690                 :         159 :                        gist_between(key, (lquery *) query, siglen));
     691                 :        3950 :             break;
     692                 :        2051 :         case 14:
     693                 :             :         case 15:
     694                 :        2051 :             query = PG_GETARG_LTXTQUERY_P(1);
     695         [ +  + ]:        2051 :             if (GIST_LEAF(entry))
     696                 :        2012 :                 res = DatumGetBool(DirectFunctionCall2(ltxtq_exec,
     697                 :             :                                                        PointerGetDatum(LTG_NODE(key)),
     698                 :             :                                                        PointerGetDatum((ltxtquery *) query)
     699                 :             :                                                        ));
     700                 :             :             else
     701                 :          39 :                 res = gist_qtxt(key, (ltxtquery *) query, siglen);
     702                 :        2051 :             break;
     703                 :         570 :         case 16:
     704                 :             :         case 17:
     705                 :         570 :             query = PG_GETARG_ARRAYTYPE_P(1);
     706         [ +  + ]:         570 :             if (GIST_LEAF(entry))
     707                 :         538 :                 res = DatumGetBool(DirectFunctionCall2(lt_q_regex,
     708                 :             :                                                        PointerGetDatum(LTG_NODE(key)),
     709                 :             :                                                        PointerGetDatum((ArrayType *) query)
     710                 :             :                                                        ));
     711                 :             :             else
     712                 :          32 :                 res = arrq_cons(key, (ArrayType *) query, siglen);
     713                 :         570 :             break;
     714                 :           0 :         default:
     715                 :             :             /* internal error */
     716         [ #  # ]:           0 :             elog(ERROR, "unrecognized StrategyNumber: %d", strategy);
     717                 :             :     }
     718                 :             : 
     719         [ +  + ]:        9713 :     PG_FREE_IF_COPY(query, 1);
     720                 :        9713 :     PG_RETURN_BOOL(res);
     721                 :             : }
     722                 :             : 
     723                 :             : static void
     724                 :           3 : ltree_gist_relopts_validator(void *parsed_options, relopt_value *vals,
     725                 :             :                              int nvals)
     726                 :             : {
     727                 :           3 :     LtreeGistOptions *options = (LtreeGistOptions *) parsed_options;
     728                 :             : 
     729         [ +  + ]:           3 :     if (options->siglen != INTALIGN(options->siglen))
     730         [ +  - ]:           1 :         ereport(ERROR,
     731                 :             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     732                 :             :                  errmsg("siglen value must be a multiple of %d", ALIGNOF_INT)));
     733                 :           2 : }
     734                 :             : 
     735                 :             : Datum
     736                 :          14 : ltree_gist_options(PG_FUNCTION_ARGS)
     737                 :             : {
     738                 :          14 :     local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
     739                 :             : 
     740                 :          14 :     init_local_reloptions(relopts, sizeof(LtreeGistOptions));
     741                 :          14 :     add_local_int_reloption(relopts, "siglen",
     742                 :             :                             "signature length in bytes",
     743                 :             :                             LTREE_SIGLEN_DEFAULT,
     744                 :             :                             INTALIGN(1),
     745                 :             :                             LTREE_SIGLEN_MAX,
     746                 :             :                             offsetof(LtreeGistOptions, siglen));
     747                 :          14 :     register_reloptions_validator(relopts, ltree_gist_relopts_validator);
     748                 :             : 
     749                 :          14 :     PG_RETURN_VOID();
     750                 :             : }
        

Generated by: LCOV version 2.0-1