1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-14 08:21:07 +03:00
Files
config
contrib
adminpack
auth_delay
auto_explain
btree_gin
btree_gist
data
expected
sql
.gitignore
Makefile
btree_bit.c
btree_bytea.c
btree_cash.c
btree_date.c
btree_float4.c
btree_float8.c
btree_gist--1.0.sql
btree_gist--unpackaged--1.0.sql
btree_gist.c
btree_gist.control
btree_gist.h
btree_inet.c
btree_int2.c
btree_int4.c
btree_int8.c
btree_interval.c
btree_macaddr.c
btree_numeric.c
btree_oid.c
btree_text.c
btree_time.c
btree_ts.c
btree_utils_num.c
btree_utils_num.h
btree_utils_var.c
btree_utils_var.h
chkpass
citext
cube
dblink
dict_int
dict_xsyn
dummy_seclabel
earthdistance
file_fdw
fuzzystrmatch
hstore
intagg
intarray
isn
lo
ltree
oid2name
pageinspect
passwordcheck
pg_archivecleanup
pg_buffercache
pg_freespacemap
pg_prewarm
pg_standby
pg_stat_statements
pg_test_fsync
pg_test_timing
pg_trgm
pg_upgrade
pg_upgrade_support
pg_xlogdump
pgbench
pgcrypto
pgrowlocks
pgstattuple
postgres_fdw
seg
sepgsql
spi
sslinfo
start-scripts
tablefunc
tcn
test_decoding
test_parser
test_shm_mq
tsearch2
unaccent
uuid-ossp
vacuumlo
worker_spi
xml2
Makefile
README
contrib-global.mk
doc
src
.dir-locals.el
.gitattributes
.gitignore
COPYRIGHT
GNUmakefile.in
HISTORY
Makefile
README
README.git
aclocal.m4
configure
configure.in
postgres/contrib/btree_gist/btree_interval.c
Tom Lane 82bbb60c30 Fix valgrind warning for btree_gist indexes on macaddr.
The macaddr opclass stores two macaddr structs (each of size 6) in an
index column that's declared as being of type gbtreekey16, ie 16 bytes.
In the original coding this led to passing a palloc'd value of size 12
to the index insertion code, so that data would be fetched past the
end of the allocated value during index tuple construction.  This makes
valgrind unhappy.  In principle it could result in a SIGSEGV, though
with the current implementation of palloc there's no risk since
the 12-byte request size would be rounded up to 16 bytes anyway.

To fix, add a field to struct gbtree_ninfo showing the declared size of
the index datums, and use that in the palloc requests; and use palloc0
to be sure that any wasted bytes are cleanly initialized.

Per report from Andres Freund.  No back-patch since there's no current
risk of a real problem.
2014-05-16 15:11:51 -04:00

294 lines
6.9 KiB
C

/*
* contrib/btree_gist/btree_interval.c
*/
#include "postgres.h"
#include "btree_gist.h"
#include "btree_utils_num.h"
#include "utils/timestamp.h"
typedef struct
{
Interval lower,
upper;
} intvKEY;
/*
** Interval ops
*/
PG_FUNCTION_INFO_V1(gbt_intv_compress);
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);
static bool
gbt_intvgt(const void *a, const void *b)
{
return DatumGetBool(DirectFunctionCall2(interval_gt, IntervalPGetDatum(a), IntervalPGetDatum(b)));
}
static bool
gbt_intvge(const void *a, const void *b)
{
return DatumGetBool(DirectFunctionCall2(interval_ge, IntervalPGetDatum(a), IntervalPGetDatum(b)));
}
static bool
gbt_intveq(const void *a, const void *b)
{
return DatumGetBool(DirectFunctionCall2(interval_eq, IntervalPGetDatum(a), IntervalPGetDatum(b)));
}
static bool
gbt_intvle(const void *a, const void *b)
{
return DatumGetBool(DirectFunctionCall2(interval_le, IntervalPGetDatum(a), IntervalPGetDatum(b)));
}
static bool
gbt_intvlt(const void *a, const void *b)
{
return DatumGetBool(DirectFunctionCall2(interval_lt, IntervalPGetDatum(a), IntervalPGetDatum(b)));
}
static int
gbt_intvkey_cmp(const void *a, const void *b)
{
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)
{
return (float8) Abs(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 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)));
}
/**************************************************
* interval ops
**************************************************/
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(sizeof(GISTENTRY));
if (entry->leafkey)
{
Interval *key = DatumGetIntervalP(entry->key);
memcpy((void *) r, (void *) key, INTERVALSIZE);
memcpy((void *) (r + INTERVALSIZE), (void *) 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_decompress(PG_FUNCTION_ARGS)
{
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
GISTENTRY *retval = entry;
if (INTERVALSIZE != sizeof(Interval))
{
intvKEY *r = palloc(sizeof(intvKEY));
char *key = DatumGetPointer(entry->key);
retval = palloc(sizeof(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, (void *) query, &strategy, GIST_LEAF(entry), &tinfo)
);
}
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, (void *) query, GIST_LEAF(entry), &tinfo)
);
}
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((void *) out, entryvec, &tinfo));
}
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
));
}
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);
PG_RETURN_POINTER(result);
}