summaryrefslogtreecommitdiff
path: root/contrib/btree_gist/btree_utils_var.c
diff options
context:
space:
mode:
authorTeodor Sigaev2004-05-28 10:43:32 +0000
committerTeodor Sigaev2004-05-28 10:43:32 +0000
commit42d069886f38687839388c615af608706508b557 (patch)
tree0409615407a17d22e2511ac14745277467853453 /contrib/btree_gist/btree_utils_var.c
parent1a321f26d88e5c64bccba9d36920aede1e201729 (diff)
New version. Add support for int2, int8, float4, float8, timestamp with/without time zone, time with/without time zone, date, interval, oid, money and macaddr, char, varchar/text, bytea, numeric, bit, varbit, inet/cidr types for GiST
Diffstat (limited to 'contrib/btree_gist/btree_utils_var.c')
-rw-r--r--contrib/btree_gist/btree_utils_var.c617
1 files changed, 617 insertions, 0 deletions
diff --git a/contrib/btree_gist/btree_utils_var.c b/contrib/btree_gist/btree_utils_var.c
new file mode 100644
index 00000000000..65ecbf33aef
--- /dev/null
+++ b/contrib/btree_gist/btree_utils_var.c
@@ -0,0 +1,617 @@
+#include "btree_gist.h"
+#include "utils/pg_locale.h"
+#include "btree_utils_var.h"
+
+/* Returns a better readable representaion of variable key ( sets pointer ) */
+
+extern GBT_VARKEY_R gbt_var_key_readable ( const GBT_VARKEY * k ){
+
+ GBT_VARKEY_R r ;
+ r.lower = ( bytea * ) &(((char*)k)[VARHDRSZ] ) ;
+ if ( VARSIZE(k) > ( VARHDRSZ+(VARSIZE(r.lower)) ) )
+ r.upper = ( bytea * ) &(((char*)k)[VARHDRSZ+(VARSIZE(r.lower))] ) ;
+ else
+ r.upper = r.lower;
+ return r;
+}
+
+
+extern GBT_VARKEY * gbt_var_key_copy ( const GBT_VARKEY_R * u , bool force_node ){
+
+ GBT_VARKEY * r = NULL;
+
+ if ( u->lower == u->upper && !force_node ){ /* leaf key mode */
+
+ r = (GBT_VARKEY *) palloc(VARSIZE(u->lower) + VARHDRSZ );
+ memcpy ( (void*) VARDATA(r), (void*) u->lower , VARSIZE(u->lower) );
+ r->vl_len = VARSIZE(u->lower) + VARHDRSZ ;
+
+ } else { /* node key mode */
+
+ r = (GBT_VARKEY *) palloc(VARSIZE(u->lower) + VARSIZE(u->upper) + VARHDRSZ );
+ memcpy ( (void*) VARDATA(r) , (void*) u->lower , VARSIZE(u->lower) );
+ memcpy ( (void*)&(((char *)r)[VARHDRSZ+VARSIZE(u->lower)]), (void*) u->upper , VARSIZE(u->upper) );
+ r->vl_len = VARSIZE(u->lower) + VARSIZE(u->upper) + VARHDRSZ ;
+
+ }
+ return r;
+
+}
+
+
+static GBT_VARKEY * gbt_var_leaf2node ( GBT_VARKEY * leaf, const gbtree_vinfo * tinfo )
+{
+
+ GBT_VARKEY *out = leaf ;
+
+ if ( tinfo->f_l2n )
+ {
+ out = (*tinfo->f_l2n) (leaf);
+ }
+
+ return out;
+
+}
+
+
+/*
+ * returns the common prefix length of a node key
+*/
+static int32 gbt_var_node_cp_len ( const GBT_VARKEY * node , const gbtree_vinfo * tinfo )
+{
+ int32 i ;
+ int32 s = (tinfo->str)?(1):(0);
+ GBT_VARKEY_R r = gbt_var_key_readable ( node );
+ int32 t1len = VARSIZE(r.lower) - VARHDRSZ - s;
+ int32 t2len = VARSIZE(r.upper) - VARHDRSZ - s;
+ int32 ml = Min(t1len,t2len) ;
+
+ char * p1 = VARDATA(r.lower) ,
+ * p2 = VARDATA(r.upper) ;
+
+ for ( i=0 ; i<ml; i++ )
+ {
+ if ( *p1 != *p2 )
+ {
+ return i;
+ }
+ p1++;
+ p2++;
+ }
+ return ( ml );
+}
+
+
+
+/*
+ * returns true, if query matches prefix using common prefix
+*/
+
+static bool gbt_bytea_pf_match ( const bytea * pf , const bytea * query , const gbtree_vinfo * tinfo )
+{
+
+ int k ;
+ int32 s = (tinfo->str)?(1):(0);
+ bool out = FALSE ;
+ int32 qlen = VARSIZE(query) - VARHDRSZ - s ;
+ int32 nlen = VARSIZE(pf) - VARHDRSZ - s ;
+ if ( nlen <= qlen )
+ {
+ char *q = VARDATA(query) ;
+ char *n = VARDATA(pf) ;
+ out = TRUE;
+ for ( k=0 ; k<nlen; k++ )
+ {
+ if ( *n != *q ){
+ out = FALSE;
+ break;
+ }
+ if ( k < (nlen-1) )
+ {
+ q++;
+ n++;
+ }
+ }
+ }
+
+ return out;
+}
+
+
+
+
+/*
+ * returns true, if query matches node using common prefix
+*/
+
+static bool gbt_var_node_pf_match ( const GBT_VARKEY_R * node , const bytea * query , const gbtree_vinfo * tinfo )
+{
+
+ return (
+ gbt_bytea_pf_match ( node->lower, query , tinfo ) ||
+ gbt_bytea_pf_match ( node->upper, query , tinfo )
+ );
+
+}
+
+
+/*
+* truncates / compresses the node key
+*/
+static GBT_VARKEY * gbt_var_node_truncate ( const GBT_VARKEY * node , int32 length , const gbtree_vinfo * tinfo )
+{
+
+ int32 s = (tinfo->str)?(1):(0);
+ GBT_VARKEY * out = NULL;
+ GBT_VARKEY_R r = gbt_var_key_readable ( node );
+ int32 len1 = VARSIZE(r.lower) - VARHDRSZ;
+ int32 len2 = VARSIZE(r.upper) - VARHDRSZ;
+ int32 si = 0;
+
+ if (tinfo->str)
+ length++; /* because of tailing '\0' */
+
+ len1 = Min( len1, length ) ;
+ len2 = Min( len2, length ) ;
+ si = 3*VARHDRSZ + len1 + len2;
+ out = (GBT_VARKEY *) palloc ( si );
+ out->vl_len = si;
+ memcpy ( (void*) &(((char*)out)[VARHDRSZ]) , (void*)r.lower, len1+VARHDRSZ-s );
+ memcpy ( (void*) &(((char*)out)[2*VARHDRSZ+len1]) , (void*)r.upper, len2+VARHDRSZ-s );
+
+ if (tinfo->str)
+ {
+ ((char*)out)[2*VARHDRSZ+len1-1] = '\0';
+ ((char*)out)[3*VARHDRSZ+len1+len2-1] = '\0';
+ }
+ *((int32*)&(((char*)out)[VARHDRSZ])) = len1 + VARHDRSZ;
+ *((int32*)&(((char*)out)[2*VARHDRSZ+len1])) = len2 + VARHDRSZ;
+
+ return out;
+}
+
+
+
+extern void
+gbt_var_bin_union ( Datum * u , GBT_VARKEY * e , const gbtree_vinfo * tinfo )
+{
+
+ GBT_VARKEY * nk = NULL;
+ GBT_VARKEY * tmp = NULL;
+ GBT_VARKEY_R nr ;
+ GBT_VARKEY_R eo = gbt_var_key_readable ( e );
+
+
+ if ( eo.lower == eo.upper ) /* leaf */
+ {
+ tmp = gbt_var_leaf2node ( e , tinfo );
+ if ( tmp != e )
+ eo = gbt_var_key_readable ( tmp );
+ }
+
+ if ( DatumGetPointer(*u))
+ {
+
+ GBT_VARKEY_R ro = gbt_var_key_readable ( ( GBT_VARKEY *) DatumGetPointer (*u) );
+
+ if ( (*tinfo->f_cmp) ( (bytea*)ro.lower, (bytea*)eo.lower ) > 0 ) {
+ nr.lower = eo.lower;
+ nr.upper = ro.upper;
+ nk = gbt_var_key_copy ( &nr, TRUE );
+ }
+ if ( (*tinfo->f_cmp) ( (bytea*)ro.upper, (bytea*)eo.upper ) < 0 ) {
+ nr.upper = eo.upper;
+ nr.lower = ro.lower;
+ nk = gbt_var_key_copy ( &nr, TRUE );
+ }
+ if ( nk )
+ {
+ pfree( DatumGetPointer (*u) );
+ *u = PointerGetDatum(nk);
+ }
+
+
+
+ }
+ else
+ {
+ nr.lower = eo.lower;
+ nr.upper = eo.upper;
+ *u = PointerGetDatum( gbt_var_key_copy ( &nr, TRUE ) );
+ }
+
+ if ( tmp && tmp != e )
+ pfree ( tmp );
+
+}
+
+
+
+extern GISTENTRY *
+gbt_var_compress ( GISTENTRY *entry , const gbtree_vinfo * tinfo )
+{
+
+ GISTENTRY * retval;
+
+ if (entry->leafkey)
+ {
+ GBT_VARKEY * r = NULL;
+ bytea * tstd = ( bytea * ) DatumGetPointer ( entry->key ); /* toasted */
+ bytea * leaf = ( bytea * ) DatumGetPointer ( PG_DETOAST_DATUM ( entry->key ) ); /* untoasted */
+ GBT_VARKEY_R u ;
+
+ u.lower = u.upper = leaf;
+ r = gbt_var_key_copy ( &u , FALSE );
+
+ if ( tstd != leaf ){
+ pfree(leaf);
+ }
+ retval = palloc(sizeof(GISTENTRY));
+ gistentryinit(*retval, PointerGetDatum(r),
+ entry->rel, entry->page,
+ entry->offset, VARSIZE(r), TRUE);
+ } else {
+ retval = entry;
+
+
+ }
+
+ return (retval);
+}
+
+
+
+extern GBT_VARKEY *
+gbt_var_union ( const GistEntryVector * entryvec , int32 * size , const gbtree_vinfo * tinfo )
+{
+
+ int i = 0,
+ numranges = entryvec->n;
+ GBT_VARKEY *cur,
+ *tst=NULL;
+ Datum out;
+ GBT_VARKEY_R rk;
+
+ *size = sizeof(GBT_VARKEY);
+
+ tst = (GBT_VARKEY *) DatumGetPointer((entryvec->vector[0].key));
+ cur = (GBT_VARKEY *) DatumGetPointer(PG_DETOAST_DATUM((entryvec->vector[0].key)));
+ rk = gbt_var_key_readable ( cur );
+ out = PointerGetDatum ( gbt_var_key_copy( &rk, TRUE ) );
+ if ( tst != cur ) pfree ( cur );
+
+ for (i = 1; i < numranges; i++)
+ {
+ tst = (GBT_VARKEY *) DatumGetPointer((entryvec->vector[i].key));
+ cur = (GBT_VARKEY *) DatumGetPointer(PG_DETOAST_DATUM((entryvec->vector[i].key)));
+ gbt_var_bin_union ( &out , cur , tinfo );
+ if ( tst != cur ) pfree ( cur );
+ }
+
+
+ /* Truncate (=compress) key */
+
+ if ( tinfo->trnc )
+ {
+ int32 plen ;
+ GBT_VARKEY *trc = NULL;
+
+ plen = gbt_var_node_cp_len ( (GBT_VARKEY *) DatumGetPointer(out) , tinfo );
+ trc = gbt_var_node_truncate ( (GBT_VARKEY *) DatumGetPointer(out) , plen+1 , tinfo ) ;
+
+ pfree ( DatumGetPointer(out) );
+ out = PointerGetDatum ( trc );
+ }
+
+ return ( (GBT_VARKEY *) DatumGetPointer ( out ) );
+}
+
+
+extern bool gbt_var_same ( bool * result, const Datum d1 , const Datum d2 , const gbtree_vinfo * tinfo ){
+
+ GBT_VARKEY *tst1 = (GBT_VARKEY *) DatumGetPointer(d1);
+ GBT_VARKEY *t1 = (GBT_VARKEY *) DatumGetPointer( PG_DETOAST_DATUM(d1) );
+ GBT_VARKEY *tst2 = (GBT_VARKEY *) DatumGetPointer(d2);
+ GBT_VARKEY *t2 = (GBT_VARKEY *) DatumGetPointer( PG_DETOAST_DATUM(d2) );
+ GBT_VARKEY_R r1, r2;
+ r1 = gbt_var_key_readable ( t1 );
+ r2 = gbt_var_key_readable ( t2 );
+
+ if (t1 && t2){
+ *result = ( ( (*tinfo->f_cmp ) ( (bytea*)r1.lower, (bytea*)r2.lower) == 0
+ && (*tinfo->f_cmp) ( (bytea*)r1.upper, (bytea*)r2.upper) == 0 ) ? TRUE : FALSE );
+ } else
+ *result = (t1 == NULL && t2 == NULL) ? TRUE : FALSE;
+
+ if ( tst1 != t1 ) pfree (t1);
+ if ( tst2 != t2 ) pfree (t2);
+
+ PG_RETURN_POINTER(result);
+}
+
+
+
+extern float *
+gbt_var_penalty ( float * res , const GISTENTRY * o , const GISTENTRY * n, const gbtree_vinfo * tinfo )
+{
+
+ GBT_VARKEY *orgt = (GBT_VARKEY *) DatumGetPointer(o->key);
+ GBT_VARKEY *orge = (GBT_VARKEY *) DatumGetPointer( PG_DETOAST_DATUM(o->key) );
+ GBT_VARKEY *newt = (GBT_VARKEY *) DatumGetPointer(n->key);
+ GBT_VARKEY *newe = (GBT_VARKEY *) DatumGetPointer( PG_DETOAST_DATUM(n->key) );
+ GBT_VARKEY_R ok , nk;
+ GBT_VARKEY *tmp = NULL;
+ int32 s = (tinfo->str)?(1):(0);
+
+ *res = 0.0;
+
+ nk = gbt_var_key_readable ( newe );
+ if ( nk.lower == nk.upper ) /* leaf */
+ {
+ tmp = gbt_var_leaf2node ( newe , tinfo );
+ if ( tmp != newe )
+ nk = gbt_var_key_readable ( tmp );
+ }
+ ok = gbt_var_key_readable ( orge );
+
+ if ( ( VARSIZE(ok.lower) - VARHDRSZ ) == s && ( VARSIZE(ok.upper) - VARHDRSZ ) == s )
+ {
+ *res = 0.0;
+ } else
+ if ( ! (
+ (
+ ( (*tinfo->f_cmp) (nk.lower, ok.lower)>=0 || gbt_bytea_pf_match(ok.lower, nk.lower, tinfo ) ) &&
+ ( (*tinfo->f_cmp) (nk.upper, ok.upper)<=0 || gbt_bytea_pf_match(ok.upper, nk.upper, tinfo ) )
+ )
+ ) )
+ {
+ Datum d = PointerGetDatum (0);
+ double dres = 0.0;
+ int32 ol, ul;
+
+ gbt_var_bin_union ( &d , orge , tinfo );
+ ol = gbt_var_node_cp_len ( ( GBT_VARKEY *) DatumGetPointer(d), tinfo );
+ gbt_var_bin_union ( &d , newe , tinfo );
+ ul = gbt_var_node_cp_len ( ( GBT_VARKEY *) DatumGetPointer(d), tinfo );
+
+ if ( ul < ol ) {
+ dres = ( ol-ul ) ; /* lost of common prefix len */
+ } else {
+ GBT_VARKEY_R uk = gbt_var_key_readable ( ( GBT_VARKEY *) DatumGetPointer(d) );
+ if ( tinfo->str )
+ {
+ dres = ( VARDATA(ok.lower)[ul]-VARDATA(uk.lower)[ul] ) +
+ ( VARDATA(uk.upper)[ul]-VARDATA(ok.upper)[ul] );
+ } else {
+ char tmp[4];
+ tmp[0] = ( ( VARSIZE(ok.lower) - VARHDRSZ ) == ul )?(CHAR_MIN):(VARDATA(ok.lower)[ul]);
+ tmp[1] = ( ( VARSIZE(uk.lower) - VARHDRSZ ) == ul )?(CHAR_MIN):(VARDATA(uk.lower)[ul]);
+ tmp[2] = ( ( VARSIZE(ok.upper) - VARHDRSZ ) == ul )?(CHAR_MIN):(VARDATA(ok.upper)[ul]);
+ tmp[3] = ( ( VARSIZE(uk.upper) - VARHDRSZ ) == ul )?(CHAR_MIN):(VARDATA(uk.upper)[ul]);
+ dres = ( tmp[0] - tmp[1] ) +
+ ( tmp[3] - tmp[2] );
+ }
+ dres /= 256.0;
+ }
+ pfree ( DatumGetPointer(d) );
+
+ *res += FLT_MIN ;
+ *res += (float) ( dres / ( (double) ( ol +1 ) ) );
+ *res *= ( FLT_MAX / ( o->rel->rd_att->natts + 1 ) );
+
+ }
+
+ if ( tmp && tmp != newe )
+ pfree (tmp);
+
+ if ( newe != newt ){
+ pfree ( newe );
+ }
+
+ if ( orge != orgt ){
+ pfree ( orge );
+ }
+ return res ;
+
+}
+
+
+static int32 gbt_vsrt_cmp ( const Vsrt * a , const Vsrt * b , const gbtree_vinfo * tinfo )
+{
+ GBT_VARKEY_R ar = gbt_var_key_readable ( a->t );
+ GBT_VARKEY_R br = gbt_var_key_readable ( b->t );
+ return (*tinfo->f_cmp) ( ar.lower, br.lower );
+}
+
+
+
+extern GIST_SPLITVEC *
+gbt_var_picksplit( const GistEntryVector *entryvec, GIST_SPLITVEC *v, const gbtree_vinfo * tinfo )
+{
+
+ OffsetNumber i ,
+ maxoff = entryvec->n - 1;
+
+ Vsrt arr[maxoff+1] ;
+ int pfrcntr = 0 ,
+ svcntr = 0 ,
+ nbytes ;
+ char * tst ,
+ * cur ;
+
+ char **pfr = NULL ;
+ GBT_VARKEY **sv = NULL;
+
+ static int cmp (const void *a, const void *b ){
+ return gbt_vsrt_cmp ((Vsrt *) a , (Vsrt *) b , tinfo );
+ }
+
+ 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;
+
+ pfr = palloc ( sizeof ( GBT_VARKEY* ) * (maxoff+1) );
+ sv = palloc ( sizeof ( bytea * ) * (maxoff+1) );
+
+ /* Sort entries */
+
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ {
+ GBT_VARKEY_R ro;
+ tst = (char *) DatumGetPointer((entryvec->vector[i].key));
+ cur = (char *) DatumGetPointer(PG_DETOAST_DATUM((entryvec->vector[i].key)));
+ if ( tst != cur ){
+ pfr[pfrcntr] = cur ;
+ pfrcntr++;
+ }
+ ro = gbt_var_key_readable( ( GBT_VARKEY *) cur );
+ if ( ro.lower == ro.upper ) /* leaf */
+ {
+ sv[svcntr] = gbt_var_leaf2node ( ( GBT_VARKEY *) cur , tinfo );
+ arr[i].t = sv[svcntr];
+ if ( sv[svcntr] != ( GBT_VARKEY *) cur )
+ svcntr++;
+ } else {
+ arr[i].t = ( GBT_VARKEY *) cur;
+ }
+ arr[i].i = i;
+ }
+
+ /* sort */
+ qsort ( (void*) &arr[FirstOffsetNumber], maxoff-FirstOffsetNumber+1,sizeof(Vsrt), cmp );
+
+
+ /* We do simply create two parts */
+
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ {
+ if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
+ {
+ gbt_var_bin_union(&v->spl_ldatum, arr[i].t, tinfo);
+ v->spl_left[v->spl_nleft] = arr[i].i;
+ v->spl_nleft++;
+ }
+ else
+ {
+ gbt_var_bin_union(&v->spl_rdatum, arr[i].t, tinfo);
+ v->spl_right[v->spl_nright] = arr[i].i;
+ v->spl_nright++;
+ }
+ }
+
+ /* Free detoasted keys */
+ for ( i=0 ; i<pfrcntr; i++ ){
+ pfree( pfr[i] );
+ }
+
+ /* Free strxfrm'ed leafs */
+ for ( i=0 ; i<svcntr; i++ ){
+ pfree( sv[i] );
+ }
+
+ if ( pfr )
+ {
+ pfree (pfr);
+ }
+
+ if ( sv )
+ {
+ pfree (sv);
+ }
+
+ /* Truncate (=compress) key */
+
+ if ( tinfo->trnc )
+ {
+
+ int32 ll = gbt_var_node_cp_len ( (GBT_VARKEY *) DatumGetPointer(v->spl_ldatum) , tinfo );
+ int32 lr = gbt_var_node_cp_len ( (GBT_VARKEY *) DatumGetPointer(v->spl_rdatum) , tinfo );
+ GBT_VARKEY * dl ;
+ GBT_VARKEY * dr ;
+
+ ll = Max (ll,lr);
+ ll++;
+
+ dl = gbt_var_node_truncate ( (GBT_VARKEY *) DatumGetPointer(v->spl_ldatum) , ll, tinfo ) ;
+ dr = gbt_var_node_truncate ( (GBT_VARKEY *) DatumGetPointer(v->spl_rdatum) , ll, tinfo ) ;
+ pfree( DatumGetPointer(v->spl_ldatum) );
+ pfree( DatumGetPointer(v->spl_rdatum) );
+ v->spl_ldatum = PointerGetDatum ( dl );
+ v->spl_rdatum = PointerGetDatum ( dr );
+
+ }
+
+ return v;
+
+}
+
+
+
+
+
+/*
+** The GiST consistent method
+*/
+
+extern bool
+gbt_var_consistent(
+ GBT_VARKEY_R * key,
+ const void * query,
+ const StrategyNumber * strategy,
+ bool is_leaf,
+ const gbtree_vinfo * tinfo
+)
+{
+ bool retval = FALSE;
+
+ switch (*strategy)
+ {
+ case BTLessEqualStrategyNumber:
+ if ( is_leaf )
+ retval = (*tinfo->f_ge)(query, (void*) key->lower);
+ else
+ retval = (*tinfo->f_cmp)((bytea*) query, key->lower) >= 0
+ || gbt_var_node_pf_match( key ,query, tinfo );
+ break;
+ case BTLessStrategyNumber:
+ if ( is_leaf )
+ retval = (*tinfo->f_gt)(query, (void*) key->lower);
+ else
+ retval = (*tinfo->f_cmp)((bytea*)query, key->lower) >= 0
+ || gbt_var_node_pf_match( key, query , tinfo );
+ break;
+ case BTEqualStrategyNumber:
+ if ( is_leaf )
+ retval = (*tinfo->f_eq)(query, (void*) key->lower);
+ else
+ retval = (
+ (
+ (*tinfo->f_cmp) (key->lower,(bytea*) query)<=0 &&
+ (*tinfo->f_cmp) ((bytea*)query, (void*) key->upper)<=0
+ ) || gbt_var_node_pf_match( key, query, tinfo )
+ );
+ break;
+ case BTGreaterStrategyNumber:
+ if ( is_leaf )
+ retval = (*tinfo->f_lt)(query, (void*) key->upper);
+ else
+ retval = (*tinfo->f_cmp)((bytea*)query, key->upper)<=0
+ || gbt_var_node_pf_match( key, query, tinfo );
+ break;
+ case BTGreaterEqualStrategyNumber:
+ if ( is_leaf )
+ retval = (*tinfo->f_le)(query, (void*) key->upper);
+ else
+ retval = (*tinfo->f_cmp)((bytea*) query, key->upper)<=0
+ || gbt_var_node_pf_match( key, query, tinfo );
+ break;
+ default:
+ retval = FALSE;
+ }
+
+ return (retval);
+}