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

Generated by: LCOV version 2.3.2-1