postgresql/contrib/hstore/hstore_gin.c
Tom Lane 87b8db3774 Adjust the APIs for GIN opclass support functions to allow the extractQuery()
method to pass extra data to the consistent() and comparePartial() methods.
This is the core infrastructure needed to support the soon-to-appear
contrib/btree_gin module.  The APIs are still upward compatible with the
definitions used in 8.3 and before, although *not* with the previous 8.4devel
function definitions.

catversion bump for changes in pg_proc entries (although these are just
cosmetic, since GIN doesn't actually look at the function signature before
calling it...)

Teodor Sigaev and Oleg Bartunov
2009-03-25 22:19:02 +00:00

154 lines
3.2 KiB
C

/*
* $PostgreSQL: pgsql/contrib/hstore/hstore_gin.c,v 1.5 2009/03/25 22:19:01 tgl Exp $
*/
#include "postgres.h"
#include "access/gin.h"
#include "hstore.h"
#define KEYFLAG 'K'
#define VALFLAG 'V'
#define NULLFLAG 'N'
PG_FUNCTION_INFO_V1(gin_extract_hstore);
Datum gin_extract_hstore(PG_FUNCTION_ARGS);
static text *
makeitem(char *str, int len)
{
text *item;
item = (text *) palloc(VARHDRSZ + len + 1);
SET_VARSIZE(item, VARHDRSZ + len + 1);
if (str && len > 0)
memcpy(VARDATA(item) + 1, str, len);
return item;
}
Datum
gin_extract_hstore(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0);
int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL;
*nentries = 2 * hs->size;
if (hs->size > 0)
{
HEntry *ptr = ARRPTR(hs);
char *words = STRPTR(hs);
int i = 0;
entries = (Datum *) palloc(sizeof(Datum) * 2 * hs->size);
while (ptr - ARRPTR(hs) < hs->size)
{
text *item;
item = makeitem(words + ptr->pos, ptr->keylen);
*VARDATA(item) = KEYFLAG;
entries[i++] = PointerGetDatum(item);
if (ptr->valisnull)
{
item = makeitem(NULL, 0);
*VARDATA(item) = NULLFLAG;
}
else
{
item = makeitem(words + ptr->pos + ptr->keylen, ptr->vallen);
*VARDATA(item) = VALFLAG;
}
entries[i++] = PointerGetDatum(item);
ptr++;
}
}
PG_FREE_IF_COPY(hs, 0);
PG_RETURN_POINTER(entries);
}
PG_FUNCTION_INFO_V1(gin_extract_hstore_query);
Datum gin_extract_hstore_query(PG_FUNCTION_ARGS);
Datum
gin_extract_hstore_query(PG_FUNCTION_ARGS)
{
StrategyNumber strategy = PG_GETARG_UINT16(2);
if (strategy == HStoreContainsStrategyNumber)
{
PG_RETURN_DATUM(DirectFunctionCall2(
gin_extract_hstore,
PG_GETARG_DATUM(0),
PG_GETARG_DATUM(1)
));
}
else if (strategy == HStoreExistsStrategyNumber)
{
text *item,
*q = PG_GETARG_TEXT_P(0);
int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL;
*nentries = 1;
entries = (Datum *) palloc(sizeof(Datum));
item = makeitem(VARDATA(q), VARSIZE(q) - VARHDRSZ);
*VARDATA(item) = KEYFLAG;
entries[0] = PointerGetDatum(item);
PG_RETURN_POINTER(entries);
}
else
elog(ERROR, "Unsupported strategy number: %d", strategy);
PG_RETURN_POINTER(NULL);
}
PG_FUNCTION_INFO_V1(gin_consistent_hstore);
Datum gin_consistent_hstore(PG_FUNCTION_ARGS);
Datum
gin_consistent_hstore(PG_FUNCTION_ARGS)
{
bool *check = (bool *) PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1);
HStore *query = PG_GETARG_HS(2);
/* int32 nkeys = PG_GETARG_INT32(3); */
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
bool *recheck = (bool *) PG_GETARG_POINTER(5);
bool res = true;
if (strategy == HStoreContainsStrategyNumber)
{
int i;
/*
* Index lost information about correspondence of keys
* and values, so we need recheck
*/
*recheck = true;
for (i = 0; res && i < 2 * query->size; i++)
if (check[i] == false)
res = false;
}
else if (strategy == HStoreExistsStrategyNumber)
{
/* Existence of key is guaranteed */
*recheck = false;
res = true;
}
else
elog(ERROR, "Unsupported strategy number: %d", strategy);
PG_RETURN_BOOL(res);
}