mirror of
https://github.com/postgres/postgres.git
synced 2025-12-09 02:08:45 +03:00
The idea is to encourage more the use of these new routines across the tree, as these offer stronger type safety guarantees than palloc(). In an ideal world, palloc() would then act as an internal routine of these flavors, whose footprint in the tree is minimal. The patch sent by the author is very large, and this chunk of changes represents something like 10% of the overall patch submitted. The code compiled is the same before and after this commit, using objdump to do some validation with a difference taken in-between. There are some diffs, which are caused by changes in line numbers because some of the new allocation formulas are shorter, for the following files: trgm_regexp.c, xpath.c and pg_walinspect.c. Author: David Geier <geidav.pg@gmail.com> Discussion: https://postgr.es/m/ad0748d4-3080-436e-b0bc-ac8f86a3466a@gmail.com
320 lines
7.9 KiB
C
320 lines
7.9 KiB
C
/*
|
|
* contrib/btree_gist/btree_interval.c
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "btree_gist.h"
|
|
#include "btree_utils_num.h"
|
|
#include "utils/fmgrprotos.h"
|
|
#include "utils/rel.h"
|
|
#include "utils/sortsupport.h"
|
|
#include "utils/timestamp.h"
|
|
|
|
typedef struct
|
|
{
|
|
Interval lower,
|
|
upper;
|
|
} intvKEY;
|
|
|
|
/* GiST support functions */
|
|
PG_FUNCTION_INFO_V1(gbt_intv_compress);
|
|
PG_FUNCTION_INFO_V1(gbt_intv_fetch);
|
|
PG_FUNCTION_INFO_V1(gbt_intv_decompress);
|
|
PG_FUNCTION_INFO_V1(gbt_intv_union);
|
|
PG_FUNCTION_INFO_V1(gbt_intv_picksplit);
|
|
PG_FUNCTION_INFO_V1(gbt_intv_consistent);
|
|
PG_FUNCTION_INFO_V1(gbt_intv_distance);
|
|
PG_FUNCTION_INFO_V1(gbt_intv_penalty);
|
|
PG_FUNCTION_INFO_V1(gbt_intv_same);
|
|
PG_FUNCTION_INFO_V1(gbt_intv_sortsupport);
|
|
|
|
|
|
static bool
|
|
gbt_intvgt(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
return DatumGetBool(DirectFunctionCall2(interval_gt, IntervalPGetDatum(a), IntervalPGetDatum(b)));
|
|
}
|
|
|
|
static bool
|
|
gbt_intvge(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
return DatumGetBool(DirectFunctionCall2(interval_ge, IntervalPGetDatum(a), IntervalPGetDatum(b)));
|
|
}
|
|
|
|
static bool
|
|
gbt_intveq(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
return DatumGetBool(DirectFunctionCall2(interval_eq, IntervalPGetDatum(a), IntervalPGetDatum(b)));
|
|
}
|
|
|
|
static bool
|
|
gbt_intvle(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
return DatumGetBool(DirectFunctionCall2(interval_le, IntervalPGetDatum(a), IntervalPGetDatum(b)));
|
|
}
|
|
|
|
static bool
|
|
gbt_intvlt(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
return DatumGetBool(DirectFunctionCall2(interval_lt, IntervalPGetDatum(a), IntervalPGetDatum(b)));
|
|
}
|
|
|
|
static int
|
|
gbt_intvkey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
intvKEY *ia = (intvKEY *) (((const Nsrt *) a)->t);
|
|
intvKEY *ib = (intvKEY *) (((const Nsrt *) b)->t);
|
|
int res;
|
|
|
|
res = DatumGetInt32(DirectFunctionCall2(interval_cmp, IntervalPGetDatum(&ia->lower), IntervalPGetDatum(&ib->lower)));
|
|
if (res == 0)
|
|
return DatumGetInt32(DirectFunctionCall2(interval_cmp, IntervalPGetDatum(&ia->upper), IntervalPGetDatum(&ib->upper)));
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
static double
|
|
intr2num(const Interval *i)
|
|
{
|
|
return INTERVAL_TO_SEC(i);
|
|
}
|
|
|
|
static float8
|
|
gbt_intv_dist(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
return fabs(intr2num((const Interval *) a) - intr2num((const Interval *) b));
|
|
}
|
|
|
|
/*
|
|
* INTERVALSIZE should be the actual size-on-disk of an Interval, as shown
|
|
* in pg_type. This might be less than sizeof(Interval) if the compiler
|
|
* insists on adding alignment padding at the end of the struct. (Note:
|
|
* this concern is obsolete with the current definition of Interval, but
|
|
* was real before a separate "day" field was added to it.)
|
|
*/
|
|
#define INTERVALSIZE 16
|
|
|
|
static const gbtree_ninfo tinfo =
|
|
{
|
|
gbt_t_intv,
|
|
sizeof(Interval),
|
|
32, /* sizeof(gbtreekey32) */
|
|
gbt_intvgt,
|
|
gbt_intvge,
|
|
gbt_intveq,
|
|
gbt_intvle,
|
|
gbt_intvlt,
|
|
gbt_intvkey_cmp,
|
|
gbt_intv_dist
|
|
};
|
|
|
|
|
|
Interval *
|
|
abs_interval(Interval *a)
|
|
{
|
|
static const Interval zero = {0, 0, 0};
|
|
|
|
if (DatumGetBool(DirectFunctionCall2(interval_lt,
|
|
IntervalPGetDatum(a),
|
|
IntervalPGetDatum(&zero))))
|
|
a = DatumGetIntervalP(DirectFunctionCall1(interval_um,
|
|
IntervalPGetDatum(a)));
|
|
|
|
return a;
|
|
}
|
|
|
|
PG_FUNCTION_INFO_V1(interval_dist);
|
|
Datum
|
|
interval_dist(PG_FUNCTION_ARGS)
|
|
{
|
|
Datum diff = DirectFunctionCall2(interval_mi,
|
|
PG_GETARG_DATUM(0),
|
|
PG_GETARG_DATUM(1));
|
|
|
|
PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff)));
|
|
}
|
|
|
|
|
|
/**************************************************
|
|
* GiST support functions
|
|
**************************************************/
|
|
|
|
Datum
|
|
gbt_intv_compress(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
GISTENTRY *retval = entry;
|
|
|
|
if (entry->leafkey || INTERVALSIZE != sizeof(Interval))
|
|
{
|
|
char *r = (char *) palloc(2 * INTERVALSIZE);
|
|
|
|
retval = palloc_object(GISTENTRY);
|
|
|
|
if (entry->leafkey)
|
|
{
|
|
Interval *key = DatumGetIntervalP(entry->key);
|
|
|
|
memcpy(r, key, INTERVALSIZE);
|
|
memcpy(r + INTERVALSIZE, key, INTERVALSIZE);
|
|
}
|
|
else
|
|
{
|
|
intvKEY *key = (intvKEY *) DatumGetPointer(entry->key);
|
|
|
|
memcpy(r, &key->lower, INTERVALSIZE);
|
|
memcpy(r + INTERVALSIZE, &key->upper, INTERVALSIZE);
|
|
}
|
|
gistentryinit(*retval, PointerGetDatum(r),
|
|
entry->rel, entry->page,
|
|
entry->offset, false);
|
|
}
|
|
|
|
PG_RETURN_POINTER(retval);
|
|
}
|
|
|
|
Datum
|
|
gbt_intv_fetch(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
|
|
}
|
|
|
|
Datum
|
|
gbt_intv_decompress(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
GISTENTRY *retval = entry;
|
|
|
|
if (INTERVALSIZE != sizeof(Interval))
|
|
{
|
|
intvKEY *r = palloc_object(intvKEY);
|
|
char *key = DatumGetPointer(entry->key);
|
|
|
|
retval = palloc_object(GISTENTRY);
|
|
memcpy(&r->lower, key, INTERVALSIZE);
|
|
memcpy(&r->upper, key + INTERVALSIZE, INTERVALSIZE);
|
|
|
|
gistentryinit(*retval, PointerGetDatum(r),
|
|
entry->rel, entry->page,
|
|
entry->offset, false);
|
|
}
|
|
PG_RETURN_POINTER(retval);
|
|
}
|
|
|
|
|
|
Datum
|
|
gbt_intv_consistent(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
Interval *query = PG_GETARG_INTERVAL_P(1);
|
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
|
|
|
/* Oid subtype = PG_GETARG_OID(3); */
|
|
bool *recheck = (bool *) PG_GETARG_POINTER(4);
|
|
intvKEY *kkk = (intvKEY *) DatumGetPointer(entry->key);
|
|
GBT_NUMKEY_R key;
|
|
|
|
/* All cases served by this function are exact */
|
|
*recheck = false;
|
|
|
|
key.lower = (GBT_NUMKEY *) &kkk->lower;
|
|
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
|
|
|
PG_RETURN_BOOL(gbt_num_consistent(&key, query, &strategy,
|
|
GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
|
|
}
|
|
|
|
|
|
Datum
|
|
gbt_intv_distance(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
Interval *query = PG_GETARG_INTERVAL_P(1);
|
|
|
|
/* Oid subtype = PG_GETARG_OID(3); */
|
|
intvKEY *kkk = (intvKEY *) DatumGetPointer(entry->key);
|
|
GBT_NUMKEY_R key;
|
|
|
|
key.lower = (GBT_NUMKEY *) &kkk->lower;
|
|
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
|
|
|
PG_RETURN_FLOAT8(gbt_num_distance(&key, query, GIST_LEAF(entry),
|
|
&tinfo, fcinfo->flinfo));
|
|
}
|
|
|
|
|
|
Datum
|
|
gbt_intv_union(PG_FUNCTION_ARGS)
|
|
{
|
|
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
|
void *out = palloc(sizeof(intvKEY));
|
|
|
|
*(int *) PG_GETARG_POINTER(1) = sizeof(intvKEY);
|
|
PG_RETURN_POINTER(gbt_num_union(out, entryvec, &tinfo, fcinfo->flinfo));
|
|
}
|
|
|
|
|
|
Datum
|
|
gbt_intv_penalty(PG_FUNCTION_ARGS)
|
|
{
|
|
intvKEY *origentry = (intvKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
|
|
intvKEY *newentry = (intvKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
|
|
float *result = (float *) PG_GETARG_POINTER(2);
|
|
double iorg[2],
|
|
inew[2];
|
|
|
|
iorg[0] = intr2num(&origentry->lower);
|
|
iorg[1] = intr2num(&origentry->upper);
|
|
inew[0] = intr2num(&newentry->lower);
|
|
inew[1] = intr2num(&newentry->upper);
|
|
|
|
penalty_num(result, iorg[0], iorg[1], inew[0], inew[1]);
|
|
|
|
PG_RETURN_POINTER(result);
|
|
}
|
|
|
|
Datum
|
|
gbt_intv_picksplit(PG_FUNCTION_ARGS)
|
|
{
|
|
PG_RETURN_POINTER(gbt_num_picksplit((GistEntryVector *) PG_GETARG_POINTER(0),
|
|
(GIST_SPLITVEC *) PG_GETARG_POINTER(1),
|
|
&tinfo, fcinfo->flinfo));
|
|
}
|
|
|
|
Datum
|
|
gbt_intv_same(PG_FUNCTION_ARGS)
|
|
{
|
|
intvKEY *b1 = (intvKEY *) PG_GETARG_POINTER(0);
|
|
intvKEY *b2 = (intvKEY *) PG_GETARG_POINTER(1);
|
|
bool *result = (bool *) PG_GETARG_POINTER(2);
|
|
|
|
*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
|
|
PG_RETURN_POINTER(result);
|
|
}
|
|
|
|
static int
|
|
gbt_intv_ssup_cmp(Datum x, Datum y, SortSupport ssup)
|
|
{
|
|
intvKEY *arg1 = (intvKEY *) DatumGetPointer(x);
|
|
intvKEY *arg2 = (intvKEY *) DatumGetPointer(y);
|
|
|
|
/* for leaf items we expect lower == upper, so only compare lower */
|
|
return DatumGetInt32(DirectFunctionCall2(interval_cmp,
|
|
IntervalPGetDatum(&arg1->lower),
|
|
IntervalPGetDatum(&arg2->lower)));
|
|
}
|
|
|
|
Datum
|
|
gbt_intv_sortsupport(PG_FUNCTION_ARGS)
|
|
{
|
|
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
|
|
|
|
ssup->comparator = gbt_intv_ssup_cmp;
|
|
ssup->ssup_extra = NULL;
|
|
|
|
PG_RETURN_VOID();
|
|
}
|