LTP GCOV extension - code coverage report
Current view: directory - access/gist - gistproc.c
Test: unnamed
Date: 2008-07-03 Instrumented lines: 320
Code covered: 60.9 % Executed lines: 195
Legend: not executed executed

       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * gistproc.c
       4                 :  *        Support procedures for GiSTs over 2-D objects (boxes, polygons, circles).
       5                 :  *
       6                 :  * This gives R-tree behavior, with Guttman's poly-time split algorithm.
       7                 :  *
       8                 :  *
       9                 :  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
      10                 :  * Portions Copyright (c) 1994, Regents of the University of California
      11                 :  *
      12                 :  * IDENTIFICATION
      13                 :  *      $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.12 2007/11/15 21:14:31 momjian Exp $
      14                 :  *
      15                 :  *-------------------------------------------------------------------------
      16                 :  */
      17                 : #include "postgres.h"
      18                 : 
      19                 : #include "access/gist.h"
      20                 : #include "access/skey.h"
      21                 : #include "utils/geo_decls.h"
      22                 : 
      23                 : 
      24                 : static bool gist_box_leaf_consistent(BOX *key, BOX *query,
      25                 :                                                  StrategyNumber strategy);
      26                 : static double size_box(Datum dbox);
      27                 : static bool rtree_internal_consistent(BOX *key, BOX *query,
      28                 :                                                   StrategyNumber strategy);
      29                 : 
      30                 : 
      31                 : /**************************************************
      32                 :  * Box ops
      33                 :  **************************************************/
      34                 : 
      35                 : static Datum
      36                 : rt_box_union(PG_FUNCTION_ARGS)
      37           94306 : {
      38           94306 :         BOX                *a = PG_GETARG_BOX_P(0);
      39           94306 :         BOX                *b = PG_GETARG_BOX_P(1);
      40                 :         BOX                *n;
      41                 : 
      42           94306 :         n = (BOX *) palloc(sizeof(BOX));
      43                 : 
      44           94306 :         n->high.x = Max(a->high.x, b->high.x);
      45           94306 :         n->high.y = Max(a->high.y, b->high.y);
      46           94306 :         n->low.x = Min(a->low.x, b->low.x);
      47           94306 :         n->low.y = Min(a->low.y, b->low.y);
      48                 : 
      49           94306 :         PG_RETURN_BOX_P(n);
      50                 : }
      51                 : 
      52                 : static Datum
      53                 : rt_box_inter(PG_FUNCTION_ARGS)
      54               8 : {
      55               8 :         BOX                *a = PG_GETARG_BOX_P(0);
      56               8 :         BOX                *b = PG_GETARG_BOX_P(1);
      57                 :         BOX                *n;
      58                 : 
      59               8 :         n = (BOX *) palloc(sizeof(BOX));
      60                 : 
      61               8 :         n->high.x = Min(a->high.x, b->high.x);
      62               8 :         n->high.y = Min(a->high.y, b->high.y);
      63               8 :         n->low.x = Max(a->low.x, b->low.x);
      64               8 :         n->low.y = Max(a->low.y, b->low.y);
      65                 : 
      66               8 :         if (n->high.x < n->low.x || n->high.y < n->low.y)
      67                 :         {
      68               8 :                 pfree(n);
      69                 :                 /* Indicate "no intersection" by returning NULL pointer */
      70               8 :                 n = NULL;
      71                 :         }
      72                 : 
      73               8 :         PG_RETURN_BOX_P(n);
      74                 : }
      75                 : 
      76                 : /*
      77                 :  * The GiST Consistent method for boxes
      78                 :  *
      79                 :  * Should return false if for all data items x below entry,
      80                 :  * the predicate x op query must be FALSE, where op is the oper
      81                 :  * corresponding to strategy in the pg_amop table.
      82                 :  */
      83                 : Datum
      84                 : gist_box_consistent(PG_FUNCTION_ARGS)
      85             260 : {
      86             260 :         GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
      87             260 :         BOX                *query = PG_GETARG_BOX_P(1);
      88             260 :         StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
      89                 : 
      90             260 :         if (DatumGetBoxP(entry->key) == NULL || query == NULL)
      91               0 :                 PG_RETURN_BOOL(FALSE);
      92                 : 
      93                 :         /*
      94                 :          * if entry is not leaf, use rtree_internal_consistent, else use
      95                 :          * gist_box_leaf_consistent
      96                 :          */
      97             260 :         if (GIST_LEAF(entry))
      98             198 :                 PG_RETURN_BOOL(gist_box_leaf_consistent(DatumGetBoxP(entry->key),
      99                 :                                                                                                 query,
     100                 :                                                                                                 strategy));
     101                 :         else
     102              62 :                 PG_RETURN_BOOL(rtree_internal_consistent(DatumGetBoxP(entry->key),
     103                 :                                                                                                  query,
     104                 :                                                                                                  strategy));
     105                 : }
     106                 : 
     107                 : static void
     108                 : adjustBox(BOX *b, BOX *addon)
     109           23905 : {
     110           23905 :         if (b->high.x < addon->high.x)
     111             688 :                 b->high.x = addon->high.x;
     112           23905 :         if (b->low.x > addon->low.x)
     113             576 :                 b->low.x = addon->low.x;
     114           23905 :         if (b->high.y < addon->high.y)
     115             638 :                 b->high.y = addon->high.y;
     116           23905 :         if (b->low.y > addon->low.y)
     117             596 :                 b->low.y = addon->low.y;
     118           23905 : }
     119                 : 
     120                 : /*
     121                 :  * The GiST Union method for boxes
     122                 :  *
     123                 :  * returns the minimal bounding box that encloses all the entries in entryvec
     124                 :  */
     125                 : Datum
     126                 : gist_box_union(PG_FUNCTION_ARGS)
     127            8814 : {
     128            8814 :         GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     129            8814 :         int                *sizep = (int *) PG_GETARG_POINTER(1);
     130                 :         int                     numranges,
     131                 :                                 i;
     132                 :         BOX                *cur,
     133                 :                            *pageunion;
     134                 : 
     135            8814 :         numranges = entryvec->n;
     136            8814 :         pageunion = (BOX *) palloc(sizeof(BOX));
     137            8814 :         cur = DatumGetBoxP(entryvec->vector[0].key);
     138            8814 :         memcpy((void *) pageunion, (void *) cur, sizeof(BOX));
     139                 : 
     140           18111 :         for (i = 1; i < numranges; i++)
     141                 :         {
     142            9297 :                 cur = DatumGetBoxP(entryvec->vector[i].key);
     143            9297 :                 adjustBox(pageunion, cur);
     144                 :         }
     145            8814 :         *sizep = sizeof(BOX);
     146                 : 
     147            8814 :         PG_RETURN_POINTER(pageunion);
     148                 : }
     149                 : 
     150                 : /*
     151                 :  * GiST Compress methods for boxes
     152                 :  *
     153                 :  * do not do anything.
     154                 :  */
     155                 : Datum
     156                 : gist_box_compress(PG_FUNCTION_ARGS)
     157            3299 : {
     158            3299 :         PG_RETURN_POINTER(PG_GETARG_POINTER(0));
     159                 : }
     160                 : 
     161                 : /*
     162                 :  * GiST DeCompress method for boxes (also used for polygons and circles)
     163                 :  *
     164                 :  * do not do anything --- we just use the stored box as is.
     165                 :  */
     166                 : Datum
     167                 : gist_box_decompress(PG_FUNCTION_ARGS)
     168          137379 : {
     169          137379 :         PG_RETURN_POINTER(PG_GETARG_POINTER(0));
     170                 : }
     171                 : 
     172                 : /*
     173                 :  * The GiST Penalty method for boxes
     174                 :  *
     175                 :  * As in the R-tree paper, we use change in area as our penalty metric
     176                 :  */
     177                 : Datum
     178                 : gist_box_penalty(PG_FUNCTION_ARGS)
     179           94306 : {
     180           94306 :         GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
     181           94306 :         GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
     182           94306 :         float      *result = (float *) PG_GETARG_POINTER(2);
     183                 :         Datum           ud;
     184                 : 
     185           94306 :         ud = DirectFunctionCall2(rt_box_union, origentry->key, newentry->key);
     186           94306 :         *result = (float) (size_box(ud) - size_box(origentry->key));
     187           94306 :         PG_RETURN_POINTER(result);
     188                 : }
     189                 : 
     190                 : static void
     191                 : chooseLR(GIST_SPLITVEC *v,
     192                 :                  OffsetNumber *list1, int nlist1, BOX *union1,
     193                 :                  OffsetNumber *list2, int nlist2, BOX *union2)
     194              88 : {
     195              88 :         bool            firstToLeft = true;
     196                 : 
     197              88 :         if (v->spl_ldatum_exists || v->spl_rdatum_exists)
     198                 :         {
     199               0 :                 if (v->spl_ldatum_exists && v->spl_rdatum_exists)
     200                 :                 {
     201               0 :                         BOX                     LRl = *union1,
     202               0 :                                                 LRr = *union2;
     203               0 :                         BOX                     RLl = *union2,
     204               0 :                                                 RLr = *union1;
     205                 :                         double          sizeLR,
     206                 :                                                 sizeRL;
     207                 : 
     208               0 :                         adjustBox(&LRl, DatumGetBoxP(v->spl_ldatum));
     209               0 :                         adjustBox(&LRr, DatumGetBoxP(v->spl_rdatum));
     210               0 :                         adjustBox(&RLl, DatumGetBoxP(v->spl_ldatum));
     211               0 :                         adjustBox(&RLr, DatumGetBoxP(v->spl_rdatum));
     212                 : 
     213               0 :                         sizeLR = size_box(DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&LRl), BoxPGetDatum(&LRr)));
     214               0 :                         sizeRL = size_box(DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&RLl), BoxPGetDatum(&RLr)));
     215                 : 
     216               0 :                         if (sizeLR > sizeRL)
     217               0 :                                 firstToLeft = false;
     218                 : 
     219                 :                 }
     220                 :                 else
     221                 :                 {
     222                 :                         float           p1,
     223                 :                                                 p2;
     224                 :                         GISTENTRY       oldUnion,
     225                 :                                                 addon;
     226                 : 
     227               0 :                         gistentryinit(oldUnion, (v->spl_ldatum_exists) ? v->spl_ldatum : v->spl_rdatum,
     228                 :                                                   NULL, NULL, InvalidOffsetNumber, FALSE);
     229                 : 
     230               0 :                         gistentryinit(addon, BoxPGetDatum(union1), NULL, NULL, InvalidOffsetNumber, FALSE);
     231               0 :                         DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union1), PointerGetDatum(&p1));
     232               0 :                         gistentryinit(addon, BoxPGetDatum(union2), NULL, NULL, InvalidOffsetNumber, FALSE);
     233               0 :                         DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union2), PointerGetDatum(&p2));
     234                 : 
     235               0 :                         if ((v->spl_ldatum_exists && p1 > p2) || (v->spl_rdatum_exists && p1 < p2))
     236               0 :                                 firstToLeft = false;
     237                 :                 }
     238                 :         }
     239                 : 
     240              88 :         if (firstToLeft)
     241                 :         {
     242              88 :                 v->spl_left = list1;
     243              88 :                 v->spl_right = list2;
     244              88 :                 v->spl_nleft = nlist1;
     245              88 :                 v->spl_nright = nlist2;
     246              88 :                 if (v->spl_ldatum_exists)
     247               0 :                         adjustBox(union1, DatumGetBoxP(v->spl_ldatum));
     248              88 :                 v->spl_ldatum = BoxPGetDatum(union1);
     249              88 :                 if (v->spl_rdatum_exists)
     250               0 :                         adjustBox(union2, DatumGetBoxP(v->spl_rdatum));
     251              88 :                 v->spl_rdatum = BoxPGetDatum(union2);
     252                 :         }
     253                 :         else
     254                 :         {
     255               0 :                 v->spl_left = list2;
     256               0 :                 v->spl_right = list1;
     257               0 :                 v->spl_nleft = nlist2;
     258               0 :                 v->spl_nright = nlist1;
     259               0 :                 if (v->spl_ldatum_exists)
     260               0 :                         adjustBox(union2, DatumGetBoxP(v->spl_ldatum));
     261               0 :                 v->spl_ldatum = BoxPGetDatum(union2);
     262               0 :                 if (v->spl_rdatum_exists)
     263               0 :                         adjustBox(union1, DatumGetBoxP(v->spl_rdatum));
     264               0 :                 v->spl_rdatum = BoxPGetDatum(union1);
     265                 :         }
     266                 : 
     267              88 :         v->spl_ldatum_exists = v->spl_rdatum_exists = false;
     268              88 : }
     269                 : 
     270                 : /*
     271                 :  * The GiST PickSplit method
     272                 :  *
     273                 :  * New linear algorithm, see 'New Linear Node Splitting Algorithm for R-tree',
     274                 :  * C.H.Ang and T.C.Tan
     275                 :  */
     276                 : Datum
     277                 : gist_box_picksplit(PG_FUNCTION_ARGS)
     278              88 : {
     279              88 :         GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     280              88 :         GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
     281                 :         OffsetNumber i;
     282                 :         OffsetNumber *listL,
     283                 :                            *listR,
     284                 :                            *listB,
     285                 :                            *listT;
     286                 :         BOX                *unionL,
     287                 :                            *unionR,
     288                 :                            *unionB,
     289                 :                            *unionT;
     290                 :         int                     posL,
     291                 :                                 posR,
     292                 :                                 posB,
     293                 :                                 posT;
     294                 :         BOX                     pageunion;
     295                 :         BOX                *cur;
     296              88 :         char            direction = ' ';
     297              88 :         bool            allisequal = true;
     298                 :         OffsetNumber maxoff;
     299                 :         int                     nbytes;
     300                 : 
     301              88 :         posL = posR = posB = posT = 0;
     302              88 :         maxoff = entryvec->n - 1;
     303                 : 
     304              88 :         cur = DatumGetBoxP(entryvec->vector[FirstOffsetNumber].key);
     305              88 :         memcpy((void *) &pageunion, (void *) cur, sizeof(BOX));
     306                 : 
     307                 :         /* find MBR */
     308           14696 :         for (i = OffsetNumberNext(FirstOffsetNumber); i <= maxoff; i = OffsetNumberNext(i))
     309                 :         {
     310           14608 :                 cur = DatumGetBoxP(entryvec->vector[i].key);
     311           14608 :                 if (allisequal == true && (
     312                 :                                                                    pageunion.high.x != cur->high.x ||
     313                 :                                                                    pageunion.high.y != cur->high.y ||
     314                 :                                                                    pageunion.low.x != cur->low.x ||
     315                 :                                                                    pageunion.low.y != cur->low.y
     316                 :                                                                    ))
     317              88 :                         allisequal = false;
     318                 : 
     319           14608 :                 adjustBox(&pageunion, cur);
     320                 :         }
     321                 : 
     322              88 :         nbytes = (maxoff + 2) * sizeof(OffsetNumber);
     323              88 :         listL = (OffsetNumber *) palloc(nbytes);
     324              88 :         listR = (OffsetNumber *) palloc(nbytes);
     325              88 :         unionL = (BOX *) palloc(sizeof(BOX));
     326              88 :         unionR = (BOX *) palloc(sizeof(BOX));
     327              88 :         if (allisequal)
     328                 :         {
     329               0 :                 cur = DatumGetBoxP(entryvec->vector[OffsetNumberNext(FirstOffsetNumber)].key);
     330               0 :                 if (memcmp((void *) cur, (void *) &pageunion, sizeof(BOX)) == 0)
     331                 :                 {
     332               0 :                         v->spl_left = listL;
     333               0 :                         v->spl_right = listR;
     334               0 :                         v->spl_nleft = v->spl_nright = 0;
     335               0 :                         memcpy((void *) unionL, (void *) &pageunion, sizeof(BOX));
     336               0 :                         memcpy((void *) unionR, (void *) &pageunion, sizeof(BOX));
     337                 : 
     338               0 :                         for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
     339                 :                         {
     340               0 :                                 if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
     341                 :                                 {
     342               0 :                                         v->spl_left[v->spl_nleft] = i;
     343               0 :                                         v->spl_nleft++;
     344                 :                                 }
     345                 :                                 else
     346                 :                                 {
     347               0 :                                         v->spl_right[v->spl_nright] = i;
     348               0 :                                         v->spl_nright++;
     349                 :                                 }
     350                 :                         }
     351                 : 
     352               0 :                         if (v->spl_ldatum_exists)
     353               0 :                                 adjustBox(unionL, DatumGetBoxP(v->spl_ldatum));
     354               0 :                         v->spl_ldatum = BoxPGetDatum(unionL);
     355                 : 
     356               0 :                         if (v->spl_rdatum_exists)
     357               0 :                                 adjustBox(unionR, DatumGetBoxP(v->spl_rdatum));
     358               0 :                         v->spl_rdatum = BoxPGetDatum(unionR);
     359                 : 
     360               0 :                         v->spl_ldatum_exists = v->spl_rdatum_exists = false;
     361                 : 
     362               0 :                         PG_RETURN_POINTER(v);
     363                 :                 }
     364                 :         }
     365                 : 
     366              88 :         listB = (OffsetNumber *) palloc(nbytes);
     367              88 :         listT = (OffsetNumber *) palloc(nbytes);
     368              88 :         unionB = (BOX *) palloc(sizeof(BOX));
     369              88 :         unionT = (BOX *) palloc(sizeof(BOX));
     370                 : 
     371                 : #define ADDLIST( list, unionD, pos, num ) do { \
     372                 :         if ( pos ) { \
     373                 :                 if ( (unionD)->high.x < cur->high.x ) (unionD)->high.x      = cur->high.x; \
     374                 :                 if ( (unionD)->low.x  > cur->low.x     ) (unionD)->low.x    = cur->low.x; \
     375                 :                 if ( (unionD)->high.y < cur->high.y ) (unionD)->high.y      = cur->high.y; \
     376                 :                 if ( (unionD)->low.y  > cur->low.y     ) (unionD)->low.y    = cur->low.y; \
     377                 :         } else { \
     378                 :                         memcpy( (void*)(unionD), (void*) cur, sizeof( BOX ) );  \
     379                 :         } \
     380                 :         (list)[pos] = num; \
     381                 :         (pos)++; \
     382                 : } while(0)
     383                 : 
     384           14784 :         for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
     385                 :         {
     386           14696 :                 cur = DatumGetBoxP(entryvec->vector[i].key);
     387           14696 :                 if (cur->low.x - pageunion.low.x < pageunion.high.x - cur->high.x)
     388            7277 :                         ADDLIST(listL, unionL, posL, i);
     389                 :                 else
     390            7419 :                         ADDLIST(listR, unionR, posR, i);
     391           14696 :                 if (cur->low.y - pageunion.low.y < pageunion.high.y - cur->high.y)
     392            7059 :                         ADDLIST(listB, unionB, posB, i);
     393                 :                 else
     394            7637 :                         ADDLIST(listT, unionT, posT, i);
     395                 :         }
     396                 : 
     397                 : #define LIMIT_RATIO 0.1
     398                 : #define _IS_BADRATIO(x,y)       ( (y) == 0 || (float)(x)/(float)(y) < LIMIT_RATIO )
     399                 : #define IS_BADRATIO(x,y) ( _IS_BADRATIO((x),(y)) || _IS_BADRATIO((y),(x)) )
     400                 :         /* bad disposition, try to split by centers of boxes  */
     401              88 :         if (IS_BADRATIO(posR, posL) && IS_BADRATIO(posT, posB))
     402                 :         {
     403               0 :                 double          avgCenterX = 0.0,
     404               0 :                                         avgCenterY = 0.0;
     405                 :                 double          CenterX,
     406                 :                                         CenterY;
     407                 : 
     408               0 :                 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
     409                 :                 {
     410               0 :                         cur = DatumGetBoxP(entryvec->vector[i].key);
     411               0 :                         avgCenterX += ((double) cur->high.x + (double) cur->low.x) / 2.0;
     412               0 :                         avgCenterY += ((double) cur->high.y + (double) cur->low.y) / 2.0;
     413                 :                 }
     414                 : 
     415               0 :                 avgCenterX /= maxoff;
     416               0 :                 avgCenterY /= maxoff;
     417                 : 
     418               0 :                 posL = posR = posB = posT = 0;
     419               0 :                 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
     420                 :                 {
     421               0 :                         cur = DatumGetBoxP(entryvec->vector[i].key);
     422                 : 
     423               0 :                         CenterX = ((double) cur->high.x + (double) cur->low.x) / 2.0;
     424               0 :                         CenterY = ((double) cur->high.y + (double) cur->low.y) / 2.0;
     425                 : 
     426               0 :                         if (CenterX < avgCenterX)
     427               0 :                                 ADDLIST(listL, unionL, posL, i);
     428               0 :                         else if (CenterX == avgCenterX)
     429                 :                         {
     430               0 :                                 if (posL > posR)
     431               0 :                                         ADDLIST(listR, unionR, posR, i);
     432                 :                                 else
     433               0 :                                         ADDLIST(listL, unionL, posL, i);
     434                 :                         }
     435                 :                         else
     436               0 :                                 ADDLIST(listR, unionR, posR, i);
     437                 : 
     438               0 :                         if (CenterY < avgCenterY)
     439               0 :                                 ADDLIST(listB, unionB, posB, i);
     440               0 :                         else if (CenterY == avgCenterY)
     441                 :                         {
     442               0 :                                 if (posB > posT)
     443               0 :                                         ADDLIST(listT, unionT, posT, i);
     444                 :                                 else
     445               0 :                                         ADDLIST(listB, unionB, posB, i);
     446                 :                         }
     447                 :                         else
     448               0 :                                 ADDLIST(listT, unionT, posT, i);
     449                 :                 }
     450                 :         }
     451                 : 
     452                 :         /* which split more optimal? */
     453              88 :         if (Max(posL, posR) < Max(posB, posT))
     454              48 :                 direction = 'x';
     455              40 :         else if (Max(posL, posR) > Max(posB, posT))
     456              36 :                 direction = 'y';
     457                 :         else
     458                 :         {
     459                 :                 Datum           interLR = DirectFunctionCall2(rt_box_inter,
     460                 :                                                                                                   BoxPGetDatum(unionL),
     461               4 :                                                                                                   BoxPGetDatum(unionR));
     462                 :                 Datum           interBT = DirectFunctionCall2(rt_box_inter,
     463                 :                                                                                                   BoxPGetDatum(unionB),
     464               4 :                                                                                                   BoxPGetDatum(unionT));
     465                 :                 double          sizeLR,
     466                 :                                         sizeBT;
     467                 : 
     468               4 :                 sizeLR = size_box(interLR);
     469               4 :                 sizeBT = size_box(interBT);
     470                 : 
     471               4 :                 if (sizeLR < sizeBT)
     472               0 :                         direction = 'x';
     473                 :                 else
     474               4 :                         direction = 'y';
     475                 :         }
     476                 : 
     477              88 :         if (direction == 'x')
     478              48 :                 chooseLR(v,
     479                 :                                  listL, posL, unionL,
     480                 :                                  listR, posR, unionR);
     481                 :         else
     482              40 :                 chooseLR(v,
     483                 :                                  listB, posB, unionB,
     484                 :                                  listT, posT, unionT);
     485                 : 
     486              88 :         PG_RETURN_POINTER(v);
     487                 : }
     488                 : 
     489                 : /*
     490                 :  * Equality method
     491                 :  */
     492                 : Datum
     493                 : gist_box_same(PG_FUNCTION_ARGS)
     494            8723 : {
     495            8723 :         BOX                *b1 = PG_GETARG_BOX_P(0);
     496            8723 :         BOX                *b2 = PG_GETARG_BOX_P(1);
     497            8723 :         bool       *result = (bool *) PG_GETARG_POINTER(2);
     498                 : 
     499            8723 :         if (b1 && b2)
     500            8723 :                 *result = DatumGetBool(DirectFunctionCall2(box_same,
     501                 :                                                                                                    PointerGetDatum(b1),
     502                 :                                                                                                    PointerGetDatum(b2)));
     503                 :         else
     504               0 :                 *result = (b1 == NULL && b2 == NULL) ? TRUE : FALSE;
     505            8723 :         PG_RETURN_POINTER(result);
     506                 : }
     507                 : 
     508                 : /*
     509                 :  * Leaf-level consistency for boxes: just apply the query operator
     510                 :  */
     511                 : static bool
     512                 : gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
     513             198 : {
     514                 :         bool            retval;
     515                 : 
     516             198 :         switch (strategy)
     517                 :         {
     518                 :                 case RTLeftStrategyNumber:
     519               0 :                         retval = DatumGetBool(DirectFunctionCall2(box_left,
     520                 :                                                                                                           PointerGetDatum(key),
     521                 :                                                                                                         PointerGetDatum(query)));
     522               0 :                         break;
     523                 :                 case RTOverLeftStrategyNumber:
     524               0 :                         retval = DatumGetBool(DirectFunctionCall2(box_overleft,
     525                 :                                                                                                           PointerGetDatum(key),
     526                 :                                                                                                         PointerGetDatum(query)));
     527               0 :                         break;
     528                 :                 case RTOverlapStrategyNumber:
     529              99 :                         retval = DatumGetBool(DirectFunctionCall2(box_overlap,
     530                 :                                                                                                           PointerGetDatum(key),
     531                 :                                                                                                         PointerGetDatum(query)));
     532              99 :                         break;
     533                 :                 case RTOverRightStrategyNumber:
     534               0 :                         retval = DatumGetBool(DirectFunctionCall2(box_overright,
     535                 :                                                                                                           PointerGetDatum(key),
     536                 :                                                                                                         PointerGetDatum(query)));
     537               0 :                         break;
     538                 :                 case RTRightStrategyNumber:
     539               0 :                         retval = DatumGetBool(DirectFunctionCall2(box_right,
     540                 :                                                                                                           PointerGetDatum(key),
     541                 :                                                                                                         PointerGetDatum(query)));
     542               0 :                         break;
     543                 :                 case RTSameStrategyNumber:
     544               0 :                         retval = DatumGetBool(DirectFunctionCall2(box_same,
     545                 :                                                                                                           PointerGetDatum(key),
     546                 :                                                                                                         PointerGetDatum(query)));
     547               0 :                         break;
     548                 :                 case RTContainsStrategyNumber:
     549                 :                 case RTOldContainsStrategyNumber:
     550               0 :                         retval = DatumGetBool(DirectFunctionCall2(box_contain,
     551                 :                                                                                                           PointerGetDatum(key),
     552                 :                                                                                                         PointerGetDatum(query)));
     553               0 :                         break;
     554                 :                 case RTContainedByStrategyNumber:
     555                 :                 case RTOldContainedByStrategyNumber:
     556              99 :                         retval = DatumGetBool(DirectFunctionCall2(box_contained,
     557                 :                                                                                                           PointerGetDatum(key),
     558                 :                                                                                                         PointerGetDatum(query)));
     559              99 :                         break;
     560                 :                 case RTOverBelowStrategyNumber:
     561               0 :                         retval = DatumGetBool(DirectFunctionCall2(box_overbelow,
     562                 :                                                                                                           PointerGetDatum(key),
     563                 :                                                                                                         PointerGetDatum(query)));
     564               0 :                         break;
     565                 :                 case RTBelowStrategyNumber:
     566               0 :                         retval = DatumGetBool(DirectFunctionCall2(box_below,
     567                 :                                                                                                           PointerGetDatum(key),
     568                 :                                                                                                         PointerGetDatum(query)));
     569               0 :                         break;
     570                 :                 case RTAboveStrategyNumber:
     571               0 :                         retval = DatumGetBool(DirectFunctionCall2(box_above,
     572                 :                                                                                                           PointerGetDatum(key),
     573                 :                                                                                                         PointerGetDatum(query)));
     574               0 :                         break;
     575                 :                 case RTOverAboveStrategyNumber:
     576               0 :                         retval = DatumGetBool(DirectFunctionCall2(box_overabove,
     577                 :                                                                                                           PointerGetDatum(key),
     578                 :                                                                                                         PointerGetDatum(query)));
     579               0 :                         break;
     580                 :                 default:
     581               0 :                         retval = FALSE;
     582                 :         }
     583             198 :         return retval;
     584                 : }
     585                 : 
     586                 : static double
     587                 : size_box(Datum dbox)
     588          188620 : {
     589          188620 :         BOX                *box = DatumGetBoxP(dbox);
     590                 : 
     591          188620 :         if (box == NULL || box->high.x <= box->low.x || box->high.y <= box->low.y)
     592               8 :                 return 0.0;
     593          188612 :         return (box->high.x - box->low.x) * (box->high.y - box->low.y);
     594                 : }
     595                 : 
     596                 : /*****************************************
     597                 :  * Common rtree functions (for boxes, polygons, and circles)
     598                 :  *****************************************/
     599                 : 
     600                 : /*
     601                 :  * Internal-page consistency for all these types
     602                 :  *
     603                 :  * We can use the same function since all types use bounding boxes as the
     604                 :  * internal-page representation.
     605                 :  */
     606                 : static bool
     607                 : rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy)
     608             768 : {
     609                 :         bool            retval;
     610                 : 
     611             768 :         switch (strategy)
     612                 :         {
     613                 :                 case RTLeftStrategyNumber:
     614               0 :                         retval = !DatumGetBool(DirectFunctionCall2(box_overright,
     615                 :                                                                                                            PointerGetDatum(key),
     616                 :                                                                                                         PointerGetDatum(query)));
     617               0 :                         break;
     618                 :                 case RTOverLeftStrategyNumber:
     619               0 :                         retval = !DatumGetBool(DirectFunctionCall2(box_right,
     620                 :                                                                                                            PointerGetDatum(key),
     621                 :                                                                                                         PointerGetDatum(query)));
     622               0 :                         break;
     623                 :                 case RTOverlapStrategyNumber:
     624             733 :                         retval = DatumGetBool(DirectFunctionCall2(box_overlap,
     625                 :                                                                                                           PointerGetDatum(key),
     626                 :                                                                                                         PointerGetDatum(query)));
     627             733 :                         break;
     628                 :                 case RTOverRightStrategyNumber:
     629               0 :                         retval = !DatumGetBool(DirectFunctionCall2(box_left,
     630                 :                                                                                                            PointerGetDatum(key),
     631                 :                                                                                                         PointerGetDatum(query)));
     632               0 :                         break;
     633                 :                 case RTRightStrategyNumber:
     634               0 :                         retval = !DatumGetBool(DirectFunctionCall2(box_overleft,
     635                 :                                                                                                            PointerGetDatum(key),
     636                 :                                                                                                         PointerGetDatum(query)));
     637               0 :                         break;
     638                 :                 case RTSameStrategyNumber:
     639                 :                 case RTContainsStrategyNumber:
     640                 :                 case RTOldContainsStrategyNumber:
     641               4 :                         retval = DatumGetBool(DirectFunctionCall2(box_contain,
     642                 :                                                                                                           PointerGetDatum(key),
     643                 :                                                                                                         PointerGetDatum(query)));
     644               4 :                         break;
     645                 :                 case RTContainedByStrategyNumber:
     646                 :                 case RTOldContainedByStrategyNumber:
     647              31 :                         retval = DatumGetBool(DirectFunctionCall2(box_overlap,
     648                 :                                                                                                           PointerGetDatum(key),
     649                 :                                                                                                         PointerGetDatum(query)));
     650              31 :                         break;
     651                 :                 case RTOverBelowStrategyNumber:
     652               0 :                         retval = !DatumGetBool(DirectFunctionCall2(box_above,
     653                 :                                                                                                            PointerGetDatum(key),
     654                 :                                                                                                         PointerGetDatum(query)));
     655               0 :                         break;
     656                 :                 case RTBelowStrategyNumber:
     657               0 :                         retval = !DatumGetBool(DirectFunctionCall2(box_overabove,
     658                 :                                                                                                            PointerGetDatum(key),
     659                 :                                                                                                         PointerGetDatum(query)));
     660               0 :                         break;
     661                 :                 case RTAboveStrategyNumber:
     662               0 :                         retval = !DatumGetBool(DirectFunctionCall2(box_overbelow,
     663                 :                                                                                                            PointerGetDatum(key),
     664                 :                                                                                                         PointerGetDatum(query)));
     665               0 :                         break;
     666                 :                 case RTOverAboveStrategyNumber:
     667               0 :                         retval = !DatumGetBool(DirectFunctionCall2(box_below,
     668                 :                                                                                                            PointerGetDatum(key),
     669                 :                                                                                                         PointerGetDatum(query)));
     670               0 :                         break;
     671                 :                 default:
     672               0 :                         retval = FALSE;
     673                 :         }
     674             768 :         return retval;
     675                 : }
     676                 : 
     677                 : /**************************************************
     678                 :  * Polygon ops
     679                 :  **************************************************/
     680                 : 
     681                 : /*
     682                 :  * GiST compress for polygons: represent a polygon by its bounding box
     683                 :  */
     684                 : Datum
     685                 : gist_poly_compress(PG_FUNCTION_ARGS)
     686            3303 : {
     687            3303 :         GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     688                 :         GISTENTRY  *retval;
     689                 : 
     690            3303 :         if (entry->leafkey)
     691                 :         {
     692            3104 :                 retval = palloc(sizeof(GISTENTRY));
     693            3104 :                 if (DatumGetPointer(entry->key) != NULL)
     694                 :                 {
     695            3104 :                         POLYGON    *in = DatumGetPolygonP(entry->key);
     696                 :                         BOX                *r;
     697                 : 
     698            3104 :                         r = (BOX *) palloc(sizeof(BOX));
     699            3104 :                         memcpy((void *) r, (void *) &(in->boundbox), sizeof(BOX));
     700            3104 :                         gistentryinit(*retval, PointerGetDatum(r),
     701                 :                                                   entry->rel, entry->page,
     702                 :                                                   entry->offset, FALSE);
     703                 : 
     704                 :                 }
     705                 :                 else
     706                 :                 {
     707               0 :                         gistentryinit(*retval, (Datum) 0,
     708                 :                                                   entry->rel, entry->page,
     709                 :                                                   entry->offset, FALSE);
     710                 :                 }
     711                 :         }
     712                 :         else
     713             199 :                 retval = entry;
     714            3303 :         PG_RETURN_POINTER(retval);
     715                 : }
     716                 : 
     717                 : /*
     718                 :  * The GiST Consistent method for polygons
     719                 :  */
     720                 : Datum
     721                 : gist_poly_consistent(PG_FUNCTION_ARGS)
     722             134 : {
     723             134 :         GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     724             134 :         POLYGON    *query = PG_GETARG_POLYGON_P(1);
     725             134 :         StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     726                 :         bool            result;
     727                 : 
     728             134 :         if (DatumGetBoxP(entry->key) == NULL || query == NULL)
     729               0 :                 PG_RETURN_BOOL(FALSE);
     730                 : 
     731                 :         /*
     732                 :          * Since the operators are marked lossy anyway, we can just use
     733                 :          * rtree_internal_consistent even at leaf nodes.  (This works in part
     734                 :          * because the index entries are bounding boxes not polygons.)
     735                 :          */
     736             134 :         result = rtree_internal_consistent(DatumGetBoxP(entry->key),
     737                 :                                                                            &(query->boundbox), strategy);
     738                 : 
     739                 :         /* Avoid memory leak if supplied poly is toasted */
     740             134 :         PG_FREE_IF_COPY(query, 1);
     741                 : 
     742             134 :         PG_RETURN_BOOL(result);
     743                 : }
     744                 : 
     745                 : /**************************************************
     746                 :  * Circle ops
     747                 :  **************************************************/
     748                 : 
     749                 : /*
     750                 :  * GiST compress for circles: represent a circle by its bounding box
     751                 :  */
     752                 : Datum
     753                 : gist_circle_compress(PG_FUNCTION_ARGS)
     754            3378 : {
     755            3378 :         GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     756                 :         GISTENTRY  *retval;
     757                 : 
     758            3378 :         if (entry->leafkey)
     759                 :         {
     760            3106 :                 retval = palloc(sizeof(GISTENTRY));
     761            3106 :                 if (DatumGetCircleP(entry->key) != NULL)
     762                 :                 {
     763            3106 :                         CIRCLE     *in = DatumGetCircleP(entry->key);
     764                 :                         BOX                *r;
     765                 : 
     766            3106 :                         r = (BOX *) palloc(sizeof(BOX));
     767            3106 :                         r->high.x = in->center.x + in->radius;
     768            3106 :                         r->low.x = in->center.x - in->radius;
     769            3106 :                         r->high.y = in->center.y + in->radius;
     770            3106 :                         r->low.y = in->center.y - in->radius;
     771            3106 :                         gistentryinit(*retval, PointerGetDatum(r),
     772                 :                                                   entry->rel, entry->page,
     773                 :                                                   entry->offset, FALSE);
     774                 : 
     775                 :                 }
     776                 :                 else
     777                 :                 {
     778               0 :                         gistentryinit(*retval, (Datum) 0,
     779                 :                                                   entry->rel, entry->page,
     780                 :                                                   entry->offset, FALSE);
     781                 :                 }
     782                 :         }
     783                 :         else
     784             272 :                 retval = entry;
     785            3378 :         PG_RETURN_POINTER(retval);
     786                 : }
     787                 : 
     788                 : /*
     789                 :  * The GiST Consistent method for circles
     790                 :  */
     791                 : Datum
     792                 : gist_circle_consistent(PG_FUNCTION_ARGS)
     793             572 : {
     794             572 :         GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     795             572 :         CIRCLE     *query = PG_GETARG_CIRCLE_P(1);
     796             572 :         StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     797                 :         BOX                     bbox;
     798                 :         bool            result;
     799                 : 
     800             572 :         if (DatumGetBoxP(entry->key) == NULL || query == NULL)
     801               0 :                 PG_RETURN_BOOL(FALSE);
     802                 : 
     803                 :         /*
     804                 :          * Since the operators are marked lossy anyway, we can just use
     805                 :          * rtree_internal_consistent even at leaf nodes.  (This works in part
     806                 :          * because the index entries are bounding boxes not circles.)
     807                 :          */
     808             572 :         bbox.high.x = query->center.x + query->radius;
     809             572 :         bbox.low.x = query->center.x - query->radius;
     810             572 :         bbox.high.y = query->center.y + query->radius;
     811             572 :         bbox.low.y = query->center.y - query->radius;
     812                 : 
     813             572 :         result = rtree_internal_consistent(DatumGetBoxP(entry->key),
     814                 :                                                                            &bbox, strategy);
     815                 : 
     816             572 :         PG_RETURN_BOOL(result);
     817                 : }

Generated by: LTP GCOV extension version 1.5