mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-07 12:19:22 +02: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;
|
|
|
|
}
|
|
|