From 754148d81f9150fd860b4d5aac0eb420e4cd6886 Mon Sep 17 00:00:00 2001 From: Teodor Sigaev Date: Wed, 14 Mar 2007 14:21:53 +0000 Subject: [PATCH] Add GIN support for pg_trgm. From Guillaume Smet with minor editorization by me. Hstore improvements * add operation hstore ? text - excat equivalent of exist() * remove undocumented behaviour of contains operation with NULL value * now 'key'::text=>NULL returns '"key"=>NULL' instead of NULL * Add GIN support for contains and exist operations * Add GiST support for exist operatiion * improve regression tests --- contrib/hstore/Makefile | 4 +- contrib/hstore/README.hstore | 16 ++-- contrib/hstore/data/hstore.data | 1 + contrib/hstore/expected/hstore.out | 91 ++++++++++++++++--- contrib/hstore/hstore.h | 3 + contrib/hstore/hstore.sql.in | 42 ++++++++- contrib/hstore/hstore_gin.c | 135 ++++++++++++++++++++++++++++ contrib/hstore/hstore_gist.c | 53 ++++++----- contrib/hstore/hstore_op.c | 49 +++++++--- contrib/hstore/sql/hstore.sql | 23 ++++- contrib/hstore/uninstall_hstore.sql | 5 ++ 11 files changed, 359 insertions(+), 63 deletions(-) create mode 100644 contrib/hstore/hstore_gin.c diff --git a/contrib/hstore/Makefile b/contrib/hstore/Makefile index d15d2ae775..5257bbfcc0 100644 --- a/contrib/hstore/Makefile +++ b/contrib/hstore/Makefile @@ -1,11 +1,11 @@ -# $PostgreSQL: pgsql/contrib/hstore/Makefile,v 1.4 2007/02/09 17:24:33 petere Exp $ +# $PostgreSQL: pgsql/contrib/hstore/Makefile,v 1.5 2007/03/14 14:21:52 teodor Exp $ subdir = contrib/hstore top_builddir = ../.. include $(top_builddir)/src/Makefile.global MODULE_big = hstore -OBJS = hstore_io.o hstore_op.o hstore_gist.o crc32.o +OBJS = hstore_io.o hstore_op.o hstore_gist.o hstore_gin.o crc32.o DATA_built = hstore.sql DATA = uninstall_hstore.sql diff --git a/contrib/hstore/README.hstore b/contrib/hstore/README.hstore index 5fdceb1b98..b8c9711389 100644 --- a/contrib/hstore/README.hstore +++ b/contrib/hstore/README.hstore @@ -117,13 +117,14 @@ regression=# select * from each('a=>1,b=>2'); a | 1 b | 2 - * exist (hstore,text) - returns 'true if key is exists in hstore and - false otherwise. + * exist (hstore,text) + * hstore ? text + - returns 'true if key is exists in hstore and false otherwise. -regression=# select exist('a=>1','a'); - exist ----------- - t +regression=# select exist('a=>1','a'), 'a=>1' ? 'a'; + exist | ?column? +-------+---------- + t | t * defined (hstore,text) - returns true if key is exists in hstore and its value is not NULL. @@ -135,9 +136,10 @@ regression=# select defined('a=>NULL','a'); Indices -Module provides index support for '@>' and '<@' operations. +Module provides index support for '@>' and '?' operations. create index hidx on testhstore using gist(h); +create index hidx on testhstore using gin(h); Note diff --git a/contrib/hstore/data/hstore.data b/contrib/hstore/data/hstore.data index 7651a10f08..b7391daffb 100644 --- a/contrib/hstore/data/hstore.data +++ b/contrib/hstore/data/hstore.data @@ -998,3 +998,4 @@ auth=>BC, title=>CAC, subtitle=>BA, line=>997, date=>BAA wait=>AB, user=>ABC, line=>998, pos=>41, node=>CAC state=>4, title=>AC, bad=>t, status=>59, line=>999, disabled=>t user=>BC, line=>1000 +wait=>NULL, line=>1000 diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out index 94194a6d00..eee23d3a05 100644 --- a/contrib/hstore/expected/hstore.out +++ b/contrib/hstore/expected/hstore.out @@ -272,6 +272,12 @@ select ('aa=>NULL, c=>d , b=>16'::hstore->'aa') is null; t (1 row) +select ('aa=>"NULL", c=>d , b=>16'::hstore->'aa') is null; + ?column? +---------- + f +(1 row) + -- exists/defined select exist('a=>NULL, b=>qq', 'a'); exist @@ -291,6 +297,12 @@ select exist('a=>NULL, b=>qq', 'c'); f (1 row) +select exist('a=>"NULL", b=>qq', 'a'); + exist +------- + t +(1 row) + select defined('a=>NULL, b=>qq', 'a'); defined --------- @@ -309,6 +321,12 @@ select defined('a=>NULL, b=>qq', 'c'); f (1 row) +select defined('a=>"NULL", b=>qq', 'a'); + defined +--------- + t +(1 row) + -- delete select delete('a=>1 , b=>2, c=>3'::hstore, 'a'); delete @@ -384,6 +402,18 @@ select 'a=>g, b=>c'::hstore || ( 'b'=>'gf' ); "a"=>"g", "b"=>"gf" (1 row) +select 'a=>g, b=>c'::hstore || ( 'b'=>'NULL' ); + ?column? +----------------------- + "a"=>"g", "b"=>"NULL" +(1 row) + +select 'a=>g, b=>c'::hstore || ( 'b'=>NULL ); + ?column? +--------------------- + "a"=>"g", "b"=>NULL +(1 row) + -- keys/values select akeys('aa=>1 , b=>2, cq=>3'::hstore || 'cq=>l, b=>g, fg=>f'); akeys @@ -485,19 +515,19 @@ select * from each('aaa=>bq, b=>NULL, ""=>1 '); (3 rows) -- @> -select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>NULL'; +select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>b'; ?column? ---------- t (1 row) -select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>NULL, c=>NULL'; +select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>b, c=>NULL'; ?column? ---------- t (1 row) -select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>NULL, g=>NULL'; +select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>b, g=>NULL'; ?column? ---------- f @@ -521,12 +551,6 @@ select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>b'; t (1 row) -select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>b, c=>NULL'; - ?column? ----------- - t -(1 row) - select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>b, c=>q'; ?column? ---------- @@ -538,7 +562,7 @@ CREATE TABLE testhstore (h hstore); select count(*) from testhstore where h @> 'wait=>NULL'; count ------- - 189 + 1 (1 row) select count(*) from testhstore where h @> 'wait=>CC'; @@ -553,12 +577,18 @@ select count(*) from testhstore where h @> 'wait=>CC, public=>t'; 2 (1 row) +select count(*) from testhstore where h ? 'public'; + count +------- + 194 +(1 row) + create index hidx on testhstore using gist(h); set enable_seqscan=off; select count(*) from testhstore where h @> 'wait=>NULL'; count ------- - 189 + 1 (1 row) select count(*) from testhstore where h @> 'wait=>CC'; @@ -573,16 +603,49 @@ select count(*) from testhstore where h @> 'wait=>CC, public=>t'; 2 (1 row) +select count(*) from testhstore where h ? 'public'; + count +------- + 194 +(1 row) + +drop index hidx; +create index hidx on testhstore using gin (h); +set enable_seqscan=off; +select count(*) from testhstore where h @> 'wait=>NULL'; + count +------- + 1 +(1 row) + +select count(*) from testhstore where h @> 'wait=>CC'; + count +------- + 15 +(1 row) + +select count(*) from testhstore where h @> 'wait=>CC, public=>t'; + count +------- + 2 +(1 row) + +select count(*) from testhstore where h ? 'public'; + count +------- + 194 +(1 row) + select count(*) from (select (each(h)).key from testhstore) as wow ; count ------- - 4779 + 4781 (1 row) select key, count(*) from (select (each(h)).key from testhstore) as wow group by key order by count desc, key; key | count -----------+------- - line | 883 + line | 884 query | 207 pos | 203 node | 202 @@ -590,9 +653,9 @@ select key, count(*) from (select (each(h)).key from testhstore) as wow group by status | 195 public | 194 title | 190 + wait | 190 org | 189 user | 189 - wait | 189 coauthors | 188 disabled | 185 indexed | 184 diff --git a/contrib/hstore/hstore.h b/contrib/hstore/hstore.h index a601906764..5ef18abd8e 100644 --- a/contrib/hstore/hstore.h +++ b/contrib/hstore/hstore.h @@ -50,4 +50,7 @@ typedef struct int comparePairs(const void *a, const void *b); int uniquePairs(Pairs * a, int4 l, int4 *buflen); +#define HStoreContainsStrategyNumber 7 +#define HStoreExistsStrategyNumber 9 + #endif diff --git a/contrib/hstore/hstore.sql.in b/contrib/hstore/hstore.sql.in index 95cecf15d2..3e0821a952 100644 --- a/contrib/hstore/hstore.sql.in +++ b/contrib/hstore/hstore.sql.in @@ -40,6 +40,14 @@ RETURNS bool AS 'MODULE_PATHNAME','exists' LANGUAGE 'C' with (isstrict,iscachable); +CREATE OPERATOR ? ( + LEFTARG = hstore, + RIGHTARG = text, + PROCEDURE = exist, + RESTRICT = contsel, + JOIN = contjoinsel +); + CREATE FUNCTION isdefined(hstore,text) RETURNS bool AS 'MODULE_PATHNAME','defined' @@ -116,7 +124,7 @@ CREATE OPERATOR ~ ( CREATE FUNCTION tconvert(text,text) RETURNS hstore AS 'MODULE_PATHNAME' -LANGUAGE 'C' with (isstrict,iscachable); +LANGUAGE 'C' with (iscachable); CREATE OPERATOR => ( LEFTARG = text, @@ -210,7 +218,8 @@ LANGUAGE 'C'; CREATE OPERATOR CLASS gist_hstore_ops DEFAULT FOR TYPE hstore USING gist AS - OPERATOR 7 @> RECHECK, + OPERATOR 7 @> RECHECK, + OPERATOR 9 ?(hstore,text) RECHECK, --OPERATOR 8 <@ RECHECK, OPERATOR 13 @ RECHECK, --OPERATOR 14 ~ RECHECK, @@ -223,4 +232,33 @@ AS FUNCTION 7 ghstore_same (internal, internal, internal), STORAGE ghstore; +-- define the GIN support methods + +CREATE FUNCTION gin_extract_hstore(internal, internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C; + +CREATE FUNCTION gin_extract_hstore_query(internal, internal, int2) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C; + +CREATE FUNCTION gin_consistent_hstore(internal, int2, internal) +RETURNS internal +AS 'MODULE_PATHNAME' +LANGUAGE C; + +CREATE OPERATOR CLASS gin_hstore_ops +DEFAULT FOR TYPE hstore USING gin +AS + OPERATOR 7 @> RECHECK, + OPERATOR 9 ?(hstore,text), + FUNCTION 1 bttextcmp(text,text), + FUNCTION 2 gin_extract_hstore(internal, internal), + FUNCTION 3 gin_extract_hstore_query(internal, internal, int2), + FUNCTION 4 gin_consistent_hstore(internal, int2, internal), +STORAGE text; + + END; diff --git a/contrib/hstore/hstore_gin.c b/contrib/hstore/hstore_gin.c new file mode 100644 index 0000000000..f6fab2b89d --- /dev/null +++ b/contrib/hstore/hstore_gin.c @@ -0,0 +1,135 @@ +#include "hstore.h" + +#include "access/gin.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) +{ + StrategyNumber strategy = PG_GETARG_UINT16(1); + bool res = true; + + if ( strategy == HStoreContainsStrategyNumber ) + { + bool *check = (bool *) PG_GETARG_POINTER(0); + HStore *query = PG_GETARG_HS(2); + int i; + + for(i=0;res && i<2*query->size;i++) + if ( check[i] == false ) + res = false; + } + else if ( strategy == HStoreExistsStrategyNumber ) + res = true; + else + elog(ERROR, "Unsupported strategy number: %d", strategy); + + PG_RETURN_BOOL(res); +} + diff --git a/contrib/hstore/hstore_gist.c b/contrib/hstore/hstore_gist.c index c3923dacf2..fbee64be7d 100644 --- a/contrib/hstore/hstore_gist.c +++ b/contrib/hstore/hstore_gist.c @@ -492,37 +492,48 @@ Datum ghstore_consistent(PG_FUNCTION_ARGS) { GISTTYPE *entry = (GISTTYPE *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key); - HStore *query = PG_GETARG_HS(1); + StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2); bool res = true; - HEntry *qe = ARRPTR(query); - char *qv = STRPTR(query); BITVECP sign; if (ISALLTRUE(entry)) - { - PG_FREE_IF_COPY(query, 1); PG_RETURN_BOOL(true); - } sign = GETSIGN(entry); - while (res && qe - ARRPTR(query) < query->size) + + if ( strategy == HStoreContainsStrategyNumber || strategy == 13 /* hack for old strats */ ) { - int crc = crc32_sz((char *) (qv + qe->pos), qe->keylen); + HStore *query = PG_GETARG_HS(1); + HEntry *qe = ARRPTR(query); + char *qv = STRPTR(query); - if (GETBIT(sign, HASHVAL(crc))) + while (res && qe - ARRPTR(query) < query->size) { - if (!qe->valisnull) - { - crc = crc32_sz((char *) (qv + qe->pos + qe->keylen), qe->vallen); - if (!GETBIT(sign, HASHVAL(crc))) - res = false; - } - } - else - res = false; - qe++; - } + int crc = crc32_sz((char *) (qv + qe->pos), qe->keylen); + + if (GETBIT(sign, HASHVAL(crc))) + { + if (!qe->valisnull) + { + crc = crc32_sz((char *) (qv + qe->pos + qe->keylen), qe->vallen); + if (!GETBIT(sign, HASHVAL(crc))) + res = false; + } + } + else + res = false; + qe++; + } + } + else if ( strategy == HStoreExistsStrategyNumber ) + { + text *query = PG_GETARG_TEXT_P(1); + int crc = crc32_sz( VARDATA(query), VARSIZE(query)-VARHDRSZ ); + + res = (GETBIT(sign, HASHVAL(crc))) ? true : false; + } + else + elog(ERROR, "Unsupported strategy number: %d", strategy); - PG_FREE_IF_COPY(query, 1); PG_RETURN_BOOL(res); } diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c index ef3eb86ca3..326948afc1 100644 --- a/contrib/hstore/hstore_op.c +++ b/contrib/hstore/hstore_op.c @@ -270,26 +270,48 @@ Datum tconvert(PG_FUNCTION_ARGS); Datum tconvert(PG_FUNCTION_ARGS) { - text *key = PG_GETARG_TEXT_P(0); - text *val = PG_GETARG_TEXT_P(1); + text *key; + text *val = NULL; int len; HStore *out; - len = CALCDATASIZE(1, VARSIZE(key) + VARSIZE(val) - 2 * VARHDRSZ); + if ( PG_ARGISNULL(0) ) + PG_RETURN_NULL(); + + key = PG_GETARG_TEXT_P(0); + + if ( PG_ARGISNULL(1) ) + len = CALCDATASIZE(1, VARSIZE(key) ); + else + { + val = PG_GETARG_TEXT_P(1); + len = CALCDATASIZE(1, VARSIZE(key) + VARSIZE(val) - 2 * VARHDRSZ); + } out = palloc(len); SET_VARSIZE(out, len); out->size = 1; ARRPTR(out)->keylen = VARSIZE(key) - VARHDRSZ; - ARRPTR(out)->vallen = VARSIZE(val) - VARHDRSZ; - ARRPTR(out)->valisnull = false; + if ( PG_ARGISNULL(1) ) + { + ARRPTR(out)->vallen = 0; + ARRPTR(out)->valisnull = true; + } + else + { + ARRPTR(out)->vallen = VARSIZE(val) - VARHDRSZ; + ARRPTR(out)->valisnull = false; + } ARRPTR(out)->pos = 0; memcpy(STRPTR(out), VARDATA(key), ARRPTR(out)->keylen); - memcpy(STRPTR(out) + ARRPTR(out)->keylen, VARDATA(val), ARRPTR(out)->vallen); + if (!PG_ARGISNULL(1)) + { + memcpy(STRPTR(out) + ARRPTR(out)->keylen, VARDATA(val), ARRPTR(out)->vallen); + PG_FREE_IF_COPY(val, 1); + } PG_FREE_IF_COPY(key, 0); - PG_FREE_IF_COPY(val, 1); PG_RETURN_POINTER(out); } @@ -515,17 +537,18 @@ hs_contains(PG_FUNCTION_ARGS) if (entry) { - if (!te->valisnull) + if ( te->valisnull || entry->valisnull ) { - if (entry->valisnull || !( - te->vallen == entry->vallen && + if ( !(te->valisnull && entry->valisnull) ) + res = false; + } + else if ( te->vallen != entry->vallen || strncmp( vv + entry->pos + entry->keylen, tv + te->pos + te->keylen, - te->vallen) == 0 - )) + te->vallen) + ) res = false; - } } else res = false; diff --git a/contrib/hstore/sql/hstore.sql b/contrib/hstore/sql/hstore.sql index f268da557c..9da6cd13df 100644 --- a/contrib/hstore/sql/hstore.sql +++ b/contrib/hstore/sql/hstore.sql @@ -63,15 +63,18 @@ select 'aa=>b, c=>d , b=>16'::hstore->'b'; select 'aa=>b, c=>d , b=>16'::hstore->'aa'; select ('aa=>b, c=>d , b=>16'::hstore->'gg') is null; select ('aa=>NULL, c=>d , b=>16'::hstore->'aa') is null; +select ('aa=>"NULL", c=>d , b=>16'::hstore->'aa') is null; -- exists/defined select exist('a=>NULL, b=>qq', 'a'); select exist('a=>NULL, b=>qq', 'b'); select exist('a=>NULL, b=>qq', 'c'); +select exist('a=>"NULL", b=>qq', 'a'); select defined('a=>NULL, b=>qq', 'a'); select defined('a=>NULL, b=>qq', 'b'); select defined('a=>NULL, b=>qq', 'c'); +select defined('a=>"NULL", b=>qq', 'a'); -- delete @@ -91,6 +94,8 @@ select ''::hstore || 'cq=>l, b=>g, fg=>f'; -- => select 'a=>g, b=>c'::hstore || ( 'asd'=>'gf' ); select 'a=>g, b=>c'::hstore || ( 'b'=>'gf' ); +select 'a=>g, b=>c'::hstore || ( 'b'=>'NULL' ); +select 'a=>g, b=>c'::hstore || ( 'b'=>NULL ); -- keys/values select akeys('aa=>1 , b=>2, cq=>3'::hstore || 'cq=>l, b=>g, fg=>f'); @@ -112,13 +117,12 @@ select * from svals(''); select * from each('aaa=>bq, b=>NULL, ""=>1 '); -- @> -select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>NULL'; -select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>NULL, c=>NULL'; -select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>NULL, g=>NULL'; +select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>b'; +select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>b, c=>NULL'; +select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>b, g=>NULL'; select 'a=>b, b=>1, c=>NULL'::hstore @> 'g=>NULL'; select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>c'; select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>b'; -select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>b, c=>NULL'; select 'a=>b, b=>1, c=>NULL'::hstore @> 'a=>b, c=>q'; CREATE TABLE testhstore (h hstore); @@ -127,6 +131,7 @@ CREATE TABLE testhstore (h hstore); select count(*) from testhstore where h @> 'wait=>NULL'; select count(*) from testhstore where h @> 'wait=>CC'; select count(*) from testhstore where h @> 'wait=>CC, public=>t'; +select count(*) from testhstore where h ? 'public'; create index hidx on testhstore using gist(h); set enable_seqscan=off; @@ -134,6 +139,16 @@ set enable_seqscan=off; select count(*) from testhstore where h @> 'wait=>NULL'; select count(*) from testhstore where h @> 'wait=>CC'; select count(*) from testhstore where h @> 'wait=>CC, public=>t'; +select count(*) from testhstore where h ? 'public'; + +drop index hidx; +create index hidx on testhstore using gin (h); +set enable_seqscan=off; + +select count(*) from testhstore where h @> 'wait=>NULL'; +select count(*) from testhstore where h @> 'wait=>CC'; +select count(*) from testhstore where h @> 'wait=>CC, public=>t'; +select count(*) from testhstore where h ? 'public'; select count(*) from (select (each(h)).key from testhstore) as wow ; select key, count(*) from (select (each(h)).key from testhstore) as wow group by key order by count desc, key; diff --git a/contrib/hstore/uninstall_hstore.sql b/contrib/hstore/uninstall_hstore.sql index bfa2e738dc..a24bc72f9f 100644 --- a/contrib/hstore/uninstall_hstore.sql +++ b/contrib/hstore/uninstall_hstore.sql @@ -1,7 +1,9 @@ BEGIN; DROP OPERATOR CLASS gist_hstore_ops USING gist CASCADE; +DROP OPERATOR CLASS gin_hstore_ops USING gin CASCADE; +DROP OPERATOR ? ( hstore, text ); DROP OPERATOR ->( hstore, text ); DROP OPERATOR ||( hstore, hstore ); DROP OPERATOR @>( hstore, hstore ); @@ -33,6 +35,9 @@ DROP FUNCTION ghstore_picksplit(internal, internal); DROP FUNCTION ghstore_union(internal, internal); DROP FUNCTION ghstore_same(internal, internal, internal); DROP FUNCTION ghstore_consistent(internal,internal,int4); +DROP FUNCTION gin_consistent_hstore(internal, smallint, internal); +DROP FUNCTION gin_extract_hstore(internal, internal); +DROP FUNCTION gin_extract_hstore_query(internal, internal, smallint); DROP TYPE hstore CASCADE; DROP TYPE hs_each CASCADE;