LCOV - code coverage report
Current view: top level - contrib/ltree - ltree_op.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 284 312 91.0 %
Date: 2019-11-22 07:06:56 Functions: 44 46 95.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * op function for ltree
       3             :  * Teodor Sigaev <teodor@stack.net>
       4             :  * contrib/ltree/ltree_op.c
       5             :  */
       6             : #include "postgres.h"
       7             : 
       8             : #include <ctype.h>
       9             : 
      10             : #include "access/htup_details.h"
      11             : #include "catalog/pg_statistic.h"
      12             : #include "ltree.h"
      13             : #include "utils/builtins.h"
      14             : #include "utils/lsyscache.h"
      15             : #include "utils/selfuncs.h"
      16             : 
      17           6 : PG_MODULE_MAGIC;
      18             : 
      19             : /* compare functions */
      20           6 : PG_FUNCTION_INFO_V1(ltree_cmp);
      21           6 : PG_FUNCTION_INFO_V1(ltree_lt);
      22           6 : PG_FUNCTION_INFO_V1(ltree_le);
      23           6 : PG_FUNCTION_INFO_V1(ltree_eq);
      24           4 : PG_FUNCTION_INFO_V1(ltree_ne);
      25           6 : PG_FUNCTION_INFO_V1(ltree_ge);
      26           6 : PG_FUNCTION_INFO_V1(ltree_gt);
      27           6 : PG_FUNCTION_INFO_V1(nlevel);
      28           6 : PG_FUNCTION_INFO_V1(ltree_isparent);
      29           6 : PG_FUNCTION_INFO_V1(ltree_risparent);
      30           6 : PG_FUNCTION_INFO_V1(subltree);
      31          12 : PG_FUNCTION_INFO_V1(subpath);
      32          12 : PG_FUNCTION_INFO_V1(ltree_index);
      33           6 : PG_FUNCTION_INFO_V1(ltree_addltree);
      34           6 : PG_FUNCTION_INFO_V1(ltree_addtext);
      35           4 : PG_FUNCTION_INFO_V1(ltree_textadd);
      36          32 : PG_FUNCTION_INFO_V1(lca);
      37           6 : PG_FUNCTION_INFO_V1(ltree2text);
      38           6 : PG_FUNCTION_INFO_V1(text2ltree);
      39           6 : PG_FUNCTION_INFO_V1(ltreeparentsel);
      40             : 
      41             : int
      42      170390 : ltree_compare(const ltree *a, const ltree *b)
      43             : {
      44      170390 :     ltree_level *al = LTREE_FIRST(a);
      45      170390 :     ltree_level *bl = LTREE_FIRST(b);
      46      170390 :     int         an = a->numlevel;
      47      170390 :     int         bn = b->numlevel;
      48             : 
      49      435330 :     while (an > 0 && bn > 0)
      50             :     {
      51             :         int         res;
      52             : 
      53      257746 :         if ((res = memcmp(al->name, bl->name, Min(al->len, bl->len))) == 0)
      54             :         {
      55      107276 :             if (al->len != bl->len)
      56       12726 :                 return (al->len - bl->len) * 10 * (an + 1);
      57             :         }
      58             :         else
      59             :         {
      60      150470 :             if (res < 0)
      61       70796 :                 res = -1;
      62             :             else
      63       79674 :                 res = 1;
      64      150470 :             return res * 10 * (an + 1);
      65             :         }
      66             : 
      67       94550 :         an--;
      68       94550 :         bn--;
      69       94550 :         al = LEVEL_NEXT(al);
      70       94550 :         bl = LEVEL_NEXT(bl);
      71             :     }
      72             : 
      73        7194 :     return (a->numlevel - b->numlevel) * 10 * (an + 1);
      74             : }
      75             : 
      76             : #define RUNCMP                      \
      77             : ltree *a = PG_GETARG_LTREE_P(0);    \
      78             : ltree *b = PG_GETARG_LTREE_P(1);    \
      79             : int res = ltree_compare(a,b);       \
      80             : PG_FREE_IF_COPY(a,0);               \
      81             : PG_FREE_IF_COPY(b,1)
      82             : 
      83             : Datum
      84      101438 : ltree_cmp(PG_FUNCTION_ARGS)
      85             : {
      86      101438 :     RUNCMP;
      87      101438 :     PG_RETURN_INT32(res);
      88             : }
      89             : 
      90             : Datum
      91        2264 : ltree_lt(PG_FUNCTION_ARGS)
      92             : {
      93        2264 :     RUNCMP;
      94        2264 :     PG_RETURN_BOOL((res < 0) ? true : false);
      95             : }
      96             : 
      97             : Datum
      98        2266 : ltree_le(PG_FUNCTION_ARGS)
      99             : {
     100        2266 :     RUNCMP;
     101        2266 :     PG_RETURN_BOOL((res <= 0) ? true : false);
     102             : }
     103             : 
     104             : Datum
     105        2018 : ltree_eq(PG_FUNCTION_ARGS)
     106             : {
     107        2018 :     RUNCMP;
     108        2018 :     PG_RETURN_BOOL((res == 0) ? true : false);
     109             : }
     110             : 
     111             : Datum
     112        3798 : ltree_ge(PG_FUNCTION_ARGS)
     113             : {
     114        3798 :     RUNCMP;
     115        3798 :     PG_RETURN_BOOL((res >= 0) ? true : false);
     116             : }
     117             : 
     118             : Datum
     119        3796 : ltree_gt(PG_FUNCTION_ARGS)
     120             : {
     121        3796 :     RUNCMP;
     122        3796 :     PG_RETURN_BOOL((res > 0) ? true : false);
     123             : }
     124             : 
     125             : Datum
     126           0 : ltree_ne(PG_FUNCTION_ARGS)
     127             : {
     128           0 :     RUNCMP;
     129           0 :     PG_RETURN_BOOL((res != 0) ? true : false);
     130             : }
     131             : 
     132             : Datum
     133           2 : nlevel(PG_FUNCTION_ARGS)
     134             : {
     135           2 :     ltree      *a = PG_GETARG_LTREE_P(0);
     136           2 :     int         res = a->numlevel;
     137             : 
     138           2 :     PG_FREE_IF_COPY(a, 0);
     139           2 :     PG_RETURN_INT32(res);
     140             : }
     141             : 
     142             : bool
     143       31108 : inner_isparent(const ltree *c, const ltree *p)
     144             : {
     145       31108 :     ltree_level *cl = LTREE_FIRST(c);
     146       31108 :     ltree_level *pl = LTREE_FIRST(p);
     147       31108 :     int         pn = p->numlevel;
     148             : 
     149       31108 :     if (pn > c->numlevel)
     150       14298 :         return false;
     151             : 
     152       34978 :     while (pn > 0)
     153             :     {
     154       17980 :         if (cl->len != pl->len)
     155       12188 :             return false;
     156        5792 :         if (memcmp(cl->name, pl->name, cl->len) != 0)
     157        4434 :             return false;
     158             : 
     159        1358 :         pn--;
     160        1358 :         cl = LEVEL_NEXT(cl);
     161        1358 :         pl = LEVEL_NEXT(pl);
     162             :     }
     163         188 :     return true;
     164             : }
     165             : 
     166             : Datum
     167       16072 : ltree_isparent(PG_FUNCTION_ARGS)
     168             : {
     169       16072 :     ltree      *c = PG_GETARG_LTREE_P(1);
     170       16072 :     ltree      *p = PG_GETARG_LTREE_P(0);
     171       16072 :     bool        res = inner_isparent(c, p);
     172             : 
     173       16072 :     PG_FREE_IF_COPY(c, 1);
     174       16072 :     PG_FREE_IF_COPY(p, 0);
     175       16072 :     PG_RETURN_BOOL(res);
     176             : }
     177             : 
     178             : Datum
     179       14708 : ltree_risparent(PG_FUNCTION_ARGS)
     180             : {
     181       14708 :     ltree      *c = PG_GETARG_LTREE_P(0);
     182       14708 :     ltree      *p = PG_GETARG_LTREE_P(1);
     183       14708 :     bool        res = inner_isparent(c, p);
     184             : 
     185       14708 :     PG_FREE_IF_COPY(c, 0);
     186       14708 :     PG_FREE_IF_COPY(p, 1);
     187       14708 :     PG_RETURN_BOOL(res);
     188             : }
     189             : 
     190             : 
     191             : static ltree *
     192          18 : inner_subltree(ltree *t, int32 startpos, int32 endpos)
     193             : {
     194          18 :     char       *start = NULL,
     195          18 :                *end = NULL;
     196          18 :     ltree_level *ptr = LTREE_FIRST(t);
     197             :     ltree      *res;
     198             :     int         i;
     199             : 
     200          18 :     if (startpos < 0 || endpos < 0 || startpos >= t->numlevel || startpos > endpos)
     201           0 :         ereport(ERROR,
     202             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     203             :                  errmsg("invalid positions")));
     204             : 
     205          18 :     if (endpos > t->numlevel)
     206           4 :         endpos = t->numlevel;
     207             : 
     208          18 :     start = end = (char *) ptr;
     209          38 :     for (i = 0; i < endpos; i++)
     210             :     {
     211          36 :         if (i == startpos)
     212          14 :             start = (char *) ptr;
     213          36 :         if (i == endpos - 1)
     214             :         {
     215          16 :             end = (char *) LEVEL_NEXT(ptr);
     216          16 :             break;
     217             :         }
     218          20 :         ptr = LEVEL_NEXT(ptr);
     219             :     }
     220             : 
     221          18 :     res = (ltree *) palloc0(LTREE_HDRSIZE + (end - start));
     222          18 :     SET_VARSIZE(res, LTREE_HDRSIZE + (end - start));
     223          18 :     res->numlevel = endpos - startpos;
     224             : 
     225          18 :     memcpy(LTREE_FIRST(res), start, end - start);
     226             : 
     227          18 :     return res;
     228             : }
     229             : 
     230             : Datum
     231           2 : subltree(PG_FUNCTION_ARGS)
     232             : {
     233           2 :     ltree      *t = PG_GETARG_LTREE_P(0);
     234           2 :     ltree      *res = inner_subltree(t, PG_GETARG_INT32(1), PG_GETARG_INT32(2));
     235             : 
     236           2 :     PG_FREE_IF_COPY(t, 0);
     237           2 :     PG_RETURN_POINTER(res);
     238             : }
     239             : 
     240             : Datum
     241          16 : subpath(PG_FUNCTION_ARGS)
     242             : {
     243          16 :     ltree      *t = PG_GETARG_LTREE_P(0);
     244          16 :     int32       start = PG_GETARG_INT32(1);
     245          16 :     int32       len = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
     246             :     int32       end;
     247             :     ltree      *res;
     248             : 
     249          16 :     end = start + len;
     250             : 
     251          16 :     if (start < 0)
     252             :     {
     253           2 :         start = t->numlevel + start;
     254           2 :         end = start + len;
     255             :     }
     256          16 :     if (start < 0)
     257             :     {                           /* start > t->numlevel */
     258           0 :         start = t->numlevel + start;
     259           0 :         end = start + len;
     260             :     }
     261             : 
     262          16 :     if (len < 0)
     263           4 :         end = t->numlevel + len;
     264          12 :     else if (len == 0)
     265           8 :         end = (fcinfo->nargs == 3) ? start : 0xffff;
     266             : 
     267          16 :     res = inner_subltree(t, start, end);
     268             : 
     269          16 :     PG_FREE_IF_COPY(t, 0);
     270          16 :     PG_RETURN_POINTER(res);
     271             : }
     272             : 
     273             : static ltree *
     274          10 : ltree_concat(ltree *a, ltree *b)
     275             : {
     276             :     ltree      *r;
     277             : 
     278          10 :     r = (ltree *) palloc0(VARSIZE(a) + VARSIZE(b) - LTREE_HDRSIZE);
     279          10 :     SET_VARSIZE(r, VARSIZE(a) + VARSIZE(b) - LTREE_HDRSIZE);
     280          10 :     r->numlevel = a->numlevel + b->numlevel;
     281             : 
     282          10 :     memcpy(LTREE_FIRST(r), LTREE_FIRST(a), VARSIZE(a) - LTREE_HDRSIZE);
     283          10 :     memcpy(((char *) LTREE_FIRST(r)) + VARSIZE(a) - LTREE_HDRSIZE,
     284             :            LTREE_FIRST(b),
     285          10 :            VARSIZE(b) - LTREE_HDRSIZE);
     286          10 :     return r;
     287             : }
     288             : 
     289             : Datum
     290           8 : ltree_addltree(PG_FUNCTION_ARGS)
     291             : {
     292           8 :     ltree      *a = PG_GETARG_LTREE_P(0);
     293           8 :     ltree      *b = PG_GETARG_LTREE_P(1);
     294             :     ltree      *r;
     295             : 
     296           8 :     r = ltree_concat(a, b);
     297           8 :     PG_FREE_IF_COPY(a, 0);
     298           8 :     PG_FREE_IF_COPY(b, 1);
     299           8 :     PG_RETURN_POINTER(r);
     300             : }
     301             : 
     302             : Datum
     303           2 : ltree_addtext(PG_FUNCTION_ARGS)
     304             : {
     305           2 :     ltree      *a = PG_GETARG_LTREE_P(0);
     306           2 :     text       *b = PG_GETARG_TEXT_PP(1);
     307             :     char       *s;
     308             :     ltree      *r,
     309             :                *tmp;
     310             : 
     311           2 :     s = text_to_cstring(b);
     312             : 
     313           2 :     tmp = (ltree *) DatumGetPointer(DirectFunctionCall1(ltree_in,
     314             :                                                         PointerGetDatum(s)));
     315             : 
     316           2 :     pfree(s);
     317             : 
     318           2 :     r = ltree_concat(a, tmp);
     319             : 
     320           2 :     pfree(tmp);
     321             : 
     322           2 :     PG_FREE_IF_COPY(a, 0);
     323           2 :     PG_FREE_IF_COPY(b, 1);
     324           2 :     PG_RETURN_POINTER(r);
     325             : }
     326             : 
     327             : Datum
     328          36 : ltree_index(PG_FUNCTION_ARGS)
     329             : {
     330          36 :     ltree      *a = PG_GETARG_LTREE_P(0);
     331          36 :     ltree      *b = PG_GETARG_LTREE_P(1);
     332          36 :     int         start = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
     333             :     int         i,
     334             :                 j;
     335             :     ltree_level *startptr,
     336             :                *aptr,
     337             :                *bptr;
     338          36 :     bool        found = false;
     339             : 
     340          36 :     if (start < 0)
     341             :     {
     342          10 :         if (-start >= a->numlevel)
     343           2 :             start = 0;
     344             :         else
     345           8 :             start = (int) (a->numlevel) + start;
     346             :     }
     347             : 
     348          36 :     if (a->numlevel - start < b->numlevel || a->numlevel == 0 || b->numlevel == 0)
     349             :     {
     350           2 :         PG_FREE_IF_COPY(a, 0);
     351           2 :         PG_FREE_IF_COPY(b, 1);
     352           2 :         PG_RETURN_INT32(-1);
     353             :     }
     354             : 
     355          34 :     startptr = LTREE_FIRST(a);
     356         218 :     for (i = 0; i <= a->numlevel - b->numlevel; i++)
     357             :     {
     358         212 :         if (i >= start)
     359             :         {
     360         116 :             aptr = startptr;
     361         116 :             bptr = LTREE_FIRST(b);
     362         186 :             for (j = 0; j < b->numlevel; j++)
     363             :             {
     364         158 :                 if (!(aptr->len == bptr->len && memcmp(aptr->name, bptr->name, aptr->len) == 0))
     365             :                     break;
     366          70 :                 aptr = LEVEL_NEXT(aptr);
     367          70 :                 bptr = LEVEL_NEXT(bptr);
     368             :             }
     369             : 
     370         116 :             if (j == b->numlevel)
     371             :             {
     372          28 :                 found = true;
     373          28 :                 break;
     374             :             }
     375             :         }
     376         184 :         startptr = LEVEL_NEXT(startptr);
     377             :     }
     378             : 
     379          34 :     if (!found)
     380           6 :         i = -1;
     381             : 
     382          34 :     PG_FREE_IF_COPY(a, 0);
     383          34 :     PG_FREE_IF_COPY(b, 1);
     384          34 :     PG_RETURN_INT32(i);
     385             : }
     386             : 
     387             : Datum
     388           0 : ltree_textadd(PG_FUNCTION_ARGS)
     389             : {
     390           0 :     ltree      *a = PG_GETARG_LTREE_P(1);
     391           0 :     text       *b = PG_GETARG_TEXT_PP(0);
     392             :     char       *s;
     393             :     ltree      *r,
     394             :                *tmp;
     395             : 
     396           0 :     s = text_to_cstring(b);
     397             : 
     398           0 :     tmp = (ltree *) DatumGetPointer(DirectFunctionCall1(ltree_in,
     399             :                                                         PointerGetDatum(s)));
     400             : 
     401           0 :     pfree(s);
     402             : 
     403           0 :     r = ltree_concat(tmp, a);
     404             : 
     405           0 :     pfree(tmp);
     406             : 
     407           0 :     PG_FREE_IF_COPY(a, 1);
     408           0 :     PG_FREE_IF_COPY(b, 0);
     409           0 :     PG_RETURN_POINTER(r);
     410             : }
     411             : 
     412             : /*
     413             :  * Common code for variants of lca(), find longest common ancestor of inputs
     414             :  *
     415             :  * Returns NULL if there is no common ancestor, ie, the longest common
     416             :  * prefix is empty.
     417             :  */
     418             : ltree *
     419          28 : lca_inner(ltree **a, int len)
     420             : {
     421             :     int         tmp,
     422             :                 num,
     423             :                 i,
     424             :                 reslen;
     425             :     ltree     **ptr;
     426             :     ltree_level *l1,
     427             :                *l2;
     428             :     ltree      *res;
     429             : 
     430          28 :     if (len <= 0)
     431           2 :         return NULL;            /* no inputs? */
     432          26 :     if ((*a)->numlevel == 0)
     433           2 :         return NULL;            /* any empty input means NULL result */
     434             : 
     435             :     /* num is the length of the longest common ancestor so far */
     436          24 :     num = (*a)->numlevel - 1;
     437             : 
     438             :     /* Compare each additional input to *a */
     439          24 :     ptr = a + 1;
     440          70 :     while (ptr - a < len)
     441             :     {
     442          24 :         if ((*ptr)->numlevel == 0)
     443           2 :             return NULL;
     444          22 :         else if ((*ptr)->numlevel == 1)
     445           4 :             num = 0;
     446             :         else
     447             :         {
     448          18 :             l1 = LTREE_FIRST(*a);
     449          18 :             l2 = LTREE_FIRST(*ptr);
     450          18 :             tmp = Min(num, (*ptr)->numlevel - 1);
     451          18 :             num = 0;
     452          46 :             for (i = 0; i < tmp; i++)
     453             :             {
     454          78 :                 if (l1->len == l2->len &&
     455          36 :                     memcmp(l1->name, l2->name, l1->len) == 0)
     456          28 :                     num = i + 1;
     457             :                 else
     458             :                     break;
     459          28 :                 l1 = LEVEL_NEXT(l1);
     460          28 :                 l2 = LEVEL_NEXT(l2);
     461             :             }
     462             :         }
     463          22 :         ptr++;
     464             :     }
     465             : 
     466             :     /* Now compute size of result ... */
     467          22 :     reslen = LTREE_HDRSIZE;
     468          22 :     l1 = LTREE_FIRST(*a);
     469          42 :     for (i = 0; i < num; i++)
     470             :     {
     471          20 :         reslen += MAXALIGN(l1->len + LEVEL_HDRSIZE);
     472          20 :         l1 = LEVEL_NEXT(l1);
     473             :     }
     474             : 
     475             :     /* ... and construct it by copying from *a */
     476          22 :     res = (ltree *) palloc0(reslen);
     477          22 :     SET_VARSIZE(res, reslen);
     478          22 :     res->numlevel = num;
     479             : 
     480          22 :     l1 = LTREE_FIRST(*a);
     481          22 :     l2 = LTREE_FIRST(res);
     482             : 
     483          42 :     for (i = 0; i < num; i++)
     484             :     {
     485          20 :         memcpy(l2, l1, MAXALIGN(l1->len + LEVEL_HDRSIZE));
     486          20 :         l1 = LEVEL_NEXT(l1);
     487          20 :         l2 = LEVEL_NEXT(l2);
     488             :     }
     489             : 
     490          22 :     return res;
     491             : }
     492             : 
     493             : Datum
     494          12 : lca(PG_FUNCTION_ARGS)
     495             : {
     496             :     int         i;
     497             :     ltree     **a,
     498             :                *res;
     499             : 
     500          12 :     a = (ltree **) palloc(sizeof(ltree *) * fcinfo->nargs);
     501          42 :     for (i = 0; i < fcinfo->nargs; i++)
     502          30 :         a[i] = PG_GETARG_LTREE_P(i);
     503          12 :     res = lca_inner(a, (int) fcinfo->nargs);
     504          42 :     for (i = 0; i < fcinfo->nargs; i++)
     505          30 :         PG_FREE_IF_COPY(a[i], i);
     506          12 :     pfree(a);
     507             : 
     508          12 :     if (res)
     509          10 :         PG_RETURN_POINTER(res);
     510             :     else
     511           2 :         PG_RETURN_NULL();
     512             : }
     513             : 
     514             : Datum
     515           2 : text2ltree(PG_FUNCTION_ARGS)
     516             : {
     517           2 :     text       *in = PG_GETARG_TEXT_PP(0);
     518             :     char       *s;
     519             :     ltree      *out;
     520             : 
     521           2 :     s = text_to_cstring(in);
     522             : 
     523           2 :     out = (ltree *) DatumGetPointer(DirectFunctionCall1(ltree_in,
     524             :                                                         PointerGetDatum(s)));
     525           2 :     pfree(s);
     526           2 :     PG_FREE_IF_COPY(in, 0);
     527           2 :     PG_RETURN_POINTER(out);
     528             : }
     529             : 
     530             : 
     531             : Datum
     532           2 : ltree2text(PG_FUNCTION_ARGS)
     533             : {
     534           2 :     ltree      *in = PG_GETARG_LTREE_P(0);
     535             :     char       *ptr;
     536             :     int         i;
     537             :     ltree_level *curlevel;
     538             :     text       *out;
     539             : 
     540           2 :     out = (text *) palloc(VARSIZE(in) + VARHDRSZ);
     541           2 :     ptr = VARDATA(out);
     542           2 :     curlevel = LTREE_FIRST(in);
     543          12 :     for (i = 0; i < in->numlevel; i++)
     544             :     {
     545          10 :         if (i != 0)
     546             :         {
     547           8 :             *ptr = '.';
     548           8 :             ptr++;
     549             :         }
     550          10 :         memcpy(ptr, curlevel->name, curlevel->len);
     551          10 :         ptr += curlevel->len;
     552          10 :         curlevel = LEVEL_NEXT(curlevel);
     553             :     }
     554             : 
     555           2 :     SET_VARSIZE(out, ptr - ((char *) out));
     556           2 :     PG_FREE_IF_COPY(in, 0);
     557             : 
     558           2 :     PG_RETURN_POINTER(out);
     559             : }
     560             : 
     561             : 
     562             : #define DEFAULT_PARENT_SEL 0.001
     563             : 
     564             : /*
     565             :  *  ltreeparentsel - Selectivity of parent relationship for ltree data types.
     566             :  */
     567             : Datum
     568           8 : ltreeparentsel(PG_FUNCTION_ARGS)
     569             : {
     570           8 :     PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
     571           8 :     Oid         operator = PG_GETARG_OID(1);
     572           8 :     List       *args = (List *) PG_GETARG_POINTER(2);
     573           8 :     int         varRelid = PG_GETARG_INT32(3);
     574             :     VariableStatData vardata;
     575             :     Node       *other;
     576             :     bool        varonleft;
     577             :     double      selec;
     578             : 
     579             :     /*
     580             :      * If expression is not variable <@ something or something <@ variable,
     581             :      * then punt and return a default estimate.
     582             :      */
     583           8 :     if (!get_restriction_variable(root, args, varRelid,
     584             :                                   &vardata, &other, &varonleft))
     585           0 :         PG_RETURN_FLOAT8(DEFAULT_PARENT_SEL);
     586             : 
     587             :     /*
     588             :      * If the something is a NULL constant, assume operator is strict and
     589             :      * return zero, ie, operator will never return TRUE.
     590             :      */
     591          16 :     if (IsA(other, Const) &&
     592           8 :         ((Const *) other)->constisnull)
     593             :     {
     594           0 :         ReleaseVariableStats(vardata);
     595           0 :         PG_RETURN_FLOAT8(0.0);
     596             :     }
     597             : 
     598           8 :     if (IsA(other, Const))
     599             :     {
     600             :         /* Variable is being compared to a known non-null constant */
     601           8 :         Datum       constval = ((Const *) other)->constvalue;
     602             :         FmgrInfo    contproc;
     603             :         double      mcvsum;
     604             :         double      mcvsel;
     605             :         double      nullfrac;
     606             :         int         hist_size;
     607             : 
     608           8 :         fmgr_info(get_opcode(operator), &contproc);
     609             : 
     610             :         /*
     611             :          * Is the constant "<@" to any of the column's most common values?
     612             :          */
     613           8 :         mcvsel = mcv_selectivity(&vardata, &contproc, constval, varonleft,
     614             :                                  &mcvsum);
     615             : 
     616             :         /*
     617             :          * If the histogram is large enough, see what fraction of it the
     618             :          * constant is "<@" to, and assume that's representative of the
     619             :          * non-MCV population.  Otherwise use the default selectivity for the
     620             :          * non-MCV population.
     621             :          */
     622           8 :         selec = histogram_selectivity(&vardata, &contproc,
     623             :                                       constval, varonleft,
     624             :                                       10, 1, &hist_size);
     625           8 :         if (selec < 0)
     626             :         {
     627             :             /* Nope, fall back on default */
     628           8 :             selec = DEFAULT_PARENT_SEL;
     629             :         }
     630           0 :         else if (hist_size < 100)
     631             :         {
     632             :             /*
     633             :              * For histogram sizes from 10 to 100, we combine the histogram
     634             :              * and default selectivities, putting increasingly more trust in
     635             :              * the histogram for larger sizes.
     636             :              */
     637           0 :             double      hist_weight = hist_size / 100.0;
     638             : 
     639           0 :             selec = selec * hist_weight +
     640           0 :                 DEFAULT_PARENT_SEL * (1.0 - hist_weight);
     641             :         }
     642             : 
     643             :         /* In any case, don't believe extremely small or large estimates. */
     644           8 :         if (selec < 0.0001)
     645           0 :             selec = 0.0001;
     646           8 :         else if (selec > 0.9999)
     647           0 :             selec = 0.9999;
     648             : 
     649           8 :         if (HeapTupleIsValid(vardata.statsTuple))
     650           0 :             nullfrac = ((Form_pg_statistic) GETSTRUCT(vardata.statsTuple))->stanullfrac;
     651             :         else
     652           8 :             nullfrac = 0.0;
     653             : 
     654             :         /*
     655             :          * Now merge the results from the MCV and histogram calculations,
     656             :          * realizing that the histogram covers only the non-null values that
     657             :          * are not listed in MCV.
     658             :          */
     659           8 :         selec *= 1.0 - nullfrac - mcvsum;
     660           8 :         selec += mcvsel;
     661             :     }
     662             :     else
     663           0 :         selec = DEFAULT_PARENT_SEL;
     664             : 
     665           8 :     ReleaseVariableStats(vardata);
     666             : 
     667             :     /* result should be in range, but make sure... */
     668           8 :     CLAMP_PROBABILITY(selec);
     669             : 
     670           8 :     PG_RETURN_FLOAT8((float8) selec);
     671             : }

Generated by: LCOV version 1.13