mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-29 22:49:41 +03:00 
			
		
		
		
	- Add aligment for interval data types - Avoid floating point overflow in penalty functions Janko Richter <jankorichter@yahoo.de> and teodor
		
			
				
	
	
		
			255 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "btree_gist.h"
 | |
| #include "btree_utils_num.h"
 | |
| #include "utils/date.h"
 | |
| 
 | |
| extern GISTENTRY *
 | |
| gbt_num_compress( GISTENTRY  *retval , GISTENTRY  *entry , const gbtree_ninfo * tinfo )
 | |
| {
 | |
| 
 | |
|     if (entry->leafkey)
 | |
|     {
 | |
| 
 | |
|        union {
 | |
|          int16      i2;
 | |
|          int32      i4;
 | |
|          TimeADT    ts;
 | |
|          DateADT    dt;
 | |
|        } v ;
 | |
|        
 | |
|        GBT_NUMKEY  *r  = ( GBT_NUMKEY * ) palloc(2 * tinfo->size );
 | |
|        void  *leaf  = NULL;
 | |
| 
 | |
|        switch ( tinfo->t )
 | |
|        {
 | |
|          case gbt_t_int2 :
 | |
|            v.i2     = DatumGetInt16(entry->key);
 | |
|            leaf     = &v.i2;
 | |
|            break;
 | |
|          case gbt_t_int4 :
 | |
|            v.i4     = DatumGetInt32(entry->key);
 | |
|            leaf     = &v.i4;
 | |
|            break;
 | |
|          case gbt_t_oid  :
 | |
|            v.i4     = DatumGetObjectId(entry->key);
 | |
|            leaf     = &v.i4;
 | |
|            break;
 | |
|          case gbt_t_time  :
 | |
|            v.ts     = DatumGetTimeADT(entry->key);
 | |
|            leaf     = &v.ts;
 | |
|            break;
 | |
|          case gbt_t_date  :
 | |
|            v.dt     = DatumGetDateADT(entry->key);
 | |
|            leaf     = &v.dt;
 | |
|            break;
 | |
|          default :
 | |
|            leaf = DatumGetPointer(entry->key);
 | |
|        }
 | |
| 
 | |
|        memset ( (void*) &r[0]  , 0   , 2*tinfo->size );
 | |
|        memcpy ( (void*) &r[0]  , leaf, tinfo->size ); 
 | |
|        memcpy ( (void*) &r[tinfo->size] , leaf, tinfo->size );
 | |
|        retval = palloc(sizeof(GISTENTRY));
 | |
|        gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page,
 | |
|                                  entry->offset,( 2 * tinfo->size ), FALSE);
 | |
|     } else
 | |
|        retval = entry;
 | |
| 
 | |
|     return retval;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** The GiST union method for numerical values
 | |
| */
 | |
| 
 | |
| extern void *
 | |
| gbt_num_union( GBT_NUMKEY * out, const GistEntryVector * entryvec, const gbtree_ninfo * tinfo )
 | |
| {
 | |
|         int                     i,
 | |
|                                 numranges;
 | |
|         GBT_NUMKEY *   cur ;
 | |
|         GBT_NUMKEY_R   o, c;
 | |
| 
 | |
|         numranges = entryvec->n;
 | |
|         cur       = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[0].key));
 | |
| 
 | |
| 
 | |
|         o.lower = &((GBT_NUMKEY *)out)[0];
 | |
|         o.upper = &((GBT_NUMKEY *)out)[tinfo->size];
 | |
| 
 | |
|         memcpy( (void*)out, (void*) cur, 2*tinfo->size );
 | |
| 
 | |
|         for (i = 1; i < numranges; i++)
 | |
|         {
 | |
|                 cur = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[i].key));
 | |
|                 c.lower = &cur[0];
 | |
|                 c.upper = &cur[tinfo->size];
 | |
|                 if ( (*tinfo->f_gt)(o.lower, c.lower) ) /* out->lower > cur->lower */
 | |
|                      memcpy( (void* ) o.lower, (void*) c.lower, tinfo->size );
 | |
|                 if ( (*tinfo->f_lt)(o.upper, c.upper) ) /* out->upper < cur->upper */
 | |
|                      memcpy( (void*) o.upper, (void*) c.upper, tinfo->size );
 | |
|         }
 | |
| 
 | |
|         return out;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** The GiST same method for numerical values
 | |
| */
 | |
| 
 | |
| extern bool gbt_num_same ( const GBT_NUMKEY * a, const GBT_NUMKEY * b, const gbtree_ninfo * tinfo )
 | |
| {
 | |
| 
 | |
|   GBT_NUMKEY_R b1, b2 ;
 | |
| 
 | |
|   b1.lower = &(((GBT_NUMKEY *)a)[0]);
 | |
|   b1.upper = &(((GBT_NUMKEY *)a)[tinfo->size]);
 | |
|   b2.lower = &(((GBT_NUMKEY *)b)[0]);
 | |
|   b2.upper = &(((GBT_NUMKEY *)b)[tinfo->size]);
 | |
| 
 | |
|   if (
 | |
|     (*tinfo->f_eq)( b1.lower, b2.lower) &&
 | |
|     (*tinfo->f_eq)( b1.upper, b2.upper)
 | |
|   )
 | |
|     return TRUE;
 | |
|   return FALSE;
 | |
|  
 | |
| }
 | |
| 
 | |
| 
 | |
| extern void
 | |
| gbt_num_bin_union(Datum * u , GBT_NUMKEY * e , const gbtree_ninfo * tinfo )
 | |
| {
 | |
| 
 | |
|   GBT_NUMKEY_R rd;
 | |
| 
 | |
|   rd.lower = &e[0];
 | |
|   rd.upper = &e[tinfo->size];
 | |
| 
 | |
|   if (!DatumGetPointer(*u))
 | |
|   {
 | |
|     *u  = PointerGetDatum(palloc(2 * tinfo->size));
 | |
|     memcpy( (void* ) &( ( (GBT_NUMKEY *) DatumGetPointer(*u) )[0] ) , (void*)rd.lower , tinfo->size );
 | |
|     memcpy( (void* ) &( ( (GBT_NUMKEY *) DatumGetPointer(*u) )[tinfo->size]) , (void*)rd.upper , tinfo->size );
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     GBT_NUMKEY_R  ur ;
 | |
|     ur.lower   = &( ( (GBT_NUMKEY *) DatumGetPointer(*u) )[0] ) ;
 | |
|     ur.upper   = &( ( (GBT_NUMKEY *) DatumGetPointer(*u) )[tinfo->size]) ;
 | |
|     if ( (*tinfo->f_gt)((void*)ur.lower, (void*)rd.lower) )
 | |
|        memcpy( (void*) ur.lower, (void*) rd.lower, tinfo->size );
 | |
|     if ( (*tinfo->f_lt)((void*)ur.upper, (void*)rd.upper) )
 | |
|        memcpy( (void*) ur.upper, (void*) rd.upper, tinfo->size );
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** The GiST consistent method
 | |
| */
 | |
| 
 | |
| extern bool  
 | |
| gbt_num_consistent(
 | |
|   const GBT_NUMKEY_R * key,
 | |
|   const void         * query,
 | |
|   const StrategyNumber * strategy,
 | |
|   bool is_leaf,
 | |
|   const gbtree_ninfo * tinfo
 | |
| )
 | |
| {
 | |
| 
 | |
|         bool    retval = FALSE;
 | |
| 
 | |
|         switch (*strategy)
 | |
|         {
 | |
|                 case BTLessEqualStrategyNumber:
 | |
|                         retval    = (*tinfo->f_ge)(query, key->lower);
 | |
|                         break;
 | |
|                 case BTLessStrategyNumber:
 | |
|                         if ( is_leaf )
 | |
|                           retval  = (*tinfo->f_gt)(query, key->lower);
 | |
|                         else 
 | |
|                           retval  = (*tinfo->f_ge)(query, key->lower);
 | |
|                         break;
 | |
|                 case BTEqualStrategyNumber:
 | |
|                         if ( is_leaf )
 | |
|                            retval = (*tinfo->f_eq)(query, key->lower);
 | |
|                         else
 | |
|                            retval = (*tinfo->f_le)(key->lower, query) && (*tinfo->f_le)(query, key->upper );
 | |
|                         break;
 | |
|                 case BTGreaterStrategyNumber:
 | |
|                         if ( is_leaf )
 | |
|                           retval  = (*tinfo->f_lt)(query, key->upper);
 | |
|                         else
 | |
|                           retval  = (*tinfo->f_le)(query, key->upper);
 | |
|                         break;
 | |
|                 case BTGreaterEqualStrategyNumber:
 | |
|                         retval    = (*tinfo->f_le)(query, key->upper);
 | |
|                         break;
 | |
|                 default:
 | |
|                         retval = FALSE;
 | |
|         }
 | |
| 
 | |
|         return (retval);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| GIST_SPLITVEC *
 | |
| gbt_num_picksplit( const GistEntryVector *entryvec, GIST_SPLITVEC *v, const gbtree_ninfo * tinfo )
 | |
| {
 | |
| 
 | |
|     OffsetNumber  i   ,
 | |
| 
 | |
|     maxoff    = entryvec->n - 1;
 | |
| 
 | |
|     Nsrt     arr[maxoff+1]  ;
 | |
|     int       nbytes  ;   
 | |
| 
 | |
|     nbytes        = (maxoff + 2) * sizeof(OffsetNumber);
 | |
|     v->spl_left   = (OffsetNumber *) palloc(nbytes);
 | |
|     v->spl_right  = (OffsetNumber *) palloc(nbytes);   
 | |
|     v->spl_ldatum = PointerGetDatum(0);
 | |
|     v->spl_rdatum = PointerGetDatum(0);
 | |
|     v->spl_nleft  = 0;
 | |
|     v->spl_nright = 0; 
 | |
| 
 | |
|     /* Sort entries */
 | |
| 
 | |
|     for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 | |
|     {
 | |
|       arr[i].t  = (GBT_NUMKEY *) DatumGetPointer((entryvec->vector[i].key));
 | |
|       arr[i].i = i;
 | |
|     }
 | |
|     qsort ( (void*) &arr[FirstOffsetNumber], maxoff-FirstOffsetNumber+1,sizeof(Nsrt), tinfo->f_cmp );
 | |
| 
 | |
|     /* We do simply create two parts */
 | |
| 
 | |
|     for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
 | |
|     {
 | |
|       if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
 | |
|       {
 | |
|         gbt_num_bin_union(&v->spl_ldatum, arr[i].t, tinfo);
 | |
|         v->spl_left[v->spl_nleft]   = arr[i].i;
 | |
|         v->spl_nleft++;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         gbt_num_bin_union(&v->spl_rdatum, arr[i].t, tinfo);
 | |
|         v->spl_right[v->spl_nright]   = arr[i].i;
 | |
|         v->spl_nright++;
 | |
|       }
 | |
|     }  
 | |
| 
 | |
|     return v;
 | |
| 
 | |
| }
 | |
| 
 |