Commit 172eacba authored by Tom Lane's avatar Tom Lane

Assorted improvements in contrib/hstore.

Remove the 64K limit on the lengths of keys and values within an hstore.
(This changes the on-disk format, but the old format can still be read.)
Add support for btree/hash opclasses for hstore --- this is not so much
for actual indexing purposes as to allow use of GROUP BY, DISTINCT, etc.
Add various other new functions and operators.

Andrew Gierth
parent 1d43e531
# $PostgreSQL: pgsql/contrib/hstore/Makefile,v 1.6 2007/11/10 23:59:51 momjian Exp $ # $PostgreSQL: pgsql/contrib/hstore/Makefile,v 1.7 2009/09/30 19:50:22 tgl Exp $
subdir = contrib/hstore subdir = contrib/hstore
top_builddir = ../.. top_builddir = ../..
include $(top_builddir)/src/Makefile.global include $(top_builddir)/src/Makefile.global
MODULE_big = hstore MODULE_big = hstore
OBJS = hstore_io.o hstore_op.o hstore_gist.o hstore_gin.o crc32.o OBJS = hstore_io.o hstore_op.o hstore_gist.o hstore_gin.o hstore_compat.o \
crc32.o
DATA_built = hstore.sql DATA_built = hstore.sql
DATA = uninstall_hstore.sql DATA = uninstall_hstore.sql
......
This diff is collapsed.
/* /*
* $PostgreSQL: pgsql/contrib/hstore/hstore.h,v 1.8 2009/06/11 14:48:51 momjian Exp $ * $PostgreSQL: pgsql/contrib/hstore/hstore.h,v 1.9 2009/09/30 19:50:22 tgl Exp $
*/ */
#ifndef __HSTORE_H__ #ifndef __HSTORE_H__
#define __HSTORE_H__ #define __HSTORE_H__
#include "fmgr.h" #include "fmgr.h"
#include "utils/array.h"
/*
* HEntry: there is one of these for each key _and_ value in an hstore
*
* the position offset points to the _end_ so that we can get the length
* by subtraction from the previous entry. the ISFIRST flag lets us tell
* whether there is a previous entry.
*/
typedef struct typedef struct
{ {
uint16 keylen; uint32 entry;
uint16 vallen;
uint32
valisnull:1,
pos:31;
} HEntry; } HEntry;
/* these are determined by the sizes of the keylen and vallen fields */ #define HENTRY_ISFIRST 0x80000000
/* in struct HEntry and struct Pairs */ #define HENTRY_ISNULL 0x40000000
#define HSTORE_MAX_KEY_LEN 65535 #define HENTRY_POSMASK 0x3FFFFFFF
#define HSTORE_MAX_VALUE_LEN 65535
/* note possible multiple evaluations, also access to prior array element */
#define HSE_ISFIRST(he_) (((he_).entry & HENTRY_ISFIRST) != 0)
#define HSE_ISNULL(he_) (((he_).entry & HENTRY_ISNULL) != 0)
#define HSE_ENDPOS(he_) ((he_).entry & HENTRY_POSMASK)
#define HSE_OFF(he_) (HSE_ISFIRST(he_) ? 0 : HSE_ENDPOS((&(he_))[-1]))
#define HSE_LEN(he_) (HSE_ISFIRST(he_) \
? HSE_ENDPOS(he_) \
: HSE_ENDPOS(he_) - HSE_ENDPOS((&(he_))[-1]))
/*
* determined by the size of "endpos" (ie HENTRY_POSMASK), though this is a
* bit academic since currently varlenas (and hence both the input and the
* whole hstore) have the same limit
*/
#define HSTORE_MAX_KEY_LEN 0x3FFFFFFF
#define HSTORE_MAX_VALUE_LEN 0x3FFFFFFF
typedef struct typedef struct
{ {
int32 vl_len_; /* varlena header (do not touch directly!) */ int32 vl_len_; /* varlena header (do not touch directly!) */
int4 size; uint32 size_; /* flags and number of items in hstore */
char data[1]; /* array of HEntry follows */
} HStore; } HStore;
#define HSHRDSIZE (VARHDRSZ + sizeof(int4)) /*
#define CALCDATASIZE(x, lenstr) ( (x) * sizeof(HEntry) + HSHRDSIZE + (lenstr) ) * it's not possible to get more than 2^28 items into an hstore,
#define ARRPTR(x) ( (HEntry*) ( (char*)(x) + HSHRDSIZE ) ) * so we reserve the top few bits of the size field. See hstore_compat.c
#define STRPTR(x) ( (char*)(x) + HSHRDSIZE + ( sizeof(HEntry) * ((HStore*)x)->size ) ) * for one reason why. Some bits are left for future use here.
*/
#define HS_FLAG_NEWVERSION 0x80000000
#define HS_COUNT(hsp_) ((hsp_)->size_ & 0x0FFFFFFF)
#define HS_SETCOUNT(hsp_,c_) ((hsp_)->size_ = (c_) | HS_FLAG_NEWVERSION)
#define HSHRDSIZE (sizeof(HStore))
#define CALCDATASIZE(x, lenstr) ( (x) * 2 * sizeof(HEntry) + HSHRDSIZE + (lenstr) )
/* note multiple evaluations of x */
#define ARRPTR(x) ( (HEntry*) ( (HStore*)(x) + 1 ) )
#define STRPTR(x) ( (char*)(ARRPTR(x) + HS_COUNT((HStore*)(x)) * 2) )
/* note multiple/non evaluations */
#define HS_KEY(arr_,str_,i_) ((str_) + HSE_OFF((arr_)[2*(i_)]))
#define HS_VAL(arr_,str_,i_) ((str_) + HSE_OFF((arr_)[2*(i_)+1]))
#define HS_KEYLEN(arr_,i_) (HSE_LEN((arr_)[2*(i_)]))
#define HS_VALLEN(arr_,i_) (HSE_LEN((arr_)[2*(i_)+1]))
#define HS_VALISNULL(arr_,i_) (HSE_ISNULL((arr_)[2*(i_)+1]))
/*
* currently, these following macros are the _only_ places that rely
* on internal knowledge of HEntry. Everything else should be using
* the above macros. Exception: the in-place upgrade in hstore_compat.c
* messes with entries directly.
*/
/*
* copy one key/value pair (which must be contiguous starting at
* sptr_) into an under-construction hstore; dent_ is an HEntry*,
* dbuf_ is the destination's string buffer, dptr_ is the current
* position in the destination. lots of modification and multiple
* evaluation here.
*/
#define HS_COPYITEM(dent_,dbuf_,dptr_,sptr_,klen_,vlen_,vnull_) \
do { \
memcpy((dptr_), (sptr_), (klen_)+(vlen_)); \
(dptr_) += (klen_)+(vlen_); \
(dent_)++->entry = ((dptr_) - (dbuf_) - (vlen_)) & HENTRY_POSMASK; \
(dent_)++->entry = ((((dptr_) - (dbuf_)) & HENTRY_POSMASK) \
| ((vnull_) ? HENTRY_ISNULL : 0)); \
} while(0)
/*
* add one key/item pair, from a Pairs structure, into an
* under-construction hstore
*/
#define HS_ADDITEM(dent_,dbuf_,dptr_,pair_) \
do { \
memcpy((dptr_), (pair_).key, (pair_).keylen); \
(dptr_) += (pair_).keylen; \
(dent_)++->entry = ((dptr_) - (dbuf_)) & HENTRY_POSMASK; \
if ((pair_).isnull) \
(dent_)++->entry = ((((dptr_) - (dbuf_)) & HENTRY_POSMASK) \
| HENTRY_ISNULL); \
else \
{ \
memcpy((dptr_), (pair_).val, (pair_).vallen); \
(dptr_) += (pair_).vallen; \
(dent_)++->entry = ((dptr_) - (dbuf_)) & HENTRY_POSMASK; \
} \
} while (0)
/* finalize a newly-constructed hstore */
#define HS_FINALIZE(hsp_,count_,buf_,ptr_) \
do { \
int buflen = (ptr_) - (buf_); \
if ((count_)) \
ARRPTR(hsp_)[0].entry |= HENTRY_ISFIRST; \
if ((count_) != HS_COUNT((hsp_))) \
{ \
HS_SETCOUNT((hsp_),(count_)); \
memmove(STRPTR(hsp_), (buf_), buflen); \
} \
SET_VARSIZE((hsp_), CALCDATASIZE((count_), buflen)); \
} while (0)
/* ensure the varlena size of an existing hstore is correct */
#define HS_FIXSIZE(hsp_,count_) \
do { \
int bl = (count_) ? HSE_ENDPOS(ARRPTR(hsp_)[2*(count_)-1]) : 0; \
SET_VARSIZE((hsp_), CALCDATASIZE((count_),bl)); \
} while (0)
/* DatumGetHStoreP includes support for reading old-format hstore values */
extern HStore *hstoreUpgrade(Datum orig);
#define DatumGetHStoreP(d) hstoreUpgrade(d)
#define PG_GETARG_HS(x) ((HStore*)PG_DETOAST_DATUM(PG_GETARG_DATUM(x))) #define PG_GETARG_HS(x) DatumGetHStoreP(PG_GETARG_DATUM(x))
/*
* Pairs is a "decompressed" representation of one key/value pair.
* The two strings are not necessarily null-terminated.
*/
typedef struct typedef struct
{ {
char *key; char *key;
char *val; char *val;
uint16 keylen; size_t keylen;
uint16 vallen; size_t vallen;
bool isnull; bool isnull; /* value is null? */
bool needfree; bool needfree; /* need to pfree the value? */
} Pairs; } Pairs;
int comparePairs(const void *a, const void *b); extern int hstoreUniquePairs(Pairs *a, int4 l, int4 *buflen);
int uniquePairs(Pairs *a, int4 l, int4 *buflen); extern HStore *hstorePairs(Pairs *pairs, int4 pcount, int4 buflen);
extern size_t hstoreCheckKeyLen(size_t len);
extern size_t hstoreCheckValLen(size_t len);
size_t hstoreCheckKeyLen(size_t len); extern int hstoreFindKey(HStore *hs, int *lowbound, char *key, int keylen);
size_t hstoreCheckValLen(size_t len); extern Pairs *hstoreArrayToPairs(ArrayType *a, int *npairs);
#define HStoreContainsStrategyNumber 7 #define HStoreContainsStrategyNumber 7
#define HStoreExistsStrategyNumber 9 #define HStoreExistsStrategyNumber 9
#define HStoreExistsAnyStrategyNumber 10
#define HStoreExistsAllStrategyNumber 11
#define HStoreOldContainsStrategyNumber 13 /* backwards compatibility */
/*
* defining HSTORE_POLLUTE_NAMESPACE=0 will prevent use of old function names;
* for now, we default to on for the benefit of people restoring old dumps
*/
#ifndef HSTORE_POLLUTE_NAMESPACE
#define HSTORE_POLLUTE_NAMESPACE 1
#endif
#if HSTORE_POLLUTE_NAMESPACE
#define HSTORE_POLLUTE(newname_,oldname_) \
PG_FUNCTION_INFO_V1(oldname_); \
Datum oldname_(PG_FUNCTION_ARGS); \
Datum newname_(PG_FUNCTION_ARGS); \
Datum oldname_(PG_FUNCTION_ARGS) { return newname_(fcinfo); } \
extern int no_such_variable
#else
#define HSTORE_POLLUTE(newname_,oldname_) \
extern int no_such_variable
#endif
#endif /* __HSTORE_H__ */ #endif /* __HSTORE_H__ */
This diff is collapsed.
This diff is collapsed.
/* /*
* $PostgreSQL: pgsql/contrib/hstore/hstore_gin.c,v 1.6 2009/06/11 14:48:51 momjian Exp $ * $PostgreSQL: pgsql/contrib/hstore/hstore_gin.c,v 1.7 2009/09/30 19:50:22 tgl Exp $
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/gin.h" #include "access/gin.h"
#include "catalog/pg_type.h"
#include "hstore.h" #include "hstore.h"
...@@ -35,43 +36,36 @@ gin_extract_hstore(PG_FUNCTION_ARGS) ...@@ -35,43 +36,36 @@ gin_extract_hstore(PG_FUNCTION_ARGS)
HStore *hs = PG_GETARG_HS(0); HStore *hs = PG_GETARG_HS(0);
int32 *nentries = (int32 *) PG_GETARG_POINTER(1); int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL; Datum *entries = NULL;
HEntry *hsent = ARRPTR(hs);
char *ptr = STRPTR(hs);
int count = HS_COUNT(hs);
int i;
*nentries = 2 * hs->size; *nentries = 2 * count;
if (count)
if (hs->size > 0) entries = (Datum *) palloc(sizeof(Datum) * 2 * count);
{
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) for (i = 0; i < count; ++i)
{ {
text *item; text *item;
item = makeitem(words + ptr->pos, ptr->keylen); item = makeitem(HS_KEY(hsent,ptr,i), HS_KEYLEN(hsent,i));
*VARDATA(item) = KEYFLAG; *VARDATA(item) = KEYFLAG;
entries[i++] = PointerGetDatum(item); entries[2*i] = PointerGetDatum(item);
if (ptr->valisnull) if (HS_VALISNULL(hsent,i))
{ {
item = makeitem(NULL, 0); item = makeitem(NULL, 0);
*VARDATA(item) = NULLFLAG; *VARDATA(item) = NULLFLAG;
} }
else else
{ {
item = makeitem(words + ptr->pos + ptr->keylen, ptr->vallen); item = makeitem(HS_VAL(hsent,ptr,i), HS_VALLEN(hsent,i));
*VARDATA(item) = VALFLAG; *VARDATA(item) = VALFLAG;
} }
entries[i++] = PointerGetDatum(item); entries[2*i+1] = PointerGetDatum(item);
ptr++;
}
} }
PG_FREE_IF_COPY(hs, 0);
PG_RETURN_POINTER(entries); PG_RETURN_POINTER(entries);
} }
...@@ -85,8 +79,7 @@ gin_extract_hstore_query(PG_FUNCTION_ARGS) ...@@ -85,8 +79,7 @@ gin_extract_hstore_query(PG_FUNCTION_ARGS)
if (strategy == HStoreContainsStrategyNumber) if (strategy == HStoreContainsStrategyNumber)
{ {
PG_RETURN_DATUM(DirectFunctionCall2( PG_RETURN_DATUM(DirectFunctionCall2(gin_extract_hstore,
gin_extract_hstore,
PG_GETARG_DATUM(0), PG_GETARG_DATUM(0),
PG_GETARG_DATUM(1) PG_GETARG_DATUM(1)
)); ));
...@@ -94,19 +87,50 @@ gin_extract_hstore_query(PG_FUNCTION_ARGS) ...@@ -94,19 +87,50 @@ gin_extract_hstore_query(PG_FUNCTION_ARGS)
else if (strategy == HStoreExistsStrategyNumber) else if (strategy == HStoreExistsStrategyNumber)
{ {
text *item, text *item,
*q = PG_GETARG_TEXT_P(0); *query = PG_GETARG_TEXT_PP(0);
int32 *nentries = (int32 *) PG_GETARG_POINTER(1); int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL; Datum *entries = NULL;
*nentries = 1; *nentries = 1;
entries = (Datum *) palloc(sizeof(Datum)); entries = (Datum *) palloc(sizeof(Datum));
item = makeitem(VARDATA(q), VARSIZE(q) - VARHDRSZ); item = makeitem(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query));
*VARDATA(item) = KEYFLAG; *VARDATA(item) = KEYFLAG;
entries[0] = PointerGetDatum(item); entries[0] = PointerGetDatum(item);
PG_RETURN_POINTER(entries); 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 else
elog(ERROR, "Unsupported strategy number: %d", strategy); elog(ERROR, "Unsupported strategy number: %d", strategy);
...@@ -121,32 +145,45 @@ gin_consistent_hstore(PG_FUNCTION_ARGS) ...@@ -121,32 +145,45 @@ gin_consistent_hstore(PG_FUNCTION_ARGS)
{ {
bool *check = (bool *) PG_GETARG_POINTER(0); bool *check = (bool *) PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1); StrategyNumber strategy = PG_GETARG_UINT16(1);
HStore *query = PG_GETARG_HS(2); /* HStore *query = PG_GETARG_HS(2); */
int32 nkeys = PG_GETARG_INT32(3);
/* int32 nkeys = PG_GETARG_INT32(3); */
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */ /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
bool *recheck = (bool *) PG_GETARG_POINTER(5); bool *recheck = (bool *) PG_GETARG_POINTER(5);
bool res = true; bool res = true;
*recheck = false;
if (strategy == HStoreContainsStrategyNumber) if (strategy == HStoreContainsStrategyNumber)
{ {
int i; int i;
/* /*
* Index lost information about correspondence of keys and values, so * Index lost information about correspondence of keys and values, so
* we need recheck * we need recheck (pre-8.4 this is handled at SQL level)
*/ */
*recheck = true; *recheck = true;
for (i = 0; res && i < 2 * query->size; i++) for (i = 0; res && i < nkeys; i++)
if (check[i] == false) if (check[i] == false)
res = false; res = false;
} }
else if (strategy == HStoreExistsStrategyNumber) else if (strategy == HStoreExistsStrategyNumber)
{ {
/* Existence of key is guaranteed */ /* Existence of key is guaranteed */
*recheck = false;
res = true; 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 else
elog(ERROR, "Unsupported strategy number: %d", strategy); elog(ERROR, "Unsupported strategy number: %d", strategy);
......
/* /*
* $PostgreSQL: pgsql/contrib/hstore/hstore_gist.c,v 1.10 2009/06/11 14:48:51 momjian Exp $ * $PostgreSQL: pgsql/contrib/hstore/hstore_gist.c,v 1.11 2009/09/30 19:50:22 tgl Exp $
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/gist.h" #include "access/gist.h"
#include "access/itup.h" #include "access/itup.h"
#include "access/skey.h" #include "access/skey.h"
#include "crc32.h" #include "catalog/pg_type.h"
#include "crc32.h"
#include "hstore.h" #include "hstore.h"
/* bigint defines */ /* bigint defines */
...@@ -114,30 +115,27 @@ ghstore_compress(PG_FUNCTION_ARGS) ...@@ -114,30 +115,27 @@ ghstore_compress(PG_FUNCTION_ARGS)
if (entry->leafkey) if (entry->leafkey)
{ {
GISTTYPE *res = (GISTTYPE *) palloc0(CALCGTSIZE(0)); GISTTYPE *res = (GISTTYPE *) palloc0(CALCGTSIZE(0));
HStore *toastedval = (HStore *) DatumGetPointer(entry->key); HStore *val = DatumGetHStoreP(entry->key);
HStore *val = (HStore *) DatumGetPointer(PG_DETOAST_DATUM(entry->key)); HEntry *hsent = ARRPTR(val);
HEntry *ptr = ARRPTR(val); char *ptr = STRPTR(val);
char *words = STRPTR(val); int count = HS_COUNT(val);
int i;
SET_VARSIZE(res, CALCGTSIZE(0)); SET_VARSIZE(res, CALCGTSIZE(0));
while (ptr - ARRPTR(val) < val->size) for (i = 0; i < count; ++i)
{ {
int h; int h;
h = crc32_sz((char *) (words + ptr->pos), ptr->keylen); h = crc32_sz((char *) HS_KEY(hsent,ptr,i), HS_KEYLEN(hsent,i));
HASH(GETSIGN(res), h); HASH(GETSIGN(res), h);
if (!ptr->valisnull) if (!HS_VALISNULL(hsent,i))
{ {
h = crc32_sz((char *) (words + ptr->pos + ptr->keylen), ptr->vallen); h = crc32_sz((char *) HS_VAL(hsent,ptr,i), HS_VALLEN(hsent,i));
HASH(GETSIGN(res), h); HASH(GETSIGN(res), h);
} }
ptr++;
} }
if (val != toastedval)
pfree(val);
retval = (GISTENTRY *) palloc(sizeof(GISTENTRY)); retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
gistentryinit(*retval, PointerGetDatum(res), gistentryinit(*retval, PointerGetDatum(res),
entry->rel, entry->page, entry->rel, entry->page,
...@@ -177,7 +175,7 @@ ghstore_decompress(PG_FUNCTION_ARGS) ...@@ -177,7 +175,7 @@ ghstore_decompress(PG_FUNCTION_ARGS)
GISTENTRY *retval; GISTENTRY *retval;
HStore *key; HStore *key;
key = (HStore *) PG_DETOAST_DATUM(entry->key); key = DatumGetHStoreP(entry->key);
if (key != (HStore *) DatumGetPointer(entry->key)) if (key != (HStore *) DatumGetPointer(entry->key))
{ {
...@@ -500,7 +498,6 @@ ghstore_picksplit(PG_FUNCTION_ARGS) ...@@ -500,7 +498,6 @@ ghstore_picksplit(PG_FUNCTION_ARGS)
} }
*right = *left = FirstOffsetNumber; *right = *left = FirstOffsetNumber;
pfree(costvector);
v->spl_ldatum = PointerGetDatum(datum_l); v->spl_ldatum = PointerGetDatum(datum_l);
v->spl_rdatum = PointerGetDatum(datum_r); v->spl_rdatum = PointerGetDatum(datum_r);
...@@ -514,7 +511,6 @@ ghstore_consistent(PG_FUNCTION_ARGS) ...@@ -514,7 +511,6 @@ ghstore_consistent(PG_FUNCTION_ARGS)
{ {
GISTTYPE *entry = (GISTTYPE *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key); GISTTYPE *entry = (GISTTYPE *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
/* Oid subtype = PG_GETARG_OID(3); */ /* Oid subtype = PG_GETARG_OID(3); */
bool *recheck = (bool *) PG_GETARG_POINTER(4); bool *recheck = (bool *) PG_GETARG_POINTER(4);
bool res = true; bool res = true;
...@@ -528,37 +524,85 @@ ghstore_consistent(PG_FUNCTION_ARGS) ...@@ -528,37 +524,85 @@ ghstore_consistent(PG_FUNCTION_ARGS)
sign = GETSIGN(entry); sign = GETSIGN(entry);
if (strategy == HStoreContainsStrategyNumber || strategy == 13 /* hack for old strats */ ) if (strategy == HStoreContainsStrategyNumber ||
strategy == HStoreOldContainsStrategyNumber)
{ {
HStore *query = PG_GETARG_HS(1); HStore *query = PG_GETARG_HS(1);
HEntry *qe = ARRPTR(query); HEntry *qe = ARRPTR(query);
char *qv = STRPTR(query); char *qv = STRPTR(query);
int count = HS_COUNT(query);
int i;
while (res && qe - ARRPTR(query) < query->size) for (i = 0; res && i < count; ++i)
{ {
int crc = crc32_sz((char *) (qv + qe->pos), qe->keylen); int crc = crc32_sz((char *) HS_KEY(qe,qv,i), HS_KEYLEN(qe,i));
if (GETBIT(sign, HASHVAL(crc))) if (GETBIT(sign, HASHVAL(crc)))
{ {
if (!qe->valisnull) if (!HS_VALISNULL(qe,i))
{ {
crc = crc32_sz((char *) (qv + qe->pos + qe->keylen), qe->vallen); crc = crc32_sz((char *) HS_VAL(qe,qv,i), HS_VALLEN(qe,i));
if (!GETBIT(sign, HASHVAL(crc))) if (!GETBIT(sign, HASHVAL(crc)))
res = false; res = false;
} }
} }
else else
res = false; res = false;
qe++;
} }
} }
else if (strategy == HStoreExistsStrategyNumber) else if (strategy == HStoreExistsStrategyNumber)
{ {
text *query = PG_GETARG_TEXT_P(1); text *query = PG_GETARG_TEXT_PP(1);
int crc = crc32_sz(VARDATA(query), VARSIZE(query) - VARHDRSZ); int crc = crc32_sz(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query));
res = (GETBIT(sign, HASHVAL(crc))) ? true : false; res = (GETBIT(sign, HASHVAL(crc))) ? true : false;
} }
else if (strategy == HStoreExistsAllStrategyNumber)
{
ArrayType *query = PG_GETARG_ARRAYTYPE_P(1);
Datum *key_datums;
bool *key_nulls;
int key_count;
int i;
deconstruct_array(query,
TEXTOID, -1, false, 'i',
&key_datums, &key_nulls, &key_count);
for (i = 0; res && i < key_count; ++i)
{
int crc;
if (key_nulls[i])
continue;
crc = crc32_sz(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ);
if (!(GETBIT(sign, HASHVAL(crc))))
res = FALSE;
}
}
else if (strategy == HStoreExistsAnyStrategyNumber)
{
ArrayType *query = PG_GETARG_ARRAYTYPE_P(1);
Datum *key_datums;
bool *key_nulls;
int key_count;
int i;
deconstruct_array(query,
TEXTOID, -1, false, 'i',
&key_datums, &key_nulls, &key_count);
res = FALSE;
for (i = 0; !res && i < key_count; ++i)
{
int crc;
if (key_nulls[i])
continue;
crc = crc32_sz(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ);
if (GETBIT(sign, HASHVAL(crc)))
res = TRUE;
}
}
else else
elog(ERROR, "Unsupported strategy number: %d", strategy); elog(ERROR, "Unsupported strategy number: %d", strategy);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* $PostgreSQL: pgsql/contrib/hstore/uninstall_hstore.sql,v 1.8 2009/03/25 22:19:01 tgl Exp $ */ /* $PostgreSQL: pgsql/contrib/hstore/uninstall_hstore.sql,v 1.9 2009/09/30 19:50:22 tgl Exp $ */
-- Adjust this setting to control where the objects get dropped. -- Adjust this setting to control where the objects get dropped.
SET search_path = public; SET search_path = public;
DROP OPERATOR CLASS gist_hstore_ops USING gist CASCADE; DROP OPERATOR CLASS gist_hstore_ops USING gist CASCADE;
DROP OPERATOR CLASS gin_hstore_ops USING gin CASCADE; DROP OPERATOR CLASS gin_hstore_ops USING gin CASCADE;
DROP OPERATOR CLASS hash_hstore_ops USING hash CASCADE;
DROP OPERATOR CLASS btree_hstore_ops USING btree CASCADE;
DROP OPERATOR - ( hstore, text );
DROP OPERATOR - ( hstore, text[] );
DROP OPERATOR - ( hstore, hstore );
DROP OPERATOR ? ( hstore, text ); DROP OPERATOR ? ( hstore, text );
DROP OPERATOR ->( hstore, text ); DROP OPERATOR ?& ( hstore, text[] );
DROP OPERATOR ||( hstore, hstore ); DROP OPERATOR ?| ( hstore, text[] );
DROP OPERATOR @>( hstore, hstore ); DROP OPERATOR -> ( hstore, text );
DROP OPERATOR <@( hstore, hstore ); DROP OPERATOR -> ( hstore, text[] );
DROP OPERATOR @( hstore, hstore ); DROP OPERATOR || ( hstore, hstore );
DROP OPERATOR ~( hstore, hstore ); DROP OPERATOR @> ( hstore, hstore );
DROP OPERATOR =>( text, text ); DROP OPERATOR <@ ( hstore, hstore );
DROP OPERATOR @ ( hstore, hstore );
DROP OPERATOR ~ ( hstore, hstore );
DROP OPERATOR => ( text, text );
DROP OPERATOR => ( text[], text[] );
DROP OPERATOR => ( hstore, text[] );
DROP OPERATOR #= ( anyelement, hstore );
DROP OPERATOR %% ( NONE, hstore );
DROP OPERATOR %# ( NONE, hstore );
DROP OPERATOR = ( hstore, hstore );
DROP OPERATOR <> ( hstore, hstore );
DROP OPERATOR #<# ( hstore, hstore );
DROP OPERATOR #<=# ( hstore, hstore );
DROP OPERATOR #># ( hstore, hstore );
DROP OPERATOR #>=# ( hstore, hstore );
DROP CAST (text[] AS hstore);
DROP FUNCTION hstore_eq(hstore,hstore);
DROP FUNCTION hstore_ne(hstore,hstore);
DROP FUNCTION hstore_gt(hstore,hstore);
DROP FUNCTION hstore_ge(hstore,hstore);
DROP FUNCTION hstore_lt(hstore,hstore);
DROP FUNCTION hstore_le(hstore,hstore);
DROP FUNCTION hstore_cmp(hstore,hstore);
DROP FUNCTION hstore_hash(hstore);
DROP FUNCTION slice_array(hstore,text[]);
DROP FUNCTION slice_hstore(hstore,text[]);
DROP FUNCTION fetchval(hstore,text); DROP FUNCTION fetchval(hstore,text);
DROP FUNCTION isexists(hstore,text); DROP FUNCTION isexists(hstore,text);
DROP FUNCTION exist(hstore,text); DROP FUNCTION exist(hstore,text);
DROP FUNCTION exists_any(hstore,text[]);
DROP FUNCTION exists_all(hstore,text[]);
DROP FUNCTION isdefined(hstore,text); DROP FUNCTION isdefined(hstore,text);
DROP FUNCTION defined(hstore,text); DROP FUNCTION defined(hstore,text);
DROP FUNCTION delete(hstore,text); DROP FUNCTION delete(hstore,text);
DROP FUNCTION delete(hstore,text[]);
DROP FUNCTION delete(hstore,hstore);
DROP FUNCTION hs_concat(hstore,hstore); DROP FUNCTION hs_concat(hstore,hstore);
DROP FUNCTION hs_contains(hstore,hstore); DROP FUNCTION hs_contains(hstore,hstore);
DROP FUNCTION hs_contained(hstore,hstore); DROP FUNCTION hs_contained(hstore,hstore);
DROP FUNCTION tconvert(text,text); DROP FUNCTION tconvert(text,text);
DROP FUNCTION hstore(text,text);
DROP FUNCTION hstore(text[],text[]);
DROP FUNCTION hstore_to_array(hstore);
DROP FUNCTION hstore_to_matrix(hstore);
DROP FUNCTION hstore(record);
DROP FUNCTION hstore(text[]);
DROP FUNCTION akeys(hstore); DROP FUNCTION akeys(hstore);
DROP FUNCTION avals(hstore); DROP FUNCTION avals(hstore);
DROP FUNCTION skeys(hstore); DROP FUNCTION skeys(hstore);
DROP FUNCTION svals(hstore); DROP FUNCTION svals(hstore);
DROP FUNCTION each(hstore); DROP FUNCTION each(hstore);
DROP FUNCTION populate_record(anyelement,hstore);
DROP FUNCTION ghstore_compress(internal); DROP FUNCTION ghstore_compress(internal);
DROP FUNCTION ghstore_decompress(internal); DROP FUNCTION ghstore_decompress(internal);
DROP FUNCTION ghstore_penalty(internal,internal,internal); DROP FUNCTION ghstore_penalty(internal,internal,internal);
...@@ -41,6 +82,7 @@ DROP FUNCTION ghstore_consistent(internal,internal,int,oid,internal); ...@@ -41,6 +82,7 @@ DROP FUNCTION ghstore_consistent(internal,internal,int,oid,internal);
DROP FUNCTION gin_consistent_hstore(internal, int2, internal, int4, internal, internal); DROP FUNCTION gin_consistent_hstore(internal, int2, internal, int4, internal, internal);
DROP FUNCTION gin_extract_hstore(internal, internal); DROP FUNCTION gin_extract_hstore(internal, internal);
DROP FUNCTION gin_extract_hstore_query(internal, internal, smallint, internal, internal); DROP FUNCTION gin_extract_hstore_query(internal, internal, smallint, internal, internal);
DROP FUNCTION hstore_version_diag(hstore);
DROP TYPE hstore CASCADE; DROP TYPE hstore CASCADE;
DROP TYPE ghstore CASCADE; DROP TYPE ghstore CASCADE;
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment