LCOV - differential code coverage report
Current view: top level - contrib/ltree - ltree_gist.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 93.5 % 382 357 9 12 4 10 148 1 198 10 149 1 1
Current Date: 2023-04-08 15:15:32 Functions: 93.8 % 32 30 2 30 2 30
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a