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

Generated by: LCOV version 1.14