From 80064e90355a443096d16c7310722008315918a2 Mon Sep 17 00:00:00 2001 From: Blake Smith Date: Tue, 20 Aug 2013 19:08:01 -0500 Subject: [PATCH] Use one index entry for a key/value pair --- contrib/hstore/hstore_gin.c | 87 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 12 deletions(-) diff --git a/contrib/hstore/hstore_gin.c b/contrib/hstore/hstore_gin.c index 2007801..e45a244 100644 --- a/contrib/hstore/hstore_gin.c +++ b/contrib/hstore/hstore_gin.c @@ -24,7 +24,6 @@ PG_FUNCTION_INFO_V1(gin_extract_hstore); Datum gin_extract_hstore(PG_FUNCTION_ARGS); -/* Build an indexable text value */ static text * makeitem(char *str, int len, char flag) { @@ -41,6 +40,73 @@ makeitem(char *str, int len, char flag) return item; } +/* Build an indexable text value */ +static text * +makeCombinedItem(HEntry *hsent, char *ptr, int i) { + int keylen; + int vallen; + int len; + int valflag; + text *item; + + keylen = HS_KEYLEN(hsent, i); + + if (HS_VALISNULL(hsent, i)) { + valflag = NULLFLAG; + vallen = 0; + } else { + valflag = VALFLAG; + vallen = HS_VALLEN(hsent, i); + } + + len = keylen + vallen + 2; + item = (text *) palloc(len); + SET_VARSIZE(item, len); + + *VARDATA(item) = KEYFLAG; + + memcpy(VARDATA(item) + 1, + HS_KEY(hsent, ptr, i), keylen); + + *(VARDATA(item) + 1 + keylen) = valflag; + + memcpy(VARDATA(item) + 2 + keylen, + HS_VAL(hsent, ptr, i), vallen); + + return item; +} + +static Datum +gin_extract_hstore_contains(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 = count; + if (count) + entries = (Datum *) palloc(sizeof(Datum) * count); + + for (i = 0; i < count; ++i) + { + text *item; + + item = makeCombinedItem(hsent, ptr, i); + entries[i] = PointerGetDatum(item); + } + + PG_RETURN_POINTER(entries); +} + +/* + * Called during indexing. This produces both the combined key/value + * index text for contains queries, as well as the key only query for + * key contains queries + */ Datum gin_extract_hstore(PG_FUNCTION_ARGS) { @@ -58,18 +124,15 @@ gin_extract_hstore(PG_FUNCTION_ARGS) for (i = 0; i < count; ++i) { - text *item; + text *combined; + text *keyonly; - item = makeitem(HS_KEY(hsent, ptr, i), HS_KEYLEN(hsent, i), - KEYFLAG); - entries[2 * i] = PointerGetDatum(item); + combined = makeCombinedItem(hsent, ptr, i); + keyonly = makeitem(HS_KEY(hsent, ptr, i), HS_KEYLEN(hsent, i), + KEYFLAG); - if (HS_VALISNULL(hsent, i)) - item = makeitem(NULL, 0, NULLFLAG); - else - item = makeitem(HS_VAL(hsent, ptr, i), HS_VALLEN(hsent, i), - VALFLAG); - entries[2 * i + 1] = PointerGetDatum(item); + entries[2 * i] = PointerGetDatum(combined); + entries[2 * i + 1] = PointerGetDatum(keyonly); } PG_RETURN_POINTER(entries); @@ -90,7 +153,7 @@ gin_extract_hstore_query(PG_FUNCTION_ARGS) { /* Query is an hstore, so just apply gin_extract_hstore... */ entries = (Datum *) - DatumGetPointer(DirectFunctionCall2(gin_extract_hstore, + DatumGetPointer(DirectFunctionCall2(gin_extract_hstore_contains, PG_GETARG_DATUM(0), PointerGetDatum(nentries))); /* ... except that "contains {}" requires a full index scan */ -- 1.7.12.4 (Apple Git-37)