mirror of https://github.com/postgres/postgres
(7.3 and current CVS) with support of int8, float4, float8 in addition to int4. Thanks Janko Richter for contribution. Oleg BartunovWIN32_DEV
parent
4996eea81c
commit
4efbbd7318
@ -1,12 +1,26 @@ |
||||
# $Header: /cvsroot/pgsql/contrib/btree_gist/Makefile,v 1.3 2001/09/06 10:49:29 petere Exp $
|
||||
|
||||
subdir = contrib/btree_gist
|
||||
top_builddir = ../..
|
||||
include $(top_builddir)/src/Makefile.global |
||||
|
||||
MODULES = btree_gist
|
||||
MODULE_big = btree_gist
|
||||
OBJS= btree_common.o btree_int4.o btree_int8.o btree_float4.o btree_float8.o btree_ts.o
|
||||
DATA_built = btree_gist.sql
|
||||
DOCS = README.btree_gist
|
||||
REGRESS = btree_gist
|
||||
|
||||
EXTRA_CLEAN = btree_int4.c btree_int8.c btree_float4.c btree_float8.c
|
||||
|
||||
include $(top_srcdir)/contrib/contrib-global.mk |
||||
|
||||
btree_int4.c: btree_num.c.in |
||||
sed 's,__DEFINE_BTREE_TYPE_HERE__,BTREE_GIST_INT4,g;s,__BTREE_GIST_TYPE__,int32,g;s,__BTREE_GIST_TYPE2__,int4,g' < $< > $@
|
||||
|
||||
btree_int8.c: btree_num.c.in |
||||
sed 's,__DEFINE_BTREE_TYPE_HERE__,BTREE_GIST_INT8,g;s,__BTREE_GIST_TYPE__,int64,g;s,__BTREE_GIST_TYPE2__,int8,g' < $< > $@
|
||||
|
||||
btree_float4.c: btree_num.c.in |
||||
sed 's,__DEFINE_BTREE_TYPE_HERE__,BTREE_GIST_FLOAT4,g;s,__BTREE_GIST_TYPE__,float4,g;s,__BTREE_GIST_TYPE2__,float4,g' < $< > $@
|
||||
|
||||
btree_float8.c: btree_num.c.in |
||||
sed 's,__DEFINE_BTREE_TYPE_HERE__,BTREE_GIST_FLOAT8,g;s,__BTREE_GIST_TYPE__,float8,g;s,__BTREE_GIST_TYPE2__,float8,g' < $< > $@
|
||||
|
||||
@ -0,0 +1,69 @@ |
||||
#include "btree_gist.h" |
||||
|
||||
PG_FUNCTION_INFO_V1(btree_decompress); |
||||
Datum btree_decompress(PG_FUNCTION_ARGS); |
||||
|
||||
/*
|
||||
** GiST DeCompress methods |
||||
** do not do anything. |
||||
*/ |
||||
Datum |
||||
btree_decompress(PG_FUNCTION_ARGS) |
||||
{ |
||||
PG_RETURN_POINTER(PG_GETARG_POINTER(0)); |
||||
} |
||||
|
||||
|
||||
/**************************************************
|
||||
* Common btree-function (for all ops) |
||||
**************************************************/ |
||||
|
||||
/*
|
||||
** The GiST PickSplit method |
||||
*/ |
||||
extern GIST_SPLITVEC * |
||||
btree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, BINARY_UNION bu, CMPFUNC cmp) |
||||
{ |
||||
OffsetNumber i; |
||||
RIX *array; |
||||
OffsetNumber maxoff; |
||||
int nbytes; |
||||
|
||||
maxoff = ((VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY)) - 1; |
||||
nbytes = (maxoff + 2) * sizeof(OffsetNumber); |
||||
v->spl_left = (OffsetNumber *) palloc(nbytes); |
||||
v->spl_right = (OffsetNumber *) palloc(nbytes); |
||||
v->spl_nleft = 0; |
||||
v->spl_nright = 0; |
||||
v->spl_ldatum = PointerGetDatum(0); |
||||
v->spl_rdatum = PointerGetDatum(0); |
||||
array = (RIX *) palloc(sizeof(RIX) * (maxoff + 1)); |
||||
|
||||
/* copy the data into RIXes, and sort the RIXes */ |
||||
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) |
||||
{ |
||||
array[i].index = i; |
||||
array[i].r = (char *) DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[i].key)); |
||||
} |
||||
qsort((void *) &array[FirstOffsetNumber], maxoff - FirstOffsetNumber + 1, |
||||
sizeof(RIX), cmp); |
||||
|
||||
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) |
||||
{ |
||||
if (i <= (maxoff - FirstOffsetNumber + 1) / 2) |
||||
{ |
||||
v->spl_left[v->spl_nleft] = array[i].index; |
||||
v->spl_nleft++; |
||||
(*bu) (&v->spl_ldatum, array[i].r); |
||||
} |
||||
else |
||||
{ |
||||
v->spl_right[v->spl_nright] = array[i].index; |
||||
v->spl_nright++; |
||||
(*bu) (&v->spl_rdatum, array[i].r); |
||||
} |
||||
} |
||||
pfree(array); |
||||
|
||||
return (v); |
||||
} |
||||
@ -1,584 +0,0 @@ |
||||
#include "postgres.h" |
||||
|
||||
#include "access/gist.h" |
||||
#include "access/itup.h" |
||||
#include "access/nbtree.h" |
||||
|
||||
#include "utils/palloc.h" |
||||
#include "utils/geo_decls.h" |
||||
#include "utils/elog.h" |
||||
|
||||
typedef int (*CMPFUNC) (const void *a, const void *b); |
||||
typedef void (*BINARY_UNION) (Datum *, char *); |
||||
|
||||
typedef struct intkey |
||||
{ |
||||
int4 lower; |
||||
int4 upper; |
||||
} INT4KEY; |
||||
|
||||
typedef struct tskey |
||||
{ |
||||
Timestamp lower; |
||||
Timestamp upper; |
||||
} TSKEY; |
||||
|
||||
/* used for sorting */ |
||||
typedef struct rix |
||||
{ |
||||
int index; |
||||
char *r; |
||||
} RIX; |
||||
|
||||
/*
|
||||
** int4key in/out |
||||
*/ |
||||
PG_FUNCTION_INFO_V1(int4key_in); |
||||
PG_FUNCTION_INFO_V1(int4key_out); |
||||
Datum int4key_in(PG_FUNCTION_ARGS); |
||||
Datum int4key_out(PG_FUNCTION_ARGS); |
||||
|
||||
/*
|
||||
** tskey in/out |
||||
*/ |
||||
PG_FUNCTION_INFO_V1(tskey_in); |
||||
PG_FUNCTION_INFO_V1(tskey_out); |
||||
Datum tskey_in(PG_FUNCTION_ARGS); |
||||
Datum tskey_out(PG_FUNCTION_ARGS); |
||||
|
||||
/*
|
||||
** int4 ops |
||||
*/ |
||||
PG_FUNCTION_INFO_V1(gint4_compress); |
||||
PG_FUNCTION_INFO_V1(gint4_union); |
||||
PG_FUNCTION_INFO_V1(gint4_picksplit); |
||||
PG_FUNCTION_INFO_V1(gint4_consistent); |
||||
PG_FUNCTION_INFO_V1(gint4_penalty); |
||||
PG_FUNCTION_INFO_V1(gint4_same); |
||||
|
||||
Datum gint4_compress(PG_FUNCTION_ARGS); |
||||
Datum gint4_union(PG_FUNCTION_ARGS); |
||||
Datum gint4_picksplit(PG_FUNCTION_ARGS); |
||||
Datum gint4_consistent(PG_FUNCTION_ARGS); |
||||
Datum gint4_penalty(PG_FUNCTION_ARGS); |
||||
Datum gint4_same(PG_FUNCTION_ARGS); |
||||
|
||||
static void gint4_binary_union(Datum *r1, char *r2); |
||||
static int int4key_cmp(const void *a, const void *b); |
||||
|
||||
/*
|
||||
** timestamp ops |
||||
*/ |
||||
PG_FUNCTION_INFO_V1(gts_compress); |
||||
PG_FUNCTION_INFO_V1(gts_union); |
||||
PG_FUNCTION_INFO_V1(gts_picksplit); |
||||
PG_FUNCTION_INFO_V1(gts_consistent); |
||||
PG_FUNCTION_INFO_V1(gts_penalty); |
||||
PG_FUNCTION_INFO_V1(gts_same); |
||||
|
||||
Datum gts_compress(PG_FUNCTION_ARGS); |
||||
Datum gts_union(PG_FUNCTION_ARGS); |
||||
Datum gts_picksplit(PG_FUNCTION_ARGS); |
||||
Datum gts_consistent(PG_FUNCTION_ARGS); |
||||
Datum gts_penalty(PG_FUNCTION_ARGS); |
||||
Datum gts_same(PG_FUNCTION_ARGS); |
||||
|
||||
static void gts_binary_union(Datum *r1, char *r2); |
||||
static int tskey_cmp(const void *a, const void *b); |
||||
|
||||
#define TimestampGetDatumFast(X) Float8GetDatumFast(X) |
||||
|
||||
/* define for comparison */ |
||||
#define TSGE( ts1, ts2 ) (DatumGetBool(DirectFunctionCall2( \ |
||||
timestamp_ge, \
|
||||
PointerGetDatum( ts1 ), \
|
||||
PointerGetDatum( ts2 ) \
|
||||
))) |
||||
#define TSGT( ts1, ts2 ) (DatumGetBool(DirectFunctionCall2( \ |
||||
timestamp_gt, \
|
||||
PointerGetDatum( ts1 ), \
|
||||
PointerGetDatum( ts2 ) \
|
||||
))) |
||||
#define TSEQ( ts1, ts2 ) (DatumGetBool(DirectFunctionCall2( \ |
||||
timestamp_eq, \
|
||||
PointerGetDatum( ts1 ), \
|
||||
PointerGetDatum( ts2 ) \
|
||||
))) |
||||
#define TSLT( ts1, ts2 ) (DatumGetBool(DirectFunctionCall2( \ |
||||
timestamp_lt, \
|
||||
PointerGetDatum( ts1 ), \
|
||||
PointerGetDatum( ts2 ) \
|
||||
))) |
||||
#define TSLE( ts1, ts2 ) (DatumGetBool(DirectFunctionCall2( \ |
||||
timestamp_le, \
|
||||
PointerGetDatum( ts1 ), \
|
||||
PointerGetDatum( ts2 ) \
|
||||
))) |
||||
|
||||
/*
|
||||
** Common btree-function (for all ops) |
||||
*/ |
||||
static GIST_SPLITVEC *btree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, |
||||
BINARY_UNION bu, CMPFUNC cmp); |
||||
|
||||
PG_FUNCTION_INFO_V1(btree_decompress); |
||||
Datum btree_decompress(PG_FUNCTION_ARGS); |
||||
|
||||
/**************************************************
|
||||
* int4 ops |
||||
**************************************************/ |
||||
|
||||
Datum |
||||
gint4_compress(PG_FUNCTION_ARGS) |
||||
{ |
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); |
||||
GISTENTRY *retval; |
||||
|
||||
if (entry->leafkey) |
||||
{ |
||||
INT4KEY *r = palloc(sizeof(INT4KEY)); |
||||
|
||||
retval = palloc(sizeof(GISTENTRY)); |
||||
r->lower = r->upper = (entry->key); |
||||
|
||||
gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, |
||||
entry->offset, sizeof(INT4KEY), FALSE); |
||||
|
||||
} |
||||
else |
||||
retval = entry; |
||||
PG_RETURN_POINTER(retval); |
||||
} |
||||
|
||||
Datum |
||||
gint4_consistent(PG_FUNCTION_ARGS) |
||||
{ |
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); |
||||
int4 query = PG_GETARG_INT32(1); |
||||
INT4KEY *kkk = (INT4KEY *) DatumGetPointer(entry->key); |
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); |
||||
bool retval; |
||||
|
||||
switch (strategy) |
||||
{ |
||||
case BTLessEqualStrategyNumber: |
||||
retval = (query >= kkk->lower); |
||||
break; |
||||
case BTLessStrategyNumber: |
||||
if (GIST_LEAF(entry)) |
||||
retval = (query > kkk->lower); |
||||
else |
||||
retval = (query >= kkk->lower); |
||||
break; |
||||
case BTEqualStrategyNumber: |
||||
/* in leaf page kkk->lower always = kkk->upper */ |
||||
if (GIST_LEAF(entry)) |
||||
retval = (query == kkk->lower); |
||||
else |
||||
retval = (kkk->lower <= query && query <= kkk->upper); |
||||
break; |
||||
case BTGreaterStrategyNumber: |
||||
if (GIST_LEAF(entry)) |
||||
retval = (query < kkk->upper); |
||||
else |
||||
retval = (query <= kkk->upper); |
||||
break; |
||||
case BTGreaterEqualStrategyNumber: |
||||
retval = (query <= kkk->upper); |
||||
break; |
||||
default: |
||||
retval = FALSE; |
||||
} |
||||
PG_RETURN_BOOL(retval); |
||||
} |
||||
|
||||
Datum |
||||
gint4_union(PG_FUNCTION_ARGS) |
||||
{ |
||||
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0); |
||||
int i, |
||||
numranges; |
||||
INT4KEY *cur, |
||||
*out = palloc(sizeof(INT4KEY)); |
||||
|
||||
numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY); |
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(INT4KEY); |
||||
|
||||
cur = (INT4KEY *) DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[0].key)); |
||||
out->lower = cur->lower; |
||||
out->upper = cur->upper; |
||||
|
||||
for (i = 1; i < numranges; i++) |
||||
{ |
||||
cur = (INT4KEY *) DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[i].key)); |
||||
if (out->lower > cur->lower) |
||||
out->lower = cur->lower; |
||||
if (out->upper < cur->upper) |
||||
out->upper = cur->upper; |
||||
} |
||||
|
||||
PG_RETURN_POINTER(out); |
||||
} |
||||
|
||||
Datum |
||||
gint4_penalty(PG_FUNCTION_ARGS) |
||||
{ |
||||
INT4KEY *origentry = (INT4KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key); |
||||
INT4KEY *newentry = (INT4KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key); |
||||
float *result = (float *) PG_GETARG_POINTER(2); |
||||
|
||||
*result = Max(newentry->upper - origentry->upper, 0) + |
||||
Max(origentry->lower - newentry->lower, 0); |
||||
|
||||
PG_RETURN_POINTER(result); |
||||
} |
||||
|
||||
Datum |
||||
gint4_picksplit(PG_FUNCTION_ARGS) |
||||
{ |
||||
PG_RETURN_POINTER(btree_picksplit( |
||||
(bytea *) PG_GETARG_POINTER(0), |
||||
(GIST_SPLITVEC *) PG_GETARG_POINTER(1), |
||||
gint4_binary_union, |
||||
int4key_cmp |
||||
)); |
||||
} |
||||
|
||||
Datum |
||||
gint4_same(PG_FUNCTION_ARGS) |
||||
{ |
||||
INT4KEY *b1 = (INT4KEY *) PG_GETARG_POINTER(0); |
||||
INT4KEY *b2 = (INT4KEY *) PG_GETARG_POINTER(1); |
||||
bool *result = (bool *) PG_GETARG_POINTER(2); |
||||
|
||||
*result = (b1->lower == b2->lower && b1->upper == b2->upper) ? TRUE : FALSE; |
||||
PG_RETURN_POINTER(result); |
||||
} |
||||
|
||||
static void |
||||
gint4_binary_union(Datum *r1, char *r2) |
||||
{ |
||||
INT4KEY *b1; |
||||
INT4KEY *b2 = (INT4KEY *) r2; |
||||
|
||||
if (!DatumGetPointer(*r1)) |
||||
{ |
||||
*r1 = PointerGetDatum(palloc(sizeof(INT4KEY))); |
||||
b1 = (INT4KEY *) DatumGetPointer(*r1); |
||||
b1->upper = b2->upper; |
||||
b1->lower = b2->lower; |
||||
} |
||||
else |
||||
{ |
||||
b1 = (INT4KEY *) DatumGetPointer(*r1); |
||||
|
||||
b1->lower = (b1->lower > b2->lower) ? |
||||
b2->lower : b1->lower; |
||||
b1->upper = (b1->upper > b2->upper) ? |
||||
b1->upper : b2->upper; |
||||
} |
||||
} |
||||
|
||||
|
||||
static int |
||||
int4key_cmp(const void *a, const void *b) |
||||
{ |
||||
return (((INT4KEY *) (((RIX *) a)->r))->lower - ((INT4KEY *) (((RIX *) b)->r))->lower); |
||||
} |
||||
|
||||
/**************************************************
|
||||
* timestamp ops |
||||
**************************************************/ |
||||
|
||||
Datum |
||||
gts_compress(PG_FUNCTION_ARGS) |
||||
{ |
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); |
||||
GISTENTRY *retval; |
||||
|
||||
if (entry->leafkey) |
||||
{ |
||||
TSKEY *r = (TSKEY *) palloc(sizeof(TSKEY)); |
||||
|
||||
retval = palloc(sizeof(GISTENTRY)); |
||||
r->lower = r->upper = *(Timestamp *) (entry->key); |
||||
gistentryinit(*retval, PointerGetDatum(r), |
||||
entry->rel, entry->page, |
||||
entry->offset, sizeof(TSKEY), FALSE); |
||||
} |
||||
else |
||||
retval = entry; |
||||
PG_RETURN_POINTER(retval); |
||||
} |
||||
|
||||
Datum |
||||
gts_consistent(PG_FUNCTION_ARGS) |
||||
{ |
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); |
||||
Timestamp *query = (Timestamp *) PG_GETARG_POINTER(1); |
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); |
||||
bool retval; |
||||
TSKEY *key; |
||||
|
||||
/*
|
||||
* * if entry is not leaf, use gbox_internal_consistent, * else use |
||||
* gbox_leaf_consistent |
||||
*/ |
||||
if (!entry->key) |
||||
return FALSE; |
||||
key = (TSKEY *) DatumGetPointer(entry->key); |
||||
|
||||
switch (strategy) |
||||
{ |
||||
case BTLessEqualStrategyNumber: |
||||
retval = TSGE(query, &(key->lower)); |
||||
break; |
||||
case BTLessStrategyNumber: |
||||
if (GIST_LEAF(entry)) |
||||
retval = TSGT(query, &(key->lower)); |
||||
else |
||||
retval = TSGE(query, &(key->lower)); |
||||
break; |
||||
case BTEqualStrategyNumber: |
||||
/* in leaf page key->lower always = key->upper */ |
||||
if (GIST_LEAF(entry)) |
||||
retval = TSEQ(query, &(key->lower)); |
||||
else |
||||
retval = (TSLE(&(key->lower), query) && TSLE(query, &(key->upper))); |
||||
break; |
||||
case BTGreaterStrategyNumber: |
||||
if (GIST_LEAF(entry)) |
||||
retval = TSLT(query, &(key->upper)); |
||||
else |
||||
retval = TSLE(query, &(key->upper)); |
||||
break; |
||||
case BTGreaterEqualStrategyNumber: |
||||
retval = TSLE(query, &(key->upper)); |
||||
break; |
||||
default: |
||||
retval = FALSE; |
||||
} |
||||
PG_RETURN_BOOL(retval); |
||||
} |
||||
|
||||
Datum |
||||
gts_union(PG_FUNCTION_ARGS) |
||||
{ |
||||
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0); |
||||
int i, |
||||
numranges; |
||||
TSKEY *cur, |
||||
*out = palloc(sizeof(TSKEY)); |
||||
|
||||
numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY); |
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(TSKEY); |
||||
|
||||
cur = (TSKEY *) DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[0].key)); |
||||
out->lower = cur->lower; |
||||
out->upper = cur->upper; |
||||
|
||||
for (i = 1; i < numranges; i++) |
||||
{ |
||||
cur = (TSKEY *) DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[i].key)); |
||||
if (TSGT(&out->lower, &cur->lower)) |
||||
out->lower = cur->lower; |
||||
if (TSLT(&out->upper, &cur->upper)) |
||||
out->upper = cur->upper; |
||||
} |
||||
|
||||
PG_RETURN_POINTER(out); |
||||
} |
||||
|
||||
Datum |
||||
gts_penalty(PG_FUNCTION_ARGS) |
||||
{ |
||||
TSKEY *origentry = (TSKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key); |
||||
TSKEY *newentry = (TSKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key); |
||||
float *result = (float *) PG_GETARG_POINTER(2); |
||||
Interval *intr; |
||||
|
||||
intr = DatumGetIntervalP(DirectFunctionCall2( |
||||
timestamp_mi, |
||||
TimestampGetDatumFast(newentry->upper), |
||||
TimestampGetDatumFast(origentry->upper))); |
||||
|
||||
/* see interval_larger */ |
||||
*result = Max(intr->time + intr->month * (30.0 * 86400), 0); |
||||
pfree(intr); |
||||
|
||||
intr = DatumGetIntervalP(DirectFunctionCall2( |
||||
timestamp_mi, |
||||
TimestampGetDatumFast(origentry->lower), |
||||
TimestampGetDatumFast(newentry->lower))); |
||||
|
||||
/* see interval_larger */ |
||||
*result += Max(intr->time + intr->month * (30.0 * 86400), 0); |
||||
pfree(intr); |
||||
|
||||
PG_RETURN_POINTER(result); |
||||
} |
||||
|
||||
Datum |
||||
gts_picksplit(PG_FUNCTION_ARGS) |
||||
{ |
||||
PG_RETURN_POINTER(btree_picksplit( |
||||
(bytea *) PG_GETARG_POINTER(0), |
||||
(GIST_SPLITVEC *) PG_GETARG_POINTER(1), |
||||
gts_binary_union, |
||||
tskey_cmp |
||||
)); |
||||
} |
||||
|
||||
Datum |
||||
gts_same(PG_FUNCTION_ARGS) |
||||
{ |
||||
TSKEY *b1 = (TSKEY *) PG_GETARG_POINTER(0); |
||||
TSKEY *b2 = (TSKEY *) PG_GETARG_POINTER(1); |
||||
|
||||
bool *result = (bool *) PG_GETARG_POINTER(2); |
||||
|
||||
if (b1 && b2) |
||||
*result = (TSEQ(&(b1->lower), &(b2->lower)) && TSEQ(&(b1->upper), &(b2->upper))) ? TRUE : FALSE; |
||||
else |
||||
*result = (b1 == NULL && b2 == NULL) ? TRUE : FALSE; |
||||
PG_RETURN_POINTER(result); |
||||
} |
||||
|
||||
static void |
||||
gts_binary_union(Datum *r1, char *r2) |
||||
{ |
||||
TSKEY *b1; |
||||
TSKEY *b2 = (TSKEY *) r2; |
||||
|
||||
if (!DatumGetPointer(*r1)) |
||||
{ |
||||
*r1 = PointerGetDatum(palloc(sizeof(TSKEY))); |
||||
b1 = (TSKEY *) DatumGetPointer(*r1); |
||||
b1->upper = b2->upper; |
||||
b1->lower = b2->lower; |
||||
} |
||||
else |
||||
{ |
||||
b1 = (TSKEY *) DatumGetPointer(*r1); |
||||
|
||||
b1->lower = (TSGT(&b1->lower, &b2->lower)) ? |
||||
b2->lower : b1->lower; |
||||
b1->upper = (TSGT(&b1->upper, &b2->upper)) ? |
||||
b1->upper : b2->upper; |
||||
} |
||||
} |
||||
|
||||
static int |
||||
tskey_cmp(const void *a, const void *b) |
||||
{ |
||||
return DatumGetInt32( |
||||
DirectFunctionCall2( |
||||
timestamp_cmp, |
||||
TimestampGetDatumFast(((TSKEY *) (((RIX *) a)->r))->lower), |
||||
TimestampGetDatumFast(((TSKEY *) (((RIX *) b)->r))->lower) |
||||
) |
||||
); |
||||
} |
||||
|
||||
/**************************************************
|
||||
* Common btree-function (for all ops) |
||||
**************************************************/ |
||||
|
||||
/*
|
||||
** The GiST PickSplit method |
||||
*/ |
||||
static GIST_SPLITVEC * |
||||
btree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, BINARY_UNION bu, CMPFUNC cmp) |
||||
{ |
||||
OffsetNumber i; |
||||
RIX *array; |
||||
OffsetNumber maxoff; |
||||
int nbytes; |
||||
|
||||
maxoff = ((VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY)) - 1; |
||||
nbytes = (maxoff + 2) * sizeof(OffsetNumber); |
||||
v->spl_left = (OffsetNumber *) palloc(nbytes); |
||||
v->spl_right = (OffsetNumber *) palloc(nbytes); |
||||
v->spl_nleft = 0; |
||||
v->spl_nright = 0; |
||||
v->spl_ldatum = PointerGetDatum(0); |
||||
v->spl_rdatum = PointerGetDatum(0); |
||||
array = (RIX *) palloc(sizeof(RIX) * (maxoff + 1)); |
||||
|
||||
/* copy the data into RIXes, and sort the RIXes */ |
||||
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) |
||||
{ |
||||
array[i].index = i; |
||||
array[i].r = (char *) DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[i].key)); |
||||
} |
||||
qsort((void *) &array[FirstOffsetNumber], maxoff - FirstOffsetNumber + 1, |
||||
sizeof(RIX), cmp); |
||||
|
||||
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) |
||||
{ |
||||
if (i <= (maxoff - FirstOffsetNumber + 1) / 2) |
||||
{ |
||||
v->spl_left[v->spl_nleft] = array[i].index; |
||||
v->spl_nleft++; |
||||
(*bu) (&v->spl_ldatum, array[i].r); |
||||
} |
||||
else |
||||
{ |
||||
v->spl_right[v->spl_nright] = array[i].index; |
||||
v->spl_nright++; |
||||
(*bu) (&v->spl_rdatum, array[i].r); |
||||
} |
||||
} |
||||
pfree(array); |
||||
|
||||
return (v); |
||||
} |
||||
|
||||
/*
|
||||
** GiST DeCompress methods |
||||
** do not do anything. |
||||
*/ |
||||
Datum |
||||
btree_decompress(PG_FUNCTION_ARGS) |
||||
{ |
||||
PG_RETURN_POINTER(PG_GETARG_POINTER(0)); |
||||
} |
||||
|
||||
|
||||
/**************************************************
|
||||
* In/Out for keys, not really needed |
||||
**************************************************/ |
||||
Datum |
||||
int4key_in(PG_FUNCTION_ARGS) |
||||
{ |
||||
INT4KEY *key = palloc(sizeof(INT4KEY)); |
||||
|
||||
if (sscanf(PG_GETARG_POINTER(0), "%d|%d", &(key->lower), &(key->upper)) != 2) |
||||
elog(ERROR, "Error in input format"); |
||||
|
||||
PG_RETURN_POINTER(key); |
||||
} |
||||
|
||||
Datum |
||||
int4key_out(PG_FUNCTION_ARGS) |
||||
{ |
||||
INT4KEY *key = (INT4KEY *) PG_GETARG_POINTER(0); |
||||
char *str = palloc(sizeof(char) * 22); |
||||
|
||||
sprintf(str, "%d|%d", key->lower, key->upper); |
||||
PG_RETURN_POINTER(str); |
||||
} |
||||
|
||||
Datum |
||||
tskey_in(PG_FUNCTION_ARGS) |
||||
{ |
||||
elog(ERROR, "Not implemented"); |
||||
PG_RETURN_POINTER(NULL); |
||||
} |
||||
|
||||
Datum |
||||
tskey_out(PG_FUNCTION_ARGS) |
||||
{ |
||||
elog(ERROR, "Not implemented"); |
||||
PG_RETURN_POINTER(NULL); |
||||
} |
||||
@ -0,0 +1,29 @@ |
||||
#include "postgres.h" |
||||
|
||||
#include "access/gist.h" |
||||
#include "access/itup.h" |
||||
#include "access/nbtree.h" |
||||
|
||||
#include "utils/palloc.h" |
||||
#include "utils/geo_decls.h" |
||||
#include "utils/elog.h" |
||||
|
||||
typedef int (*CMPFUNC) (const void *a, const void *b); |
||||
typedef void (*BINARY_UNION) (Datum *, char *); |
||||
|
||||
|
||||
/* used for sorting */ |
||||
|
||||
typedef struct rix |
||||
{ |
||||
int index; |
||||
char *r; |
||||
} RIX; |
||||
|
||||
/*
|
||||
** Common btree-function (for all ops) |
||||
*/ |
||||
|
||||
extern GIST_SPLITVEC *btree_picksplit(bytea *entryvec, GIST_SPLITVEC *v, |
||||
BINARY_UNION bu, CMPFUNC cmp); |
||||
|
||||
@ -0,0 +1,254 @@ |
||||
#include "btree_gist.h" |
||||
|
||||
#define __DEFINE_BTREE_TYPE_HERE__ 1 |
||||
|
||||
typedef struct __BTREE_GIST_TYPE__key |
||||
{ |
||||
__BTREE_GIST_TYPE__ lower; |
||||
__BTREE_GIST_TYPE__ upper; |
||||
} __BTREE_GIST_TYPE__KEY; |
||||
|
||||
|
||||
/*
|
||||
** __BTREE_GIST_TYPE__key in/out |
||||
*/ |
||||
PG_FUNCTION_INFO_V1(__BTREE_GIST_TYPE2__key_in); |
||||
PG_FUNCTION_INFO_V1(__BTREE_GIST_TYPE2__key_out); |
||||
Datum __BTREE_GIST_TYPE2__key_in(PG_FUNCTION_ARGS); |
||||
Datum __BTREE_GIST_TYPE2__key_out(PG_FUNCTION_ARGS); |
||||
|
||||
/*
|
||||
** __BTREE_GIST_TYPE__ ops |
||||
*/ |
||||
PG_FUNCTION_INFO_V1(g__BTREE_GIST_TYPE2___compress); |
||||
PG_FUNCTION_INFO_V1(g__BTREE_GIST_TYPE2___union); |
||||
PG_FUNCTION_INFO_V1(g__BTREE_GIST_TYPE2___picksplit); |
||||
PG_FUNCTION_INFO_V1(g__BTREE_GIST_TYPE2___consistent); |
||||
PG_FUNCTION_INFO_V1(g__BTREE_GIST_TYPE2___penalty); |
||||
PG_FUNCTION_INFO_V1(g__BTREE_GIST_TYPE2___same); |
||||
|
||||
Datum g__BTREE_GIST_TYPE2___compress(PG_FUNCTION_ARGS); |
||||
Datum g__BTREE_GIST_TYPE2___union(PG_FUNCTION_ARGS); |
||||
Datum g__BTREE_GIST_TYPE2___picksplit(PG_FUNCTION_ARGS); |
||||
Datum g__BTREE_GIST_TYPE2___consistent(PG_FUNCTION_ARGS); |
||||
Datum g__BTREE_GIST_TYPE2___penalty(PG_FUNCTION_ARGS); |
||||
Datum g__BTREE_GIST_TYPE2___same(PG_FUNCTION_ARGS); |
||||
|
||||
static void g__BTREE_GIST_TYPE2___binary_union(Datum *r1, char *r2); |
||||
static int __BTREE_GIST_TYPE2__key_cmp(const void *a, const void *b); |
||||
|
||||
|
||||
/**************************************************
|
||||
* __BTREE_GIST_TYPE__ ops |
||||
**************************************************/ |
||||
|
||||
Datum |
||||
g__BTREE_GIST_TYPE2___compress(PG_FUNCTION_ARGS) |
||||
{ |
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); |
||||
GISTENTRY *retval; |
||||
|
||||
if (entry->leafkey) |
||||
{ |
||||
__BTREE_GIST_TYPE__KEY *r = ( __BTREE_GIST_TYPE__KEY * ) palloc(sizeof(__BTREE_GIST_TYPE__KEY)); |
||||
#ifdef BTREE_GIST_INT4 |
||||
int32 leaf = DatumGetInt32(entry->key); |
||||
#endif |
||||
#ifdef BTREE_GIST_INT8 |
||||
int64 leaf = DatumGetInt64(entry->key); |
||||
#endif |
||||
#ifdef BTREE_GIST_FLOAT4 |
||||
float4 leaf = DatumGetFloat4(entry->key); |
||||
#endif |
||||
#ifdef BTREE_GIST_FLOAT8 |
||||
float8 leaf = DatumGetFloat8(entry->key); |
||||
#endif |
||||
|
||||
retval = palloc(sizeof(GISTENTRY)); |
||||
r->lower = r->upper = leaf ; |
||||
|
||||
gistentryinit(*retval, PointerGetDatum(r), entry->rel, entry->page, |
||||
entry->offset, sizeof(__BTREE_GIST_TYPE__KEY), FALSE); |
||||
|
||||
} |
||||
else |
||||
retval = entry; |
||||
PG_RETURN_POINTER(retval); |
||||
} |
||||
|
||||
Datum |
||||
g__BTREE_GIST_TYPE2___consistent(PG_FUNCTION_ARGS) |
||||
{ |
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); |
||||
#ifdef BTREE_GIST_INT4 |
||||
int32 query = PG_GETARG_INT32(1); |
||||
#endif |
||||
#ifdef BTREE_GIST_INT8 |
||||
int64 query = PG_GETARG_INT64(1); |
||||
#endif |
||||
#ifdef BTREE_GIST_FLOAT4 |
||||
float4 query = PG_GETARG_FLOAT4(1); |
||||
#endif |
||||
#ifdef BTREE_GIST_FLOAT8 |
||||
float8 query = PG_GETARG_FLOAT8(1); |
||||
#endif |
||||
__BTREE_GIST_TYPE__KEY *kkk = (__BTREE_GIST_TYPE__KEY *) DatumGetPointer(entry->key); |
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); |
||||
bool retval; |
||||
|
||||
switch (strategy) |
||||
{ |
||||
case BTLessEqualStrategyNumber: |
||||
retval = (query >= kkk->lower); |
||||
break; |
||||
case BTLessStrategyNumber: |
||||
if (GIST_LEAF(entry)) |
||||
retval = (query > kkk->lower); |
||||
else |
||||
retval = (query >= kkk->lower); |
||||
break; |
||||
case BTEqualStrategyNumber: |
||||
/* in leaf page kkk->lower always = kkk->upper */ |
||||
if (GIST_LEAF(entry)) |
||||
retval = (query == kkk->lower); |
||||
else |
||||
retval = (kkk->lower <= query && query <= kkk->upper); |
||||
break; |
||||
case BTGreaterStrategyNumber: |
||||
if (GIST_LEAF(entry)) |
||||
retval = (query < kkk->upper); |
||||
else |
||||
retval = (query <= kkk->upper); |
||||
break; |
||||
case BTGreaterEqualStrategyNumber: |
||||
retval = (query <= kkk->upper); |
||||
break; |
||||
default: |
||||
retval = FALSE; |
||||
} |
||||
PG_RETURN_BOOL(retval); |
||||
} |
||||
|
||||
Datum |
||||
g__BTREE_GIST_TYPE2___union(PG_FUNCTION_ARGS) |
||||
{ |
||||
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0); |
||||
int i, |
||||
numranges; |
||||
__BTREE_GIST_TYPE__KEY *cur, |
||||
*out = palloc(sizeof(__BTREE_GIST_TYPE__KEY)); |
||||
|
||||
numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY); |
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(__BTREE_GIST_TYPE__KEY); |
||||
|
||||
cur = (__BTREE_GIST_TYPE__KEY *) DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[0].key)); |
||||
out->lower = cur->lower; |
||||
out->upper = cur->upper; |
||||
|
||||
for (i = 1; i < numranges; i++) |
||||
{ |
||||
cur = (__BTREE_GIST_TYPE__KEY *) DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[i].key)); |
||||
if (out->lower > cur->lower) |
||||
out->lower = cur->lower; |
||||
if (out->upper < cur->upper) |
||||
out->upper = cur->upper; |
||||
} |
||||
|
||||
PG_RETURN_POINTER(out); |
||||
} |
||||
|
||||
Datum |
||||
g__BTREE_GIST_TYPE2___penalty(PG_FUNCTION_ARGS) |
||||
{ |
||||
__BTREE_GIST_TYPE__KEY *origentry = (__BTREE_GIST_TYPE__KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key); |
||||
__BTREE_GIST_TYPE__KEY *newentry = (__BTREE_GIST_TYPE__KEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key); |
||||
float *result = (float *) PG_GETARG_POINTER(2); |
||||
|
||||
*result = Max(newentry->upper - origentry->upper, 0) + |
||||
Max(origentry->lower - newentry->lower, 0); |
||||
|
||||
PG_RETURN_POINTER(result); |
||||
} |
||||
|
||||
Datum |
||||
g__BTREE_GIST_TYPE2___picksplit(PG_FUNCTION_ARGS) |
||||
{ |
||||
PG_RETURN_POINTER(btree_picksplit( |
||||
(bytea *) PG_GETARG_POINTER(0), |
||||
(GIST_SPLITVEC *) PG_GETARG_POINTER(1), |
||||
g__BTREE_GIST_TYPE2___binary_union, |
||||
__BTREE_GIST_TYPE2__key_cmp |
||||
)); |
||||
} |
||||
|
||||
Datum |
||||
g__BTREE_GIST_TYPE2___same(PG_FUNCTION_ARGS) |
||||
{ |
||||
__BTREE_GIST_TYPE__KEY *b1 = (__BTREE_GIST_TYPE__KEY *) PG_GETARG_POINTER(0); |
||||
__BTREE_GIST_TYPE__KEY *b2 = (__BTREE_GIST_TYPE__KEY *) PG_GETARG_POINTER(1); |
||||
bool *result = (bool *) PG_GETARG_POINTER(2); |
||||
|
||||
*result = (b1->lower == b2->lower && b1->upper == b2->upper) ? TRUE : FALSE; |
||||
PG_RETURN_POINTER(result); |
||||
} |
||||
|
||||
static void |
||||
g__BTREE_GIST_TYPE2___binary_union(Datum *r1, char *r2) |
||||
{ |
||||
__BTREE_GIST_TYPE__KEY *b1; |
||||
__BTREE_GIST_TYPE__KEY *b2 = (__BTREE_GIST_TYPE__KEY *) r2; |
||||
|
||||
if (!DatumGetPointer(*r1)) |
||||
{ |
||||
*r1 = PointerGetDatum(palloc(sizeof(__BTREE_GIST_TYPE__KEY))); |
||||
b1 = (__BTREE_GIST_TYPE__KEY *) DatumGetPointer(*r1); |
||||
b1->upper = b2->upper; |
||||
b1->lower = b2->lower; |
||||
} |
||||
else |
||||
{ |
||||
b1 = (__BTREE_GIST_TYPE__KEY *) DatumGetPointer(*r1); |
||||
|
||||
b1->lower = (b1->lower > b2->lower) ? |
||||
b2->lower : b1->lower; |
||||
b1->upper = (b1->upper > b2->upper) ? |
||||
b1->upper : b2->upper; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
static int |
||||
__BTREE_GIST_TYPE2__key_cmp(const void *a, const void *b) |
||||
{ |
||||
|
||||
|
||||
if (((__BTREE_GIST_TYPE__KEY *) (((RIX *) a)->r))->lower > ((__BTREE_GIST_TYPE__KEY *) (((RIX *) b)->r))->lower){ |
||||
return 1; |
||||
} else if (((__BTREE_GIST_TYPE__KEY *) (((RIX *) a)->r))->lower < ((__BTREE_GIST_TYPE__KEY *) (((RIX *) b)->r))->lower){ |
||||
return -1; |
||||
} else { |
||||
return 0; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
/**************************************************
|
||||
* In/Out for keys |
||||
**************************************************/ |
||||
|
||||
Datum |
||||
__BTREE_GIST_TYPE2__key_in(PG_FUNCTION_ARGS) |
||||
{ |
||||
elog(ERROR, "Not implemented"); |
||||
PG_RETURN_POINTER(NULL); |
||||
} |
||||
|
||||
Datum |
||||
__BTREE_GIST_TYPE2__key_out(PG_FUNCTION_ARGS) |
||||
{ |
||||
elog(ERROR, "Not implemented"); |
||||
PG_RETURN_POINTER(NULL); |
||||
} |
||||
|
||||
@ -0,0 +1,282 @@ |
||||
#include "btree_gist.h" |
||||
|
||||
|
||||
typedef struct tskey |
||||
{ |
||||
Timestamp lower; |
||||
Timestamp upper; |
||||
} TSKEY; |
||||
|
||||
|
||||
/*
|
||||
** tskey in/out |
||||
*/ |
||||
PG_FUNCTION_INFO_V1(tskey_in); |
||||
PG_FUNCTION_INFO_V1(tskey_out); |
||||
Datum tskey_in(PG_FUNCTION_ARGS); |
||||
Datum tskey_out(PG_FUNCTION_ARGS); |
||||
|
||||
|
||||
/*
|
||||
** timestamp ops |
||||
*/ |
||||
PG_FUNCTION_INFO_V1(gts_compress); |
||||
PG_FUNCTION_INFO_V1(gts_union); |
||||
PG_FUNCTION_INFO_V1(gts_picksplit); |
||||
PG_FUNCTION_INFO_V1(gts_consistent); |
||||
PG_FUNCTION_INFO_V1(gts_penalty); |
||||
PG_FUNCTION_INFO_V1(gts_same); |
||||
|
||||
Datum gts_compress(PG_FUNCTION_ARGS); |
||||
Datum gts_union(PG_FUNCTION_ARGS); |
||||
Datum gts_picksplit(PG_FUNCTION_ARGS); |
||||
Datum gts_consistent(PG_FUNCTION_ARGS); |
||||
Datum gts_penalty(PG_FUNCTION_ARGS); |
||||
Datum gts_same(PG_FUNCTION_ARGS); |
||||
|
||||
static void gts_binary_union(Datum *r1, char *r2); |
||||
static int tskey_cmp(const void *a, const void *b); |
||||
|
||||
#define TimestampGetDatumFast(X) Float8GetDatumFast(X) |
||||
|
||||
/* define for comparison */ |
||||
#define TSGE( ts1, ts2 ) (DatumGetBool(DirectFunctionCall2( \ |
||||
timestamp_ge, \
|
||||
PointerGetDatum( ts1 ), \
|
||||
PointerGetDatum( ts2 ) \
|
||||
))) |
||||
#define TSGT( ts1, ts2 ) (DatumGetBool(DirectFunctionCall2( \ |
||||
timestamp_gt, \
|
||||
PointerGetDatum( ts1 ), \
|
||||
PointerGetDatum( ts2 ) \
|
||||
))) |
||||
#define TSEQ( ts1, ts2 ) (DatumGetBool(DirectFunctionCall2( \ |
||||
timestamp_eq, \
|
||||
PointerGetDatum( ts1 ), \
|
||||
PointerGetDatum( ts2 ) \
|
||||
))) |
||||
#define TSLT( ts1, ts2 ) (DatumGetBool(DirectFunctionCall2( \ |
||||
timestamp_lt, \
|
||||
PointerGetDatum( ts1 ), \
|
||||
PointerGetDatum( ts2 ) \
|
||||
))) |
||||
#define TSLE( ts1, ts2 ) (DatumGetBool(DirectFunctionCall2( \ |
||||
timestamp_le, \
|
||||
PointerGetDatum( ts1 ), \
|
||||
PointerGetDatum( ts2 ) \
|
||||
))) |
||||
|
||||
|
||||
|
||||
/**************************************************
|
||||
* timestamp ops |
||||
**************************************************/ |
||||
|
||||
Datum |
||||
gts_compress(PG_FUNCTION_ARGS) |
||||
{ |
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); |
||||
GISTENTRY *retval; |
||||
|
||||
if (entry->leafkey) |
||||
{ |
||||
TSKEY *r = (TSKEY *) palloc(sizeof(TSKEY)); |
||||
|
||||
retval = palloc(sizeof(GISTENTRY)); |
||||
r->lower = r->upper = *(Timestamp *) (entry->key); |
||||
gistentryinit(*retval, PointerGetDatum(r), |
||||
entry->rel, entry->page, |
||||
entry->offset, sizeof(TSKEY), FALSE); |
||||
} |
||||
else |
||||
retval = entry; |
||||
PG_RETURN_POINTER(retval); |
||||
} |
||||
|
||||
Datum |
||||
gts_consistent(PG_FUNCTION_ARGS) |
||||
{ |
||||
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); |
||||
Timestamp *query = (Timestamp *) PG_GETARG_POINTER(1); |
||||
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); |
||||
bool retval; |
||||
TSKEY *key; |
||||
|
||||
/*
|
||||
* * if entry is not leaf, use gbox_internal_consistent, * else use |
||||
* gbox_leaf_consistent |
||||
*/ |
||||
if (!entry->key) |
||||
return FALSE; |
||||
key = (TSKEY *) DatumGetPointer(entry->key); |
||||
|
||||
switch (strategy) |
||||
{ |
||||
case BTLessEqualStrategyNumber: |
||||
retval = TSGE(query, &(key->lower)); |
||||
break; |
||||
case BTLessStrategyNumber: |
||||
if (GIST_LEAF(entry)) |
||||
retval = TSGT(query, &(key->lower)); |
||||
else |
||||
retval = TSGE(query, &(key->lower)); |
||||
break; |
||||
case BTEqualStrategyNumber: |
||||
/* in leaf page key->lower always = key->upper */ |
||||
if (GIST_LEAF(entry)) |
||||
retval = TSEQ(query, &(key->lower)); |
||||
else |
||||
retval = (TSLE(&(key->lower), query) && TSLE(query, &(key->upper))); |
||||
break; |
||||
case BTGreaterStrategyNumber: |
||||
if (GIST_LEAF(entry)) |
||||
retval = TSLT(query, &(key->upper)); |
||||
else |
||||
retval = TSLE(query, &(key->upper)); |
||||
break; |
||||
case BTGreaterEqualStrategyNumber: |
||||
retval = TSLE(query, &(key->upper)); |
||||
break; |
||||
default: |
||||
retval = FALSE; |
||||
} |
||||
PG_RETURN_BOOL(retval); |
||||
} |
||||
|
||||
Datum |
||||
gts_union(PG_FUNCTION_ARGS) |
||||
{ |
||||
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0); |
||||
int i, |
||||
numranges; |
||||
TSKEY *cur, |
||||
*out = palloc(sizeof(TSKEY)); |
||||
|
||||
numranges = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY); |
||||
*(int *) PG_GETARG_POINTER(1) = sizeof(TSKEY); |
||||
|
||||
cur = (TSKEY *) DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[0].key)); |
||||
out->lower = cur->lower; |
||||
out->upper = cur->upper; |
||||
|
||||
for (i = 1; i < numranges; i++) |
||||
{ |
||||
cur = (TSKEY *) DatumGetPointer((((GISTENTRY *) (VARDATA(entryvec)))[i].key)); |
||||
if (TSGT(&out->lower, &cur->lower)) |
||||
out->lower = cur->lower; |
||||
if (TSLT(&out->upper, &cur->upper)) |
||||
out->upper = cur->upper; |
||||
} |
||||
|
||||
PG_RETURN_POINTER(out); |
||||
} |
||||
|
||||
Datum |
||||
gts_penalty(PG_FUNCTION_ARGS) |
||||
{ |
||||
TSKEY *origentry = (TSKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key); |
||||
TSKEY *newentry = (TSKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key); |
||||
float *result = (float *) PG_GETARG_POINTER(2); |
||||
Interval *intr; |
||||
|
||||
intr = DatumGetIntervalP(DirectFunctionCall2( |
||||
timestamp_mi, |
||||
TimestampGetDatumFast(newentry->upper), |
||||
TimestampGetDatumFast(origentry->upper))); |
||||
|
||||
/* see interval_larger */ |
||||
*result = Max(intr->time + intr->month * (30.0 * 86400), 0); |
||||
pfree(intr); |
||||
|
||||
intr = DatumGetIntervalP(DirectFunctionCall2( |
||||
timestamp_mi, |
||||
TimestampGetDatumFast(origentry->lower), |
||||
TimestampGetDatumFast(newentry->lower))); |
||||
|
||||
/* see interval_larger */ |
||||
*result += Max(intr->time + intr->month * (30.0 * 86400), 0); |
||||
pfree(intr); |
||||
|
||||
PG_RETURN_POINTER(result); |
||||
} |
||||
|
||||
Datum |
||||
gts_picksplit(PG_FUNCTION_ARGS) |
||||
{ |
||||
PG_RETURN_POINTER(btree_picksplit( |
||||
(bytea *) PG_GETARG_POINTER(0), |
||||
(GIST_SPLITVEC *) PG_GETARG_POINTER(1), |
||||
gts_binary_union, |
||||
tskey_cmp |
||||
)); |
||||
} |
||||
|
||||
Datum |
||||
gts_same(PG_FUNCTION_ARGS) |
||||
{ |
||||
TSKEY *b1 = (TSKEY *) PG_GETARG_POINTER(0); |
||||
TSKEY *b2 = (TSKEY *) PG_GETARG_POINTER(1); |
||||
|
||||
bool *result = (bool *) PG_GETARG_POINTER(2); |
||||
|
||||
if (b1 && b2) |
||||
*result = (TSEQ(&(b1->lower), &(b2->lower)) && TSEQ(&(b1->upper), &(b2->upper))) ? TRUE : FALSE; |
||||
else |
||||
*result = (b1 == NULL && b2 == NULL) ? TRUE : FALSE; |
||||
PG_RETURN_POINTER(result); |
||||
} |
||||
|
||||
static void |
||||
gts_binary_union(Datum *r1, char *r2) |
||||
{ |
||||
TSKEY *b1; |
||||
TSKEY *b2 = (TSKEY *) r2; |
||||
|
||||
if (!DatumGetPointer(*r1)) |
||||
{ |
||||
*r1 = PointerGetDatum(palloc(sizeof(TSKEY))); |
||||
b1 = (TSKEY *) DatumGetPointer(*r1); |
||||
b1->upper = b2->upper; |
||||
b1->lower = b2->lower; |
||||
} |
||||
else |
||||
{ |
||||
b1 = (TSKEY *) DatumGetPointer(*r1); |
||||
|
||||
b1->lower = (TSGT(&b1->lower, &b2->lower)) ? |
||||
b2->lower : b1->lower; |
||||
b1->upper = (TSGT(&b1->upper, &b2->upper)) ? |
||||
b1->upper : b2->upper; |
||||
} |
||||
} |
||||
|
||||
static int |
||||
tskey_cmp(const void *a, const void *b) |
||||
{ |
||||
return DatumGetInt32( |
||||
DirectFunctionCall2( |
||||
timestamp_cmp, |
||||
TimestampGetDatumFast(((TSKEY *) (((RIX *) a)->r))->lower), |
||||
TimestampGetDatumFast(((TSKEY *) (((RIX *) b)->r))->lower) |
||||
) |
||||
); |
||||
} |
||||
|
||||
|
||||
/**************************************************
|
||||
* In/Out for keys, not really needed |
||||
**************************************************/ |
||||
|
||||
Datum |
||||
tskey_in(PG_FUNCTION_ARGS) |
||||
{ |
||||
elog(ERROR, "Not implemented"); |
||||
PG_RETURN_POINTER(NULL); |
||||
} |
||||
|
||||
Datum |
||||
tskey_out(PG_FUNCTION_ARGS) |
||||
{ |
||||
elog(ERROR, "Not implemented"); |
||||
PG_RETURN_POINTER(NULL); |
||||
} |
||||
Loading…
Reference in new issue