/contrib/hstore/hstore_gin.c
https://gitlab.com/kajan-rezg/postgres · C · 212 lines · 156 code · 31 blank · 25 comment · 37 complexity · d8f0a1c9959970269b09988416a30839 MD5 · raw file
- /*
- * contrib/hstore/hstore_gin.c
- */
- #include "postgres.h"
- #include "access/gin.h"
- #include "access/stratnum.h"
- #include "catalog/pg_type.h"
- #include "hstore.h"
- /*
- * When using a GIN index for hstore, we choose to index both keys and values.
- * The storage format is "text" values, with K, V, or N prepended to the string
- * to indicate key, value, or null values. (As of 9.1 it might be better to
- * store null values as nulls, but we'll keep it this way for on-disk
- * compatibility.)
- */
- #define KEYFLAG 'K'
- #define VALFLAG 'V'
- #define NULLFLAG 'N'
- PG_FUNCTION_INFO_V1(gin_extract_hstore);
- /* Build an indexable text value */
- static text *
- makeitem(char *str, int len, char flag)
- {
- text *item;
- item = (text *) palloc(VARHDRSZ + len + 1);
- SET_VARSIZE(item, VARHDRSZ + len + 1);
- *VARDATA(item) = flag;
- 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(HSTORE_KEY(hsent, ptr, i),
- HSTORE_KEYLEN(hsent, i),
- KEYFLAG);
- entries[2 * i] = PointerGetDatum(item);
- if (HSTORE_VALISNULL(hsent, i))
- item = makeitem(NULL, 0, NULLFLAG);
- else
- item = makeitem(HSTORE_VAL(hsent, ptr, i),
- HSTORE_VALLEN(hsent, i),
- 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)
- {
- int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
- StrategyNumber strategy = PG_GETARG_UINT16(2);
- int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
- Datum *entries;
- if (strategy == HStoreContainsStrategyNumber)
- {
- /* Query is an hstore, so just apply gin_extract_hstore... */
- entries = (Datum *)
- DatumGetPointer(DirectFunctionCall2(gin_extract_hstore,
- PG_GETARG_DATUM(0),
- PointerGetDatum(nentries)));
- /* ... except that "contains {}" requires a full index scan */
- if (entries == NULL)
- *searchMode = GIN_SEARCH_MODE_ALL;
- }
- else if (strategy == HStoreExistsStrategyNumber)
- {
- text *query = PG_GETARG_TEXT_PP(0);
- text *item;
- *nentries = 1;
- entries = (Datum *) palloc(sizeof(Datum));
- item = makeitem(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query), KEYFLAG);
- entries[0] = PointerGetDatum(item);
- }
- 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;
- 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)
- {
- /* Nulls in the array are ignored, cf hstoreArrayToPairs */
- if (key_nulls[i])
- continue;
- item = makeitem(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ, KEYFLAG);
- entries[j++] = PointerGetDatum(item);
- }
- *nentries = j;
- /* ExistsAll with no keys should match everything */
- if (j == 0 && strategy == HStoreExistsAllStrategyNumber)
- *searchMode = GIN_SEARCH_MODE_ALL;
- }
- else
- {
- elog(ERROR, "unrecognized strategy number: %d", strategy);
- entries = NULL; /* keep compiler quiet */
- }
- PG_RETURN_POINTER(entries);
- }
- PG_FUNCTION_INFO_V1(gin_consistent_hstore);
- 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;
- int32 i;
- if (strategy == HStoreContainsStrategyNumber)
- {
- /*
- * Index doesn't have information about correspondence of keys and
- * values, so we need recheck. However, if not all the keys are
- * present, we can fail at once.
- */
- *recheck = true;
- for (i = 0; i < nkeys; i++)
- {
- if (!check[i])
- {
- res = false;
- break;
- }
- }
- }
- else if (strategy == HStoreExistsStrategyNumber)
- {
- /* Existence of key is guaranteed in default search mode */
- *recheck = false;
- res = true;
- }
- else if (strategy == HStoreExistsAnyStrategyNumber)
- {
- /* Existence of key is guaranteed in default search mode */
- *recheck = false;
- res = true;
- }
- else if (strategy == HStoreExistsAllStrategyNumber)
- {
- /* Testing for all the keys being present gives an exact result */
- *recheck = false;
- for (i = 0; i < nkeys; i++)
- {
- if (!check[i])
- {
- res = false;
- break;
- }
- }
- }
- else
- elog(ERROR, "unrecognized strategy number: %d", strategy);
- PG_RETURN_BOOL(res);
- }