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
345 lines
8.7 KiB
C
345 lines
8.7 KiB
C
/*
|
|
* contrib/btree_gist/btree_time.c
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "btree_gist.h"
|
|
#include "btree_utils_num.h"
|
|
#include "utils/fmgrprotos.h"
|
|
#include "utils/date.h"
|
|
#include "utils/rel.h"
|
|
#include "utils/sortsupport.h"
|
|
#include "utils/timestamp.h"
|
|
|
|
typedef struct
|
|
{
|
|
TimeADT lower;
|
|
TimeADT upper;
|
|
} timeKEY;
|
|
|
|
/* GiST support functions */
|
|
PG_FUNCTION_INFO_V1(gbt_time_compress);
|
|
PG_FUNCTION_INFO_V1(gbt_timetz_compress);
|
|
PG_FUNCTION_INFO_V1(gbt_time_fetch);
|
|
PG_FUNCTION_INFO_V1(gbt_time_union);
|
|
PG_FUNCTION_INFO_V1(gbt_time_picksplit);
|
|
PG_FUNCTION_INFO_V1(gbt_time_consistent);
|
|
PG_FUNCTION_INFO_V1(gbt_time_distance);
|
|
PG_FUNCTION_INFO_V1(gbt_timetz_consistent);
|
|
PG_FUNCTION_INFO_V1(gbt_time_penalty);
|
|
PG_FUNCTION_INFO_V1(gbt_time_same);
|
|
PG_FUNCTION_INFO_V1(gbt_time_sortsupport);
|
|
PG_FUNCTION_INFO_V1(gbt_timetz_sortsupport);
|
|
|
|
|
|
static bool
|
|
gbt_timegt(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
const TimeADT *aa = (const TimeADT *) a;
|
|
const TimeADT *bb = (const TimeADT *) b;
|
|
|
|
return DatumGetBool(DirectFunctionCall2(time_gt,
|
|
TimeADTGetDatum(*aa),
|
|
TimeADTGetDatum(*bb)));
|
|
}
|
|
|
|
static bool
|
|
gbt_timege(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
const TimeADT *aa = (const TimeADT *) a;
|
|
const TimeADT *bb = (const TimeADT *) b;
|
|
|
|
return DatumGetBool(DirectFunctionCall2(time_ge,
|
|
TimeADTGetDatum(*aa),
|
|
TimeADTGetDatum(*bb)));
|
|
}
|
|
|
|
static bool
|
|
gbt_timeeq(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
const TimeADT *aa = (const TimeADT *) a;
|
|
const TimeADT *bb = (const TimeADT *) b;
|
|
|
|
return DatumGetBool(DirectFunctionCall2(time_eq,
|
|
TimeADTGetDatum(*aa),
|
|
TimeADTGetDatum(*bb)));
|
|
}
|
|
|
|
static bool
|
|
gbt_timele(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
const TimeADT *aa = (const TimeADT *) a;
|
|
const TimeADT *bb = (const TimeADT *) b;
|
|
|
|
return DatumGetBool(DirectFunctionCall2(time_le,
|
|
TimeADTGetDatum(*aa),
|
|
TimeADTGetDatum(*bb)));
|
|
}
|
|
|
|
static bool
|
|
gbt_timelt(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
const TimeADT *aa = (const TimeADT *) a;
|
|
const TimeADT *bb = (const TimeADT *) b;
|
|
|
|
return DatumGetBool(DirectFunctionCall2(time_lt,
|
|
TimeADTGetDatum(*aa),
|
|
TimeADTGetDatum(*bb)));
|
|
}
|
|
|
|
static int
|
|
gbt_timekey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
timeKEY *ia = (timeKEY *) (((const Nsrt *) a)->t);
|
|
timeKEY *ib = (timeKEY *) (((const Nsrt *) b)->t);
|
|
int res;
|
|
|
|
res = DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatum(ia->lower), TimeADTGetDatum(ib->lower)));
|
|
if (res == 0)
|
|
return DatumGetInt32(DirectFunctionCall2(time_cmp, TimeADTGetDatum(ia->upper), TimeADTGetDatum(ib->upper)));
|
|
|
|
return res;
|
|
}
|
|
|
|
static float8
|
|
gbt_time_dist(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
const TimeADT *aa = (const TimeADT *) a;
|
|
const TimeADT *bb = (const TimeADT *) b;
|
|
Interval *i;
|
|
|
|
i = DatumGetIntervalP(DirectFunctionCall2(time_mi_time,
|
|
TimeADTGetDatum(*aa),
|
|
TimeADTGetDatum(*bb)));
|
|
return fabs(INTERVAL_TO_SEC(i));
|
|
}
|
|
|
|
|
|
static const gbtree_ninfo tinfo =
|
|
{
|
|
gbt_t_time,
|
|
sizeof(TimeADT),
|
|
16, /* sizeof(gbtreekey16) */
|
|
gbt_timegt,
|
|
gbt_timege,
|
|
gbt_timeeq,
|
|
gbt_timele,
|
|
gbt_timelt,
|
|
gbt_timekey_cmp,
|
|
gbt_time_dist
|
|
};
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(time_dist);
|
|
Datum
|
|
time_dist(PG_FUNCTION_ARGS)
|
|
{
|
|
Datum diff = DirectFunctionCall2(time_mi_time,
|
|
PG_GETARG_DATUM(0),
|
|
PG_GETARG_DATUM(1));
|
|
|
|
PG_RETURN_INTERVAL_P(abs_interval(DatumGetIntervalP(diff)));
|
|
}
|
|
|
|
|
|
/**************************************************
|
|
* GiST support functions
|
|
**************************************************/
|
|
|
|
Datum
|
|
gbt_time_compress(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
|
|
}
|
|
|
|
Datum
|
|
gbt_timetz_compress(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
GISTENTRY *retval;
|
|
|
|
if (entry->leafkey)
|
|
{
|
|
timeKEY *r = palloc_object(timeKEY);
|
|
TimeTzADT *tz = DatumGetTimeTzADTP(entry->key);
|
|
TimeADT tmp;
|
|
|
|
retval = palloc_object(GISTENTRY);
|
|
|
|
/* We are using the time + zone only to compress */
|
|
tmp = tz->time + (tz->zone * INT64CONST(1000000));
|
|
r->lower = r->upper = tmp;
|
|
gistentryinit(*retval, PointerGetDatum(r),
|
|
entry->rel, entry->page,
|
|
entry->offset, false);
|
|
}
|
|
else
|
|
retval = entry;
|
|
PG_RETURN_POINTER(retval);
|
|
}
|
|
|
|
Datum
|
|
gbt_time_fetch(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
|
|
}
|
|
|
|
Datum
|
|
gbt_time_consistent(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
TimeADT query = PG_GETARG_TIMEADT(1);
|
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
|
|
|
/* Oid subtype = PG_GETARG_OID(3); */
|
|
bool *recheck = (bool *) PG_GETARG_POINTER(4);
|
|
timeKEY *kkk = (timeKEY *) 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_time_distance(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
TimeADT query = PG_GETARG_TIMEADT(1);
|
|
|
|
/* Oid subtype = PG_GETARG_OID(3); */
|
|
timeKEY *kkk = (timeKEY *) 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_timetz_consistent(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
TimeTzADT *query = PG_GETARG_TIMETZADT_P(1);
|
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
|
|
|
/* Oid subtype = PG_GETARG_OID(3); */
|
|
bool *recheck = (bool *) PG_GETARG_POINTER(4);
|
|
timeKEY *kkk = (timeKEY *) DatumGetPointer(entry->key);
|
|
TimeADT qqq;
|
|
GBT_NUMKEY_R key;
|
|
|
|
/* All cases served by this function are inexact */
|
|
*recheck = true;
|
|
|
|
qqq = query->time + (query->zone * INT64CONST(1000000));
|
|
|
|
key.lower = (GBT_NUMKEY *) &kkk->lower;
|
|
key.upper = (GBT_NUMKEY *) &kkk->upper;
|
|
|
|
PG_RETURN_BOOL(gbt_num_consistent(&key, &qqq, &strategy,
|
|
GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
|
|
}
|
|
|
|
Datum
|
|
gbt_time_union(PG_FUNCTION_ARGS)
|
|
{
|
|
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
|
void *out = palloc(sizeof(timeKEY));
|
|
|
|
*(int *) PG_GETARG_POINTER(1) = sizeof(timeKEY);
|
|
PG_RETURN_POINTER(gbt_num_union(out, entryvec, &tinfo, fcinfo->flinfo));
|
|
}
|
|
|
|
Datum
|
|
gbt_time_penalty(PG_FUNCTION_ARGS)
|
|
{
|
|
timeKEY *origentry = (timeKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
|
|
timeKEY *newentry = (timeKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
|
|
float *result = (float *) PG_GETARG_POINTER(2);
|
|
Interval *intr;
|
|
double res;
|
|
double res2;
|
|
|
|
intr = DatumGetIntervalP(DirectFunctionCall2(time_mi_time,
|
|
TimeADTGetDatum(newentry->upper),
|
|
TimeADTGetDatum(origentry->upper)));
|
|
res = INTERVAL_TO_SEC(intr);
|
|
res = Max(res, 0);
|
|
|
|
intr = DatumGetIntervalP(DirectFunctionCall2(time_mi_time,
|
|
TimeADTGetDatum(origentry->lower),
|
|
TimeADTGetDatum(newentry->lower)));
|
|
res2 = INTERVAL_TO_SEC(intr);
|
|
res2 = Max(res2, 0);
|
|
|
|
res += res2;
|
|
|
|
*result = 0.0;
|
|
|
|
if (res > 0)
|
|
{
|
|
intr = DatumGetIntervalP(DirectFunctionCall2(time_mi_time,
|
|
TimeADTGetDatum(origentry->upper),
|
|
TimeADTGetDatum(origentry->lower)));
|
|
*result += FLT_MIN;
|
|
*result += (float) (res / (res + INTERVAL_TO_SEC(intr)));
|
|
*result *= (FLT_MAX / (((GISTENTRY *) PG_GETARG_POINTER(0))->rel->rd_att->natts + 1));
|
|
}
|
|
|
|
PG_RETURN_POINTER(result);
|
|
}
|
|
|
|
Datum
|
|
gbt_time_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_time_same(PG_FUNCTION_ARGS)
|
|
{
|
|
timeKEY *b1 = (timeKEY *) PG_GETARG_POINTER(0);
|
|
timeKEY *b2 = (timeKEY *) 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_timekey_ssup_cmp(Datum x, Datum y, SortSupport ssup)
|
|
{
|
|
timeKEY *arg1 = (timeKEY *) DatumGetPointer(x);
|
|
timeKEY *arg2 = (timeKEY *) DatumGetPointer(y);
|
|
|
|
/* for leaf items we expect lower == upper, so only compare lower */
|
|
return DatumGetInt32(DirectFunctionCall2(time_cmp,
|
|
TimeADTGetDatum(arg1->lower),
|
|
TimeADTGetDatum(arg2->lower)));
|
|
}
|
|
|
|
Datum
|
|
gbt_time_sortsupport(PG_FUNCTION_ARGS)
|
|
{
|
|
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
|
|
|
|
ssup->comparator = gbt_timekey_ssup_cmp;
|
|
ssup->ssup_extra = NULL;
|
|
|
|
PG_RETURN_VOID();
|
|
}
|