Header And Logo

PostgreSQL
| The world's most advanced open source database.

ltree_gist.c

Go to the documentation of this file.
00001 /*
00002  * GiST support for ltree
00003  * Teodor Sigaev <[email protected]>
00004  * contrib/ltree/ltree_gist.c
00005  */
00006 #include "postgres.h"
00007 
00008 #include "access/gist.h"
00009 #include "access/nbtree.h"
00010 #include "access/skey.h"
00011 #include "utils/array.h"
00012 #include "crc32.h"
00013 #include "ltree.h"
00014 
00015 #define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
00016 
00017 PG_FUNCTION_INFO_V1(ltree_gist_in);
00018 Datum       ltree_gist_in(PG_FUNCTION_ARGS);
00019 
00020 PG_FUNCTION_INFO_V1(ltree_gist_out);
00021 Datum       ltree_gist_out(PG_FUNCTION_ARGS);
00022 
00023 Datum
00024 ltree_gist_in(PG_FUNCTION_ARGS)
00025 {
00026     ereport(ERROR,
00027             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00028              errmsg("ltree_gist_in() not implemented")));
00029     PG_RETURN_DATUM(0);
00030 }
00031 
00032 Datum
00033 ltree_gist_out(PG_FUNCTION_ARGS)
00034 {
00035     ereport(ERROR,
00036             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00037              errmsg("ltree_gist_out() not implemented")));
00038     PG_RETURN_DATUM(0);
00039 }
00040 
00041 PG_FUNCTION_INFO_V1(ltree_compress);
00042 Datum       ltree_compress(PG_FUNCTION_ARGS);
00043 
00044 PG_FUNCTION_INFO_V1(ltree_decompress);
00045 Datum       ltree_decompress(PG_FUNCTION_ARGS);
00046 
00047 PG_FUNCTION_INFO_V1(ltree_same);
00048 Datum       ltree_same(PG_FUNCTION_ARGS);
00049 
00050 PG_FUNCTION_INFO_V1(ltree_union);
00051 Datum       ltree_union(PG_FUNCTION_ARGS);
00052 
00053 PG_FUNCTION_INFO_V1(ltree_penalty);
00054 Datum       ltree_penalty(PG_FUNCTION_ARGS);
00055 
00056 PG_FUNCTION_INFO_V1(ltree_picksplit);
00057 Datum       ltree_picksplit(PG_FUNCTION_ARGS);
00058 
00059 PG_FUNCTION_INFO_V1(ltree_consistent);
00060 Datum       ltree_consistent(PG_FUNCTION_ARGS);
00061 
00062 #define ISEQ(a,b)   ( (a)->numlevel == (b)->numlevel && ltree_compare(a,b)==0 )
00063 #define GETENTRY(vec,pos) ((ltree_gist *) DatumGetPointer((vec)->vector[(pos)].key))
00064 
00065 Datum
00066 ltree_compress(PG_FUNCTION_ARGS)
00067 {
00068     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
00069     GISTENTRY  *retval = entry;
00070 
00071     if (entry->leafkey)
00072     {                           /* ltree */
00073         ltree_gist *key;
00074         ltree      *val = (ltree *) DatumGetPointer(PG_DETOAST_DATUM(entry->key));
00075         int4        len = LTG_HDRSIZE + VARSIZE(val);
00076 
00077         key = (ltree_gist *) palloc(len);
00078         SET_VARSIZE(key, len);
00079         key->flag = LTG_ONENODE;
00080         memcpy((void *) LTG_NODE(key), (void *) val, VARSIZE(val));
00081 
00082         retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
00083         gistentryinit(*retval, PointerGetDatum(key),
00084                       entry->rel, entry->page,
00085                       entry->offset, FALSE);
00086     }
00087     PG_RETURN_POINTER(retval);
00088 }
00089 
00090 Datum
00091 ltree_decompress(PG_FUNCTION_ARGS)
00092 {
00093     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
00094     ltree_gist *key = (ltree_gist *) DatumGetPointer(PG_DETOAST_DATUM(entry->key));
00095 
00096     if (PointerGetDatum(key) != entry->key)
00097     {
00098         GISTENTRY  *retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
00099 
00100         gistentryinit(*retval, PointerGetDatum(key),
00101                       entry->rel, entry->page,
00102                       entry->offset, FALSE);
00103         PG_RETURN_POINTER(retval);
00104     }
00105     PG_RETURN_POINTER(entry);
00106 }
00107 
00108 Datum
00109 ltree_same(PG_FUNCTION_ARGS)
00110 {
00111     ltree_gist *a = (ltree_gist *) PG_GETARG_POINTER(0);
00112     ltree_gist *b = (ltree_gist *) PG_GETARG_POINTER(1);
00113     bool       *result = (bool *) PG_GETARG_POINTER(2);
00114 
00115     *result = false;
00116     if (LTG_ISONENODE(a) != LTG_ISONENODE(b))
00117         PG_RETURN_POINTER(result);
00118 
00119     if (LTG_ISONENODE(a))
00120         *result = (ISEQ(LTG_NODE(a), LTG_NODE(b))) ? true : false;
00121     else
00122     {
00123         int4        i;
00124         BITVECP     sa = LTG_SIGN(a),
00125                     sb = LTG_SIGN(b);
00126 
00127         if (LTG_ISALLTRUE(a) != LTG_ISALLTRUE(b))
00128             PG_RETURN_POINTER(result);
00129 
00130         if (!ISEQ(LTG_LNODE(a), LTG_LNODE(b)))
00131             PG_RETURN_POINTER(result);
00132         if (!ISEQ(LTG_RNODE(a), LTG_RNODE(b)))
00133             PG_RETURN_POINTER(result);
00134 
00135         *result = true;
00136         if (!LTG_ISALLTRUE(a))
00137         {
00138             LOOPBYTE
00139             {
00140                 if (sa[i] != sb[i])
00141                 {
00142                     *result = false;
00143                     break;
00144                 }
00145             }
00146         }
00147     }
00148 
00149     PG_RETURN_POINTER(result);
00150 }
00151 
00152 static void
00153 hashing(BITVECP sign, ltree *t)
00154 {
00155     int         tlen = t->numlevel;
00156     ltree_level *cur = LTREE_FIRST(t);
00157     int         hash;
00158 
00159     while (tlen > 0)
00160     {
00161         hash = ltree_crc32_sz(cur->name, cur->len);
00162         HASH(sign, hash);
00163         cur = LEVEL_NEXT(cur);
00164         tlen--;
00165     }
00166 }
00167 
00168 Datum
00169 ltree_union(PG_FUNCTION_ARGS)
00170 {
00171     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
00172     int        *size = (int *) PG_GETARG_POINTER(1);
00173     BITVEC      base;
00174     int4        i,
00175                 j;
00176     ltree_gist *result,
00177                *cur;
00178     ltree      *left = NULL,
00179                *right = NULL,
00180                *curtree;
00181     bool        isalltrue = false;
00182     bool        isleqr;
00183 
00184     MemSet((void *) base, 0, sizeof(BITVEC));
00185     for (j = 0; j < entryvec->n; j++)
00186     {
00187         cur = GETENTRY(entryvec, j);
00188         if (LTG_ISONENODE(cur))
00189         {
00190             curtree = LTG_NODE(cur);
00191             hashing(base, curtree);
00192             if (!left || ltree_compare(left, curtree) > 0)
00193                 left = curtree;
00194             if (!right || ltree_compare(right, curtree) < 0)
00195                 right = curtree;
00196         }
00197         else
00198         {
00199             if (isalltrue || LTG_ISALLTRUE(cur))
00200                 isalltrue = true;
00201             else
00202             {
00203                 BITVECP     sc = LTG_SIGN(cur);
00204 
00205                 LOOPBYTE
00206                     ((unsigned char *) base)[i] |= sc[i];
00207             }
00208 
00209             curtree = LTG_LNODE(cur);
00210             if (!left || ltree_compare(left, curtree) > 0)
00211                 left = curtree;
00212             curtree = LTG_RNODE(cur);
00213             if (!right || ltree_compare(right, curtree) < 0)
00214                 right = curtree;
00215         }
00216     }
00217 
00218     if (isalltrue == false)
00219     {
00220         isalltrue = true;
00221         LOOPBYTE
00222         {
00223             if (((unsigned char *) base)[i] != 0xff)
00224             {
00225                 isalltrue = false;
00226                 break;
00227             }
00228         }
00229     }
00230 
00231     isleqr = (left == right || ISEQ(left, right)) ? true : false;
00232     *size = LTG_HDRSIZE + ((isalltrue) ? 0 : SIGLEN) + VARSIZE(left) + ((isleqr) ? 0 : VARSIZE(right));
00233 
00234     result = (ltree_gist *) palloc(*size);
00235     SET_VARSIZE(result, *size);
00236     result->flag = 0;
00237 
00238     if (isalltrue)
00239         result->flag |= LTG_ALLTRUE;
00240     else
00241         memcpy((void *) LTG_SIGN(result), base, SIGLEN);
00242 
00243     memcpy((void *) LTG_LNODE(result), (void *) left, VARSIZE(left));
00244     if (isleqr)
00245         result->flag |= LTG_NORIGHT;
00246     else
00247         memcpy((void *) LTG_RNODE(result), (void *) right, VARSIZE(right));
00248 
00249     PG_RETURN_POINTER(result);
00250 }
00251 
00252 Datum
00253 ltree_penalty(PG_FUNCTION_ARGS)
00254 {
00255     ltree_gist *origval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
00256     ltree_gist *newval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
00257     float      *penalty = (float *) PG_GETARG_POINTER(2);
00258     int4        cmpr,
00259                 cmpl;
00260 
00261     cmpl = ltree_compare(LTG_GETLNODE(origval), LTG_GETLNODE(newval));
00262     cmpr = ltree_compare(LTG_GETRNODE(newval), LTG_GETRNODE(origval));
00263 
00264     *penalty = Max(cmpl, 0) + Max(cmpr, 0);
00265 
00266     PG_RETURN_POINTER(penalty);
00267 }
00268 
00269 /* used for sorting */
00270 typedef struct rix
00271 {
00272     int         index;
00273     ltree      *r;
00274 } RIX;
00275 
00276 static int
00277 treekey_cmp(const void *a, const void *b)
00278 {
00279     return ltree_compare(
00280                          ((RIX *) a)->r,
00281                          ((RIX *) b)->r
00282         );
00283 }
00284 
00285 
00286 Datum
00287 ltree_picksplit(PG_FUNCTION_ARGS)
00288 {
00289     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
00290     GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
00291     OffsetNumber j;
00292     int4        i;
00293     RIX        *array;
00294     OffsetNumber maxoff;
00295     int         nbytes;
00296     int         size;
00297     ltree      *lu_l,
00298                *lu_r,
00299                *ru_l,
00300                *ru_r;
00301     ltree_gist *lu,
00302                *ru;
00303     BITVEC      ls,
00304                 rs;
00305     bool        lisat = false,
00306                 risat = false,
00307                 isleqr;
00308 
00309     memset((void *) ls, 0, sizeof(BITVEC));
00310     memset((void *) rs, 0, sizeof(BITVEC));
00311     maxoff = entryvec->n - 1;
00312     nbytes = (maxoff + 2) * sizeof(OffsetNumber);
00313     v->spl_left = (OffsetNumber *) palloc(nbytes);
00314     v->spl_right = (OffsetNumber *) palloc(nbytes);
00315     v->spl_nleft = 0;
00316     v->spl_nright = 0;
00317     array = (RIX *) palloc(sizeof(RIX) * (maxoff + 1));
00318 
00319     /* copy the data into RIXes, and sort the RIXes */
00320     for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
00321     {
00322         array[j].index = j;
00323         lu = GETENTRY(entryvec, j);     /* use as tmp val */
00324         array[j].r = LTG_GETLNODE(lu);
00325     }
00326 
00327     qsort((void *) &array[FirstOffsetNumber], maxoff - FirstOffsetNumber + 1,
00328           sizeof(RIX), treekey_cmp);
00329 
00330     lu_l = lu_r = ru_l = ru_r = NULL;
00331     for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
00332     {
00333         lu = GETENTRY(entryvec, array[j].index);        /* use as tmp val */
00334         if (j <= (maxoff - FirstOffsetNumber + 1) / 2)
00335         {
00336             v->spl_left[v->spl_nleft] = array[j].index;
00337             v->spl_nleft++;
00338             if (lu_r == NULL || ltree_compare(LTG_GETRNODE(lu), lu_r) > 0)
00339                 lu_r = LTG_GETRNODE(lu);
00340             if (LTG_ISONENODE(lu))
00341                 hashing(ls, LTG_NODE(lu));
00342             else
00343             {
00344                 if (lisat || LTG_ISALLTRUE(lu))
00345                     lisat = true;
00346                 else
00347                 {
00348                     BITVECP     sc = LTG_SIGN(lu);
00349 
00350                     LOOPBYTE
00351                         ((unsigned char *) ls)[i] |= sc[i];
00352                 }
00353             }
00354         }
00355         else
00356         {
00357             v->spl_right[v->spl_nright] = array[j].index;
00358             v->spl_nright++;
00359             if (ru_r == NULL || ltree_compare(LTG_GETRNODE(lu), ru_r) > 0)
00360                 ru_r = LTG_GETRNODE(lu);
00361             if (LTG_ISONENODE(lu))
00362                 hashing(rs, LTG_NODE(lu));
00363             else
00364             {
00365                 if (risat || LTG_ISALLTRUE(lu))
00366                     risat = true;
00367                 else
00368                 {
00369                     BITVECP     sc = LTG_SIGN(lu);
00370 
00371                     LOOPBYTE
00372                         ((unsigned char *) rs)[i] |= sc[i];
00373                 }
00374             }
00375         }
00376     }
00377 
00378     if (lisat == false)
00379     {
00380         lisat = true;
00381         LOOPBYTE
00382         {
00383             if (((unsigned char *) ls)[i] != 0xff)
00384             {
00385                 lisat = false;
00386                 break;
00387             }
00388         }
00389     }
00390 
00391     if (risat == false)
00392     {
00393         risat = true;
00394         LOOPBYTE
00395         {
00396             if (((unsigned char *) rs)[i] != 0xff)
00397             {
00398                 risat = false;
00399                 break;
00400             }
00401         }
00402     }
00403 
00404     lu_l = LTG_GETLNODE(GETENTRY(entryvec, array[FirstOffsetNumber].index));
00405     isleqr = (lu_l == lu_r || ISEQ(lu_l, lu_r)) ? true : false;
00406     size = LTG_HDRSIZE + ((lisat) ? 0 : SIGLEN) + VARSIZE(lu_l) + ((isleqr) ? 0 : VARSIZE(lu_r));
00407     lu = (ltree_gist *) palloc(size);
00408     SET_VARSIZE(lu, size);
00409     lu->flag = 0;
00410     if (lisat)
00411         lu->flag |= LTG_ALLTRUE;
00412     else
00413         memcpy((void *) LTG_SIGN(lu), ls, SIGLEN);
00414     memcpy((void *) LTG_LNODE(lu), (void *) lu_l, VARSIZE(lu_l));
00415     if (isleqr)
00416         lu->flag |= LTG_NORIGHT;
00417     else
00418         memcpy((void *) LTG_RNODE(lu), (void *) lu_r, VARSIZE(lu_r));
00419 
00420 
00421     ru_l = LTG_GETLNODE(GETENTRY(entryvec, array[1 + ((maxoff - FirstOffsetNumber + 1) / 2)].index));
00422     isleqr = (ru_l == ru_r || ISEQ(ru_l, ru_r)) ? true : false;
00423     size = LTG_HDRSIZE + ((risat) ? 0 : SIGLEN) + VARSIZE(ru_l) + ((isleqr) ? 0 : VARSIZE(ru_r));
00424     ru = (ltree_gist *) palloc(size);
00425     SET_VARSIZE(ru, size);
00426     ru->flag = 0;
00427     if (risat)
00428         ru->flag |= LTG_ALLTRUE;
00429     else
00430         memcpy((void *) LTG_SIGN(ru), rs, SIGLEN);
00431     memcpy((void *) LTG_LNODE(ru), (void *) ru_l, VARSIZE(ru_l));
00432     if (isleqr)
00433         ru->flag |= LTG_NORIGHT;
00434     else
00435         memcpy((void *) LTG_RNODE(ru), (void *) ru_r, VARSIZE(ru_r));
00436 
00437     v->spl_ldatum = PointerGetDatum(lu);
00438     v->spl_rdatum = PointerGetDatum(ru);
00439 
00440     PG_RETURN_POINTER(v);
00441 }
00442 
00443 static bool
00444 gist_isparent(ltree_gist *key, ltree *query)
00445 {
00446     int4        numlevel = query->numlevel;
00447     int         i;
00448 
00449     for (i = query->numlevel; i >= 0; i--)
00450     {
00451         query->numlevel = i;
00452         if (ltree_compare(query, LTG_GETLNODE(key)) >= 0 && ltree_compare(query, LTG_GETRNODE(key)) <= 0)
00453         {
00454             query->numlevel = numlevel;
00455             return true;
00456         }
00457     }
00458 
00459     query->numlevel = numlevel;
00460     return false;
00461 }
00462 
00463 static ltree *
00464 copy_ltree(ltree *src)
00465 {
00466     ltree      *dst = (ltree *) palloc(VARSIZE(src));
00467 
00468     memcpy(dst, src, VARSIZE(src));
00469     return dst;
00470 }
00471 
00472 static bool
00473 gist_ischild(ltree_gist *key, ltree *query)
00474 {
00475     ltree      *left = copy_ltree(LTG_GETLNODE(key));
00476     ltree      *right = copy_ltree(LTG_GETRNODE(key));
00477     bool        res = true;
00478 
00479     if (left->numlevel > query->numlevel)
00480         left->numlevel = query->numlevel;
00481 
00482     if (ltree_compare(query, left) < 0)
00483         res = false;
00484 
00485     if (right->numlevel > query->numlevel)
00486         right->numlevel = query->numlevel;
00487 
00488     if (res && ltree_compare(query, right) > 0)
00489         res = false;
00490 
00491     pfree(left);
00492     pfree(right);
00493 
00494     return res;
00495 }
00496 
00497 static bool
00498 gist_qe(ltree_gist *key, lquery *query)
00499 {
00500     lquery_level *curq = LQUERY_FIRST(query);
00501     BITVECP     sign = LTG_SIGN(key);
00502     int         qlen = query->numlevel;
00503 
00504     if (LTG_ISALLTRUE(key))
00505         return true;
00506 
00507     while (qlen > 0)
00508     {
00509         if (curq->numvar && LQL_CANLOOKSIGN(curq))
00510         {
00511             bool        isexist = false;
00512             int         vlen = curq->numvar;
00513             lquery_variant *curv = LQL_FIRST(curq);
00514 
00515             while (vlen > 0)
00516             {
00517                 if (GETBIT(sign, HASHVAL(curv->val)))
00518                 {
00519                     isexist = true;
00520                     break;
00521                 }
00522                 curv = LVAR_NEXT(curv);
00523                 vlen--;
00524             }
00525             if (!isexist)
00526                 return false;
00527         }
00528 
00529         curq = LQL_NEXT(curq);
00530         qlen--;
00531     }
00532 
00533     return true;
00534 }
00535 
00536 static int
00537 gist_tqcmp(ltree *t, lquery *q)
00538 {
00539     ltree_level *al = LTREE_FIRST(t);
00540     lquery_level *ql = LQUERY_FIRST(q);
00541     lquery_variant *bl;
00542     int         an = t->numlevel;
00543     int         bn = q->firstgood;
00544     int         res = 0;
00545 
00546     while (an > 0 && bn > 0)
00547     {
00548         bl = LQL_FIRST(ql);
00549         if ((res = memcmp(al->name, bl->name, Min(al->len, bl->len))) == 0)
00550         {
00551             if (al->len != bl->len)
00552                 return al->len - bl->len;
00553         }
00554         else
00555             return res;
00556         an--;
00557         bn--;
00558         al = LEVEL_NEXT(al);
00559         ql = LQL_NEXT(ql);
00560     }
00561 
00562     return Min(t->numlevel, q->firstgood) - q->firstgood;
00563 }
00564 
00565 static bool
00566 gist_between(ltree_gist *key, lquery *query)
00567 {
00568     if (query->firstgood == 0)
00569         return true;
00570 
00571     if (gist_tqcmp(LTG_GETLNODE(key), query) > 0)
00572         return false;
00573 
00574     if (gist_tqcmp(LTG_GETRNODE(key), query) < 0)
00575         return false;
00576 
00577     return true;
00578 }
00579 
00580 static bool
00581 checkcondition_bit(void *checkval, ITEM *val)
00582 {
00583     return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(checkval, HASHVAL(val->val)) : true;
00584 }
00585 
00586 static bool
00587 gist_qtxt(ltree_gist *key, ltxtquery *query)
00588 {
00589     if (LTG_ISALLTRUE(key))
00590         return true;
00591 
00592     return ltree_execute(
00593                          GETQUERY(query),
00594                          (void *) LTG_SIGN(key), false,
00595                          checkcondition_bit
00596         );
00597 }
00598 
00599 static bool
00600 arrq_cons(ltree_gist *key, ArrayType *_query)
00601 {
00602     lquery     *query = (lquery *) ARR_DATA_PTR(_query);
00603     int         num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
00604 
00605     if (ARR_NDIM(_query) > 1)
00606         ereport(ERROR,
00607                 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
00608                  errmsg("array must be one-dimensional")));
00609     if (array_contains_nulls(_query))
00610         ereport(ERROR,
00611                 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
00612                  errmsg("array must not contain nulls")));
00613 
00614     while (num > 0)
00615     {
00616         if (gist_qe(key, query) && gist_between(key, query))
00617             return true;
00618         num--;
00619         query = NEXTVAL(query);
00620     }
00621     return false;
00622 }
00623 
00624 Datum
00625 ltree_consistent(PG_FUNCTION_ARGS)
00626 {
00627     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
00628     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
00629 
00630     /* Oid      subtype = PG_GETARG_OID(3); */
00631     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
00632     ltree_gist *key = (ltree_gist *) DatumGetPointer(entry->key);
00633     void       *query = NULL;
00634     bool        res = false;
00635 
00636     /* All cases served by this function are exact */
00637     *recheck = false;
00638 
00639     switch (strategy)
00640     {
00641         case BTLessStrategyNumber:
00642             query = PG_GETARG_LTREE(1);
00643             res = (GIST_LEAF(entry)) ?
00644                 (ltree_compare((ltree *) query, LTG_NODE(key)) > 0)
00645                 :
00646                 (ltree_compare((ltree *) query, LTG_GETLNODE(key)) >= 0);
00647             break;
00648         case BTLessEqualStrategyNumber:
00649             query = PG_GETARG_LTREE(1);
00650             res = (ltree_compare((ltree *) query, LTG_GETLNODE(key)) >= 0);
00651             break;
00652         case BTEqualStrategyNumber:
00653             query = PG_GETARG_LTREE(1);
00654             if (GIST_LEAF(entry))
00655                 res = (ltree_compare((ltree *) query, LTG_NODE(key)) == 0);
00656             else
00657                 res = (
00658                        ltree_compare((ltree *) query, LTG_GETLNODE(key)) >= 0
00659                        &&
00660                        ltree_compare((ltree *) query, LTG_GETRNODE(key)) <= 0
00661                     );
00662             break;
00663         case BTGreaterEqualStrategyNumber:
00664             query = PG_GETARG_LTREE(1);
00665             res = (ltree_compare((ltree *) query, LTG_GETRNODE(key)) <= 0);
00666             break;
00667         case BTGreaterStrategyNumber:
00668             query = PG_GETARG_LTREE(1);
00669             res = (GIST_LEAF(entry)) ?
00670                 (ltree_compare((ltree *) query, LTG_GETRNODE(key)) < 0)
00671                 :
00672                 (ltree_compare((ltree *) query, LTG_GETRNODE(key)) <= 0);
00673             break;
00674         case 10:
00675             query = PG_GETARG_LTREE_COPY(1);
00676             res = (GIST_LEAF(entry)) ?
00677                 inner_isparent((ltree *) query, LTG_NODE(key))
00678                 :
00679                 gist_isparent(key, (ltree *) query);
00680             break;
00681         case 11:
00682             query = PG_GETARG_LTREE(1);
00683             res = (GIST_LEAF(entry)) ?
00684                 inner_isparent(LTG_NODE(key), (ltree *) query)
00685                 :
00686                 gist_ischild(key, (ltree *) query);
00687             break;
00688         case 12:
00689         case 13:
00690             query = PG_GETARG_LQUERY(1);
00691             if (GIST_LEAF(entry))
00692                 res = DatumGetBool(DirectFunctionCall2(ltq_regex,
00693                                               PointerGetDatum(LTG_NODE(key)),
00694                                             PointerGetDatum((lquery *) query)
00695                                                        ));
00696             else
00697                 res = (gist_qe(key, (lquery *) query) && gist_between(key, (lquery *) query));
00698             break;
00699         case 14:
00700         case 15:
00701             query = PG_GETARG_LQUERY(1);
00702             if (GIST_LEAF(entry))
00703                 res = DatumGetBool(DirectFunctionCall2(ltxtq_exec,
00704                                               PointerGetDatum(LTG_NODE(key)),
00705                                             PointerGetDatum((lquery *) query)
00706                                                        ));
00707             else
00708                 res = gist_qtxt(key, (ltxtquery *) query);
00709             break;
00710         case 16:
00711         case 17:
00712             query = DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
00713             if (GIST_LEAF(entry))
00714                 res = DatumGetBool(DirectFunctionCall2(lt_q_regex,
00715                                               PointerGetDatum(LTG_NODE(key)),
00716                                          PointerGetDatum((ArrayType *) query)
00717                                                        ));
00718             else
00719                 res = arrq_cons(key, (ArrayType *) query);
00720             break;
00721         default:
00722             /* internal error */
00723             elog(ERROR, "unrecognized StrategyNumber: %d", strategy);
00724     }
00725 
00726     PG_FREE_IF_COPY(query, 1);
00727     PG_RETURN_BOOL(res);
00728 }