LCOV - code coverage report
Current view: top level - contrib/ltree - ltree_gist.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 93.5 % 383 358
Test Date: 2026-02-17 17:20:33 Functions: 93.9 % 33 31
Legend: Lines:     hit not hit

            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        17084 : ltree_gist_alloc(bool isalltrue, BITVECP sign, int siglen,
      43              :                  ltree *left, ltree *right)
      44              : {
      45        22363 :     int32       size = LTG_HDRSIZE + (isalltrue ? 0 : siglen) +
      46         5279 :         (left ? VARSIZE(left) + (right ? VARSIZE(right) : 0) : 0);
      47        17084 :     ltree_gist *result = palloc(size);
      48              : 
      49        17084 :     SET_VARSIZE(result, size);
      50              : 
      51        17084 :     if (siglen)
      52              :     {
      53        15072 :         result->flag = 0;
      54              : 
      55        15072 :         if (isalltrue)
      56            0 :             result->flag |= LTG_ALLTRUE;
      57        15072 :         else if (sign)
      58         5025 :             memcpy(LTG_SIGN(result), sign, siglen);
      59              :         else
      60        10047 :             memset(LTG_SIGN(result), 0, siglen);
      61              : 
      62        15072 :         if (left)
      63              :         {
      64         3267 :             memcpy(LTG_LNODE(result, siglen), left, VARSIZE(left));
      65              : 
      66         3267 :             if (!right || left == right || ISEQ(left, right))
      67            0 :                 result->flag |= LTG_NORIGHT;
      68              :             else
      69         3267 :                 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        17084 :     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         2099 : ltree_compress(PG_FUNCTION_ARGS)
      95              : {
      96         2099 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
      97         2099 :     GISTENTRY  *retval = entry;
      98              : 
      99         2099 :     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         2099 :     PG_RETURN_POINTER(retval);
     110              : }
     111              : 
     112              : Datum
     113        99721 : ltree_decompress(PG_FUNCTION_ARGS)
     114              : {
     115        99721 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     116        99721 :     ltree_gist *key = (ltree_gist *) PG_DETOAST_DATUM(entry->key);
     117              : 
     118        99721 :     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        99721 :     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           11 :             PG_RETURN_POINTER(result);
     155         3188 :         if (!ISEQ(LTG_RNODE(a, siglen), LTG_RNODE(b, siglen)))
     156            6 :             PG_RETURN_POINTER(result);
     157              : 
     158         3182 :         *result = true;
     159         3182 :         if (!LTG_ISALLTRUE(a))
     160              :         {
     161      4620898 :             LOOPBYTE(siglen)
     162              :             {
     163      4617718 :                 if (sa[i] != sb[i])
     164              :                 {
     165            2 :                     *result = false;
     166            2 :                     break;
     167              :                 }
     168              :             }
     169              :         }
     170              :     }
     171              : 
     172         3182 :     PG_RETURN_POINTER(result);
     173              : }
     174              : 
     175              : static void
     176         5776 : hashing(BITVECP sign, ltree *t, int siglen)
     177              : {
     178         5776 :     int         tlen = t->numlevel;
     179         5776 :     ltree_level *cur = LTREE_FIRST(t);
     180              :     int         hash;
     181              : 
     182        43651 :     while (tlen > 0)
     183              :     {
     184        37875 :         hash = ltree_crc32_sz(cur->name, cur->len);
     185        37875 :         HASH(sign, hash, siglen);
     186        37875 :         cur = LEVEL_NEXT(cur);
     187        37875 :         tlen--;
     188              :     }
     189         5776 : }
     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           11 :                 left = curtree;
     216         3199 :             if (!right || ltree_compare(right, curtree) < 0)
     217            6 :                 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         9757 : ltree_penalty(PG_FUNCTION_ARGS)
     262              : {
     263         9757 :     ltree_gist *origval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
     264         9757 :     ltree_gist *newval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
     265         9757 :     float      *penalty = (float *) PG_GETARG_POINTER(2);
     266         9757 :     int         siglen = LTREE_GET_SIGLEN();
     267              :     int32       cmpr,
     268              :                 cmpl;
     269              : 
     270         9757 :     cmpl = ltree_compare(LTG_GETLNODE(origval, siglen), LTG_GETLNODE(newval, siglen));
     271         9757 :     cmpr = ltree_compare(LTG_GETRNODE(newval, siglen), LTG_GETRNODE(origval, siglen));
     272              : 
     273         9757 :     *penalty = Max(cmpl, 0) + Max(cmpr, 0);
     274              : 
     275         9757 :     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        18348 : treekey_cmp(const void *a, const void *b)
     287              : {
     288        36696 :     return ltree_compare(((const RIX *) a)->r,
     289        18348 :                          ((const RIX *) b)->r);
     290              : }
     291              : 
     292              : 
     293              : Datum
     294           34 : ltree_picksplit(PG_FUNCTION_ARGS)
     295              : {
     296           34 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     297           34 :     GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
     298           34 :     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           34 :     BITVECP     ls = palloc0(siglen),
     311           34 :                 rs = palloc0(siglen);
     312           34 :     bool        lisat = false,
     313           34 :                 risat = false;
     314              : 
     315           34 :     maxoff = entryvec->n - 1;
     316           34 :     nbytes = (maxoff + 2) * sizeof(OffsetNumber);
     317           34 :     v->spl_left = (OffsetNumber *) palloc(nbytes);
     318           34 :     v->spl_right = (OffsetNumber *) palloc(nbytes);
     319           34 :     v->spl_nleft = 0;
     320           34 :     v->spl_nright = 0;
     321           34 :     array = palloc_array(RIX, maxoff + 1);
     322              : 
     323              :     /* copy the data into RIXes, and sort the RIXes */
     324         2635 :     for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
     325              :     {
     326         2601 :         array[j].index = j;
     327         2601 :         lu = GETENTRY(entryvec, j); /* use as tmp val */
     328         2601 :         array[j].r = LTG_GETLNODE(lu, siglen);
     329              :     }
     330              : 
     331           34 :     qsort(&array[FirstOffsetNumber], maxoff - FirstOffsetNumber + 1,
     332              :           sizeof(RIX), treekey_cmp);
     333              : 
     334           34 :     lu_l = lu_r = ru_l = ru_r = NULL;
     335         2635 :     for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
     336              :     {
     337         2601 :         lu = GETENTRY(entryvec, array[j].index);    /* use as tmp val */
     338         2601 :         if (j <= (maxoff - FirstOffsetNumber + 1) / 2)
     339              :         {
     340         1294 :             v->spl_left[v->spl_nleft] = array[j].index;
     341         1294 :             v->spl_nleft++;
     342         1294 :             if (lu_r == NULL || ltree_compare(LTG_GETRNODE(lu, siglen), lu_r) > 0)
     343         1293 :                 lu_r = LTG_GETRNODE(lu, siglen);
     344         1294 :             if (LTG_ISONENODE(lu))
     345         1282 :                 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         1307 :             v->spl_right[v->spl_nright] = array[j].index;
     362         1307 :             v->spl_nright++;
     363         1307 :             if (ru_r == NULL || ltree_compare(LTG_GETRNODE(lu, siglen), ru_r) > 0)
     364         1306 :                 ru_r = LTG_GETRNODE(lu, siglen);
     365         1307 :             if (LTG_ISONENODE(lu))
     366         1295 :                 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           34 :     if (lisat == false)
     383              :     {
     384           34 :         lisat = true;
     385           34 :         LOOPBYTE(siglen)
     386              :         {
     387           34 :             if (((unsigned char *) ls)[i] != 0xff)
     388              :             {
     389           34 :                 lisat = false;
     390           34 :                 break;
     391              :             }
     392              :         }
     393              :     }
     394              : 
     395           34 :     if (risat == false)
     396              :     {
     397           34 :         risat = true;
     398           34 :         LOOPBYTE(siglen)
     399              :         {
     400           34 :             if (((unsigned char *) rs)[i] != 0xff)
     401              :             {
     402           34 :                 risat = false;
     403           34 :                 break;
     404              :             }
     405              :         }
     406              :     }
     407              : 
     408           34 :     lu_l = LTG_GETLNODE(GETENTRY(entryvec, array[FirstOffsetNumber].index), siglen);
     409           34 :     lu = ltree_gist_alloc(lisat, ls, siglen, lu_l, lu_r);
     410              : 
     411           34 :     ru_l = LTG_GETLNODE(GETENTRY(entryvec, array[1 + ((maxoff - FirstOffsetNumber + 1) / 2)].index), siglen);
     412           34 :     ru = ltree_gist_alloc(risat, rs, siglen, ru_l, ru_r);
     413              : 
     414           34 :     pfree(ls);
     415           34 :     pfree(rs);
     416              : 
     417           34 :     v->spl_ldatum = PointerGetDatum(lu);
     418           34 :     v->spl_rdatum = PointerGetDatum(ru);
     419              : 
     420           34 :     PG_RETURN_POINTER(v);
     421              : }
     422              : 
     423              : static bool
     424           23 : gist_isparent(ltree_gist *key, ltree *query, int siglen)
     425              : {
     426           23 :     int32       numlevel = query->numlevel;
     427              :     int         i;
     428              : 
     429           99 :     for (i = query->numlevel; i >= 0; i--)
     430              :     {
     431           80 :         query->numlevel = i;
     432           84 :         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           19 :     query->numlevel = numlevel;
     441           19 :     return false;
     442              : }
     443              : 
     444              : static ltree *
     445           46 : copy_ltree(ltree *src)
     446              : {
     447           46 :     ltree      *dst = (ltree *) palloc0(VARSIZE(src));
     448              : 
     449           46 :     memcpy(dst, src, VARSIZE(src));
     450           46 :     return dst;
     451              : }
     452              : 
     453              : static bool
     454           23 : gist_ischild(ltree_gist *key, ltree *query, int siglen)
     455              : {
     456           23 :     ltree      *left = copy_ltree(LTG_GETLNODE(key, siglen));
     457           23 :     ltree      *right = copy_ltree(LTG_GETRNODE(key, siglen));
     458           23 :     bool        res = true;
     459              : 
     460           23 :     if (left->numlevel > query->numlevel)
     461           18 :         left->numlevel = query->numlevel;
     462              : 
     463           23 :     if (ltree_compare(query, left) < 0)
     464           19 :         res = false;
     465              : 
     466           23 :     if (right->numlevel > query->numlevel)
     467           17 :         right->numlevel = query->numlevel;
     468              : 
     469           23 :     if (res && ltree_compare(query, right) > 0)
     470            0 :         res = false;
     471              : 
     472           23 :     pfree(left);
     473           23 :     pfree(right);
     474              : 
     475           23 :     return res;
     476              : }
     477              : 
     478              : static bool
     479          202 : gist_qe(ltree_gist *key, lquery *query, int siglen)
     480              : {
     481          202 :     lquery_level *curq = LQUERY_FIRST(query);
     482          202 :     BITVECP     sign = LTG_SIGN(key);
     483          202 :     int         qlen = query->numlevel;
     484              : 
     485          202 :     if (LTG_ISALLTRUE(key))
     486            0 :         return true;
     487              : 
     488          793 :     while (qlen > 0)
     489              :     {
     490          591 :         if (curq->numvar && LQL_CANLOOKSIGN(curq))
     491              :         {
     492          389 :             bool        isexist = false;
     493          389 :             int         vlen = curq->numvar;
     494          389 :             lquery_variant *curv = LQL_FIRST(curq);
     495              : 
     496          389 :             while (vlen > 0)
     497              :             {
     498          389 :                 if (GETBIT(sign, HASHVAL(curv->val, siglen)))
     499              :                 {
     500          389 :                     isexist = true;
     501          389 :                     break;
     502              :                 }
     503            0 :                 curv = LVAR_NEXT(curv);
     504            0 :                 vlen--;
     505              :             }
     506          389 :             if (!isexist)
     507            0 :                 return false;
     508              :         }
     509              : 
     510          591 :         curq = LQL_NEXT(curq);
     511          591 :         qlen--;
     512              :     }
     513              : 
     514          202 :     return true;
     515              : }
     516              : 
     517              : static int
     518          264 : gist_tqcmp(ltree *t, lquery *q)
     519              : {
     520          264 :     ltree_level *al = LTREE_FIRST(t);
     521          264 :     lquery_level *ql = LQUERY_FIRST(q);
     522              :     lquery_variant *bl;
     523          264 :     int         an = t->numlevel;
     524          264 :     int         bn = q->firstgood;
     525          264 :     int         res = 0;
     526              : 
     527          320 :     while (an > 0 && bn > 0)
     528              :     {
     529          246 :         bl = LQL_FIRST(ql);
     530          246 :         if ((res = memcmp(al->name, bl->name, Min(al->len, bl->len))) == 0)
     531              :         {
     532           90 :             if (al->len != bl->len)
     533           34 :                 return al->len - bl->len;
     534              :         }
     535              :         else
     536          156 :             return res;
     537           56 :         an--;
     538           56 :         bn--;
     539           56 :         al = LEVEL_NEXT(al);
     540           56 :         ql = LQL_NEXT(ql);
     541              :     }
     542              : 
     543           74 :     return Min(t->numlevel, q->firstgood) - q->firstgood;
     544              : }
     545              : 
     546              : static bool
     547          202 : gist_between(ltree_gist *key, lquery *query, int siglen)
     548              : {
     549          202 :     if (query->firstgood == 0)
     550           38 :         return true;
     551              : 
     552          164 :     if (gist_tqcmp(LTG_GETLNODE(key, siglen), query) > 0)
     553           64 :         return false;
     554              : 
     555          100 :     if (gist_tqcmp(LTG_GETRNODE(key, siglen), query) < 0)
     556           40 :         return false;
     557              : 
     558           60 :     return true;
     559              : }
     560              : 
     561              : typedef struct LtreeSignature
     562              : {
     563              :     BITVECP     sign;
     564              :     int         siglen;
     565              : } LtreeSignature;
     566              : 
     567              : static bool
     568           76 : checkcondition_bit(void *cxt, ITEM *val)
     569              : {
     570           76 :     LtreeSignature *sig = cxt;
     571              : 
     572           76 :     return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(sig->sign, HASHVAL(val->val, sig->siglen)) : true;
     573              : }
     574              : 
     575              : static bool
     576           38 : gist_qtxt(ltree_gist *key, ltxtquery *query, int siglen)
     577              : {
     578              :     LtreeSignature sig;
     579              : 
     580           38 :     if (LTG_ISALLTRUE(key))
     581            0 :         return true;
     582              : 
     583           38 :     sig.sign = LTG_SIGN(key);
     584           38 :     sig.siglen = siglen;
     585              : 
     586           38 :     return ltree_execute(GETQUERY(query),
     587              :                          &sig, false,
     588              :                          checkcondition_bit);
     589              : }
     590              : 
     591              : static bool
     592           31 : arrq_cons(ltree_gist *key, ArrayType *_query, int siglen)
     593              : {
     594           31 :     lquery     *query = (lquery *) ARR_DATA_PTR(_query);
     595           31 :     int         num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
     596              : 
     597           31 :     if (ARR_NDIM(_query) > 1)
     598            0 :         ereport(ERROR,
     599              :                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
     600              :                  errmsg("array must be one-dimensional")));
     601           31 :     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           65 :     while (num > 0)
     607              :     {
     608           48 :         if (gist_qe(key, query, siglen) && gist_between(key, query, siglen))
     609           14 :             return true;
     610           34 :         num--;
     611           34 :         query = NEXTVAL(query);
     612              :     }
     613           17 :     return false;
     614              : }
     615              : 
     616              : Datum
     617        10140 : ltree_consistent(PG_FUNCTION_ARGS)
     618              : {
     619        10140 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     620        10140 :     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     621              : #ifdef NOT_USED
     622              :     Oid         subtype = PG_GETARG_OID(3);
     623              : #endif
     624        10140 :     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
     625        10140 :     int         siglen = LTREE_GET_SIGLEN();
     626        10140 :     ltree_gist *key = (ltree_gist *) DatumGetPointer(entry->key);
     627        10140 :     void       *query = NULL;
     628        10140 :     bool        res = false;
     629              : 
     630              :     /* All cases served by this function are exact */
     631        10140 :     *recheck = false;
     632              : 
     633        10140 :     switch (strategy)
     634              :     {
     635          328 :         case BTLessStrategyNumber:
     636          328 :             query = PG_GETARG_LTREE_P(1);
     637          328 :             res = (GIST_LEAF(entry)) ?
     638          313 :                 (ltree_compare((ltree *) query, LTG_NODE(key)) > 0)
     639              :                 :
     640          641 :                 (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0);
     641          328 :             break;
     642          328 :         case BTLessEqualStrategyNumber:
     643          328 :             query = PG_GETARG_LTREE_P(1);
     644          328 :             res = (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0);
     645          328 :             break;
     646          309 :         case BTEqualStrategyNumber:
     647          309 :             query = PG_GETARG_LTREE_P(1);
     648          309 :             if (GIST_LEAF(entry))
     649          286 :                 res = (ltree_compare((ltree *) query, LTG_NODE(key)) == 0);
     650              :             else
     651           46 :                 res = (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0
     652           31 :                        &&
     653            8 :                        ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0);
     654          309 :             break;
     655          939 :         case BTGreaterEqualStrategyNumber:
     656          939 :             query = PG_GETARG_LTREE_P(1);
     657          939 :             res = (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0);
     658          939 :             break;
     659          939 :         case BTGreaterStrategyNumber:
     660          939 :             query = PG_GETARG_LTREE_P(1);
     661          939 :             res = (GIST_LEAF(entry)) ?
     662          924 :                 (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) < 0)
     663              :                 :
     664         1863 :                 (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0);
     665          939 :             break;
     666          187 :         case 10:
     667          187 :             query = PG_GETARG_LTREE_P_COPY(1);
     668          187 :             res = (GIST_LEAF(entry)) ?
     669          164 :                 inner_isparent((ltree *) query, LTG_NODE(key))
     670              :                 :
     671          351 :                 gist_isparent(key, (ltree *) query, siglen);
     672          187 :             break;
     673          187 :         case 11:
     674          187 :             query = PG_GETARG_LTREE_P(1);
     675          187 :             res = (GIST_LEAF(entry)) ?
     676          164 :                 inner_isparent(LTG_NODE(key), (ltree *) query)
     677              :                 :
     678          351 :                 gist_ischild(key, (ltree *) query, siglen);
     679          187 :             break;
     680         4214 :         case 12:
     681              :         case 13:
     682         4214 :             query = PG_GETARG_LQUERY_P(1);
     683         4214 :             if (GIST_LEAF(entry))
     684         4060 :                 res = DatumGetBool(DirectFunctionCall2(ltq_regex,
     685              :                                                        PointerGetDatum(LTG_NODE(key)),
     686              :                                                        PointerGetDatum((lquery *) query)
     687              :                                                        ));
     688              :             else
     689          308 :                 res = (gist_qe(key, (lquery *) query, siglen) &&
     690          154 :                        gist_between(key, (lquery *) query, siglen));
     691         4214 :             break;
     692         2050 :         case 14:
     693              :         case 15:
     694         2050 :             query = PG_GETARG_LTXTQUERY_P(1);
     695         2050 :             if (GIST_LEAF(entry))
     696         2012 :                 res = DatumGetBool(DirectFunctionCall2(ltxtq_exec,
     697              :                                                        PointerGetDatum(LTG_NODE(key)),
     698              :                                                        PointerGetDatum((ltxtquery *) query)
     699              :                                                        ));
     700              :             else
     701           38 :                 res = gist_qtxt(key, (ltxtquery *) query, siglen);
     702         2050 :             break;
     703          659 :         case 16:
     704              :         case 17:
     705          659 :             query = PG_GETARG_ARRAYTYPE_P(1);
     706          659 :             if (GIST_LEAF(entry))
     707          628 :                 res = DatumGetBool(DirectFunctionCall2(lt_q_regex,
     708              :                                                        PointerGetDatum(LTG_NODE(key)),
     709              :                                                        PointerGetDatum((ArrayType *) query)
     710              :                                                        ));
     711              :             else
     712           31 :                 res = arrq_cons(key, (ArrayType *) query, siglen);
     713          659 :             break;
     714            0 :         default:
     715              :             /* internal error */
     716            0 :             elog(ERROR, "unrecognized StrategyNumber: %d", strategy);
     717              :     }
     718              : 
     719        10140 :     PG_FREE_IF_COPY(query, 1);
     720        10140 :     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