mirror of
https://github.com/postgres/postgres.git
synced 2025-10-24 00:03:18 -04:00
Upcoming patches are going to address performance issues that involve
slow system provided ntohs/htons etc. To address that expand
pg_bswap.h to provide pg_ntoh{16,32,64}, pg_hton{16,32,64} and
optimize their respective implementations by using compiler intrinsics
for gcc compatible compilers and msvc. Fall back to manual
implementations using shifts etc otherwise.
Additionally remove multiple evaluation hazards from the existing
BSWAP32/64 macros, by replacing them with inline functions when
necessary. In the course of that the naming scheme is changed to
pg_bswap16/32/64.
Author: Andres Freund
Discussion: https://postgr.es/m/20170927172019.gheidqy6xvlxb325@alap3.anarazel.de
239 lines
5.6 KiB
C
239 lines
5.6 KiB
C
/*
|
|
* contrib/btree_gist/btree_uuid.c
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "btree_gist.h"
|
|
#include "btree_utils_num.h"
|
|
#include "port/pg_bswap.h"
|
|
#include "utils/uuid.h"
|
|
|
|
typedef struct
|
|
{
|
|
pg_uuid_t lower,
|
|
upper;
|
|
} uuidKEY;
|
|
|
|
|
|
/*
|
|
* UUID ops
|
|
*/
|
|
PG_FUNCTION_INFO_V1(gbt_uuid_compress);
|
|
PG_FUNCTION_INFO_V1(gbt_uuid_fetch);
|
|
PG_FUNCTION_INFO_V1(gbt_uuid_union);
|
|
PG_FUNCTION_INFO_V1(gbt_uuid_picksplit);
|
|
PG_FUNCTION_INFO_V1(gbt_uuid_consistent);
|
|
PG_FUNCTION_INFO_V1(gbt_uuid_penalty);
|
|
PG_FUNCTION_INFO_V1(gbt_uuid_same);
|
|
|
|
|
|
static int
|
|
uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2)
|
|
{
|
|
return memcmp(arg1->data, arg2->data, UUID_LEN);
|
|
}
|
|
|
|
static bool
|
|
gbt_uuidgt(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) > 0;
|
|
}
|
|
|
|
static bool
|
|
gbt_uuidge(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) >= 0;
|
|
}
|
|
|
|
static bool
|
|
gbt_uuideq(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) == 0;
|
|
}
|
|
|
|
static bool
|
|
gbt_uuidle(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) <= 0;
|
|
}
|
|
|
|
static bool
|
|
gbt_uuidlt(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) < 0;
|
|
}
|
|
|
|
static int
|
|
gbt_uuidkey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
|
|
{
|
|
uuidKEY *ia = (uuidKEY *) (((const Nsrt *) a)->t);
|
|
uuidKEY *ib = (uuidKEY *) (((const Nsrt *) b)->t);
|
|
int res;
|
|
|
|
res = uuid_internal_cmp(&ia->lower, &ib->lower);
|
|
if (res == 0)
|
|
res = uuid_internal_cmp(&ia->upper, &ib->upper);
|
|
return res;
|
|
}
|
|
|
|
|
|
static const gbtree_ninfo tinfo =
|
|
{
|
|
gbt_t_uuid,
|
|
UUID_LEN,
|
|
32, /* sizeof(gbtreekey32) */
|
|
gbt_uuidgt,
|
|
gbt_uuidge,
|
|
gbt_uuideq,
|
|
gbt_uuidle,
|
|
gbt_uuidlt,
|
|
gbt_uuidkey_cmp,
|
|
NULL
|
|
};
|
|
|
|
|
|
/**************************************************
|
|
* uuid ops
|
|
**************************************************/
|
|
|
|
|
|
Datum
|
|
gbt_uuid_compress(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
GISTENTRY *retval;
|
|
|
|
if (entry->leafkey)
|
|
{
|
|
char *r = (char *) palloc(2 * UUID_LEN);
|
|
pg_uuid_t *key = DatumGetUUIDP(entry->key);
|
|
|
|
retval = palloc(sizeof(GISTENTRY));
|
|
|
|
memcpy((void *) r, (void *) key, UUID_LEN);
|
|
memcpy((void *) (r + UUID_LEN), (void *) key, UUID_LEN);
|
|
gistentryinit(*retval, PointerGetDatum(r),
|
|
entry->rel, entry->page,
|
|
entry->offset, FALSE);
|
|
}
|
|
else
|
|
retval = entry;
|
|
|
|
PG_RETURN_POINTER(retval);
|
|
}
|
|
|
|
Datum
|
|
gbt_uuid_fetch(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
|
|
PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
|
|
}
|
|
|
|
Datum
|
|
gbt_uuid_consistent(PG_FUNCTION_ARGS)
|
|
{
|
|
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
|
pg_uuid_t *query = PG_GETARG_UUID_P(1);
|
|
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
|
|
|
|
/* Oid subtype = PG_GETARG_OID(3); */
|
|
bool *recheck = (bool *) PG_GETARG_POINTER(4);
|
|
uuidKEY *kkk = (uuidKEY *) 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, (void *) query, &strategy,
|
|
GIST_LEAF(entry), &tinfo, fcinfo->flinfo)
|
|
);
|
|
}
|
|
|
|
Datum
|
|
gbt_uuid_union(PG_FUNCTION_ARGS)
|
|
{
|
|
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
|
|
void *out = palloc(sizeof(uuidKEY));
|
|
|
|
*(int *) PG_GETARG_POINTER(1) = sizeof(uuidKEY);
|
|
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
|
|
}
|
|
|
|
/*
|
|
* Convert a uuid to a "double" value for estimating sizes of ranges.
|
|
*/
|
|
static double
|
|
uuid_2_double(const pg_uuid_t *u)
|
|
{
|
|
uint64 uu[2];
|
|
const double two64 = 18446744073709551616.0; /* 2^64 */
|
|
|
|
/* Source data may not be suitably aligned, so copy */
|
|
memcpy(uu, u->data, UUID_LEN);
|
|
|
|
/*
|
|
* uuid values should be considered as big-endian numbers, since that
|
|
* corresponds to how memcmp will compare them. On a little-endian
|
|
* machine, byte-swap each half so we can use native uint64 arithmetic.
|
|
*/
|
|
#ifndef WORDS_BIGENDIAN
|
|
uu[0] = pg_bswap64(uu[0]);
|
|
uu[1] = pg_bswap64(uu[1]);
|
|
#endif
|
|
|
|
/*
|
|
* 2^128 is about 3.4e38, which in theory could exceed the range of
|
|
* "double" (POSIX only requires 1e37). To avoid any risk of overflow,
|
|
* put the decimal point between the two halves rather than treating the
|
|
* uuid value as a 128-bit integer.
|
|
*/
|
|
return (double) uu[0] + (double) uu[1] / two64;
|
|
}
|
|
|
|
Datum
|
|
gbt_uuid_penalty(PG_FUNCTION_ARGS)
|
|
{
|
|
uuidKEY *origentry = (uuidKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
|
|
uuidKEY *newentry = (uuidKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
|
|
float *result = (float *) PG_GETARG_POINTER(2);
|
|
double olower,
|
|
oupper,
|
|
nlower,
|
|
nupper;
|
|
|
|
olower = uuid_2_double(&origentry->lower);
|
|
oupper = uuid_2_double(&origentry->upper);
|
|
nlower = uuid_2_double(&newentry->lower);
|
|
nupper = uuid_2_double(&newentry->upper);
|
|
|
|
penalty_num(result, olower, oupper, nlower, nupper);
|
|
|
|
PG_RETURN_POINTER(result);
|
|
}
|
|
|
|
Datum
|
|
gbt_uuid_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_uuid_same(PG_FUNCTION_ARGS)
|
|
{
|
|
uuidKEY *b1 = (uuidKEY *) PG_GETARG_POINTER(0);
|
|
uuidKEY *b2 = (uuidKEY *) 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);
|
|
}
|