postgresql/contrib/hstore/hstore_gin.c
2010-09-20 22:08:53 +02:00

195 lines
4.2 KiB
C

/*
* contrib/hstore/hstore_gin.c
*/
#include "postgres.h"
#include "access/gin.h"
#include "catalog/pg_type.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;
HEntry *hsent = ARRPTR(hs);
char *ptr = STRPTR(hs);
int count = HS_COUNT(hs);
int i;
*nentries = 2 * count;
if (count)
entries = (Datum *) palloc(sizeof(Datum) * 2 * count);
for (i = 0; i < count; ++i)
{
text *item;
item = makeitem(HS_KEY(hsent, ptr, i), HS_KEYLEN(hsent, i));
*VARDATA(item) = KEYFLAG;
entries[2 * i] = PointerGetDatum(item);
if (HS_VALISNULL(hsent, i))
{
item = makeitem(NULL, 0);
*VARDATA(item) = NULLFLAG;
}
else
{
item = makeitem(HS_VAL(hsent, ptr, i), HS_VALLEN(hsent, i));
*VARDATA(item) = VALFLAG;
}
entries[2 * i + 1] = PointerGetDatum(item);
}
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,
*query = PG_GETARG_TEXT_PP(0);
int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL;
*nentries = 1;
entries = (Datum *) palloc(sizeof(Datum));
item = makeitem(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query));
*VARDATA(item) = KEYFLAG;
entries[0] = PointerGetDatum(item);
PG_RETURN_POINTER(entries);
}
else if (strategy == HStoreExistsAnyStrategyNumber ||
strategy == HStoreExistsAllStrategyNumber)
{
ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
Datum *key_datums;
bool *key_nulls;
int key_count;
int i,
j;
int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL;
text *item;
deconstruct_array(query,
TEXTOID, -1, false, 'i',
&key_datums, &key_nulls, &key_count);
entries = (Datum *) palloc(sizeof(Datum) * key_count);
for (i = 0, j = 0; i < key_count; ++i)
{
if (key_nulls[i])
continue;
item = makeitem(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ);
*VARDATA(item) = KEYFLAG;
entries[j++] = PointerGetDatum(item);
}
*nentries = j ? j : -1;
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;
*recheck = false;
if (strategy == HStoreContainsStrategyNumber)
{
int i;
/*
* Index lost information about correspondence of keys and values, so
* we need recheck (pre-8.4 this is handled at SQL level)
*/
*recheck = true;
for (i = 0; res && i < nkeys; i++)
if (check[i] == false)
res = false;
}
else if (strategy == HStoreExistsStrategyNumber)
{
/* Existence of key is guaranteed */
res = true;
}
else if (strategy == HStoreExistsAnyStrategyNumber)
{
/* Existence of key is guaranteed */
res = true;
}
else if (strategy == HStoreExistsAllStrategyNumber)
{
int i;
for (i = 0; res && i < nkeys; ++i)
if (!check[i])
res = false;
}
else
elog(ERROR, "Unsupported strategy number: %d", strategy);
PG_RETURN_BOOL(res);
}