diff options
Diffstat (limited to 'contrib')
34 files changed, 2376 insertions, 559 deletions
diff --git a/contrib/bloom/bloom.h b/contrib/bloom/bloom.h index d8fb36831f..23aa7ac441 100644 --- a/contrib/bloom/bloom.h +++ b/contrib/bloom/bloom.h @@ -22,7 +22,8 @@ /* Support procedures numbers */ #define BLOOM_HASH_PROC 1 -#define BLOOM_NPROC 1 +#define BLOOM_OPTIONS_PROC 2 +#define BLOOM_NPROC 2 /* Scan strategies */ #define BLOOM_EQUAL_STRATEGY 1 diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c index 0104d02f67..d3bf8665df 100644 --- a/contrib/bloom/blutils.c +++ b/contrib/bloom/blutils.c @@ -109,6 +109,7 @@ blhandler(PG_FUNCTION_ARGS) amroutine->amstrategies = BLOOM_NSTRATEGIES; amroutine->amsupport = BLOOM_NPROC; + amroutine->amoptsprocnum = BLOOM_OPTIONS_PROC; amroutine->amcanorder = false; amroutine->amcanorderbyop = false; amroutine->amcanbackward = false; diff --git a/contrib/bloom/blvalidate.c b/contrib/bloom/blvalidate.c index 12773fcf5d..3c05e5b01c 100644 --- a/contrib/bloom/blvalidate.c +++ b/contrib/bloom/blvalidate.c @@ -108,6 +108,9 @@ blvalidate(Oid opclassoid) ok = check_amproc_signature(procform->amproc, INT4OID, false, 1, 1, opckeytype); break; + case BLOOM_OPTIONS_PROC: + ok = check_amoptsproc_signature(procform->amproc); + break; default: ereport(INFO, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), @@ -204,6 +207,8 @@ blvalidate(Oid opclassoid) if (opclassgroup && (opclassgroup->functionset & (((uint64) 1) << i)) != 0) continue; /* got it */ + if (i == BLOOM_OPTIONS_PROC) + continue; /* optional method */ ereport(INFO, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("bloom opclass %s is missing support function %d", diff --git a/contrib/hstore/Makefile b/contrib/hstore/Makefile index 24a9b02d06..872ca03cd1 100644 --- a/contrib/hstore/Makefile +++ b/contrib/hstore/Makefile @@ -11,6 +11,7 @@ OBJS = \ EXTENSION = hstore DATA = hstore--1.4.sql \ + hstore--1.6--1.7.sql \ hstore--1.5--1.6.sql \ hstore--1.4--1.5.sql \ hstore--1.3--1.4.sql hstore--1.2--1.3.sql \ diff --git a/contrib/hstore/expected/hstore.out b/contrib/hstore/expected/hstore.out index 4f1db01b3e..8901079438 100644 --- a/contrib/hstore/expected/hstore.out +++ b/contrib/hstore/expected/hstore.out @@ -1345,6 +1345,51 @@ select count(*) from testhstore where h ?& ARRAY['public','disabled']; (1 row) drop index hidx; +create index hidx on testhstore using gist(h gist_hstore_ops(siglen=0)); +ERROR: value 0 out of bounds for option "siglen" +DETAIL: Valid values are between "1" and "2024". +create index hidx on testhstore using gist(h gist_hstore_ops(siglen=2025)); +ERROR: value 2025 out of bounds for option "siglen" +DETAIL: Valid values are between "1" and "2024". +create index hidx on testhstore using gist(h gist_hstore_ops(siglen=2024)); +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 testhstore where h ?| ARRAY['public','disabled']; + count +------- + 337 +(1 row) + +select count(*) from testhstore where h ?& ARRAY['public','disabled']; + count +------- + 42 +(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'; diff --git a/contrib/hstore/hstore--1.6--1.7.sql b/contrib/hstore/hstore--1.6--1.7.sql new file mode 100644 index 0000000000..0d126ef8a9 --- /dev/null +++ b/contrib/hstore/hstore--1.6--1.7.sql @@ -0,0 +1,12 @@ +/* contrib/hstore/hstore--1.6--1.7.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION hstore UPDATE TO '1.7'" to load this file. \quit + +CREATE FUNCTION ghstore_options(internal) +RETURNS void +AS 'MODULE_PATHNAME', 'ghstore_options' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +ALTER OPERATOR FAMILY gist_hstore_ops USING gist +ADD FUNCTION 10 (hstore) ghstore_options (internal); diff --git a/contrib/hstore/hstore.control b/contrib/hstore/hstore.control index e0fbb8bb3c..f0da772429 100644 --- a/contrib/hstore/hstore.control +++ b/contrib/hstore/hstore.control @@ -1,6 +1,6 @@ # hstore extension comment = 'data type for storing sets of (key, value) pairs' -default_version = '1.6' +default_version = '1.7' module_pathname = '$libdir/hstore' relocatable = true trusted = true diff --git a/contrib/hstore/hstore_gist.c b/contrib/hstore/hstore_gist.c index d198c4b7d7..102c9cea72 100644 --- a/contrib/hstore/hstore_gist.c +++ b/contrib/hstore/hstore_gist.c @@ -4,25 +4,36 @@ #include "postgres.h" #include "access/gist.h" +#include "access/reloptions.h" #include "access/stratnum.h" #include "catalog/pg_type.h" #include "hstore.h" #include "utils/pg_crc.h" +/* gist_hstore_ops opclass options */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int siglen; /* signature length in bytes */ +} GistHstoreOptions; + /* bigint defines */ #define BITBYTE 8 -#define SIGLENINT 4 /* >122 => key will toast, so very slow!!! */ -#define SIGLEN ( sizeof(int)*SIGLENINT ) -#define SIGLENBIT (SIGLEN*BITBYTE) +#define SIGLEN_DEFAULT (sizeof(int32) * 4) +#define SIGLEN_MAX GISTMaxIndexKeySize +#define SIGLENBIT(siglen) ((siglen) * BITBYTE) +#define GET_SIGLEN() (PG_HAS_OPCLASS_OPTIONS() ? \ + ((GistHstoreOptions *) PG_GET_OPCLASS_OPTIONS())->siglen : \ + SIGLEN_DEFAULT) + -typedef char BITVEC[SIGLEN]; typedef char *BITVECP; -#define LOOPBYTE \ - for(i=0;i<SIGLEN;i++) +#define LOOPBYTE(siglen) \ + for (i = 0; i < (siglen); i++) -#define LOOPBIT \ - for(i=0;i<SIGLENBIT;i++) +#define LOOPBIT(siglen) \ + for (i = 0; i < SIGLENBIT(siglen); i++) /* beware of multiple evaluation of arguments to these macros! */ #define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITBYTE ) ) ) @@ -30,8 +41,8 @@ typedef char *BITVECP; #define CLRBIT(x,i) GETBYTE(x,i) &= ~( 0x01 << ( (i) % BITBYTE ) ) #define SETBIT(x,i) GETBYTE(x,i) |= ( 0x01 << ( (i) % BITBYTE ) ) #define GETBIT(x,i) ( (GETBYTE(x,i) >> ( (i) % BITBYTE )) & 0x01 ) -#define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT) -#define HASH(sign, val) SETBIT((sign), HASHVAL(val)) +#define HASHVAL(val, siglen) (((unsigned int)(val)) % SIGLENBIT(siglen)) +#define HASH(sign, val, siglen) SETBIT((sign), HASHVAL(val, siglen)) typedef struct { @@ -45,7 +56,7 @@ typedef struct #define ISALLTRUE(x) ( ((GISTTYPE*)x)->flag & ALLISTRUE ) #define GTHDRSIZE (VARHDRSZ + sizeof(int32)) -#define CALCGTSIZE(flag) ( GTHDRSIZE+(((flag) & ALLISTRUE) ? 0 : SIGLEN) ) +#define CALCGTSIZE(flag, siglen) ( GTHDRSIZE+(((flag) & ALLISTRUE) ? 0 : (siglen)) ) #define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) ) @@ -96,6 +107,27 @@ ghstore_out(PG_FUNCTION_ARGS) PG_RETURN_DATUM(0); } +static GISTTYPE * +ghstore_alloc(bool allistrue, int siglen, BITVECP sign) +{ + int flag = allistrue ? ALLISTRUE : 0; + int size = CALCGTSIZE(flag, siglen); + GISTTYPE *res = palloc(size); + + SET_VARSIZE(res, size); + res->flag = flag; + + if (!allistrue) + { + if (sign) + memcpy(GETSIGN(res), sign, siglen); + else + memset(GETSIGN(res), 0, siglen); + } + + return res; +} + PG_FUNCTION_INFO_V1(ghstore_consistent); PG_FUNCTION_INFO_V1(ghstore_compress); PG_FUNCTION_INFO_V1(ghstore_decompress); @@ -103,36 +135,36 @@ PG_FUNCTION_INFO_V1(ghstore_penalty); PG_FUNCTION_INFO_V1(ghstore_picksplit); PG_FUNCTION_INFO_V1(ghstore_union); PG_FUNCTION_INFO_V1(ghstore_same); +PG_FUNCTION_INFO_V1(ghstore_options); Datum ghstore_compress(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + int siglen = GET_SIGLEN(); GISTENTRY *retval = entry; if (entry->leafkey) { - GISTTYPE *res = (GISTTYPE *) palloc0(CALCGTSIZE(0)); + GISTTYPE *res = ghstore_alloc(false, siglen, NULL); HStore *val = DatumGetHStoreP(entry->key); HEntry *hsent = ARRPTR(val); char *ptr = STRPTR(val); int count = HS_COUNT(val); int i; - SET_VARSIZE(res, CALCGTSIZE(0)); - for (i = 0; i < count; ++i) { int h; h = crc32_sz((char *) HSTORE_KEY(hsent, ptr, i), HSTORE_KEYLEN(hsent, i)); - HASH(GETSIGN(res), h); + HASH(GETSIGN(res), h, siglen); if (!HSTORE_VALISNULL(hsent, i)) { h = crc32_sz((char *) HSTORE_VAL(hsent, ptr, i), HSTORE_VALLEN(hsent, i)); - HASH(GETSIGN(res), h); + HASH(GETSIGN(res), h, siglen); } } @@ -148,15 +180,13 @@ ghstore_compress(PG_FUNCTION_ARGS) GISTTYPE *res; BITVECP sign = GETSIGN(DatumGetPointer(entry->key)); - LOOPBYTE + LOOPBYTE(siglen) { if ((sign[i] & 0xff) != 0xff) PG_RETURN_POINTER(retval); } - res = (GISTTYPE *) palloc(CALCGTSIZE(ALLISTRUE)); - SET_VARSIZE(res, CALCGTSIZE(ALLISTRUE)); - res->flag = ALLISTRUE; + res = ghstore_alloc(true, siglen, NULL); retval = (GISTENTRY *) palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(res), @@ -184,6 +214,8 @@ ghstore_same(PG_FUNCTION_ARGS) GISTTYPE *a = (GISTTYPE *) PG_GETARG_POINTER(0); GISTTYPE *b = (GISTTYPE *) PG_GETARG_POINTER(1); bool *result = (bool *) PG_GETARG_POINTER(2); + int siglen = GET_SIGLEN(); + if (ISALLTRUE(a) && ISALLTRUE(b)) *result = true; @@ -198,7 +230,7 @@ ghstore_same(PG_FUNCTION_ARGS) sb = GETSIGN(b); *result = true; - LOOPBYTE + LOOPBYTE(siglen) { if (sa[i] != sb[i]) { @@ -211,12 +243,12 @@ ghstore_same(PG_FUNCTION_ARGS) } static int32 -sizebitvec(BITVECP sign) +sizebitvec(BITVECP sign, int siglen) { int32 size = 0, i; - LOOPBYTE + LOOPBYTE(siglen) { size += SUMBIT(sign); sign = (BITVECP) (((char *) sign) + 1); @@ -225,12 +257,12 @@ sizebitvec(BITVECP sign) } static int -hemdistsign(BITVECP a, BITVECP b) +hemdistsign(BITVECP a, BITVECP b, int siglen) { int i, dist = 0; - LOOPBIT + LOOPBIT(siglen) { if (GETBIT(a, i) != GETBIT(b, i)) dist++; @@ -239,30 +271,30 @@ hemdistsign(BITVECP a, BITVECP b) } static int -hemdist(GISTTYPE *a, GISTTYPE *b) +hemdist(GISTTYPE *a, GISTTYPE *b, int siglen) { if (ISALLTRUE(a)) { if (ISALLTRUE(b)) return 0; else - return SIGLENBIT - sizebitvec(GETSIGN(b)); + return SIGLENBIT(siglen) - sizebitvec(GETSIGN(b), siglen); } else if (ISALLTRUE(b)) - return SIGLENBIT - sizebitvec(GETSIGN(a)); + return SIGLENBIT(siglen) - sizebitvec(GETSIGN(a), siglen); - return hemdistsign(GETSIGN(a), GETSIGN(b)); + return hemdistsign(GETSIGN(a), GETSIGN(b), siglen); } static int32 -unionkey(BITVECP sbase, GISTTYPE *add) +unionkey(BITVECP sbase, GISTTYPE *add, int siglen) { int32 i; BITVECP sadd = GETSIGN(add); if (ISALLTRUE(add)) return 1; - LOOPBYTE + LOOPBYTE(siglen) sbase[i] |= sadd[i]; return 0; } @@ -274,28 +306,22 @@ ghstore_union(PG_FUNCTION_ARGS) int32 len = entryvec->n; int *size = (int *) PG_GETARG_POINTER(1); - BITVEC base; + int siglen = GET_SIGLEN(); int32 i; - int32 flag = 0; - GISTTYPE *result; + GISTTYPE *result = ghstore_alloc(false, siglen, NULL); + BITVECP base = GETSIGN(result); - MemSet((void *) base, 0, sizeof(BITVEC)); for (i = 0; i < len; i++) { - if (unionkey(base, GETENTRY(entryvec, i))) + if (unionkey(base, GETENTRY(entryvec, i), siglen)) { - flag = ALLISTRUE; + result->flag |= ALLISTRUE; + SET_VARSIZE(result, CALCGTSIZE(ALLISTRUE, siglen)); break; } } - len = CALCGTSIZE(flag); - result = (GISTTYPE *) palloc(len); - SET_VARSIZE(result, len); - result->flag = flag; - if (!ISALLTRUE(result)) - memcpy((void *) GETSIGN(result), (void *) base, sizeof(BITVEC)); - *size = len; + *size = VARSIZE(result); PG_RETURN_POINTER(result); } @@ -306,10 +332,11 @@ ghstore_penalty(PG_FUNCTION_ARGS) GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */ GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1); float *penalty = (float *) PG_GETARG_POINTER(2); + int siglen = GET_SIGLEN(); GISTTYPE *origval = (GISTTYPE *) DatumGetPointer(origentry->key); GISTTYPE *newval = (GISTTYPE *) DatumGetPointer(newentry->key); - *penalty = hemdist(origval, newval); + *penalty = hemdist(origval, newval, siglen); PG_RETURN_POINTER(penalty); } @@ -334,6 +361,7 @@ ghstore_picksplit(PG_FUNCTION_ARGS) OffsetNumber maxoff = entryvec->n - 2; GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); + int siglen = GET_SIGLEN(); OffsetNumber k, j; GISTTYPE *datum_l, @@ -364,7 +392,7 @@ ghstore_picksplit(PG_FUNCTION_ARGS) _k = GETENTRY(entryvec, k); for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) { - size_waste = hemdist(_k, GETENTRY(entryvec, j)); + size_waste = hemdist(_k, GETENTRY(entryvec, j), siglen); if (size_waste > waste) { waste = size_waste; @@ -386,33 +414,10 @@ ghstore_picksplit(PG_FUNCTION_ARGS) } /* form initial .. */ - if (ISALLTRUE(GETENTRY(entryvec, seed_1))) - { - datum_l = (GISTTYPE *) palloc(GTHDRSIZE); - SET_VARSIZE(datum_l, GTHDRSIZE); - datum_l->flag = ALLISTRUE; - } - else - { - datum_l = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN); - SET_VARSIZE(datum_l, GTHDRSIZE + SIGLEN); - datum_l->flag = 0; - memcpy((void *) GETSIGN(datum_l), (void *) GETSIGN(GETENTRY(entryvec, seed_1)), sizeof(BITVEC)) - ; - } - if (ISALLTRUE(GETENTRY(entryvec, seed_2))) - { - datum_r = (GISTTYPE *) palloc(GTHDRSIZE); - SET_VARSIZE(datum_r, GTHDRSIZE); - datum_r->flag = ALLISTRUE; - } - else - { - datum_r = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN); - SET_VARSIZE(datum_r, GTHDRSIZE + SIGLEN); - datum_r->flag = 0; - memcpy((void *) GETSIGN(datum_r), (void *) GETSIGN(GETENTRY(entryvec, seed_2)), sizeof(BITVEC)); - } + datum_l = ghstore_alloc(ISALLTRUE(GETENTRY(entryvec, seed_1)), siglen, + GETSIGN(GETENTRY(entryvec, seed_1))); + datum_r = ghstore_alloc(ISALLTRUE(GETENTRY(entryvec, seed_2)), siglen, + GETSIGN(GETENTRY(entryvec, seed_2))); maxoff = OffsetNumberNext(maxoff); /* sort before ... */ @@ -421,8 +426,8 @@ ghstore_picksplit(PG_FUNCTION_ARGS) { costvector[j - 1].pos = j; _j = GETENTRY(entryvec, j); - size_alpha = hemdist(datum_l, _j); - size_beta = hemdist(datum_r, _j); + size_alpha = hemdist(datum_l, _j, siglen); + size_beta = hemdist(datum_r, _j, siglen); costvector[j - 1].cost = abs(size_alpha - size_beta); } qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost); @@ -446,20 +451,20 @@ ghstore_picksplit(PG_FUNCTION_ARGS) continue; } _j = GETENTRY(entryvec, j); - size_alpha = hemdist(datum_l, _j); - size_beta = hemdist(datum_r, _j); + size_alpha = hemdist(datum_l, _j, siglen); + size_beta = hemdist(datum_r, _j, siglen); if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.0001)) { if (ISALLTRUE(datum_l) || ISALLTRUE(_j)) { if (!ISALLTRUE(datum_l)) - MemSet((void *) union_l, 0xff, sizeof(BITVEC)); + MemSet((void *) union_l, 0xff, siglen); } else { ptr = GETSIGN(_j); - LOOPBYTE + LOOPBYTE(siglen) union_l[i] |= ptr[i]; } *left++ = j; @@ -470,12 +475,12 @@ ghstore_picksplit(PG_FUNCTION_ARGS) if (ISALLTRUE(datum_r) || ISALLTRUE(_j)) { if (!ISALLTRUE(datum_r)) - MemSet((void *) union_r, 0xff, sizeof(BITVEC)); + MemSet((void *) union_r, 0xff, siglen); } else { ptr = GETSIGN(_j); - LOOPBYTE + LOOPBYTE(siglen) union_r[i] |= ptr[i]; } *right++ = j; @@ -500,6 +505,7 @@ ghstore_consistent(PG_FUNCTION_ARGS) /* Oid subtype = PG_GETARG_OID(3); */ bool *recheck = (bool *) PG_GETARG_POINTER(4); + int siglen = GET_SIGLEN(); bool res = true; BITVECP sign; @@ -525,13 +531,13 @@ ghstore_consistent(PG_FUNCTION_ARGS) int crc = crc32_sz((char *) HSTORE_KEY(qe, qv, i), HSTORE_KEYLEN(qe, i)); - if (GETBIT(sign, HASHVAL(crc))) + if (GETBIT(sign, HASHVAL(crc, siglen))) { if (!HSTORE_VALISNULL(qe, i)) { crc = crc32_sz((char *) HSTORE_VAL(qe, qv, i), HSTORE_VALLEN(qe, i)); - if (!GETBIT(sign, HASHVAL(crc))) + if (!GETBIT(sign, HASHVAL(crc, siglen))) res = false; } } @@ -544,7 +550,7 @@ ghstore_consistent(PG_FUNCTION_ARGS) text *query = PG_GETARG_TEXT_PP(1); int crc = crc32_sz(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query)); - res = (GETBIT(sign, HASHVAL(crc))) ? true : false; + res = (GETBIT(sign, HASHVAL(crc, siglen))) ? true : false; } else if (strategy == HStoreExistsAllStrategyNumber) { @@ -565,7 +571,7 @@ ghstore_consistent(PG_FUNCTION_ARGS) if (key_nulls[i]) continue; crc = crc32_sz(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ); - if (!(GETBIT(sign, HASHVAL(crc)))) + if (!(GETBIT(sign, HASHVAL(crc, siglen)))) res = false; } } @@ -590,7 +596,7 @@ ghstore_consistent(PG_FUNCTION_ARGS) if (key_nulls[i]) continue; crc = crc32_sz(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ); - if (GETBIT(sign, HASHVAL(crc))) + if (GETBIT(sign, HASHVAL(crc, siglen))) res = true; } } @@ -599,3 +605,17 @@ ghstore_consistent(PG_FUNCTION_ARGS) PG_RETURN_BOOL(res); } + +Datum +ghstore_options(PG_FUNCTION_ARGS) +{ + local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0); + + init_local_reloptions(relopts, sizeof(GistHstoreOptions)); + add_local_int_reloption(relopts, "siglen", + "signature length in bytes", + SIGLEN_DEFAULT, 1, SIGLEN_MAX, + offsetof(GistHstoreOptions, siglen)); + + PG_RETURN_VOID(); +} diff --git a/contrib/hstore/sql/hstore.sql b/contrib/hstore/sql/hstore.sql index 76ac48b021..a6c2f3a0ce 100644 --- a/contrib/hstore/sql/hstore.sql +++ b/contrib/hstore/sql/hstore.sql @@ -305,6 +305,19 @@ select count(*) from testhstore where h ?| ARRAY['public','disabled']; select count(*) from testhstore where h ?& ARRAY['public','disabled']; drop index hidx; +create index hidx on testhstore using gist(h gist_hstore_ops(siglen=0)); +create index hidx on testhstore using gist(h gist_hstore_ops(siglen=2025)); +create index hidx on testhstore using gist(h gist_hstore_ops(siglen=2024)); +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 testhstore where h ?| ARRAY['public','disabled']; +select count(*) from testhstore where h ?& ARRAY['public','disabled']; + +drop index hidx; create index hidx on testhstore using gin (h); set enable_seqscan=off; diff --git a/contrib/intarray/Makefile b/contrib/intarray/Makefile index d02349c049..b68959ebd6 100644 --- a/contrib/intarray/Makefile +++ b/contrib/intarray/Makefile @@ -12,7 +12,8 @@ OBJS = \ _intbig_gist.o EXTENSION = intarray -DATA = intarray--1.2.sql intarray--1.1--1.2.sql intarray--1.0--1.1.sql +DATA = intarray--1.2--1.3.sql intarray--1.2.sql intarray--1.1--1.2.sql \ + intarray--1.0--1.1.sql PGFILEDESC = "intarray - functions and operators for arrays of integers" REGRESS = _int diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h index f03fdf9add..304c29525c 100644 --- a/contrib/intarray/_int.h +++ b/contrib/intarray/_int.h @@ -8,7 +8,19 @@ #include "utils/memutils.h" /* number ranges for compression */ -#define MAXNUMRANGE 100 +#define G_INT_NUMRANGES_DEFAULT 100 +#define G_INT_NUMRANGES_MAX ((GISTMaxIndexKeySize - VARHDRSZ) / \ + (2 * sizeof(int32))) +#define G_INT_GET_NUMRANGES() (PG_HAS_OPCLASS_OPTIONS() ? \ + ((GISTIntArrayOptions *) PG_GET_OPCLASS_OPTIONS())->num_ranges : \ + G_INT_NUMRANGES_DEFAULT) + +/* gist_int_ops opclass options */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int num_ranges; /* number of ranges */ +} GISTIntArrayOptions; /* useful macros for accessing int4 arrays */ #define ARRPTR(x) ( (int32 *) ARR_DATA_PTR(x) ) @@ -47,15 +59,17 @@ /* bigint defines */ -#define SIGLENINT 63 /* >122 => key will toast, so very slow!!! */ -#define SIGLEN ( sizeof(int)*SIGLENINT ) -#define SIGLENBIT (SIGLEN*BITS_PER_BYTE) +#define SIGLEN_DEFAULT (63 * 4) +#define SIGLEN_MAX GISTMaxIndexKeySize +#define SIGLENBIT(siglen) ((siglen) * BITS_PER_BYTE) +#define GET_SIGLEN() (PG_HAS_OPCLASS_OPTIONS() ? \ + ((GISTIntArrayBigOptions *) PG_GET_OPCLASS_OPTIONS())->siglen : \ + SIGLEN_DEFAULT) -typedef char BITVEC[SIGLEN]; typedef char *BITVECP; -#define LOOPBYTE \ - for(i=0;i<SIGLEN;i++) +#define LOOPBYTE(siglen) \ + for (i = 0; i < siglen; i++) /* beware of multiple evaluation of arguments to these macros! */ #define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITS_PER_BYTE ) ) ) @@ -63,8 +77,15 @@ typedef char *BITVECP; #define CLRBIT(x,i) GETBYTE(x,i) &= ~( 0x01 << ( (i) % BITS_PER_BYTE ) ) #define SETBIT(x,i) GETBYTE(x,i) |= ( 0x01 << ( (i) % BITS_PER_BYTE ) ) #define GETBIT(x,i) ( (GETBYTE(x,i) >> ( (i) % BITS_PER_BYTE )) & 0x01 ) -#define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT) -#define HASH(sign, val) SETBIT((sign), HASHVAL(val)) +#define HASHVAL(val, siglen) (((unsigned int)(val)) % SIGLENBIT(siglen)) +#define HASH(sign, val, siglen) SETBIT((sign), HASHVAL(val, siglen)) + +/* gist_intbig_ops opclass options */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int siglen; /* signature length in bytes */ +} GISTIntArrayBigOptions; /* * type of index key @@ -81,7 +102,7 @@ typedef struct #define ISALLTRUE(x) ( ((GISTTYPE*)x)->flag & ALLISTRUE ) #define GTHDRSIZE (VARHDRSZ + sizeof(int32)) -#define CALCGTSIZE(flag) ( GTHDRSIZE+(((flag) & ALLISTRUE) ? 0 : SIGLEN) ) +#define CALCGTSIZE(flag, siglen) ( GTHDRSIZE+(((flag) & ALLISTRUE) ? 0 : (siglen)) ) #define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) ) @@ -103,7 +124,7 @@ bool inner_int_contains(ArrayType *a, ArrayType *b); ArrayType *inner_int_union(ArrayType *a, ArrayType *b); ArrayType *inner_int_inter(ArrayType *a, ArrayType *b); void rt__int_size(ArrayType *a, float *size); -void gensign(BITVEC sign, int *a, int len); +void gensign(BITVECP sign, int *a, int len, int siglen); /***************************************************************************** @@ -149,7 +170,7 @@ typedef struct QUERYTYPE #define PG_GETARG_QUERYTYPE_P(n) DatumGetQueryTypeP(PG_GETARG_DATUM(n)) #define PG_GETARG_QUERYTYPE_P_COPY(n) DatumGetQueryTypePCopy(PG_GETARG_DATUM(n)) -bool signconsistent(QUERYTYPE *query, BITVEC sign, bool calcnot); +bool signconsistent(QUERYTYPE *query, BITVECP sign, int siglen, bool calcnot); bool execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot); bool gin_bool_consistent(QUERYTYPE *query, bool *check); diff --git a/contrib/intarray/_int_bool.c b/contrib/intarray/_int_bool.c index fd976900b8..58113892d3 100644 --- a/contrib/intarray/_int_bool.c +++ b/contrib/intarray/_int_bool.c @@ -232,7 +232,7 @@ typedef struct * is there value 'val' in (sorted) array or not ? */ static bool -checkcondition_arr(void *checkval, ITEM *item) +checkcondition_arr(void *checkval, ITEM *item, void *options) { int32 *StopLow = ((CHKVAL *) checkval)->arrb; int32 *StopHigh = ((CHKVAL *) checkval)->arre; @@ -254,42 +254,42 @@ checkcondition_arr(void *checkval, ITEM *item) } static bool -checkcondition_bit(void *checkval, ITEM *item) +checkcondition_bit(void *checkval, ITEM *item, void *siglen) { - return GETBIT(checkval, HASHVAL(item->val)); + return GETBIT(checkval, HASHVAL(item->val, (int)(intptr_t) siglen)); } /* * evaluate boolean expression, using chkcond() to test the primitive cases */ static bool -execute(ITEM *curitem, void *checkval, bool calcnot, - bool (*chkcond) (void *checkval, ITEM *item)) +execute(ITEM *curitem, void *checkval, void *options, bool calcnot, + bool (*chkcond) (void *checkval, ITEM *item, void *options)) { /* since this function recurses, it could be driven to stack overflow */ check_stack_depth(); if (curitem->type == VAL) - return (*chkcond) (checkval, curitem); + return (*chkcond) (checkval, curitem, options); else if (curitem->val == (int32) '!') { return calcnot ? - ((execute(curitem - 1, checkval, calcnot, chkcond)) ? false : true) + ((execute(curitem - 1, checkval, options, calcnot, chkcond)) ? false : true) : true; } else if (curitem->val == (int32) '&') { - if (execute(curitem + curitem->left, checkval, calcnot, chkcond)) - return execute(curitem - 1, checkval, calcnot, chkcond); + if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond)) + return execute(curitem - 1, checkval, options, calcnot, chkcond); else return false; } else { /* |-operator */ - if (execute(curitem + curitem->left, checkval, calcnot, chkcond)) + if (execute(curitem + curitem->left, checkval, options, calcnot, chkcond)) return true; else - return execute(curitem - 1, checkval, calcnot, chkcond); + return execute(curitem - 1, checkval, options, calcnot, chkcond); } } @@ -297,10 +297,10 @@ execute(ITEM *curitem, void *checkval, bool calcnot, * signconsistent & execconsistent called by *_consistent */ bool -signconsistent(QUERYTYPE *query, BITVEC sign, bool calcnot) +signconsistent(QUERYTYPE *query, BITVECP sign, int siglen, bool calcnot) { return execute(GETQUERY(query) + query->size - 1, - (void *) sign, calcnot, + (void *) sign, (void *)(intptr_t) siglen, calcnot, checkcondition_bit); } @@ -314,7 +314,7 @@ execconsistent(QUERYTYPE *query, ArrayType *array, bool calcnot) chkval.arrb = ARRPTR(array); chkval.arre = chkval.arrb + ARRNELEMS(array); return execute(GETQUERY(query) + query->size - 1, - (void *) &chkval, calcnot, + (void *) &chkval, NULL, calcnot, checkcondition_arr); } @@ -325,7 +325,7 @@ typedef struct } GinChkVal; static bool -checkcondition_gin(void *checkval, ITEM *item) +checkcondition_gin(void *checkval, ITEM *item, void *options) { GinChkVal *gcv = (GinChkVal *) checkval; @@ -356,7 +356,7 @@ gin_bool_consistent(QUERYTYPE *query, bool *check) } return execute(GETQUERY(query) + query->size - 1, - (void *) &gcv, true, + (void *) &gcv, NULL, true, checkcondition_gin); } @@ -428,7 +428,7 @@ boolop(PG_FUNCTION_ARGS) chkval.arrb = ARRPTR(val); chkval.arre = chkval.arrb + ARRNELEMS(val); result = execute(GETQUERY(query) + query->size - 1, - &chkval, true, + &chkval, NULL, true, checkcondition_arr); pfree(val); diff --git a/contrib/intarray/_int_gist.c b/contrib/intarray/_int_gist.c index 50effc3ca5..fb05b06af9 100644 --- a/contrib/intarray/_int_gist.c +++ b/contrib/intarray/_int_gist.c @@ -7,6 +7,7 @@ #include "_int.h" #include "access/gist.h" +#include "access/reloptions.h" #include "access/stratnum.h" #define GETENTRY(vec,pos) ((ArrayType *) DatumGetPointer((vec)->vector[(pos)].key)) @@ -32,6 +33,7 @@ PG_FUNCTION_INFO_V1(g_int_penalty); PG_FUNCTION_INFO_V1(g_int_picksplit); PG_FUNCTION_INFO_V1(g_int_union); PG_FUNCTION_INFO_V1(g_int_same); +PG_FUNCTION_INFO_V1(g_int_options); /* @@ -156,6 +158,7 @@ g_int_compress(PG_FUNCTION_ARGS) GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *retval; ArrayType *r; + int num_ranges = G_INT_GET_NUMRANGES(); int len, lenr; int *dr; @@ -170,9 +173,9 @@ g_int_compress(PG_FUNCTION_ARGS) CHECKARRVALID(r); PREPAREARR(r); - if (ARRNELEMS(r) >= 2 * MAXNUMRANGE) + if (ARRNELEMS(r) >= 2 * num_ranges) elog(NOTICE, "input array is too big (%d maximum allowed, %d current), use gist__intbig_ops opclass instead", - 2 * MAXNUMRANGE - 1, ARRNELEMS(r)); + 2 * num_ranges - 1, ARRNELEMS(r)); retval = palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(r), @@ -195,7 +198,7 @@ g_int_compress(PG_FUNCTION_ARGS) PG_RETURN_POINTER(entry); } - if ((len = ARRNELEMS(r)) >= 2 * MAXNUMRANGE) + if ((len = ARRNELEMS(r)) >= 2 * num_ranges) { /* compress */ if (r == (ArrayType *) DatumGetPointer(entry->key)) r = DatumGetArrayTypePCopy(entry->key); @@ -208,7 +211,7 @@ g_int_compress(PG_FUNCTION_ARGS) * "lenr" is the number of ranges we must eventually remove by * merging, we must be careful to remove no more than this number. */ - lenr = len - MAXNUMRANGE; + lenr = len - num_ranges; /* * Initially assume we can merge consecutive ints into a range. but we @@ -241,7 +244,7 @@ g_int_compress(PG_FUNCTION_ARGS) */ len = 2 * (len - j); cand = 1; - while (len > MAXNUMRANGE * 2) + while (len > num_ranges * 2) { min = PG_INT64_MAX; for (i = 2; i < len; i += 2) @@ -278,6 +281,7 @@ g_int_decompress(PG_FUNCTION_ARGS) GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *retval; ArrayType *r; + int num_ranges = G_INT_GET_NUMRANGES(); int *dr, lenr; ArrayType *in; @@ -304,7 +308,7 @@ g_int_decompress(PG_FUNCTION_ARGS) lenin = ARRNELEMS(in); - if (lenin < 2 * MAXNUMRANGE) + if (lenin < 2 * num_ranges) { /* not compressed value */ if (in != (ArrayType *) DatumGetPointer(entry->key)) { @@ -604,3 +608,17 @@ g_int_picksplit(PG_FUNCTION_ARGS) PG_RETURN_POINTER(v); } + +Datum +g_int_options(PG_FUNCTION_ARGS) +{ + local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0); + + init_local_reloptions(relopts, sizeof(GISTIntArrayOptions)); + add_local_int_reloption(relopts, "numranges", + "number of ranges for compression", + G_INT_NUMRANGES_DEFAULT, 1, G_INT_NUMRANGES_MAX, + offsetof(GISTIntArrayOptions, num_ranges)); + + PG_RETURN_VOID(); +} diff --git a/contrib/intarray/_int_tool.c b/contrib/intarray/_int_tool.c index e5f4bd4064..91690aff51 100644 --- a/contrib/intarray/_int_tool.c +++ b/contrib/intarray/_int_tool.c @@ -319,14 +319,14 @@ _int_unique(ArrayType *r) } void -gensign(BITVEC sign, int *a, int len) +gensign(BITVECP sign, int *a, int len, int siglen) { int i; /* we assume that the sign vector is previously zeroed */ for (i = 0; i < len; i++) { - HASH(sign, *a); + HASH(sign, *a, siglen); a++; } } diff --git a/contrib/intarray/_intbig_gist.c b/contrib/intarray/_intbig_gist.c index be51dac1fa..67c44e99a9 100644 --- a/contrib/intarray/_intbig_gist.c +++ b/contrib/intarray/_intbig_gist.c @@ -5,6 +5,7 @@ #include "_int.h" #include "access/gist.h" +#include "access/reloptions.h" #include "access/stratnum.h" #include "port/pg_bitutils.h" @@ -19,6 +20,8 @@ PG_FUNCTION_INFO_V1(g_intbig_penalty); PG_FUNCTION_INFO_V1(g_intbig_picksplit); PG_FUNCTION_INFO_V1(g_intbig_union); PG_FUNCTION_INFO_V1(g_intbig_same); +PG_FUNCTION_INFO_V1(g_intbig_options); + PG_FUNCTION_INFO_V1(_intbig_in); PG_FUNCTION_INFO_V1(_intbig_out); @@ -40,12 +43,33 @@ _intbig_out(PG_FUNCTION_ARGS) PG_RETURN_DATUM(0); } +static GISTTYPE * +_intbig_alloc(bool allistrue, int siglen, BITVECP sign) +{ + int flag = allistrue ? ALLISTRUE : 0; + int size = CALCGTSIZE(flag, siglen); + GISTTYPE *res = (GISTTYPE *) palloc(size); + + SET_VARSIZE(res, size); + res->flag = flag; + + if (!allistrue) + { + if (sign) + memcpy(GETSIGN(res), sign, siglen); + else + memset(GETSIGN(res), 0, siglen); + } + + return res; +} + /********************************************************************* ** intbig functions *********************************************************************/ static bool -_intbig_overlap(GISTTYPE *a, ArrayType *b) +_intbig_overlap(GISTTYPE *a, ArrayType *b, int siglen) { int num = ARRNELEMS(b); int32 *ptr = ARRPTR(b); @@ -54,7 +78,7 @@ _intbig_overlap(GISTTYPE *a, ArrayType *b) while (num--) { - if (GETBIT(GETSIGN(a), HASHVAL(*ptr))) + if (GETBIT(GETSIGN(a), HASHVAL(*ptr, siglen))) return true; ptr++; } @@ -63,7 +87,7 @@ _intbig_overlap(GISTTYPE *a, ArrayType *b) } static bool -_intbig_contains(GISTTYPE *a, ArrayType *b) +_intbig_contains(GISTTYPE *a, ArrayType *b, int siglen) { int num = ARRNELEMS(b); int32 *ptr = ARRPTR(b); @@ -72,7 +96,7 @@ _intbig_contains(GISTTYPE *a, ArrayType *b) while (num--) { - if (!GETBIT(GETSIGN(a), HASHVAL(*ptr))) + if (!GETBIT(GETSIGN(a), HASHVAL(*ptr, siglen))) return false; ptr++; } @@ -86,6 +110,7 @@ g_intbig_same(PG_FUNCTION_ARGS) GISTTYPE *a = (GISTTYPE *) PG_GETARG_POINTER(0); GISTTYPE *b = (GISTTYPE *) PG_GETARG_POINTER(1); bool *result = (bool *) PG_GETARG_POINTER(2); + int siglen = GET_SIGLEN(); if (ISALLTRUE(a) && ISALLTRUE(b)) *result = true; @@ -100,7 +125,7 @@ g_intbig_same(PG_FUNCTION_ARGS) sb = GETSIGN(b); *result = true; - LOOPBYTE + LOOPBYTE(siglen) { if (sa[i] != sb[i]) { @@ -116,6 +141,7 @@ Datum g_intbig_compress(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + int siglen = GET_SIGLEN(); if (entry->leafkey) { @@ -123,7 +149,7 @@ g_intbig_compress(PG_FUNCTION_ARGS) ArrayType *in = DatumGetArrayTypeP(entry->key); int32 *ptr; int num; - GISTTYPE *res = (GISTTYPE *) palloc0(CALCGTSIZE(0)); + GISTTYPE *res = _intbig_alloc(false, siglen, NULL); CHECKARRVALID(in); if (ARRISEMPTY(in)) @@ -136,11 +162,10 @@ g_intbig_compress(PG_FUNCTION_ARGS) ptr = ARRPTR(in); num = ARRNELEMS(in); } - SET_VARSIZE(res, CALCGTSIZE(0)); while (num--) { - HASH(GETSIGN(res), *ptr); + HASH(GETSIGN(res), *ptr, siglen); ptr++; } @@ -161,16 +186,13 @@ g_intbig_compress(PG_FUNCTION_ARGS) BITVECP sign = GETSIGN(DatumGetPointer(entry->key)); GISTTYPE *res; - LOOPBYTE + LOOPBYTE(siglen) { if ((sign[i] & 0xff) != 0xff) PG_RETURN_POINTER(entry); } - res = (GISTTYPE *) palloc(CALCGTSIZE(ALLISTRUE)); - SET_VARSIZE(res, CALCGTSIZE(ALLISTRUE)); - res->flag = ALLISTRUE; - + res = _intbig_alloc(true, siglen, sign); retval = (GISTENTRY *) palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(res), entry->rel, entry->page, @@ -184,19 +206,19 @@ g_intbig_compress(PG_FUNCTION_ARGS) static int32 -sizebitvec(BITVECP sign) +sizebitvec(BITVECP sign, int siglen) { - return pg_popcount(sign, SIGLEN); + return pg_popcount(sign, siglen); } static int -hemdistsign(BITVECP a, BITVECP b) +hemdistsign(BITVECP a, BITVECP b, int siglen) { int i, diff, dist = 0; - LOOPBYTE + LOOPBYTE(siglen) { diff = (unsigned char) (a[i] ^ b[i]); /* Using the popcount functions here isn't likely to win */ @@ -206,19 +228,19 @@ hemdistsign(BITVECP a, BITVECP b) } static int -hemdist(GISTTYPE *a, GISTTYPE *b) +hemdist(GISTTYPE *a, GISTTYPE *b, int siglen) { if (ISALLTRUE(a)) { if (ISALLTRUE(b)) return 0; else - return SIGLENBIT - sizebitvec(GETSIGN(b)); + return SIGLENBIT(siglen) - sizebitvec(GETSIGN(b), siglen); } else if (ISALLTRUE(b)) - return SIGLENBIT - sizebitvec(GETSIGN(a)); + return SIGLENBIT(siglen) - sizebitvec(GETSIGN(a), siglen); - return hemdistsign(GETSIGN(a), GETSIGN(b)); + return hemdistsign(GETSIGN(a), GETSIGN(b), siglen); } Datum @@ -228,14 +250,14 @@ g_intbig_decompress(PG_FUNCTION_ARGS) } static int32 -unionkey(BITVECP sbase, GISTTYPE *add) +unionkey(BITVECP sbase, GISTTYPE *add, int siglen) { int32 i; BITVECP sadd = GETSIGN(add); if (ISALLTRUE(add)) return 1; - LOOPBYTE + LOOPBYTE(siglen) sbase[i] |= sadd[i]; return 0; } @@ -245,29 +267,22 @@ g_intbig_union(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); int *size = (int *) PG_GETARG_POINTER(1); - BITVEC base; - int32 i, - len; - int32 flag = 0; - GISTTYPE *result; + int siglen = GET_SIGLEN(); + int32 i; + GISTTYPE *result = _intbig_alloc(false, siglen, NULL); + BITVECP base = GETSIGN(result); - MemSet((void *) base, 0, sizeof(BITVEC)); for (i = 0; i < entryvec->n; i++) { - if (unionkey(base, GETENTRY(entryvec, i))) + if (unionkey(base, GETENTRY(entryvec, i), siglen)) { - flag = ALLISTRUE; + result->flag |= ALLISTRUE; + SET_VARSIZE(result, CALCGTSIZE(ALLISTRUE, siglen)); break; } } - len = CALCGTSIZE(flag); - result = (GISTTYPE *) palloc(len); - SET_VARSIZE(result, len); - result->flag = flag; - if (!ISALLTRUE(result)) - memcpy((void *) GETSIGN(result), (void *) base, sizeof(BITVEC)); - *size = len; + *size = VARSIZE(result); PG_RETURN_POINTER(result); } @@ -280,8 +295,9 @@ g_intbig_penalty(PG_FUNCTION_ARGS) float *penalty = (float *) PG_GETARG_POINTER(2); GISTTYPE *origval = (GISTTYPE *) DatumGetPointer(origentry->key); GISTTYPE *newval = (GISTTYPE *) DatumGetPointer(newentry->key); + int siglen = GET_SIGLEN(); - *penalty = hemdist(origval, newval); + *penalty = hemdist(origval, newval, siglen); PG_RETURN_POINTER(penalty); } @@ -304,6 +320,7 @@ g_intbig_picksplit(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); + int siglen = GET_SIGLEN(); OffsetNumber k, j; GISTTYPE *datum_l, @@ -336,7 +353,7 @@ g_intbig_picksplit(PG_FUNCTION_ARGS) _k = GETENTRY(entryvec, k); for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) { - size_waste = hemdist(_k, GETENTRY(entryvec, j)); + size_waste = hemdist(_k, GETENTRY(entryvec, j), siglen); if (size_waste > waste) { waste = size_waste; @@ -358,32 +375,10 @@ g_intbig_picksplit(PG_FUNCTION_ARGS) } /* form initial .. */ - if (ISALLTRUE(GETENTRY(entryvec, seed_1))) - { - datum_l = (GISTTYPE *) palloc(GTHDRSIZE); - SET_VARSIZE(datum_l, GTHDRSIZE); - datum_l->flag = ALLISTRUE; - } - else - { - datum_l = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN); - SET_VARSIZE(datum_l, GTHDRSIZE + SIGLEN); - datum_l->flag = 0; - memcpy((void *) GETSIGN(datum_l), (void *) GETSIGN(GETENTRY(entryvec, seed_1)), sizeof(BITVEC)); - } - if (ISALLTRUE(GETENTRY(entryvec, seed_2))) - { - datum_r = (GISTTYPE *) palloc(GTHDRSIZE); - SET_VARSIZE(datum_r, GTHDRSIZE); - datum_r->flag = ALLISTRUE; - } - else - { - datum_r = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN); - SET_VARSIZE(datum_r, GTHDRSIZE + SIGLEN); - datum_r->flag = 0; - memcpy((void *) GETSIGN(datum_r), (void *) GETSIGN(GETENTRY(entryvec, seed_2)), sizeof(BITVEC)); - } + datum_l = _intbig_alloc(ISALLTRUE(GETENTRY(entryvec, seed_1)), siglen, + GETSIGN(GETENTRY(entryvec, seed_1))); + datum_r = _intbig_alloc(ISALLTRUE(GETENTRY(entryvec, seed_2)), siglen, + GETSIGN(GETENTRY(entryvec, seed_2))); maxoff = OffsetNumberNext(maxoff); /* sort before ... */ @@ -392,8 +387,8 @@ g_intbig_picksplit(PG_FUNCTION_ARGS) { costvector[j - 1].pos = j; _j = GETENTRY(entryvec, j); - size_alpha = hemdist(datum_l, _j); - size_beta = hemdist(datum_r, _j); + size_alpha = hemdist(datum_l, _j, siglen); + size_beta = hemdist(datum_r, _j, siglen); costvector[j - 1].cost = Abs(size_alpha - size_beta); } qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost); @@ -417,20 +412,20 @@ g_intbig_picksplit(PG_FUNCTION_ARGS) continue; } _j = GETENTRY(entryvec, j); - size_alpha = hemdist(datum_l, _j); - size_beta = hemdist(datum_r, _j); + size_alpha = hemdist(datum_l, _j, siglen); + size_beta = hemdist(datum_r, _j, siglen); if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.00001)) { if (ISALLTRUE(datum_l) || ISALLTRUE(_j)) { if (!ISALLTRUE(datum_l)) - MemSet((void *) union_l, 0xff, sizeof(BITVEC)); + MemSet((void *) union_l, 0xff, siglen); } else { ptr = GETSIGN(_j); - LOOPBYTE + LOOPBYTE(siglen) union_l[i] |= ptr[i]; } *left++ = j; @@ -441,12 +436,12 @@ g_intbig_picksplit(PG_FUNCTION_ARGS) if (ISALLTRUE(datum_r) || ISALLTRUE(_j)) { if (!ISALLTRUE(datum_r)) - MemSet((void *) union_r, 0xff, sizeof(BITVEC)); + MemSet((void *) union_r, 0xff, siglen); } else { ptr = GETSIGN(_j); - LOOPBYTE + LOOPBYTE(siglen) union_r[i] |= ptr[i]; } *right++ = j; @@ -472,6 +467,7 @@ g_intbig_consistent(PG_FUNCTION_ARGS) /* Oid subtype = PG_GETARG_OID(3); */ bool *recheck = (bool *) PG_GETARG_POINTER(4); + int siglen = GET_SIGLEN(); bool retval; /* All cases served by this function are inexact */ @@ -484,6 +480,7 @@ g_intbig_consistent(PG_FUNCTION_ARGS) { retval = signconsistent((QUERYTYPE *) query, GETSIGN(DatumGetPointer(entry->key)), + siglen, false); PG_FREE_IF_COPY(query, 1); PG_RETURN_BOOL(retval); @@ -494,7 +491,8 @@ g_intbig_consistent(PG_FUNCTION_ARGS) switch (strategy) { case RTOverlapStrategyNumber: - retval = _intbig_overlap((GISTTYPE *) DatumGetPointer(entry->key), query); + retval = _intbig_overlap((GISTTYPE *) DatumGetPointer(entry->key), + query, siglen); break; case RTSameStrategyNumber: if (GIST_LEAF(entry)) @@ -502,22 +500,18 @@ g_intbig_consistent(PG_FUNCTION_ARGS) int i, num = ARRNELEMS(query); int32 *ptr = ARRPTR(query); - BITVEC qp; - BITVECP dq, + BITVECP dq = palloc0(siglen), de; - memset(qp, 0, sizeof(BITVEC)); - while (num--) { - HASH(qp, *ptr); + HASH(dq, *ptr, siglen); ptr++; } de = GETSIGN((GISTTYPE *) DatumGetPointer(entry->key)); - dq = qp; retval = true; - LOOPBYTE + LOOPBYTE(siglen) { if (de[i] != dq[i]) { @@ -526,13 +520,16 @@ g_intbig_consistent(PG_FUNCTION_ARGS) } } + pfree(dq); } else - retval = _intbig_contains((GISTTYPE *) DatumGetPointer(entry->key), query); + retval = _intbig_contains((GISTTYPE *) DatumGetPointer(entry->key), + query, siglen); break; case RTContainsStrategyNumber: case RTOldContainsStrategyNumber: - retval = _intbig_contains((GISTTYPE *) DatumGetPointer(entry->key), query); + retval = _intbig_contains((GISTTYPE *) DatumGetPointer(entry->key), + query, siglen); break; case RTContainedByStrategyNumber: case RTOldContainedByStrategyNumber: @@ -541,22 +538,18 @@ g_intbig_consistent(PG_FUNCTION_ARGS) int i, num = ARRNELEMS(query); int32 *ptr = ARRPTR(query); - BITVEC qp; - BITVECP dq, + BITVECP dq = palloc0(siglen), de; - memset(qp, 0, sizeof(BITVEC)); - while (num--) { - HASH(qp, *ptr); + HASH(dq, *ptr, siglen); ptr++; } de = GETSIGN((GISTTYPE *) DatumGetPointer(entry->key)); - dq = qp; retval = true; - LOOPBYTE + LOOPBYTE(siglen) { if (de[i] & ~dq[i]) { @@ -580,3 +573,17 @@ g_intbig_consistent(PG_FUNCTION_ARGS) PG_FREE_IF_COPY(query, 1); PG_RETURN_BOOL(retval); } + +Datum +g_intbig_options(PG_FUNCTION_ARGS) +{ + local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0); + + init_local_reloptions(relopts, sizeof(GISTIntArrayBigOptions)); + add_local_int_reloption(relopts, "siglen", + "signature length in bytes", + SIGLEN_DEFAULT, 1, SIGLEN_MAX, + offsetof(GISTIntArrayBigOptions, siglen)); + + PG_RETURN_VOID(); +} diff --git a/contrib/intarray/expected/_int.out b/contrib/intarray/expected/_int.out index c92a56524a..a09d40efa1 100644 --- a/contrib/intarray/expected/_int.out +++ b/contrib/intarray/expected/_int.out @@ -548,6 +548,166 @@ SELECT count(*) from test__int WHERE a @@ '!20 & !21'; (1 row) DROP INDEX text_idx; +CREATE INDEX text_idx on test__int using gist (a gist__int_ops(numranges = 0)); +ERROR: value 0 out of bounds for option "numranges" +DETAIL: Valid values are between "1" and "252". +CREATE INDEX text_idx on test__int using gist (a gist__int_ops(numranges = 253)); +ERROR: value 253 out of bounds for option "numranges" +DETAIL: Valid values are between "1" and "252". +CREATE INDEX text_idx on test__int using gist (a gist__int_ops(numranges = 252)); +SELECT count(*) from test__int WHERE a && '{23,50}'; + count +------- + 403 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '23|50'; + count +------- + 403 +(1 row) + +SELECT count(*) from test__int WHERE a @> '{23,50}'; + count +------- + 12 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '23&50'; + count +------- + 12 +(1 row) + +SELECT count(*) from test__int WHERE a @> '{20,23}'; + count +------- + 12 +(1 row) + +SELECT count(*) from test__int WHERE a <@ '{73,23,20}'; + count +------- + 10 +(1 row) + +SELECT count(*) from test__int WHERE a = '{73,23,20}'; + count +------- + 1 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '50&68'; + count +------- + 9 +(1 row) + +SELECT count(*) from test__int WHERE a @> '{20,23}' or a @> '{50,68}'; + count +------- + 21 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)'; + count +------- + 21 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '20 | !21'; + count +------- + 6566 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '!20 & !21'; + count +------- + 6343 +(1 row) + +DROP INDEX text_idx; +CREATE INDEX text_idx on test__int using gist (a gist__intbig_ops(siglen = 0)); +ERROR: value 0 out of bounds for option "siglen" +DETAIL: Valid values are between "1" and "2024". +CREATE INDEX text_idx on test__int using gist (a gist__intbig_ops(siglen = 2025)); +ERROR: value 2025 out of bounds for option "siglen" +DETAIL: Valid values are between "1" and "2024". +CREATE INDEX text_idx on test__int using gist (a gist__intbig_ops(siglen = 2024)); +SELECT count(*) from test__int WHERE a && '{23,50}'; + count +------- + 403 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '23|50'; + count +------- + 403 +(1 row) + +SELECT count(*) from test__int WHERE a @> '{23,50}'; + count +------- + 12 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '23&50'; + count +------- + 12 +(1 row) + +SELECT count(*) from test__int WHERE a @> '{20,23}'; + count +------- + 12 +(1 row) + +SELECT count(*) from test__int WHERE a <@ '{73,23,20}'; + count +------- + 10 +(1 row) + +SELECT count(*) from test__int WHERE a = '{73,23,20}'; + count +------- + 1 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '50&68'; + count +------- + 9 +(1 row) + +SELECT count(*) from test__int WHERE a @> '{20,23}' or a @> '{50,68}'; + count +------- + 21 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)'; + count +------- + 21 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '20 | !21'; + count +------- + 6566 +(1 row) + +SELECT count(*) from test__int WHERE a @@ '!20 & !21'; + count +------- + 6343 +(1 row) + +DROP INDEX text_idx; CREATE INDEX text_idx on test__int using gist ( a gist__intbig_ops ); SELECT count(*) from test__int WHERE a && '{23,50}'; count diff --git a/contrib/intarray/intarray--1.2--1.3.sql b/contrib/intarray/intarray--1.2--1.3.sql new file mode 100644 index 0000000000..790d159177 --- /dev/null +++ b/contrib/intarray/intarray--1.2--1.3.sql @@ -0,0 +1,20 @@ +/* contrib/intarray/intarray--1.2--1.3.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION intarray UPDATE TO '1.3'" to load this file. \quit + +CREATE FUNCTION g_int_options(internal) +RETURNS void +AS 'MODULE_PATHNAME', 'g_int_options' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION g_intbig_options(internal) +RETURNS void +AS 'MODULE_PATHNAME', 'g_intbig_options' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +ALTER OPERATOR FAMILY gist__int_ops USING gist +ADD FUNCTION 10 (_int4) g_int_options (internal); + +ALTER OPERATOR FAMILY gist__intbig_ops USING gist +ADD FUNCTION 10 (_int4) g_intbig_options (internal); diff --git a/contrib/intarray/intarray.control b/contrib/intarray/intarray.control index bf28804dec..db7746b6c7 100644 --- a/contrib/intarray/intarray.control +++ b/contrib/intarray/intarray.control @@ -1,6 +1,6 @@ # intarray extension comment = 'functions, operators, and index support for 1-D arrays of integers' -default_version = '1.2' +default_version = '1.3' module_pathname = '$libdir/_int' relocatable = true trusted = true diff --git a/contrib/intarray/sql/_int.sql b/contrib/intarray/sql/_int.sql index 6ca7e3cca7..b26fc57e4d 100644 --- a/contrib/intarray/sql/_int.sql +++ b/contrib/intarray/sql/_int.sql @@ -111,6 +111,42 @@ SELECT count(*) from test__int WHERE a @@ '20 | !21'; SELECT count(*) from test__int WHERE a @@ '!20 & !21'; DROP INDEX text_idx; +CREATE INDEX text_idx on test__int using gist (a gist__int_ops(numranges = 0)); +CREATE INDEX text_idx on test__int using gist (a gist__int_ops(numranges = 253)); +CREATE INDEX text_idx on test__int using gist (a gist__int_ops(numranges = 252)); + +SELECT count(*) from test__int WHERE a && '{23,50}'; +SELECT count(*) from test__int WHERE a @@ '23|50'; +SELECT count(*) from test__int WHERE a @> '{23,50}'; +SELECT count(*) from test__int WHERE a @@ '23&50'; +SELECT count(*) from test__int WHERE a @> '{20,23}'; +SELECT count(*) from test__int WHERE a <@ '{73,23,20}'; +SELECT count(*) from test__int WHERE a = '{73,23,20}'; +SELECT count(*) from test__int WHERE a @@ '50&68'; +SELECT count(*) from test__int WHERE a @> '{20,23}' or a @> '{50,68}'; +SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)'; +SELECT count(*) from test__int WHERE a @@ '20 | !21'; +SELECT count(*) from test__int WHERE a @@ '!20 & !21'; + +DROP INDEX text_idx; +CREATE INDEX text_idx on test__int using gist (a gist__intbig_ops(siglen = 0)); +CREATE INDEX text_idx on test__int using gist (a gist__intbig_ops(siglen = 2025)); +CREATE INDEX text_idx on test__int using gist (a gist__intbig_ops(siglen = 2024)); + +SELECT count(*) from test__int WHERE a && '{23,50}'; +SELECT count(*) from test__int WHERE a @@ '23|50'; +SELECT count(*) from test__int WHERE a @> '{23,50}'; +SELECT count(*) from test__int WHERE a @@ '23&50'; +SELECT count(*) from test__int WHERE a @> '{20,23}'; +SELECT count(*) from test__int WHERE a <@ '{73,23,20}'; +SELECT count(*) from test__int WHERE a = '{73,23,20}'; +SELECT count(*) from test__int WHERE a @@ '50&68'; +SELECT count(*) from test__int WHERE a @> '{20,23}' or a @> '{50,68}'; +SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)'; +SELECT count(*) from test__int WHERE a @@ '20 | !21'; +SELECT count(*) from test__int WHERE a @@ '!20 & !21'; + +DROP INDEX text_idx; CREATE INDEX text_idx on test__int using gist ( a gist__intbig_ops ); SELECT count(*) from test__int WHERE a && '{23,50}'; diff --git a/contrib/ltree/Makefile b/contrib/ltree/Makefile index 70c5e371c8..b16a566852 100644 --- a/contrib/ltree/Makefile +++ b/contrib/ltree/Makefile @@ -15,7 +15,7 @@ OBJS = \ PG_CPPFLAGS = -DLOWER_NODE EXTENSION = ltree -DATA = ltree--1.1.sql ltree--1.0--1.1.sql +DATA = ltree--1.1--1.2.sql ltree--1.1.sql ltree--1.0--1.1.sql PGFILEDESC = "ltree - hierarchical label data type" HEADERS = ltree.h diff --git a/contrib/ltree/_ltree_gist.c b/contrib/ltree/_ltree_gist.c index 50f54f2eec..95cc367dd8 100644 --- a/contrib/ltree/_ltree_gist.c +++ b/contrib/ltree/_ltree_gist.c @@ -8,6 +8,7 @@ #include "postgres.h" #include "access/gist.h" +#include "access/reloptions.h" #include "access/stratnum.h" #include "crc32.h" #include "ltree.h" @@ -19,6 +20,7 @@ PG_FUNCTION_INFO_V1(_ltree_union); PG_FUNCTION_INFO_V1(_ltree_penalty); PG_FUNCTION_INFO_V1(_ltree_picksplit); PG_FUNCTION_INFO_V1(_ltree_consistent); +PG_FUNCTION_INFO_V1(_ltree_gist_options); #define GETENTRY(vec,pos) ((ltree_gist *) DatumGetPointer((vec)->vector[(pos)].key)) #define NEXTVAL(x) ( (ltree*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) ) @@ -27,7 +29,7 @@ PG_FUNCTION_INFO_V1(_ltree_consistent); static void -hashing(BITVECP sign, ltree *t) +hashing(BITVECP sign, ltree *t, int siglen) { int tlen = t->numlevel; ltree_level *cur = LTREE_FIRST(t); @@ -36,7 +38,7 @@ hashing(BITVECP sign, ltree *t) while (tlen > 0) { hash = ltree_crc32_sz(cur->name, cur->len); - AHASH(sign, hash); + AHASH(sign, hash, siglen); cur = LEVEL_NEXT(cur); tlen--; } @@ -47,12 +49,12 @@ _ltree_compress(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *retval = entry; + int siglen = LTREE_GET_ASIGLEN(); if (entry->leafkey) { /* ltree */ ltree_gist *key; ArrayType *val = DatumGetArrayTypeP(entry->key); - int32 len = LTG_HDRSIZE + ASIGLEN; int num = ArrayGetNItems(ARR_NDIM(val), ARR_DIMS(val)); ltree *item = (ltree *) ARR_DATA_PTR(val); @@ -65,14 +67,11 @@ _ltree_compress(PG_FUNCTION_ARGS) (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("array must not contain nulls"))); - key = (ltree_gist *) palloc0(len); - SET_VARSIZE(key, len); - key->flag = 0; + key = ltree_gist_alloc(false, NULL, siglen, NULL, NULL); - MemSet(LTG_SIGN(key), 0, ASIGLEN); while (num > 0) { - hashing(LTG_SIGN(key), item); + hashing(LTG_SIGN(key), item, siglen); num--; item = NEXTVAL(item); } @@ -84,22 +83,17 @@ _ltree_compress(PG_FUNCTION_ARGS) } else if (!LTG_ISALLTRUE(entry->key)) { - int32 i, - len; + int32 i; ltree_gist *key; - BITVECP sign = LTG_SIGN(DatumGetPointer(entry->key)); - ALOOPBYTE + ALOOPBYTE(siglen) { if ((sign[i] & 0xff) != 0xff) PG_RETURN_POINTER(retval); } - len = LTG_HDRSIZE; - key = (ltree_gist *) palloc0(len); - SET_VARSIZE(key, len); - key->flag = LTG_ALLTRUE; + key = ltree_gist_alloc(true, sign, siglen, NULL, NULL); retval = (GISTENTRY *) palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(key), entry->rel, entry->page, @@ -114,6 +108,7 @@ _ltree_same(PG_FUNCTION_ARGS) ltree_gist *a = (ltree_gist *) PG_GETARG_POINTER(0); ltree_gist *b = (ltree_gist *) PG_GETARG_POINTER(1); bool *result = (bool *) PG_GETARG_POINTER(2); + int siglen = LTREE_GET_ASIGLEN(); if (LTG_ISALLTRUE(a) && LTG_ISALLTRUE(b)) *result = true; @@ -128,7 +123,7 @@ _ltree_same(PG_FUNCTION_ARGS) sb = LTG_SIGN(b); *result = true; - ALOOPBYTE + ALOOPBYTE(siglen) { if (sa[i] != sb[i]) { @@ -141,7 +136,7 @@ _ltree_same(PG_FUNCTION_ARGS) } static int32 -unionkey(BITVECP sbase, ltree_gist *add) +unionkey(BITVECP sbase, ltree_gist *add, int siglen) { int32 i; BITVECP sadd = LTG_SIGN(add); @@ -149,7 +144,7 @@ unionkey(BITVECP sbase, ltree_gist *add) if (LTG_ISALLTRUE(add)) return 1; - ALOOPBYTE + ALOOPBYTE(siglen) sbase[i] |= sadd[i]; return 0; } @@ -159,47 +154,40 @@ _ltree_union(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); int *size = (int *) PG_GETARG_POINTER(1); - ABITVEC base; - int32 i, - len; - int32 flag = 0; - ltree_gist *result; + int siglen = LTREE_GET_ASIGLEN(); + int32 i; + ltree_gist *result = ltree_gist_alloc(false, NULL, siglen, NULL, NULL); + BITVECP base = LTG_SIGN(result); - MemSet((void *) base, 0, sizeof(ABITVEC)); for (i = 0; i < entryvec->n; i++) { - if (unionkey(base, GETENTRY(entryvec, i))) + if (unionkey(base, GETENTRY(entryvec, i), siglen)) { - flag = LTG_ALLTRUE; + result->flag |= LTG_ALLTRUE; + SET_VARSIZE(result, LTG_HDRSIZE); break; } } - len = LTG_HDRSIZE + ((flag & LTG_ALLTRUE) ? 0 : ASIGLEN); - result = (ltree_gist *) palloc0(len); - SET_VARSIZE(result, len); - result->flag = flag; - if (!LTG_ISALLTRUE(result)) - memcpy((void *) LTG_SIGN(result), (void *) base, sizeof(ABITVEC)); - *size = len; + *size = VARSIZE(result); PG_RETURN_POINTER(result); } static int32 -sizebitvec(BITVECP sign) +sizebitvec(BITVECP sign, int siglen) { - return pg_popcount((const char *) sign, ASIGLEN); + return pg_popcount((const char *) sign, siglen); } static int -hemdistsign(BITVECP a, BITVECP b) +hemdistsign(BITVECP a, BITVECP b, int siglen) { int i, diff, dist = 0; - ALOOPBYTE + ALOOPBYTE(siglen) { diff = (unsigned char) (a[i] ^ b[i]); /* Using the popcount functions here isn't likely to win */ @@ -209,19 +197,19 @@ hemdistsign(BITVECP a, BITVECP b) } static int -hemdist(ltree_gist *a, ltree_gist *b) +hemdist(ltree_gist *a, ltree_gist *b, int siglen) { if (LTG_ISALLTRUE(a)) { if (LTG_ISALLTRUE(b)) return 0; else - return ASIGLENBIT - sizebitvec(LTG_SIGN(b)); + return ASIGLENBIT(siglen) - sizebitvec(LTG_SIGN(b), siglen); } else if (LTG_ISALLTRUE(b)) - return ASIGLENBIT - sizebitvec(LTG_SIGN(a)); + return ASIGLENBIT(siglen) - sizebitvec(LTG_SIGN(a), siglen); - return hemdistsign(LTG_SIGN(a), LTG_SIGN(b)); + return hemdistsign(LTG_SIGN(a), LTG_SIGN(b), siglen); } @@ -231,8 +219,9 @@ _ltree_penalty(PG_FUNCTION_ARGS) ltree_gist *origval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key); ltree_gist *newval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key); float *penalty = (float *) PG_GETARG_POINTER(2); + int siglen = LTREE_GET_ASIGLEN(); - *penalty = hemdist(origval, newval); + *penalty = hemdist(origval, newval, siglen); PG_RETURN_POINTER(penalty); } @@ -253,6 +242,7 @@ _ltree_picksplit(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); + int siglen = LTREE_GET_ASIGLEN(); OffsetNumber k, j; ltree_gist *datum_l, @@ -285,7 +275,7 @@ _ltree_picksplit(PG_FUNCTION_ARGS) _k = GETENTRY(entryvec, k); for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) { - size_waste = hemdist(_k, GETENTRY(entryvec, j)); + size_waste = hemdist(_k, GETENTRY(entryvec, j), siglen); if (size_waste > waste) { waste = size_waste; @@ -307,32 +297,13 @@ _ltree_picksplit(PG_FUNCTION_ARGS) } /* form initial .. */ - if (LTG_ISALLTRUE(GETENTRY(entryvec, seed_1))) - { - datum_l = (ltree_gist *) palloc0(LTG_HDRSIZE); - SET_VARSIZE(datum_l, LTG_HDRSIZE); - datum_l->flag = LTG_ALLTRUE; - } - else - { - datum_l = (ltree_gist *) palloc0(LTG_HDRSIZE + ASIGLEN); - SET_VARSIZE(datum_l, LTG_HDRSIZE + ASIGLEN); - datum_l->flag = 0; - memcpy((void *) LTG_SIGN(datum_l), (void *) LTG_SIGN(GETENTRY(entryvec, seed_1)), sizeof(ABITVEC)); - } - if (LTG_ISALLTRUE(GETENTRY(entryvec, seed_2))) - { - datum_r = (ltree_gist *) palloc0(LTG_HDRSIZE); - SET_VARSIZE(datum_r, LTG_HDRSIZE); - datum_r->flag = LTG_ALLTRUE; - } - else - { - datum_r = (ltree_gist *) palloc0(LTG_HDRSIZE + ASIGLEN); - SET_VARSIZE(datum_r, LTG_HDRSIZE + ASIGLEN); - datum_r->flag = 0; - memcpy((void *) LTG_SIGN(datum_r), (void *) LTG_SIGN(GETENTRY(entryvec, seed_2)), sizeof(ABITVEC)); - } + datum_l = ltree_gist_alloc(LTG_ISALLTRUE(GETENTRY(entryvec, seed_1)), + LTG_SIGN(GETENTRY(entryvec, seed_1)), + siglen, NULL, NULL); + + datum_r = ltree_gist_alloc(LTG_ISALLTRUE(GETENTRY(entryvec, seed_2)), + LTG_SIGN(GETENTRY(entryvec, seed_2)), + siglen, NULL, NULL); maxoff = OffsetNumberNext(maxoff); /* sort before ... */ @@ -341,8 +312,8 @@ _ltree_picksplit(PG_FUNCTION_ARGS) { costvector[j - 1].pos = j; _j = GETENTRY(entryvec, j); - size_alpha = hemdist(datum_l, _j); - size_beta = hemdist(datum_r, _j); + size_alpha = hemdist(datum_l, _j, siglen); + size_beta = hemdist(datum_r, _j, siglen); costvector[j - 1].cost = Abs(size_alpha - size_beta); } qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost); @@ -366,20 +337,20 @@ _ltree_picksplit(PG_FUNCTION_ARGS) continue; } _j = GETENTRY(entryvec, j); - size_alpha = hemdist(datum_l, _j); - size_beta = hemdist(datum_r, _j); + size_alpha = hemdist(datum_l, _j, siglen); + size_beta = hemdist(datum_r, _j, siglen); if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.00001)) { if (LTG_ISALLTRUE(datum_l) || LTG_ISALLTRUE(_j)) { if (!LTG_ISALLTRUE(datum_l)) - MemSet((void *) union_l, 0xff, sizeof(ABITVEC)); + MemSet((void *) union_l, 0xff, siglen); } else { ptr = LTG_SIGN(_j); - ALOOPBYTE + ALOOPBYTE(siglen) union_l[i] |= ptr[i]; } *left++ = j; @@ -390,12 +361,12 @@ _ltree_picksplit(PG_FUNCTION_ARGS) if (LTG_ISALLTRUE(datum_r) || LTG_ISALLTRUE(_j)) { if (!LTG_ISALLTRUE(datum_r)) - MemSet((void *) union_r, 0xff, sizeof(ABITVEC)); + MemSet((void *) union_r, 0xff, siglen); } else { ptr = LTG_SIGN(_j); - ALOOPBYTE + ALOOPBYTE(siglen) union_r[i] |= ptr[i]; } *right++ = j; @@ -412,7 +383,7 @@ _ltree_picksplit(PG_FUNCTION_ARGS) } static bool -gist_te(ltree_gist *key, ltree *query) +gist_te(ltree_gist *key, ltree *query, int siglen) { ltree_level *curq = LTREE_FIRST(query); BITVECP sign = LTG_SIGN(key); @@ -425,7 +396,7 @@ gist_te(ltree_gist *key, ltree *query) while (qlen > 0) { hv = ltree_crc32_sz(curq->name, curq->len); - if (!GETBIT(sign, AHASHVAL(hv))) + if (!GETBIT(sign, AHASHVAL(hv, siglen))) return false; curq = LEVEL_NEXT(curq); qlen--; @@ -434,25 +405,38 @@ gist_te(ltree_gist *key, ltree *query) return true; } +typedef struct LtreeSignature +{ + BITVECP sign; + int siglen; +} LtreeSignature; + static bool -checkcondition_bit(void *checkval, ITEM *val) +checkcondition_bit(void *cxt, ITEM *val) { - return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(checkval, AHASHVAL(val->val)) : true; + LtreeSignature *sig = cxt; + + return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(sig->sign, AHASHVAL(val->val, sig->siglen)) : true; } static bool -gist_qtxt(ltree_gist *key, ltxtquery *query) +gist_qtxt(ltree_gist *key, ltxtquery *query, int siglen) { + LtreeSignature sig; + if (LTG_ISALLTRUE(key)) return true; + sig.sign = LTG_SIGN(key); + sig.siglen = siglen; + return ltree_execute(GETQUERY(query), - (void *) LTG_SIGN(key), false, + &sig, false, checkcondition_bit); } static bool -gist_qe(ltree_gist *key, lquery *query) +gist_qe(ltree_gist *key, lquery *query, int siglen) { lquery_level *curq = LQUERY_FIRST(query); BITVECP sign = LTG_SIGN(key); @@ -471,7 +455,7 @@ gist_qe(ltree_gist *key, lquery *query) while (vlen > 0) { - if (GETBIT(sign, AHASHVAL(curv->val))) + if (GETBIT(sign, AHASHVAL(curv->val, siglen))) { isexist = true; break; @@ -491,7 +475,7 @@ gist_qe(ltree_gist *key, lquery *query) } static bool -_arrq_cons(ltree_gist *key, ArrayType *_query) +_arrq_cons(ltree_gist *key, ArrayType *_query, int siglen) { lquery *query = (lquery *) ARR_DATA_PTR(_query); int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query)); @@ -507,7 +491,7 @@ _arrq_cons(ltree_gist *key, ArrayType *_query) while (num > 0) { - if (gist_qe(key, query)) + if (gist_qe(key, query, siglen)) return true; num--; query = (lquery *) NEXTVAL(query); @@ -524,6 +508,7 @@ _ltree_consistent(PG_FUNCTION_ARGS) /* Oid subtype = PG_GETARG_OID(3); */ bool *recheck = (bool *) PG_GETARG_POINTER(4); + int siglen = LTREE_GET_ASIGLEN(); ltree_gist *key = (ltree_gist *) DatumGetPointer(entry->key); bool res = false; @@ -534,19 +519,19 @@ _ltree_consistent(PG_FUNCTION_ARGS) { case 10: case 11: - res = gist_te(key, (ltree *) query); + res = gist_te(key, (ltree *) query, siglen); break; case 12: case 13: - res = gist_qe(key, (lquery *) query); + res = gist_qe(key, (lquery *) query, siglen); break; case 14: case 15: - res = gist_qtxt(key, (ltxtquery *) query); + res = gist_qtxt(key, (ltxtquery *) query, siglen); break; case 16: case 17: - res = _arrq_cons(key, (ArrayType *) query); + res = _arrq_cons(key, (ArrayType *) query, siglen); break; default: /* internal error */ @@ -555,3 +540,16 @@ _ltree_consistent(PG_FUNCTION_ARGS) PG_FREE_IF_COPY(query, 1); PG_RETURN_BOOL(res); } + +Datum +_ltree_gist_options(PG_FUNCTION_ARGS) +{ + local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0); + + init_local_reloptions(relopts, sizeof(LtreeGistOptions)); + add_local_int_reloption(relopts, "siglen", "signature length", + LTREE_ASIGLEN_DEFAULT, 1, LTREE_ASIGLEN_MAX, + offsetof(LtreeGistOptions, siglen)); + + PG_RETURN_VOID(); +} diff --git a/contrib/ltree/expected/ltree.out b/contrib/ltree/expected/ltree.out index 1b31dbcec2..c78d372b63 100644 --- a/contrib/ltree/expected/ltree.out +++ b/contrib/ltree/expected/ltree.out @@ -7637,6 +7637,98 @@ SELECT * FROM ltreetest WHERE t ? '{23.*.1,23.*.2}' order by t asc; 23.3.32.21.5.14.10.17.1 (4 rows) +drop index tstidx; +create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=0)); +ERROR: value 0 out of bounds for option "siglen" +DETAIL: Valid values are between "1" and "2024". +create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=2025)); +ERROR: value 2025 out of bounds for option "siglen" +DETAIL: Valid values are between "1" and "2024". +create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=2024)); +SELECT count(*) FROM ltreetest WHERE t < '12.3'; + count +------- + 123 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t <= '12.3'; + count +------- + 124 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t = '12.3'; + count +------- + 1 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t >= '12.3'; + count +------- + 883 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t > '12.3'; + count +------- + 882 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t @> '1.1.1'; + count +------- + 4 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t <@ '1.1.1'; + count +------- + 4 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t @ '23 & 1'; + count +------- + 39 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t ~ '1.1.1.*'; + count +------- + 4 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t ~ '*.1'; + count +------- + 34 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t ~ '23.*{1}.1'; + count +------- + 1 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t ~ '23.*.1'; + count +------- + 3 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t ~ '23.*.2'; + count +------- + 1 +(1 row) + +SELECT count(*) FROM ltreetest WHERE t ? '{23.*.1,23.*.2}'; + count +------- + 4 +(1 row) + create table _ltreetest (t ltree[]); \copy _ltreetest FROM 'data/_ltree.data' SELECT count(*) FROM _ltreetest WHERE t @> '1.1.1' ; @@ -7749,3 +7841,65 @@ SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ; 15 (1 row) +drop index _tstidx; +create index _tstidx on _ltreetest using gist (t gist__ltree_ops(siglen=0)); +ERROR: value 0 out of bounds for option "siglen" +DETAIL: Valid values are between "1" and "2024". +create index _tstidx on _ltreetest using gist (t gist__ltree_ops(siglen=2025)); +ERROR: value 2025 out of bounds for option "siglen" +DETAIL: Valid values are between "1" and "2024". +create index _tstidx on _ltreetest using gist (t gist__ltree_ops(siglen=2024)); +SELECT count(*) FROM _ltreetest WHERE t @> '1.1.1' ; + count +------- + 15 +(1 row) + +SELECT count(*) FROM _ltreetest WHERE t <@ '1.1.1' ; + count +------- + 19 +(1 row) + +SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ; + count +------- + 147 +(1 row) + +SELECT count(*) FROM _ltreetest WHERE t ~ '1.1.1.*' ; + count +------- + 19 +(1 row) + +SELECT count(*) FROM _ltreetest WHERE t ~ '*.1' ; + count +------- + 109 +(1 row) + +SELECT count(*) FROM _ltreetest WHERE t ~ '23.*{1}.1' ; + count +------- + 5 +(1 row) + +SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ; + count +------- + 11 +(1 row) + +SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.2' ; + count +------- + 5 +(1 row) + +SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ; + count +------- + 15 +(1 row) + diff --git a/contrib/ltree/ltree--1.1--1.2.sql b/contrib/ltree/ltree--1.1--1.2.sql new file mode 100644 index 0000000000..7b4ea99867 --- /dev/null +++ b/contrib/ltree/ltree--1.1--1.2.sql @@ -0,0 +1,21 @@ +/* contrib/ltree/ltree--1.1--1.2.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION ltree UPDATE TO '1.2'" to load this file. \quit + +CREATE FUNCTION ltree_gist_options(internal) +RETURNS void +AS 'MODULE_PATHNAME', 'ltree_gist_options' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +CREATE FUNCTION _ltree_gist_options(internal) +RETURNS void +AS 'MODULE_PATHNAME', '_ltree_gist_options' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +ALTER OPERATOR FAMILY gist_ltree_ops USING gist +ADD FUNCTION 10 (ltree) ltree_gist_options (internal); + +ALTER OPERATOR FAMILY gist__ltree_ops USING gist +ADD FUNCTION 10 (_ltree) _ltree_gist_options (internal); + diff --git a/contrib/ltree/ltree.control b/contrib/ltree/ltree.control index 3118df63d3..b408d64781 100644 --- a/contrib/ltree/ltree.control +++ b/contrib/ltree/ltree.control @@ -1,6 +1,6 @@ # ltree extension comment = 'data type for hierarchical tree-like structures' -default_version = '1.1' +default_version = '1.2' module_pathname = '$libdir/ltree' relocatable = true trusted = true diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h index e5f2710c90..429cdc8131 100644 --- a/contrib/ltree/ltree.h +++ b/contrib/ltree/ltree.h @@ -209,15 +209,16 @@ int ltree_strncasecmp(const char *a, const char *b, size_t s); /* GiST support for ltree */ +#define SIGLEN_MAX GISTMaxIndexKeySize +#define SIGLEN_DEFAULT (2 * sizeof(int32)) #define BITBYTE 8 -#define SIGLENINT 2 -#define SIGLEN ( sizeof(int32)*SIGLENINT ) -#define SIGLENBIT (SIGLEN*BITBYTE) -typedef unsigned char BITVEC[SIGLEN]; +#define SIGLEN (sizeof(int32) * SIGLENINT) +#define SIGLENBIT(siglen) ((siglen) * BITBYTE) + typedef unsigned char *BITVECP; -#define LOOPBYTE \ - for(i=0;i<SIGLEN;i++) +#define LOOPBYTE(siglen) \ + for(i = 0; i < (siglen); i++) #define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITBYTE ) ) ) #define GETBITBYTE(x,i) ( ((unsigned char)(x)) >> i & 0x01 ) @@ -225,8 +226,8 @@ typedef unsigned char *BITVECP; #define SETBIT(x,i) GETBYTE(x,i) |= ( 0x01 << ( (i) % BITBYTE ) ) #define GETBIT(x,i) ( (GETBYTE(x,i) >> ( (i) % BITBYTE )) & 0x01 ) -#define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT) -#define HASH(sign, val) SETBIT((sign), HASHVAL(val)) +#define HASHVAL(val, siglen) (((unsigned int)(val)) % SIGLENBIT(siglen)) +#define HASH(sign, val, siglen) SETBIT((sign), HASHVAL(val, siglen)) /* * type of index key for ltree. Tree are combined B-Tree and R-Tree @@ -256,26 +257,37 @@ typedef struct #define LTG_ISONENODE(x) ( ((ltree_gist*)(x))->flag & LTG_ONENODE ) #define LTG_ISALLTRUE(x) ( ((ltree_gist*)(x))->flag & LTG_ALLTRUE ) #define LTG_ISNORIGHT(x) ( ((ltree_gist*)(x))->flag & LTG_NORIGHT ) -#define LTG_LNODE(x) ( (ltree*)( ( ((char*)(x))+LTG_HDRSIZE ) + ( LTG_ISALLTRUE(x) ? 0 : SIGLEN ) ) ) -#define LTG_RENODE(x) ( (ltree*)( ((char*)LTG_LNODE(x)) + VARSIZE(LTG_LNODE(x))) ) -#define LTG_RNODE(x) ( LTG_ISNORIGHT(x) ? LTG_LNODE(x) : LTG_RENODE(x) ) +#define LTG_LNODE(x, siglen) ( (ltree*)( ( ((char*)(x))+LTG_HDRSIZE ) + ( LTG_ISALLTRUE(x) ? 0 : (siglen) ) ) ) +#define LTG_RENODE(x, siglen) ( (ltree*)( ((char*)LTG_LNODE(x, siglen)) + VARSIZE(LTG_LNODE(x, siglen))) ) +#define LTG_RNODE(x, siglen) ( LTG_ISNORIGHT(x) ? LTG_LNODE(x, siglen) : LTG_RENODE(x, siglen) ) -#define LTG_GETLNODE(x) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_LNODE(x) ) -#define LTG_GETRNODE(x) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_RNODE(x) ) +#define LTG_GETLNODE(x, siglen) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_LNODE(x, siglen) ) +#define LTG_GETRNODE(x, siglen) ( LTG_ISONENODE(x) ? LTG_NODE(x) : LTG_RNODE(x, siglen) ) +extern ltree_gist *ltree_gist_alloc(bool isalltrue, BITVECP sign, int siglen, + ltree *left, ltree *right); /* GiST support for ltree[] */ -#define ASIGLENINT (7) -#define ASIGLEN (sizeof(int32)*ASIGLENINT) -#define ASIGLENBIT (ASIGLEN*BITBYTE) -typedef unsigned char ABITVEC[ASIGLEN]; +#define LTREE_ASIGLEN_DEFAULT (7 * sizeof(int32)) +#define LTREE_ASIGLEN_MAX GISTMaxIndexKeySize +#define LTREE_GET_ASIGLEN() (PG_HAS_OPCLASS_OPTIONS() ? \ + ((LtreeGistOptions *) PG_GET_OPCLASS_OPTIONS())->siglen : \ + LTREE_ASIGLEN_DEFAULT) +#define ASIGLENBIT(siglen) ((siglen) * BITBYTE) + +#define ALOOPBYTE(siglen) \ + for (i = 0; i < (siglen); i++) -#define ALOOPBYTE \ - for(i=0;i<ASIGLEN;i++) +#define AHASHVAL(val, siglen) (((unsigned int)(val)) % ASIGLENBIT(siglen)) +#define AHASH(sign, val, siglen) SETBIT((sign), AHASHVAL(val, siglen)) -#define AHASHVAL(val) (((unsigned int)(val)) % ASIGLENBIT) -#define AHASH(sign, val) SETBIT((sign), AHASHVAL(val)) +/* gist_ltree_ops and gist__ltree_ops opclass options */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int siglen; /* signature length in bytes */ +} LtreeGistOptions; /* type of key is the same to ltree_gist */ diff --git a/contrib/ltree/ltree_gist.c b/contrib/ltree/ltree_gist.c index 6ff4c3548b..041e28064f 100644 --- a/contrib/ltree/ltree_gist.c +++ b/contrib/ltree/ltree_gist.c @@ -6,11 +6,13 @@ #include "postgres.h" #include "access/gist.h" +#include "access/reloptions.h" #include "access/stratnum.h" #include "crc32.h" #include "ltree.h" #define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) ) +#define ISEQ(a,b) ( (a)->numlevel == (b)->numlevel && ltree_compare(a,b)==0 ) PG_FUNCTION_INFO_V1(ltree_gist_in); PG_FUNCTION_INFO_V1(ltree_gist_out); @@ -33,6 +35,47 @@ ltree_gist_out(PG_FUNCTION_ARGS) PG_RETURN_DATUM(0); } +ltree_gist * +ltree_gist_alloc(bool isalltrue, BITVECP sign, int siglen, + ltree *left, ltree *right) +{ + int32 size = LTG_HDRSIZE + (isalltrue ? 0 : siglen) + + (left ? VARSIZE(left) + (right ? VARSIZE(right) : 0) : 0); + ltree_gist *result = palloc(size); + + SET_VARSIZE(result, size); + + if (siglen) + { + result->flag = 0; + + if (isalltrue) + result->flag |= LTG_ALLTRUE; + else if (sign) + memcpy(LTG_SIGN(result), sign, siglen); + else + memset(LTG_SIGN(result), 0, siglen); + + if (left) + { + memcpy(LTG_LNODE(result, siglen), left, VARSIZE(left)); + + if (!right || left == right || ISEQ(left, right)) + result->flag |= LTG_NORIGHT; + else + memcpy(LTG_RNODE(result, siglen), right, VARSIZE(right)); + } + } + else + { + Assert(left); + result->flag = LTG_ONENODE; + memcpy(LTG_NODE(result), left, VARSIZE(left)); + } + + return result; +} + PG_FUNCTION_INFO_V1(ltree_compress); PG_FUNCTION_INFO_V1(ltree_decompress); PG_FUNCTION_INFO_V1(ltree_same); @@ -40,8 +83,8 @@ PG_FUNCTION_INFO_V1(ltree_union); PG_FUNCTION_INFO_V1(ltree_penalty); PG_FUNCTION_INFO_V1(ltree_picksplit); PG_FUNCTION_INFO_V1(ltree_consistent); +PG_FUNCTION_INFO_V1(ltree_gist_options); -#define ISEQ(a,b) ( (a)->numlevel == (b)->numlevel && ltree_compare(a,b)==0 ) #define GETENTRY(vec,pos) ((ltree_gist *) DatumGetPointer((vec)->vector[(pos)].key)) Datum @@ -52,14 +95,8 @@ ltree_compress(PG_FUNCTION_ARGS) if (entry->leafkey) { /* ltree */ - ltree_gist *key; ltree *val = DatumGetLtreeP(entry->key); - int32 len = LTG_HDRSIZE + VARSIZE(val); - - key = (ltree_gist *) palloc0(len); - SET_VARSIZE(key, len); - key->flag = LTG_ONENODE; - memcpy((void *) LTG_NODE(key), (void *) val, VARSIZE(val)); + ltree_gist *key = ltree_gist_alloc(false, NULL, 0, val, 0); retval = (GISTENTRY *) palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(key), @@ -93,6 +130,7 @@ ltree_same(PG_FUNCTION_ARGS) ltree_gist *a = (ltree_gist *) PG_GETARG_POINTER(0); ltree_gist *b = (ltree_gist *) PG_GETARG_POINTER(1); bool *result = (bool *) PG_GETARG_POINTER(2); + int siglen = LTREE_GET_ASIGLEN(); *result = false; if (LTG_ISONENODE(a) != LTG_ISONENODE(b)) @@ -109,15 +147,15 @@ ltree_same(PG_FUNCTION_ARGS) if (LTG_ISALLTRUE(a) != LTG_ISALLTRUE(b)) PG_RETURN_POINTER(result); - if (!ISEQ(LTG_LNODE(a), LTG_LNODE(b))) + if (!ISEQ(LTG_LNODE(a, siglen), LTG_LNODE(b, siglen))) PG_RETURN_POINTER(result); - if (!ISEQ(LTG_RNODE(a), LTG_RNODE(b))) + if (!ISEQ(LTG_RNODE(a, siglen), LTG_RNODE(b, siglen))) PG_RETURN_POINTER(result); *result = true; if (!LTG_ISALLTRUE(a)) { - LOOPBYTE + LOOPBYTE(siglen) { if (sa[i] != sb[i]) { @@ -132,7 +170,7 @@ ltree_same(PG_FUNCTION_ARGS) } static void -hashing(BITVECP sign, ltree *t) +hashing(BITVECP sign, ltree *t, int siglen) { int tlen = t->numlevel; ltree_level *cur = LTREE_FIRST(t); @@ -141,7 +179,7 @@ hashing(BITVECP sign, ltree *t) while (tlen > 0) { hash = ltree_crc32_sz(cur->name, cur->len); - HASH(sign, hash); + HASH(sign, hash, siglen); cur = LEVEL_NEXT(cur); tlen--; } @@ -152,7 +190,8 @@ ltree_union(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); int *size = (int *) PG_GETARG_POINTER(1); - BITVEC base; + int siglen = LTREE_GET_ASIGLEN(); + BITVECP base = palloc0(siglen); int32 i, j; ltree_gist *result, @@ -161,16 +200,14 @@ ltree_union(PG_FUNCTION_ARGS) *right = NULL, *curtree; bool isalltrue = false; - bool isleqr; - MemSet((void *) base, 0, sizeof(BITVEC)); for (j = 0; j < entryvec->n; j++) { cur = GETENTRY(entryvec, j); if (LTG_ISONENODE(cur)) { curtree = LTG_NODE(cur); - hashing(base, curtree); + hashing(base, curtree, siglen); if (!left || ltree_compare(left, curtree) > 0) left = curtree; if (!right || ltree_compare(right, curtree) < 0) @@ -184,14 +221,14 @@ ltree_union(PG_FUNCTION_ARGS) { BITVECP sc = LTG_SIGN(cur); - LOOPBYTE + LOOPBYTE(siglen) ((unsigned char *) base)[i] |= sc[i]; } - curtree = LTG_LNODE(cur); + curtree = LTG_LNODE(cur, siglen); if (!left || ltree_compare(left, curtree) > 0) left = curtree; - curtree = LTG_RNODE(cur); + curtree = LTG_RNODE(cur, siglen); if (!right || ltree_compare(right, curtree) < 0) right = curtree; } @@ -200,7 +237,7 @@ ltree_union(PG_FUNCTION_ARGS) if (isalltrue == false) { isalltrue = true; - LOOPBYTE + LOOPBYTE(siglen) { if (((unsigned char *) base)[i] != 0xff) { @@ -210,23 +247,9 @@ ltree_union(PG_FUNCTION_ARGS) } } - isleqr = (left == right || ISEQ(left, right)) ? true : false; - *size = LTG_HDRSIZE + ((isalltrue) ? 0 : SIGLEN) + VARSIZE(left) + ((isleqr) ? 0 : VARSIZE(right)); + result = ltree_gist_alloc(isalltrue, base, siglen, left, right); - result = (ltree_gist *) palloc0(*size); - SET_VARSIZE(result, *size); - result->flag = 0; - - if (isalltrue) - result->flag |= LTG_ALLTRUE; - else - memcpy((void *) LTG_SIGN(result), base, SIGLEN); - - memcpy((void *) LTG_LNODE(result), (void *) left, VARSIZE(left)); - if (isleqr) - result->flag |= LTG_NORIGHT; - else - memcpy((void *) LTG_RNODE(result), (void *) right, VARSIZE(right)); + *size = VARSIZE(result); PG_RETURN_POINTER(result); } @@ -237,11 +260,12 @@ ltree_penalty(PG_FUNCTION_ARGS) ltree_gist *origval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key); ltree_gist *newval = (ltree_gist *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key); float *penalty = (float *) PG_GETARG_POINTER(2); + int siglen = LTREE_GET_ASIGLEN(); int32 cmpr, cmpl; - cmpl = ltree_compare(LTG_GETLNODE(origval), LTG_GETLNODE(newval)); - cmpr = ltree_compare(LTG_GETRNODE(newval), LTG_GETRNODE(origval)); + cmpl = ltree_compare(LTG_GETLNODE(origval, siglen), LTG_GETLNODE(newval, siglen)); + cmpr = ltree_compare(LTG_GETRNODE(newval, siglen), LTG_GETRNODE(origval, siglen)); *penalty = Max(cmpl, 0) + Max(cmpr, 0); @@ -268,26 +292,23 @@ ltree_picksplit(PG_FUNCTION_ARGS) { GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); + int siglen = LTREE_GET_ASIGLEN(); OffsetNumber j; int32 i; RIX *array; OffsetNumber maxoff; int nbytes; - int size; ltree *lu_l, *lu_r, *ru_l, *ru_r; ltree_gist *lu, *ru; - BITVEC ls, - rs; + BITVECP ls = palloc0(siglen), + rs = palloc0(siglen); bool lisat = false, - risat = false, - isleqr; + risat = false; - memset((void *) ls, 0, sizeof(BITVEC)); - memset((void *) rs, 0, sizeof(BITVEC)); maxoff = entryvec->n - 1; nbytes = (maxoff + 2) * sizeof(OffsetNumber); v->spl_left = (OffsetNumber *) palloc(nbytes); @@ -301,7 +322,7 @@ ltree_picksplit(PG_FUNCTION_ARGS) { array[j].index = j; lu = GETENTRY(entryvec, j); /* use as tmp val */ - array[j].r = LTG_GETLNODE(lu); + array[j].r = LTG_GETLNODE(lu, siglen); } qsort((void *) &array[FirstOffsetNumber], maxoff - FirstOffsetNumber + 1, @@ -315,10 +336,10 @@ ltree_picksplit(PG_FUNCTION_ARGS) { v->spl_left[v->spl_nleft] = array[j].index; v->spl_nleft++; - if (lu_r == NULL || ltree_compare(LTG_GETRNODE(lu), lu_r) > 0) - lu_r = LTG_GETRNODE(lu); + if (lu_r == NULL || ltree_compare(LTG_GETRNODE(lu, siglen), lu_r) > 0) + lu_r = LTG_GETRNODE(lu, siglen); if (LTG_ISONENODE(lu)) - hashing(ls, LTG_NODE(lu)); + hashing(ls, LTG_NODE(lu), siglen); else { if (lisat || LTG_ISALLTRUE(lu)) @@ -327,7 +348,7 @@ ltree_picksplit(PG_FUNCTION_ARGS) { BITVECP sc = LTG_SIGN(lu); - LOOPBYTE + LOOPBYTE(siglen) ((unsigned char *) ls)[i] |= sc[i]; } } @@ -336,10 +357,10 @@ ltree_picksplit(PG_FUNCTION_ARGS) { v->spl_right[v->spl_nright] = array[j].index; v->spl_nright++; - if (ru_r == NULL || ltree_compare(LTG_GETRNODE(lu), ru_r) > 0) - ru_r = LTG_GETRNODE(lu); + if (ru_r == NULL || ltree_compare(LTG_GETRNODE(lu, siglen), ru_r) > 0) + ru_r = LTG_GETRNODE(lu, siglen); if (LTG_ISONENODE(lu)) - hashing(rs, LTG_NODE(lu)); + hashing(rs, LTG_NODE(lu), siglen); else { if (risat || LTG_ISALLTRUE(lu)) @@ -348,7 +369,7 @@ ltree_picksplit(PG_FUNCTION_ARGS) { BITVECP sc = LTG_SIGN(lu); - LOOPBYTE + LOOPBYTE(siglen) ((unsigned char *) rs)[i] |= sc[i]; } } @@ -358,7 +379,7 @@ ltree_picksplit(PG_FUNCTION_ARGS) if (lisat == false) { lisat = true; - LOOPBYTE + LOOPBYTE(siglen) { if (((unsigned char *) ls)[i] != 0xff) { @@ -371,7 +392,7 @@ ltree_picksplit(PG_FUNCTION_ARGS) if (risat == false) { risat = true; - LOOPBYTE + LOOPBYTE(siglen) { if (((unsigned char *) rs)[i] != 0xff) { @@ -381,38 +402,14 @@ ltree_picksplit(PG_FUNCTION_ARGS) } } - lu_l = LTG_GETLNODE(GETENTRY(entryvec, array[FirstOffsetNumber].index)); - isleqr = (lu_l == lu_r || ISEQ(lu_l, lu_r)) ? true : false; - size = LTG_HDRSIZE + ((lisat) ? 0 : SIGLEN) + VARSIZE(lu_l) + ((isleqr) ? 0 : VARSIZE(lu_r)); - lu = (ltree_gist *) palloc0(size); - SET_VARSIZE(lu, size); - lu->flag = 0; - if (lisat) - lu->flag |= LTG_ALLTRUE; - else - memcpy((void *) LTG_SIGN(lu), ls, SIGLEN); - memcpy((void *) LTG_LNODE(lu), (void *) lu_l, VARSIZE(lu_l)); - if (isleqr) - lu->flag |= LTG_NORIGHT; - else - memcpy((void *) LTG_RNODE(lu), (void *) lu_r, VARSIZE(lu_r)); + lu_l = LTG_GETLNODE(GETENTRY(entryvec, array[FirstOffsetNumber].index), siglen); + lu = ltree_gist_alloc(lisat, ls, siglen, lu_l, lu_r); + ru_l = LTG_GETLNODE(GETENTRY(entryvec, array[1 + ((maxoff - FirstOffsetNumber + 1) / 2)].index), siglen); + ru = ltree_gist_alloc(risat, rs, siglen, ru_l, ru_r); - ru_l = LTG_GETLNODE(GETENTRY(entryvec, array[1 + ((maxoff - FirstOffsetNumber + 1) / 2)].index)); - isleqr = (ru_l == ru_r || ISEQ(ru_l, ru_r)) ? true : false; - size = LTG_HDRSIZE + ((risat) ? 0 : SIGLEN) + VARSIZE(ru_l) + ((isleqr) ? 0 : VARSIZE(ru_r)); - ru = (ltree_gist *) palloc0(size); - SET_VARSIZE(ru, size); - ru->flag = 0; - if (risat) - ru->flag |= LTG_ALLTRUE; - else - memcpy((void *) LTG_SIGN(ru), rs, SIGLEN); - memcpy((void *) LTG_LNODE(ru), (void *) ru_l, VARSIZE(ru_l)); - if (isleqr) - ru->flag |= LTG_NORIGHT; - else - memcpy((void *) LTG_RNODE(ru), (void *) ru_r, VARSIZE(ru_r)); + pfree(ls); + pfree(rs); v->spl_ldatum = PointerGetDatum(lu); v->spl_rdatum = PointerGetDatum(ru); @@ -421,7 +418,7 @@ ltree_picksplit(PG_FUNCTION_ARGS) } static bool -gist_isparent(ltree_gist *key, ltree *query) +gist_isparent(ltree_gist *key, ltree *query, int siglen) { int32 numlevel = query->numlevel; int i; @@ -429,7 +426,8 @@ gist_isparent(ltree_gist *key, ltree *query) for (i = query->numlevel; i >= 0; i--) { query->numlevel = i; - if (ltree_compare(query, LTG_GETLNODE(key)) >= 0 && ltree_compare(query, LTG_GETRNODE(key)) <= 0) + if (ltree_compare(query, LTG_GETLNODE(key, siglen)) >= 0 && + ltree_compare(query, LTG_GETRNODE(key, siglen)) <= 0) { query->numlevel = numlevel; return true; @@ -450,10 +448,10 @@ copy_ltree(ltree *src) } static bool -gist_ischild(ltree_gist *key, ltree *query) +gist_ischild(ltree_gist *key, ltree *query, int siglen) { - ltree *left = copy_ltree(LTG_GETLNODE(key)); - ltree *right = copy_ltree(LTG_GETRNODE(key)); + ltree *left = copy_ltree(LTG_GETLNODE(key, siglen)); + ltree *right = copy_ltree(LTG_GETRNODE(key, siglen)); bool res = true; if (left->numlevel > query->numlevel) @@ -475,7 +473,7 @@ gist_ischild(ltree_gist *key, ltree *query) } static bool -gist_qe(ltree_gist *key, lquery *query) +gist_qe(ltree_gist *key, lquery *query, int siglen) { lquery_level *curq = LQUERY_FIRST(query); BITVECP sign = LTG_SIGN(key); @@ -494,7 +492,7 @@ gist_qe(ltree_gist *key, lquery *query) while (vlen > 0) { - if (GETBIT(sign, HASHVAL(curv->val))) + if (GETBIT(sign, HASHVAL(curv->val, siglen))) { isexist = true; break; @@ -543,39 +541,52 @@ gist_tqcmp(ltree *t, lquery *q) } static bool -gist_between(ltree_gist *key, lquery *query) +gist_between(ltree_gist *key, lquery *query, int siglen) { if (query->firstgood == 0) return true; - if (gist_tqcmp(LTG_GETLNODE(key), query) > 0) + if (gist_tqcmp(LTG_GETLNODE(key, siglen), query) > 0) return false; - if (gist_tqcmp(LTG_GETRNODE(key), query) < 0) + if (gist_tqcmp(LTG_GETRNODE(key, siglen), query) < 0) return false; return true; } +typedef struct LtreeSignature +{ + BITVECP sign; + int siglen; +} LtreeSignature; + static bool -checkcondition_bit(void *checkval, ITEM *val) +checkcondition_bit(void *cxt, ITEM *val) { - return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(checkval, HASHVAL(val->val)) : true; + LtreeSignature *sig = cxt; + + return (FLG_CANLOOKSIGN(val->flag)) ? GETBIT(sig->sign, HASHVAL(val->val, sig->siglen)) : true; } static bool -gist_qtxt(ltree_gist *key, ltxtquery *query) +gist_qtxt(ltree_gist *key, ltxtquery *query, int siglen) { + LtreeSignature sig; + if (LTG_ISALLTRUE(key)) return true; + sig.sign = LTG_SIGN(key); + sig.siglen = siglen; + return ltree_execute(GETQUERY(query), - (void *) LTG_SIGN(key), false, + &sig, false, checkcondition_bit); } static bool -arrq_cons(ltree_gist *key, ArrayType *_query) +arrq_cons(ltree_gist *key, ArrayType *_query, int siglen) { lquery *query = (lquery *) ARR_DATA_PTR(_query); int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query)); @@ -591,7 +602,7 @@ arrq_cons(ltree_gist *key, ArrayType *_query) while (num > 0) { - if (gist_qe(key, query) && gist_between(key, query)) + if (gist_qe(key, query, siglen) && gist_between(key, query, siglen)) return true; num--; query = NEXTVAL(query); @@ -607,6 +618,7 @@ ltree_consistent(PG_FUNCTION_ARGS) /* Oid subtype = PG_GETARG_OID(3); */ bool *recheck = (bool *) PG_GETARG_POINTER(4); + int siglen = LTREE_GET_ASIGLEN(); ltree_gist *key = (ltree_gist *) DatumGetPointer(entry->key); void *query = NULL; bool res = false; @@ -621,45 +633,45 @@ ltree_consistent(PG_FUNCTION_ARGS) res = (GIST_LEAF(entry)) ? (ltree_compare((ltree *) query, LTG_NODE(key)) > 0) : - (ltree_compare((ltree *) query, LTG_GETLNODE(key)) >= 0); + (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0); break; case BTLessEqualStrategyNumber: query = PG_GETARG_LTREE_P(1); - res = (ltree_compare((ltree *) query, LTG_GETLNODE(key)) >= 0); + res = (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0); break; case BTEqualStrategyNumber: query = PG_GETARG_LTREE_P(1); if (GIST_LEAF(entry)) res = (ltree_compare((ltree *) query, LTG_NODE(key)) == 0); else - res = (ltree_compare((ltree *) query, LTG_GETLNODE(key)) >= 0 + res = (ltree_compare((ltree *) query, LTG_GETLNODE(key, siglen)) >= 0 && - ltree_compare((ltree *) query, LTG_GETRNODE(key)) <= 0); + ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0); break; case BTGreaterEqualStrategyNumber: query = PG_GETARG_LTREE_P(1); - res = (ltree_compare((ltree *) query, LTG_GETRNODE(key)) <= 0); + res = (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0); break; case BTGreaterStrategyNumber: query = PG_GETARG_LTREE_P(1); res = (GIST_LEAF(entry)) ? - (ltree_compare((ltree *) query, LTG_GETRNODE(key)) < 0) + (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) < 0) : - (ltree_compare((ltree *) query, LTG_GETRNODE(key)) <= 0); + (ltree_compare((ltree *) query, LTG_GETRNODE(key, siglen)) <= 0); break; case 10: query = PG_GETARG_LTREE_P_COPY(1); res = (GIST_LEAF(entry)) ? inner_isparent((ltree *) query, LTG_NODE(key)) : - gist_isparent(key, (ltree *) query); + gist_isparent(key, (ltree *) query, siglen); break; case 11: query = PG_GETARG_LTREE_P(1); res = (GIST_LEAF(entry)) ? inner_isparent(LTG_NODE(key), (ltree *) query) : - gist_ischild(key, (ltree *) query); + gist_ischild(key, (ltree *) query, siglen); break; case 12: case 13: @@ -670,7 +682,8 @@ ltree_consistent(PG_FUNCTION_ARGS) PointerGetDatum((lquery *) query) )); else - res = (gist_qe(key, (lquery *) query) && gist_between(key, (lquery *) query)); + res = (gist_qe(key, (lquery *) query, siglen) && + gist_between(key, (lquery *) query, siglen)); break; case 14: case 15: @@ -681,7 +694,7 @@ ltree_consistent(PG_FUNCTION_ARGS) PointerGetDatum((ltxtquery *) query) )); else - res = gist_qtxt(key, (ltxtquery *) query); + res = gist_qtxt(key, (ltxtquery *) query, siglen); break; case 16: case 17: @@ -692,7 +705,7 @@ ltree_consistent(PG_FUNCTION_ARGS) PointerGetDatum((ArrayType *) query) )); else - res = arrq_cons(key, (ArrayType *) query); + res = arrq_cons(key, (ArrayType *) query, siglen); break; default: /* internal error */ @@ -702,3 +715,17 @@ ltree_consistent(PG_FUNCTION_ARGS) PG_FREE_IF_COPY(query, 1); PG_RETURN_BOOL(res); } + +Datum +ltree_gist_options(PG_FUNCTION_ARGS) +{ + local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0); + + init_local_reloptions(relopts, sizeof(LtreeGistOptions)); + add_local_int_reloption(relopts, "siglen", + "signature length in bytes", + SIGLEN_DEFAULT, 1, SIGLEN_MAX, + offsetof(LtreeGistOptions, siglen)); + + PG_RETURN_VOID(); +} diff --git a/contrib/ltree/sql/ltree.sql b/contrib/ltree/sql/ltree.sql index 1de0b2af12..d8489cbbdc 100644 --- a/contrib/ltree/sql/ltree.sql +++ b/contrib/ltree/sql/ltree.sql @@ -280,6 +280,26 @@ SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc; SELECT * FROM ltreetest WHERE t ~ '23.*.2' order by t asc; SELECT * FROM ltreetest WHERE t ? '{23.*.1,23.*.2}' order by t asc; +drop index tstidx; +create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=0)); +create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=2025)); +create index tstidx on ltreetest using gist (t gist_ltree_ops(siglen=2024)); + +SELECT count(*) FROM ltreetest WHERE t < '12.3'; +SELECT count(*) FROM ltreetest WHERE t <= '12.3'; +SELECT count(*) FROM ltreetest WHERE t = '12.3'; +SELECT count(*) FROM ltreetest WHERE t >= '12.3'; +SELECT count(*) FROM ltreetest WHERE t > '12.3'; +SELECT count(*) FROM ltreetest WHERE t @> '1.1.1'; +SELECT count(*) FROM ltreetest WHERE t <@ '1.1.1'; +SELECT count(*) FROM ltreetest WHERE t @ '23 & 1'; +SELECT count(*) FROM ltreetest WHERE t ~ '1.1.1.*'; +SELECT count(*) FROM ltreetest WHERE t ~ '*.1'; +SELECT count(*) FROM ltreetest WHERE t ~ '23.*{1}.1'; +SELECT count(*) FROM ltreetest WHERE t ~ '23.*.1'; +SELECT count(*) FROM ltreetest WHERE t ~ '23.*.2'; +SELECT count(*) FROM ltreetest WHERE t ? '{23.*.1,23.*.2}'; + create table _ltreetest (t ltree[]); \copy _ltreetest FROM 'data/_ltree.data' @@ -305,3 +325,18 @@ SELECT count(*) FROM _ltreetest WHERE t ~ '23.*{1}.1' ; SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ; SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.2' ; SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ; + +drop index _tstidx; +create index _tstidx on _ltreetest using gist (t gist__ltree_ops(siglen=0)); +create index _tstidx on _ltreetest using gist (t gist__ltree_ops(siglen=2025)); +create index _tstidx on _ltreetest using gist (t gist__ltree_ops(siglen=2024)); + +SELECT count(*) FROM _ltreetest WHERE t @> '1.1.1' ; +SELECT count(*) FROM _ltreetest WHERE t <@ '1.1.1' ; +SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ; +SELECT count(*) FROM _ltreetest WHERE t ~ '1.1.1.*' ; +SELECT count(*) FROM _ltreetest WHERE t ~ '*.1' ; +SELECT count(*) FROM _ltreetest WHERE t ~ '23.*{1}.1' ; +SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ; +SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.2' ; +SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ; diff --git a/contrib/pg_trgm/Makefile b/contrib/pg_trgm/Makefile index f0a8d9cc77..d75e9ada2e 100644 --- a/contrib/pg_trgm/Makefile +++ b/contrib/pg_trgm/Makefile @@ -9,7 +9,7 @@ OBJS = \ trgm_regexp.o EXTENSION = pg_trgm -DATA = pg_trgm--1.3--1.4.sql \ +DATA = pg_trgm--1.4--1.5.sql pg_trgm--1.3--1.4.sql \ pg_trgm--1.3.sql pg_trgm--1.2--1.3.sql pg_trgm--1.1--1.2.sql \ pg_trgm--1.0--1.1.sql PGFILEDESC = "pg_trgm - trigram matching" diff --git a/contrib/pg_trgm/expected/pg_trgm.out b/contrib/pg_trgm/expected/pg_trgm.out index 91596f8645..5746be0dc4 100644 --- a/contrib/pg_trgm/expected/pg_trgm.out +++ b/contrib/pg_trgm/expected/pg_trgm.out @@ -2364,6 +2364,1163 @@ select count(*) from test_trgm where t ~ '[qwerty]{2}-?[qwerty]{2}'; (1 row) drop index trgm_idx; +create index trgm_idx on test_trgm using gist (t gist_trgm_ops(siglen=0)); +ERROR: value 0 out of bounds for option "siglen" +DETAIL: Valid values are between "1" and "2024". +create index trgm_idx on test_trgm using gist (t gist_trgm_ops(siglen=2025)); +ERROR: value 2025 out of bounds for option "siglen" +DETAIL: Valid values are between "1" and "2024". +create index trgm_idx on test_trgm using gist (t gist_trgm_ops(siglen=2024)); +set enable_seqscan=off; +select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t; + t | sml +-------------+---------- + qwertyu0988 | 1 + qwertyu0980 | 0.714286 + qwertyu0981 | 0.714286 + qwertyu0982 | 0.714286 + qwertyu0983 | 0.714286 + qwertyu0984 | 0.714286 + qwertyu0985 | 0.714286 + qwertyu0986 | 0.714286 + qwertyu0987 | 0.714286 + qwertyu0989 | 0.714286 + qwertyu0088 | 0.6 + qwertyu0098 | 0.6 + qwertyu0188 | 0.6 + qwertyu0288 | 0.6 + qwertyu0388 | 0.6 + qwertyu0488 | 0.6 + qwertyu0588 | 0.6 + qwertyu0688 | 0.6 + qwertyu0788 | 0.6 + qwertyu0888 | 0.6 + qwertyu0900 | 0.6 + qwertyu0901 | 0.6 + qwertyu0902 | 0.6 + qwertyu0903 | 0.6 + qwertyu0904 | 0.6 + qwertyu0905 | 0.6 + qwertyu0906 | 0.6 + qwertyu0907 | 0.6 + qwertyu0908 | 0.6 + qwertyu0909 | 0.6 + qwertyu0910 | 0.6 + qwertyu0911 | 0.6 + qwertyu0912 | 0.6 + qwertyu0913 | 0.6 + qwertyu0914 | 0.6 + qwertyu0915 | 0.6 + qwertyu0916 | 0.6 + qwertyu0917 | 0.6 + qwertyu0918 | 0.6 + qwertyu0919 | 0.6 + qwertyu0920 | 0.6 + qwertyu0921 | 0.6 + qwertyu0922 | 0.6 + qwertyu0923 | 0.6 + qwertyu0924 | 0.6 + qwertyu0925 | 0.6 + qwertyu0926 | 0.6 + qwertyu0927 | 0.6 + qwertyu0928 | 0.6 + qwertyu0929 | 0.6 + qwertyu0930 | 0.6 + qwertyu0931 | 0.6 + qwertyu0932 | 0.6 + qwertyu0933 | 0.6 + qwertyu0934 | 0.6 + qwertyu0935 | 0.6 + qwertyu0936 | 0.6 + qwertyu0937 | 0.6 + qwertyu0938 | 0.6 + qwertyu0939 | 0.6 + qwertyu0940 | 0.6 + qwertyu0941 | 0.6 + qwertyu0942 | 0.6 + qwertyu0943 | 0.6 + qwertyu0944 | 0.6 + qwertyu0945 | 0.6 + qwertyu0946 | 0.6 + qwertyu0947 | 0.6 + qwertyu0948 | 0.6 + qwertyu0949 | 0.6 + qwertyu0950 | 0.6 + qwertyu0951 | 0.6 + qwertyu0952 | 0.6 + qwertyu0953 | 0.6 + qwertyu0954 | 0.6 + qwertyu0955 | 0.6 + qwertyu0956 | 0.6 + qwertyu0957 | 0.6 + qwertyu0958 | 0.6 + qwertyu0959 | 0.6 + qwertyu0960 | 0.6 + qwertyu0961 | 0.6 + qwertyu0962 | 0.6 + qwertyu0963 | 0.6 + qwertyu0964 | 0.6 + qwertyu0965 | 0.6 + qwertyu0966 | 0.6 + qwertyu0967 | 0.6 + qwertyu0968 | 0.6 + qwertyu0969 | 0.6 + qwertyu0970 | 0.6 + qwertyu0971 | 0.6 + qwertyu0972 | 0.6 + qwertyu0973 | 0.6 + qwertyu0974 | 0.6 + qwertyu0975 | 0.6 + qwertyu0976 | 0.6 + qwertyu0977 | 0.6 + qwertyu0978 | 0.6 + qwertyu0979 | 0.6 + qwertyu0990 | 0.6 + qwertyu0991 | 0.6 + qwertyu0992 | 0.6 + qwertyu0993 | 0.6 + qwertyu0994 | 0.6 + qwertyu0995 | 0.6 + qwertyu0996 | 0.6 + qwertyu0997 | 0.6 + qwertyu0998 | 0.6 + qwertyu0999 | 0.6 + qwertyu0001 | 0.5 + qwertyu0002 | 0.5 + qwertyu0003 | 0.5 + qwertyu0004 | 0.5 + qwertyu0005 | 0.5 + qwertyu0006 | 0.5 + qwertyu0007 | 0.5 + qwertyu0008 | 0.5 + qwertyu0009 | 0.5 + qwertyu0010 | 0.5 + qwertyu0011 | 0.5 + qwertyu0012 | 0.5 + qwertyu0013 | 0.5 + qwertyu0014 | 0.5 + qwertyu0015 | 0.5 + qwertyu0016 | 0.5 + qwertyu0017 | 0.5 + qwertyu0018 | 0.5 + qwertyu0019 | 0.5 + qwertyu0020 | 0.5 + qwertyu0021 | 0.5 + qwertyu0022 | 0.5 + qwertyu0023 | 0.5 + qwertyu0024 | 0.5 + qwertyu0025 | 0.5 + qwertyu0026 | 0.5 + qwertyu0027 | 0.5 + qwertyu0028 | 0.5 + qwertyu0029 | 0.5 + qwertyu0030 | 0.5 + qwertyu0031 | 0.5 + qwertyu0032 | 0.5 + qwertyu0033 | 0.5 + qwertyu0034 | 0.5 + qwertyu0035 | 0.5 + qwertyu0036 | 0.5 + qwertyu0037 | 0.5 + qwertyu0038 | 0.5 + qwertyu0039 | 0.5 + qwertyu0040 | 0.5 + qwertyu0041 | 0.5 + qwertyu0042 | 0.5 + qwertyu0043 | 0.5 + qwertyu0044 | 0.5 + qwertyu0045 | 0.5 + qwertyu0046 | 0.5 + qwertyu0047 | 0.5 + qwertyu0048 | 0.5 + qwertyu0049 | 0.5 + qwertyu0050 | 0.5 + qwertyu0051 | 0.5 + qwertyu0052 | 0.5 + qwertyu0053 | 0.5 + qwertyu0054 | 0.5 + qwertyu0055 | 0.5 + qwertyu0056 | 0.5 + qwertyu0057 | 0.5 + qwertyu0058 | 0.5 + qwertyu0059 | 0.5 + qwertyu0060 | 0.5 + qwertyu0061 | 0.5 + qwertyu0062 | 0.5 + qwertyu0063 | 0.5 + qwertyu0064 | 0.5 + qwertyu0065 | 0.5 + qwertyu0066 | 0.5 + qwertyu0067 | 0.5 + qwertyu0068 | 0.5 + qwertyu0069 | 0.5 + qwertyu0070 | 0.5 + qwertyu0071 | 0.5 + qwertyu0072 | 0.5 + qwertyu0073 | 0.5 + qwertyu0074 | 0.5 + qwertyu0075 | 0.5 + qwertyu0076 | 0.5 + qwertyu0077 | 0.5 + qwertyu0078 | 0.5 + qwertyu0079 | 0.5 + qwertyu0080 | 0.5 + qwertyu0081 | 0.5 + qwertyu0082 | 0.5 + qwertyu0083 | 0.5 + qwertyu0084 | 0.5 + qwertyu0085 | 0.5 + qwertyu0086 | 0.5 + qwertyu0087 | 0.5 + qwertyu0089 | 0.5 + qwertyu0090 | 0.5 + qwertyu0091 | 0.5 + qwertyu0092 | 0.5 + qwertyu0093 | 0.5 + qwertyu0094 | 0.5 + qwertyu0095 | 0.5 + qwertyu0096 | 0.5 + qwertyu0097 | 0.5 + qwertyu0099 | 0.5 + qwertyu0100 | 0.5 + qwertyu0101 | 0.5 + qwertyu0102 | 0.5 + qwertyu0103 | 0.5 + qwertyu0104 | 0.5 + qwertyu0105 | 0.5 + qwertyu0106 | 0.5 + qwertyu0107 | 0.5 + qwertyu0108 | 0.5 + qwertyu0109 | 0.5 + qwertyu0110 | 0.5 + qwertyu0111 | 0.5 + qwertyu0112 | 0.5 + qwertyu0113 | 0.5 + qwertyu0114 | 0.5 + qwertyu0115 | 0.5 + qwertyu0116 | 0.5 + qwertyu0117 | 0.5 + qwertyu0118 | 0.5 + qwertyu0119 | 0.5 + qwertyu0120 | 0.5 + qwertyu0121 | 0.5 + qwertyu0122 | 0.5 + qwertyu0123 | 0.5 + qwertyu0124 | 0.5 + qwertyu0125 | 0.5 + qwertyu0126 | 0.5 + qwertyu0127 | 0.5 + qwertyu0128 | 0.5 + qwertyu0129 | 0.5 + qwertyu0130 | 0.5 + qwertyu0131 | 0.5 + qwertyu0132 | 0.5 + qwertyu0133 | 0.5 + qwertyu0134 | 0.5 + qwertyu0135 | 0.5 + qwertyu0136 | 0.5 + qwertyu0137 | 0.5 + qwertyu0138 | 0.5 + qwertyu0139 | 0.5 + qwertyu0140 | 0.5 + qwertyu0141 | 0.5 + qwertyu0142 | 0.5 + qwertyu0143 | 0.5 + qwertyu0144 | 0.5 + qwertyu0145 | 0.5 + qwertyu0146 | 0.5 + qwertyu0147 | 0.5 + qwertyu0148 | 0.5 + qwertyu0149 | 0.5 + qwertyu0150 | 0.5 + qwertyu0151 | 0.5 + qwertyu0152 | 0.5 + qwertyu0153 | 0.5 + qwertyu0154 | 0.5 + qwertyu0155 | 0.5 + qwertyu0156 | 0.5 + qwertyu0157 | 0.5 + qwertyu0158 | 0.5 + qwertyu0159 | 0.5 + qwertyu0160 | 0.5 + qwertyu0161 | 0.5 + qwertyu0162 | 0.5 + qwertyu0163 | 0.5 + qwertyu0164 | 0.5 + qwertyu0165 | 0.5 + qwertyu0166 | 0.5 + qwertyu0167 | 0.5 + qwertyu0168 | 0.5 + qwertyu0169 | 0.5 + qwertyu0170 | 0.5 + qwertyu0171 | 0.5 + qwertyu0172 | 0.5 + qwertyu0173 | 0.5 + qwertyu0174 | 0.5 + qwertyu0175 | 0.5 + qwertyu0176 | 0.5 + qwertyu0177 | 0.5 + qwertyu0178 | 0.5 + qwertyu0179 | 0.5 + qwertyu0180 | 0.5 + qwertyu0181 | 0.5 + qwertyu0182 | 0.5 + qwertyu0183 | 0.5 + qwertyu0184 | 0.5 + qwertyu0185 | 0.5 + qwertyu0186 | 0.5 + qwertyu0187 | 0.5 + qwertyu0189 | 0.5 + qwertyu0190 | 0.5 + qwertyu0191 | 0.5 + qwertyu0192 | 0.5 + qwertyu0193 | 0.5 + qwertyu0194 | 0.5 + qwertyu0195 | 0.5 + qwertyu0196 | 0.5 + qwertyu0197 | 0.5 + qwertyu0198 | 0.5 + qwertyu0199 | 0.5 + qwertyu0200 | 0.5 + qwertyu0201 | 0.5 + qwertyu0202 | 0.5 + qwertyu0203 | 0.5 + qwertyu0204 | 0.5 + qwertyu0205 | 0.5 + qwertyu0206 | 0.5 + qwertyu0207 | 0.5 + qwertyu0208 | 0.5 + qwertyu0209 | 0.5 + qwertyu0210 | 0.5 + qwertyu0211 | 0.5 + qwertyu0212 | 0.5 + qwertyu0213 | 0.5 + qwertyu0214 | 0.5 + qwertyu0215 | 0.5 + qwertyu0216 | 0.5 + qwertyu0217 | 0.5 + qwertyu0218 | 0.5 + qwertyu0219 | 0.5 + qwertyu0220 | 0.5 + qwertyu0221 | 0.5 + qwertyu0222 | 0.5 + qwertyu0223 | 0.5 + qwertyu0224 | 0.5 + qwertyu0225 | 0.5 + qwertyu0226 | 0.5 + qwertyu0227 | 0.5 + qwertyu0228 | 0.5 + qwertyu0229 | 0.5 + qwertyu0230 | 0.5 + qwertyu0231 | 0.5 + qwertyu0232 | 0.5 + qwertyu0233 | 0.5 + qwertyu0234 | 0.5 + qwertyu0235 | 0.5 + qwertyu0236 | 0.5 + qwertyu0237 | 0.5 + qwertyu0238 | 0.5 + qwertyu0239 | 0.5 + qwertyu0240 | 0.5 + qwertyu0241 | 0.5 + qwertyu0242 | 0.5 + qwertyu0243 | 0.5 + qwertyu0244 | 0.5 + qwertyu0245 | 0.5 + qwertyu0246 | 0.5 + qwertyu0247 | 0.5 + qwertyu0248 | 0.5 + qwertyu0249 | 0.5 + qwertyu0250 | 0.5 + qwertyu0251 | 0.5 + qwertyu0252 | 0.5 + qwertyu0253 | 0.5 + qwertyu0254 | 0.5 + qwertyu0255 | 0.5 + qwertyu0256 | 0.5 + qwertyu0257 | 0.5 + qwertyu0258 | 0.5 + qwertyu0259 | 0.5 + qwertyu0260 | 0.5 + qwertyu0261 | 0.5 + qwertyu0262 | 0.5 + qwertyu0263 | 0.5 + qwertyu0264 | 0.5 + qwertyu0265 | 0.5 + qwertyu0266 | 0.5 + qwertyu0267 | 0.5 + qwertyu0268 | 0.5 + qwertyu0269 | 0.5 + qwertyu0270 | 0.5 + qwertyu0271 | 0.5 + qwertyu0272 | 0.5 + qwertyu0273 | 0.5 + qwertyu0274 | 0.5 + qwertyu0275 | 0.5 + qwertyu0276 | 0.5 + qwertyu0277 | 0.5 + qwertyu0278 | 0.5 + qwertyu0279 | 0.5 + qwertyu0280 | 0.5 + qwertyu0281 | 0.5 + qwertyu0282 | 0.5 + qwertyu0283 | 0.5 + qwertyu0284 | 0.5 + qwertyu0285 | 0.5 + qwertyu0286 | 0.5 + qwertyu0287 | 0.5 + qwertyu0289 | 0.5 + qwertyu0290 | 0.5 + qwertyu0291 | 0.5 + qwertyu0292 | 0.5 + qwertyu0293 | 0.5 + qwertyu0294 | 0.5 + qwertyu0295 | 0.5 + qwertyu0296 | 0.5 + qwertyu0297 | 0.5 + qwertyu0298 | 0.5 + qwertyu0299 | 0.5 + qwertyu0300 | 0.5 + qwertyu0301 | 0.5 + qwertyu0302 | 0.5 + qwertyu0303 | 0.5 + qwertyu0304 | 0.5 + qwertyu0305 | 0.5 + qwertyu0306 | 0.5 + qwertyu0307 | 0.5 + qwertyu0308 | 0.5 + qwertyu0309 | 0.5 + qwertyu0310 | 0.5 + qwertyu0311 | 0.5 + qwertyu0312 | 0.5 + qwertyu0313 | 0.5 + qwertyu0314 | 0.5 + qwertyu0315 | 0.5 + qwertyu0316 | 0.5 + qwertyu0317 | 0.5 + qwertyu0318 | 0.5 + qwertyu0319 | 0.5 + qwertyu0320 | 0.5 + qwertyu0321 | 0.5 + qwertyu0322 | 0.5 + qwertyu0323 | 0.5 + qwertyu0324 | 0.5 + qwertyu0325 | 0.5 + qwertyu0326 | 0.5 + qwertyu0327 | 0.5 + qwertyu0328 | 0.5 + qwertyu0329 | 0.5 + qwertyu0330 | 0.5 + qwertyu0331 | 0.5 + qwertyu0332 | 0.5 + qwertyu0333 | 0.5 + qwertyu0334 | 0.5 + qwertyu0335 | 0.5 + qwertyu0336 | 0.5 + qwertyu0337 | 0.5 + qwertyu0338 | 0.5 + qwertyu0339 | 0.5 + qwertyu0340 | 0.5 + qwertyu0341 | 0.5 + qwertyu0342 | 0.5 + qwertyu0343 | 0.5 + qwertyu0344 | 0.5 + qwertyu0345 | 0.5 + qwertyu0346 | 0.5 + qwertyu0347 | 0.5 + qwertyu0348 | 0.5 + qwertyu0349 | 0.5 + qwertyu0350 | 0.5 + qwertyu0351 | 0.5 + qwertyu0352 | 0.5 + qwertyu0353 | 0.5 + qwertyu0354 | 0.5 + qwertyu0355 | 0.5 + qwertyu0356 | 0.5 + qwertyu0357 | 0.5 + qwertyu0358 | 0.5 + qwertyu0359 | 0.5 + qwertyu0360 | 0.5 + qwertyu0361 | 0.5 + qwertyu0362 | 0.5 + qwertyu0363 | 0.5 + qwertyu0364 | 0.5 + qwertyu0365 | 0.5 + qwertyu0366 | 0.5 + qwertyu0367 | 0.5 + qwertyu0368 | 0.5 + qwertyu0369 | 0.5 + qwertyu0370 | 0.5 + qwertyu0371 | 0.5 + qwertyu0372 | 0.5 + qwertyu0373 | 0.5 + qwertyu0374 | 0.5 + qwertyu0375 | 0.5 + qwertyu0376 | 0.5 + qwertyu0377 | 0.5 + qwertyu0378 | 0.5 + qwertyu0379 | 0.5 + qwertyu0380 | 0.5 + qwertyu0381 | 0.5 + qwertyu0382 | 0.5 + qwertyu0383 | 0.5 + qwertyu0384 | 0.5 + qwertyu0385 | 0.5 + qwertyu0386 | 0.5 + qwertyu0387 | 0.5 + qwertyu0389 | 0.5 + qwertyu0390 | 0.5 + qwertyu0391 | 0.5 + qwertyu0392 | 0.5 + qwertyu0393 | 0.5 + qwertyu0394 | 0.5 + qwertyu0395 | 0.5 + qwertyu0396 | 0.5 + qwertyu0397 | 0.5 + qwertyu0398 | 0.5 + qwertyu0399 | 0.5 + qwertyu0400 | 0.5 + qwertyu0401 | 0.5 + qwertyu0402 | 0.5 + qwertyu0403 | 0.5 + qwertyu0404 | 0.5 + qwertyu0405 | 0.5 + qwertyu0406 | 0.5 + qwertyu0407 | 0.5 + qwertyu0408 | 0.5 + qwertyu0409 | 0.5 + qwertyu0410 | 0.5 + qwertyu0411 | 0.5 + qwertyu0412 | 0.5 + qwertyu0413 | 0.5 + qwertyu0414 | 0.5 + qwertyu0415 | 0.5 + qwertyu0416 | 0.5 + qwertyu0417 | 0.5 + qwertyu0418 | 0.5 + qwertyu0419 | 0.5 + qwertyu0420 | 0.5 + qwertyu0421 | 0.5 + qwertyu0422 | 0.5 + qwertyu0423 | 0.5 + qwertyu0424 | 0.5 + qwertyu0425 | 0.5 + qwertyu0426 | 0.5 + qwertyu0427 | 0.5 + qwertyu0428 | 0.5 + qwertyu0429 | 0.5 + qwertyu0430 | 0.5 + qwertyu0431 | 0.5 + qwertyu0432 | 0.5 + qwertyu0433 | 0.5 + qwertyu0434 | 0.5 + qwertyu0435 | 0.5 + qwertyu0436 | 0.5 + qwertyu0437 | 0.5 + qwertyu0438 | 0.5 + qwertyu0439 | 0.5 + qwertyu0440 | 0.5 + qwertyu0441 | 0.5 + qwertyu0442 | 0.5 + qwertyu0443 | 0.5 + qwertyu0444 | 0.5 + qwertyu0445 | 0.5 + qwertyu0446 | 0.5 + qwertyu0447 | 0.5 + qwertyu0448 | 0.5 + qwertyu0449 | 0.5 + qwertyu0450 | 0.5 + qwertyu0451 | 0.5 + qwertyu0452 | 0.5 + qwertyu0453 | 0.5 + qwertyu0454 | 0.5 + qwertyu0455 | 0.5 + qwertyu0456 | 0.5 + qwertyu0457 | 0.5 + qwertyu0458 | 0.5 + qwertyu0459 | 0.5 + qwertyu0460 | 0.5 + qwertyu0461 | 0.5 + qwertyu0462 | 0.5 + qwertyu0463 | 0.5 + qwertyu0464 | 0.5 + qwertyu0465 | 0.5 + qwertyu0466 | 0.5 + qwertyu0467 | 0.5 + qwertyu0468 | 0.5 + qwertyu0469 | 0.5 + qwertyu0470 | 0.5 + qwertyu0471 | 0.5 + qwertyu0472 | 0.5 + qwertyu0473 | 0.5 + qwertyu0474 | 0.5 + qwertyu0475 | 0.5 + qwertyu0476 | 0.5 + qwertyu0477 | 0.5 + qwertyu0478 | 0.5 + qwertyu0479 | 0.5 + qwertyu0480 | 0.5 + qwertyu0481 | 0.5 + qwertyu0482 | 0.5 + qwertyu0483 | 0.5 + qwertyu0484 | 0.5 + qwertyu0485 | 0.5 + qwertyu0486 | 0.5 + qwertyu0487 | 0.5 + qwertyu0489 | 0.5 + qwertyu0490 | 0.5 + qwertyu0491 | 0.5 + qwertyu0492 | 0.5 + qwertyu0493 | 0.5 + qwertyu0494 | 0.5 + qwertyu0495 | 0.5 + qwertyu0496 | 0.5 + qwertyu0497 | 0.5 + qwertyu0498 | 0.5 + qwertyu0499 | 0.5 + qwertyu0500 | 0.5 + qwertyu0501 | 0.5 + qwertyu0502 | 0.5 + qwertyu0503 | 0.5 + qwertyu0504 | 0.5 + qwertyu0505 | 0.5 + qwertyu0506 | 0.5 + qwertyu0507 | 0.5 + qwertyu0508 | 0.5 + qwertyu0509 | 0.5 + qwertyu0510 | 0.5 + qwertyu0511 | 0.5 + qwertyu0512 | 0.5 + qwertyu0513 | 0.5 + qwertyu0514 | 0.5 + qwertyu0515 | 0.5 + qwertyu0516 | 0.5 + qwertyu0517 | 0.5 + qwertyu0518 | 0.5 + qwertyu0519 | 0.5 + qwertyu0520 | 0.5 + qwertyu0521 | 0.5 + qwertyu0522 | 0.5 + qwertyu0523 | 0.5 + qwertyu0524 | 0.5 + qwertyu0525 | 0.5 + qwertyu0526 | 0.5 + qwertyu0527 | 0.5 + qwertyu0528 | 0.5 + qwertyu0529 | 0.5 + qwertyu0530 | 0.5 + qwertyu0531 | 0.5 + qwertyu0532 | 0.5 + qwertyu0533 | 0.5 + qwertyu0534 | 0.5 + qwertyu0535 | 0.5 + qwertyu0536 | 0.5 + qwertyu0537 | 0.5 + qwertyu0538 | 0.5 + qwertyu0539 | 0.5 + qwertyu0540 | 0.5 + qwertyu0541 | 0.5 + qwertyu0542 | 0.5 + qwertyu0543 | 0.5 + qwertyu0544 | 0.5 + qwertyu0545 | 0.5 + qwertyu0546 | 0.5 + qwertyu0547 | 0.5 + qwertyu0548 | 0.5 + qwertyu0549 | 0.5 + qwertyu0550 | 0.5 + qwertyu0551 | 0.5 + qwertyu0552 | 0.5 + qwertyu0553 | 0.5 + qwertyu0554 | 0.5 + qwertyu0555 | 0.5 + qwertyu0556 | 0.5 + qwertyu0557 | 0.5 + qwertyu0558 | 0.5 + qwertyu0559 | 0.5 + qwertyu0560 | 0.5 + qwertyu0561 | 0.5 + qwertyu0562 | 0.5 + qwertyu0563 | 0.5 + qwertyu0564 | 0.5 + qwertyu0565 | 0.5 + qwertyu0566 | 0.5 + qwertyu0567 | 0.5 + qwertyu0568 | 0.5 + qwertyu0569 | 0.5 + qwertyu0570 | 0.5 + qwertyu0571 | 0.5 + qwertyu0572 | 0.5 + qwertyu0573 | 0.5 + qwertyu0574 | 0.5 + qwertyu0575 | 0.5 + qwertyu0576 | 0.5 + qwertyu0577 | 0.5 + qwertyu0578 | 0.5 + qwertyu0579 | 0.5 + qwertyu0580 | 0.5 + qwertyu0581 | 0.5 + qwertyu0582 | 0.5 + qwertyu0583 | 0.5 + qwertyu0584 | 0.5 + qwertyu0585 | 0.5 + qwertyu0586 | 0.5 + qwertyu0587 | 0.5 + qwertyu0589 | 0.5 + qwertyu0590 | 0.5 + qwertyu0591 | 0.5 + qwertyu0592 | 0.5 + qwertyu0593 | 0.5 + qwertyu0594 | 0.5 + qwertyu0595 | 0.5 + qwertyu0596 | 0.5 + qwertyu0597 | 0.5 + qwertyu0598 | 0.5 + qwertyu0599 | 0.5 + qwertyu0600 | 0.5 + qwertyu0601 | 0.5 + qwertyu0602 | 0.5 + qwertyu0603 | 0.5 + qwertyu0604 | 0.5 + qwertyu0605 | 0.5 + qwertyu0606 | 0.5 + qwertyu0607 | 0.5 + qwertyu0608 | 0.5 + qwertyu0609 | 0.5 + qwertyu0610 | 0.5 + qwertyu0611 | 0.5 + qwertyu0612 | 0.5 + qwertyu0613 | 0.5 + qwertyu0614 | 0.5 + qwertyu0615 | 0.5 + qwertyu0616 | 0.5 + qwertyu0617 | 0.5 + qwertyu0618 | 0.5 + qwertyu0619 | 0.5 + qwertyu0620 | 0.5 + qwertyu0621 | 0.5 + qwertyu0622 | 0.5 + qwertyu0623 | 0.5 + qwertyu0624 | 0.5 + qwertyu0625 | 0.5 + qwertyu0626 | 0.5 + qwertyu0627 | 0.5 + qwertyu0628 | 0.5 + qwertyu0629 | 0.5 + qwertyu0630 | 0.5 + qwertyu0631 | 0.5 + qwertyu0632 | 0.5 + qwertyu0633 | 0.5 + qwertyu0634 | 0.5 + qwertyu0635 | 0.5 + qwertyu0636 | 0.5 + qwertyu0637 | 0.5 + qwertyu0638 | 0.5 + qwertyu0639 | 0.5 + qwertyu0640 | 0.5 + qwertyu0641 | 0.5 + qwertyu0642 | 0.5 + qwertyu0643 | 0.5 + qwertyu0644 | 0.5 + qwertyu0645 | 0.5 + qwertyu0646 | 0.5 + qwertyu0647 | 0.5 + qwertyu0648 | 0.5 + qwertyu0649 | 0.5 + qwertyu0650 | 0.5 + qwertyu0651 | 0.5 + qwertyu0652 | 0.5 + qwertyu0653 | 0.5 + qwertyu0654 | 0.5 + qwertyu0655 | 0.5 + qwertyu0656 | 0.5 + qwertyu0657 | 0.5 + qwertyu0658 | 0.5 + qwertyu0659 | 0.5 + qwertyu0660 | 0.5 + qwertyu0661 | 0.5 + qwertyu0662 | 0.5 + qwertyu0663 | 0.5 + qwertyu0664 | 0.5 + qwertyu0665 | 0.5 + qwertyu0666 | 0.5 + qwertyu0667 | 0.5 + qwertyu0668 | 0.5 + qwertyu0669 | 0.5 + qwertyu0670 | 0.5 + qwertyu0671 | 0.5 + qwertyu0672 | 0.5 + qwertyu0673 | 0.5 + qwertyu0674 | 0.5 + qwertyu0675 | 0.5 + qwertyu0676 | 0.5 + qwertyu0677 | 0.5 + qwertyu0678 | 0.5 + qwertyu0679 | 0.5 + qwertyu0680 | 0.5 + qwertyu0681 | 0.5 + qwertyu0682 | 0.5 + qwertyu0683 | 0.5 + qwertyu0684 | 0.5 + qwertyu0685 | 0.5 + qwertyu0686 | 0.5 + qwertyu0687 | 0.5 + qwertyu0689 | 0.5 + qwertyu0690 | 0.5 + qwertyu0691 | 0.5 + qwertyu0692 | 0.5 + qwertyu0693 | 0.5 + qwertyu0694 | 0.5 + qwertyu0695 | 0.5 + qwertyu0696 | 0.5 + qwertyu0697 | 0.5 + qwertyu0698 | 0.5 + qwertyu0699 | 0.5 + qwertyu0700 | 0.5 + qwertyu0701 | 0.5 + qwertyu0702 | 0.5 + qwertyu0703 | 0.5 + qwertyu0704 | 0.5 + qwertyu0705 | 0.5 + qwertyu0706 | 0.5 + qwertyu0707 | 0.5 + qwertyu0708 | 0.5 + qwertyu0709 | 0.5 + qwertyu0710 | 0.5 + qwertyu0711 | 0.5 + qwertyu0712 | 0.5 + qwertyu0713 | 0.5 + qwertyu0714 | 0.5 + qwertyu0715 | 0.5 + qwertyu0716 | 0.5 + qwertyu0717 | 0.5 + qwertyu0718 | 0.5 + qwertyu0719 | 0.5 + qwertyu0720 | 0.5 + qwertyu0721 | 0.5 + qwertyu0722 | 0.5 + qwertyu0723 | 0.5 + qwertyu0724 | 0.5 + qwertyu0725 | 0.5 + qwertyu0726 | 0.5 + qwertyu0727 | 0.5 + qwertyu0728 | 0.5 + qwertyu0729 | 0.5 + qwertyu0730 | 0.5 + qwertyu0731 | 0.5 + qwertyu0732 | 0.5 + qwertyu0733 | 0.5 + qwertyu0734 | 0.5 + qwertyu0735 | 0.5 + qwertyu0736 | 0.5 + qwertyu0737 | 0.5 + qwertyu0738 | 0.5 + qwertyu0739 | 0.5 + qwertyu0740 | 0.5 + qwertyu0741 | 0.5 + qwertyu0742 | 0.5 + qwertyu0743 | 0.5 + qwertyu0744 | 0.5 + qwertyu0745 | 0.5 + qwertyu0746 | 0.5 + qwertyu0747 | 0.5 + qwertyu0748 | 0.5 + qwertyu0749 | 0.5 + qwertyu0750 | 0.5 + qwertyu0751 | 0.5 + qwertyu0752 | 0.5 + qwertyu0753 | 0.5 + qwertyu0754 | 0.5 + qwertyu0755 | 0.5 + qwertyu0756 | 0.5 + qwertyu0757 | 0.5 + qwertyu0758 | 0.5 + qwertyu0759 | 0.5 + qwertyu0760 | 0.5 + qwertyu0761 | 0.5 + qwertyu0762 | 0.5 + qwertyu0763 | 0.5 + qwertyu0764 | 0.5 + qwertyu0765 | 0.5 + qwertyu0766 | 0.5 + qwertyu0767 | 0.5 + qwertyu0768 | 0.5 + qwertyu0769 | 0.5 + qwertyu0770 | 0.5 + qwertyu0771 | 0.5 + qwertyu0772 | 0.5 + qwertyu0773 | 0.5 + qwertyu0774 | 0.5 + qwertyu0775 | 0.5 + qwertyu0776 | 0.5 + qwertyu0777 | 0.5 + qwertyu0778 | 0.5 + qwertyu0779 | 0.5 + qwertyu0780 | 0.5 + qwertyu0781 | 0.5 + qwertyu0782 | 0.5 + qwertyu0783 | 0.5 + qwertyu0784 | 0.5 + qwertyu0785 | 0.5 + qwertyu0786 | 0.5 + qwertyu0787 | 0.5 + qwertyu0789 | 0.5 + qwertyu0790 | 0.5 + qwertyu0791 | 0.5 + qwertyu0792 | 0.5 + qwertyu0793 | 0.5 + qwertyu0794 | 0.5 + qwertyu0795 | 0.5 + qwertyu0796 | 0.5 + qwertyu0797 | 0.5 + qwertyu0798 | 0.5 + qwertyu0799 | 0.5 + qwertyu0800 | 0.5 + qwertyu0801 | 0.5 + qwertyu0802 | 0.5 + qwertyu0803 | 0.5 + qwertyu0804 | 0.5 + qwertyu0805 | 0.5 + qwertyu0806 | 0.5 + qwertyu0807 | 0.5 + qwertyu0808 | 0.5 + qwertyu0809 | 0.5 + qwertyu0810 | 0.5 + qwertyu0811 | 0.5 + qwertyu0812 | 0.5 + qwertyu0813 | 0.5 + qwertyu0814 | 0.5 + qwertyu0815 | 0.5 + qwertyu0816 | 0.5 + qwertyu0817 | 0.5 + qwertyu0818 | 0.5 + qwertyu0819 | 0.5 + qwertyu0820 | 0.5 + qwertyu0821 | 0.5 + qwertyu0822 | 0.5 + qwertyu0823 | 0.5 + qwertyu0824 | 0.5 + qwertyu0825 | 0.5 + qwertyu0826 | 0.5 + qwertyu0827 | 0.5 + qwertyu0828 | 0.5 + qwertyu0829 | 0.5 + qwertyu0830 | 0.5 + qwertyu0831 | 0.5 + qwertyu0832 | 0.5 + qwertyu0833 | 0.5 + qwertyu0834 | 0.5 + qwertyu0835 | 0.5 + qwertyu0836 | 0.5 + qwertyu0837 | 0.5 + qwertyu0838 | 0.5 + qwertyu0839 | 0.5 + qwertyu0840 | 0.5 + qwertyu0841 | 0.5 + qwertyu0842 | 0.5 + qwertyu0843 | 0.5 + qwertyu0844 | 0.5 + qwertyu0845 | 0.5 + qwertyu0846 | 0.5 + qwertyu0847 | 0.5 + qwertyu0848 | 0.5 + qwertyu0849 | 0.5 + qwertyu0850 | 0.5 + qwertyu0851 | 0.5 + qwertyu0852 | 0.5 + qwertyu0853 | 0.5 + qwertyu0854 | 0.5 + qwertyu0855 | 0.5 + qwertyu0856 | 0.5 + qwertyu0857 | 0.5 + qwertyu0858 | 0.5 + qwertyu0859 | 0.5 + qwertyu0860 | 0.5 + qwertyu0861 | 0.5 + qwertyu0862 | 0.5 + qwertyu0863 | 0.5 + qwertyu0864 | 0.5 + qwertyu0865 | 0.5 + qwertyu0866 | 0.5 + qwertyu0867 | 0.5 + qwertyu0868 | 0.5 + qwertyu0869 | 0.5 + qwertyu0870 | 0.5 + qwertyu0871 | 0.5 + qwertyu0872 | 0.5 + qwertyu0873 | 0.5 + qwertyu0874 | 0.5 + qwertyu0875 | 0.5 + qwertyu0876 | 0.5 + qwertyu0877 | 0.5 + qwertyu0878 | 0.5 + qwertyu0879 | 0.5 + qwertyu0880 | 0.5 + qwertyu0881 | 0.5 + qwertyu0882 | 0.5 + qwertyu0883 | 0.5 + qwertyu0884 | 0.5 + qwertyu0885 | 0.5 + qwertyu0886 | 0.5 + qwertyu0887 | 0.5 + qwertyu0889 | 0.5 + qwertyu0890 | 0.5 + qwertyu0891 | 0.5 + qwertyu0892 | 0.5 + qwertyu0893 | 0.5 + qwertyu0894 | 0.5 + qwertyu0895 | 0.5 + qwertyu0896 | 0.5 + qwertyu0897 | 0.5 + qwertyu0898 | 0.5 + qwertyu0899 | 0.5 + qwertyu1000 | 0.411765 +(1000 rows) + +select t,similarity(t,'gwertyu0988') as sml from test_trgm where t % 'gwertyu0988' order by sml desc, t; + t | sml +-------------+---------- + qwertyu0988 | 0.6 + qwertyu0980 | 0.411765 + qwertyu0981 | 0.411765 + qwertyu0982 | 0.411765 + qwertyu0983 | 0.411765 + qwertyu0984 | 0.411765 + qwertyu0985 | 0.411765 + qwertyu0986 | 0.411765 + qwertyu0987 | 0.411765 + qwertyu0989 | 0.411765 + qwertyu0088 | 0.333333 + qwertyu0098 | 0.333333 + qwertyu0188 | 0.333333 + qwertyu0288 | 0.333333 + qwertyu0388 | 0.333333 + qwertyu0488 | 0.333333 + qwertyu0588 | 0.333333 + qwertyu0688 | 0.333333 + qwertyu0788 | 0.333333 + qwertyu0888 | 0.333333 + qwertyu0900 | 0.333333 + qwertyu0901 | 0.333333 + qwertyu0902 | 0.333333 + qwertyu0903 | 0.333333 + qwertyu0904 | 0.333333 + qwertyu0905 | 0.333333 + qwertyu0906 | 0.333333 + qwertyu0907 | 0.333333 + qwertyu0908 | 0.333333 + qwertyu0909 | 0.333333 + qwertyu0910 | 0.333333 + qwertyu0911 | 0.333333 + qwertyu0912 | 0.333333 + qwertyu0913 | 0.333333 + qwertyu0914 | 0.333333 + qwertyu0915 | 0.333333 + qwertyu0916 | 0.333333 + qwertyu0917 | 0.333333 + qwertyu0918 | 0.333333 + qwertyu0919 | 0.333333 + qwertyu0920 | 0.333333 + qwertyu0921 | 0.333333 + qwertyu0922 | 0.333333 + qwertyu0923 | 0.333333 + qwertyu0924 | 0.333333 + qwertyu0925 | 0.333333 + qwertyu0926 | 0.333333 + qwertyu0927 | 0.333333 + qwertyu0928 | 0.333333 + qwertyu0929 | 0.333333 + qwertyu0930 | 0.333333 + qwertyu0931 | 0.333333 + qwertyu0932 | 0.333333 + qwertyu0933 | 0.333333 + qwertyu0934 | 0.333333 + qwertyu0935 | 0.333333 + qwertyu0936 | 0.333333 + qwertyu0937 | 0.333333 + qwertyu0938 | 0.333333 + qwertyu0939 | 0.333333 + qwertyu0940 | 0.333333 + qwertyu0941 | 0.333333 + qwertyu0942 | 0.333333 + qwertyu0943 | 0.333333 + qwertyu0944 | 0.333333 + qwertyu0945 | 0.333333 + qwertyu0946 | 0.333333 + qwertyu0947 | 0.333333 + qwertyu0948 | 0.333333 + qwertyu0949 | 0.333333 + qwertyu0950 | 0.333333 + qwertyu0951 | 0.333333 + qwertyu0952 | 0.333333 + qwertyu0953 | 0.333333 + qwertyu0954 | 0.333333 + qwertyu0955 | 0.333333 + qwertyu0956 | 0.333333 + qwertyu0957 | 0.333333 + qwertyu0958 | 0.333333 + qwertyu0959 | 0.333333 + qwertyu0960 | 0.333333 + qwertyu0961 | 0.333333 + qwertyu0962 | 0.333333 + qwertyu0963 | 0.333333 + qwertyu0964 | 0.333333 + qwertyu0965 | 0.333333 + qwertyu0966 | 0.333333 + qwertyu0967 | 0.333333 + qwertyu0968 | 0.333333 + qwertyu0969 | 0.333333 + qwertyu0970 | 0.333333 + qwertyu0971 | 0.333333 + qwertyu0972 | 0.333333 + qwertyu0973 | 0.333333 + qwertyu0974 | 0.333333 + qwertyu0975 | 0.333333 + qwertyu0976 | 0.333333 + qwertyu0977 | 0.333333 + qwertyu0978 | 0.333333 + qwertyu0979 | 0.333333 + qwertyu0990 | 0.333333 + qwertyu0991 | 0.333333 + qwertyu0992 | 0.333333 + qwertyu0993 | 0.333333 + qwertyu0994 | 0.333333 + qwertyu0995 | 0.333333 + qwertyu0996 | 0.333333 + qwertyu0997 | 0.333333 + qwertyu0998 | 0.333333 + qwertyu0999 | 0.333333 +(110 rows) + +select t,similarity(t,'gwertyu1988') as sml from test_trgm where t % 'gwertyu1988' order by sml desc, t; + t | sml +-------------+---------- + qwertyu0988 | 0.333333 +(1 row) + +explain (costs off) +select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2; + QUERY PLAN +--------------------------------------------------- + Limit + -> Index Scan using trgm_idx on test_trgm + Order By: (t <-> 'q0987wertyu0988'::text) +(3 rows) + +select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2; + ?column? | t +----------+------------- + 0.411765 | qwertyu0988 + 0.5 | qwertyu0987 +(2 rows) + +select count(*) from test_trgm where t ~ '[qwerty]{2}-?[qwerty]{2}'; + count +------- + 1000 +(1 row) + +drop index trgm_idx; create index trgm_idx on test_trgm using gin (t gin_trgm_ops); set enable_seqscan=off; select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t; diff --git a/contrib/pg_trgm/pg_trgm--1.4--1.5.sql b/contrib/pg_trgm/pg_trgm--1.4--1.5.sql new file mode 100644 index 0000000000..3804c3bc69 --- /dev/null +++ b/contrib/pg_trgm/pg_trgm--1.4--1.5.sql @@ -0,0 +1,12 @@ +/* contrib/pg_trgm/pg_trgm--1.5--1.5.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pg_trgm UPDATE TO '1.5'" to load this file. \quit + +CREATE FUNCTION gtrgm_options(internal) +RETURNS void +AS 'MODULE_PATHNAME', 'gtrgm_options' +LANGUAGE C IMMUTABLE PARALLEL SAFE; + +ALTER OPERATOR FAMILY gist_trgm_ops USING gist +ADD FUNCTION 10 (text) gtrgm_options (internal); diff --git a/contrib/pg_trgm/pg_trgm.control b/contrib/pg_trgm/pg_trgm.control index 831ba2391b..ed4487e96b 100644 --- a/contrib/pg_trgm/pg_trgm.control +++ b/contrib/pg_trgm/pg_trgm.control @@ -1,6 +1,6 @@ # pg_trgm extension comment = 'text similarity measurement and index searching based on trigrams' -default_version = '1.4' +default_version = '1.5' module_pathname = '$libdir/pg_trgm' relocatable = true trusted = true diff --git a/contrib/pg_trgm/sql/pg_trgm.sql b/contrib/pg_trgm/sql/pg_trgm.sql index 2019d1f6be..bc2a6d525c 100644 --- a/contrib/pg_trgm/sql/pg_trgm.sql +++ b/contrib/pg_trgm/sql/pg_trgm.sql @@ -47,6 +47,20 @@ select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988 select count(*) from test_trgm where t ~ '[qwerty]{2}-?[qwerty]{2}'; drop index trgm_idx; +create index trgm_idx on test_trgm using gist (t gist_trgm_ops(siglen=0)); +create index trgm_idx on test_trgm using gist (t gist_trgm_ops(siglen=2025)); +create index trgm_idx on test_trgm using gist (t gist_trgm_ops(siglen=2024)); +set enable_seqscan=off; + +select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t; +select t,similarity(t,'gwertyu0988') as sml from test_trgm where t % 'gwertyu0988' order by sml desc, t; +select t,similarity(t,'gwertyu1988') as sml from test_trgm where t % 'gwertyu1988' order by sml desc, t; +explain (costs off) +select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2; +select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2; +select count(*) from test_trgm where t ~ '[qwerty]{2}-?[qwerty]{2}'; + +drop index trgm_idx; create index trgm_idx on test_trgm using gin (t gin_trgm_ops); set enable_seqscan=off; diff --git a/contrib/pg_trgm/trgm.h b/contrib/pg_trgm/trgm.h index 0fd600d581..0c34b96d80 100644 --- a/contrib/pg_trgm/trgm.h +++ b/contrib/pg_trgm/trgm.h @@ -73,17 +73,16 @@ typedef struct #define TRGMHDRSIZE (VARHDRSZ + sizeof(uint8)) /* gist */ +#define SIGLEN_DEFAULT (sizeof(int) * 3) +#define SIGLEN_MAX GISTMaxIndexKeySize #define BITBYTE 8 -#define SIGLENINT 3 /* >122 => key will toast, so very slow!!! */ -#define SIGLEN ( sizeof(int)*SIGLENINT ) -#define SIGLENBIT (SIGLEN*BITBYTE - 1) /* see makesign */ +#define SIGLENBIT(siglen) ((siglen) * BITBYTE - 1) /* see makesign */ -typedef char BITVEC[SIGLEN]; typedef char *BITVECP; -#define LOOPBYTE \ - for(i=0;i<SIGLEN;i++) +#define LOOPBYTE(siglen) \ + for (i = 0; i < (siglen); i++) #define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITBYTE ) ) ) #define GETBITBYTE(x,i) ( (((char)(x)) >> (i)) & 0x01 ) @@ -91,8 +90,8 @@ typedef char *BITVECP; #define SETBIT(x,i) GETBYTE(x,i) |= ( 0x01 << ( (i) % BITBYTE ) ) #define GETBIT(x,i) ( (GETBYTE(x,i) >> ( (i) % BITBYTE )) & 0x01 ) -#define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT) -#define HASH(sign, val) SETBIT((sign), HASHVAL(val)) +#define HASHVAL(val, siglen) (((unsigned int)(val)) % SIGLENBIT(siglen)) +#define HASH(sign, val, siglen) SETBIT((sign), HASHVAL(val, siglen)) #define ARRKEY 0x01 #define SIGNKEY 0x02 @@ -102,7 +101,7 @@ typedef char *BITVECP; #define ISSIGNKEY(x) ( ((TRGM*)x)->flag & SIGNKEY ) #define ISALLTRUE(x) ( ((TRGM*)x)->flag & ALLISTRUE ) -#define CALCGTSIZE(flag, len) ( TRGMHDRSIZE + ( ( (flag) & ARRKEY ) ? ((len)*sizeof(trgm)) : (((flag) & ALLISTRUE) ? 0 : SIGLEN) ) ) +#define CALCGTSIZE(flag, len) ( TRGMHDRSIZE + ( ( (flag) & ARRKEY ) ? ((len)*sizeof(trgm)) : (((flag) & ALLISTRUE) ? 0 : (len)) ) ) #define GETSIGN(x) ( (BITVECP)( (char*)x+TRGMHDRSIZE ) ) #define GETARR(x) ( (trgm*)( (char*)x+TRGMHDRSIZE ) ) #define ARRNELEM(x) ( ( VARSIZE(x) - TRGMHDRSIZE )/sizeof(trgm) ) diff --git a/contrib/pg_trgm/trgm_gist.c b/contrib/pg_trgm/trgm_gist.c index 35a75c6066..9937ef9253 100644 --- a/contrib/pg_trgm/trgm_gist.c +++ b/contrib/pg_trgm/trgm_gist.c @@ -3,11 +3,23 @@ */ #include "postgres.h" +#include "access/reloptions.h" #include "access/stratnum.h" #include "fmgr.h" #include "port/pg_bitutils.h" #include "trgm.h" +/* gist_trgm_ops opclass options */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + int siglen; /* signature length in bytes */ +} TrgmGistOptions; + +#define LTREE_GET_ASIGLEN() (PG_HAS_OPCLASS_OPTIONS() ? \ + ((TrgmGistOptions *) PG_GET_OPCLASS_OPTIONS())->siglen : \ + SIGLEN_DEFAULT) + typedef struct { /* most recent inputs to gtrgm_consistent */ @@ -37,6 +49,7 @@ PG_FUNCTION_INFO_V1(gtrgm_union); PG_FUNCTION_INFO_V1(gtrgm_same); PG_FUNCTION_INFO_V1(gtrgm_penalty); PG_FUNCTION_INFO_V1(gtrgm_picksplit); +PG_FUNCTION_INFO_V1(gtrgm_options); Datum @@ -53,20 +66,41 @@ gtrgm_out(PG_FUNCTION_ARGS) PG_RETURN_DATUM(0); } +static TRGM * +gtrgm_alloc(bool isalltrue, int siglen, BITVECP sign) +{ + int flag = SIGNKEY | (isalltrue ? ALLISTRUE : 0); + int size = CALCGTSIZE(flag, siglen); + TRGM *res = palloc(size); + + SET_VARSIZE(res, size); + res->flag = flag; + + if (!isalltrue) + { + if (sign) + memcpy(GETSIGN(res), sign, siglen); + else + memset(GETSIGN(res), 0, siglen); + } + + return res; +} + static void -makesign(BITVECP sign, TRGM *a) +makesign(BITVECP sign, TRGM *a, int siglen) { int32 k, len = ARRNELEM(a); trgm *ptr = GETARR(a); int32 tmp = 0; - MemSet((void *) sign, 0, sizeof(BITVEC)); - SETBIT(sign, SIGLENBIT); /* set last unused bit */ + MemSet((void *) sign, 0, siglen); + SETBIT(sign, SIGLENBIT(siglen)); /* set last unused bit */ for (k = 0; k < len; k++) { CPTRGM(((char *) &tmp), ptr + k); - HASH(sign, tmp); + HASH(sign, tmp, siglen); } } @@ -74,6 +108,7 @@ Datum gtrgm_compress(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); + int siglen = LTREE_GET_ASIGLEN(); GISTENTRY *retval = entry; if (entry->leafkey) @@ -90,22 +125,17 @@ gtrgm_compress(PG_FUNCTION_ARGS) else if (ISSIGNKEY(DatumGetPointer(entry->key)) && !ISALLTRUE(DatumGetPointer(entry->key))) { - int32 i, - len; + int32 i; TRGM *res; BITVECP sign = GETSIGN(DatumGetPointer(entry->key)); - LOOPBYTE + LOOPBYTE(siglen) { if ((sign[i] & 0xff) != 0xff) PG_RETURN_POINTER(retval); } - len = CALCGTSIZE(SIGNKEY | ALLISTRUE, 0); - res = (TRGM *) palloc(len); - SET_VARSIZE(res, len); - res->flag = SIGNKEY | ALLISTRUE; - + res = gtrgm_alloc(true, siglen, sign); retval = (GISTENTRY *) palloc(sizeof(GISTENTRY)); gistentryinit(*retval, PointerGetDatum(res), entry->rel, entry->page, @@ -139,7 +169,7 @@ gtrgm_decompress(PG_FUNCTION_ARGS) } static int32 -cnt_sml_sign_common(TRGM *qtrg, BITVECP sign) +cnt_sml_sign_common(TRGM *qtrg, BITVECP sign, int siglen) { int32 count = 0; int32 k, @@ -150,7 +180,7 @@ cnt_sml_sign_common(TRGM *qtrg, BITVECP sign) for (k = 0; k < len; k++) { CPTRGM(((char *) &tmp), ptr + k); - count += GETBIT(sign, HASHVAL(tmp)); + count += GETBIT(sign, HASHVAL(tmp, siglen)); } return count; @@ -165,6 +195,7 @@ gtrgm_consistent(PG_FUNCTION_ARGS) /* Oid subtype = PG_GETARG_OID(3); */ bool *recheck = (bool *) PG_GETARG_POINTER(4); + int siglen = LTREE_GET_ASIGLEN(); TRGM *key = (TRGM *) DatumGetPointer(entry->key); TRGM *qtrg; bool res; @@ -292,7 +323,7 @@ gtrgm_consistent(PG_FUNCTION_ARGS) } else { /* non-leaf contains signature */ - int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key)); + int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen); int32 len = ARRNELEM(qtrg); if (len == 0) @@ -334,7 +365,7 @@ gtrgm_consistent(PG_FUNCTION_ARGS) for (k = 0; k < len; k++) { CPTRGM(((char *) &tmp), ptr + k); - if (!GETBIT(sign, HASHVAL(tmp))) + if (!GETBIT(sign, HASHVAL(tmp, siglen))) { res = false; break; @@ -387,7 +418,7 @@ gtrgm_consistent(PG_FUNCTION_ARGS) for (k = 0; k < len; k++) { CPTRGM(((char *) &tmp), ptr + k); - check[k] = GETBIT(sign, HASHVAL(tmp)); + check[k] = GETBIT(sign, HASHVAL(tmp, siglen)); } res = trigramsMatchGraph(cache->graph, check); pfree(check); @@ -417,6 +448,7 @@ gtrgm_distance(PG_FUNCTION_ARGS) /* Oid subtype = PG_GETARG_OID(3); */ bool *recheck = (bool *) PG_GETARG_POINTER(4); + int siglen = LTREE_GET_ASIGLEN(); TRGM *key = (TRGM *) DatumGetPointer(entry->key); TRGM *qtrg; float8 res; @@ -474,7 +506,7 @@ gtrgm_distance(PG_FUNCTION_ARGS) } else { /* non-leaf contains signature */ - int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key)); + int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen); int32 len = ARRNELEM(qtrg); res = (len == 0) ? -1.0 : 1.0 - ((float8) count) / ((float8) len); @@ -490,7 +522,7 @@ gtrgm_distance(PG_FUNCTION_ARGS) } static int32 -unionkey(BITVECP sbase, TRGM *add) +unionkey(BITVECP sbase, TRGM *add, int siglen) { int32 i; @@ -501,7 +533,7 @@ unionkey(BITVECP sbase, TRGM *add) if (ISALLTRUE(add)) return 1; - LOOPBYTE + LOOPBYTE(siglen) sbase[i] |= sadd[i]; } else @@ -512,7 +544,7 @@ unionkey(BITVECP sbase, TRGM *add) for (i = 0; i < ARRNELEM(add); i++) { CPTRGM(((char *) &tmp), ptr + i); - HASH(sbase, tmp); + HASH(sbase, tmp, siglen); } } return 0; @@ -525,29 +557,22 @@ gtrgm_union(PG_FUNCTION_ARGS) GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); int32 len = entryvec->n; int *size = (int *) PG_GETARG_POINTER(1); - BITVEC base; + int siglen = LTREE_GET_ASIGLEN(); int32 i; - int32 flag = 0; - TRGM *result; + TRGM *result = gtrgm_alloc(false, siglen, NULL); + BITVECP base = GETSIGN(result); - MemSet((void *) base, 0, sizeof(BITVEC)); for (i = 0; i < len; i++) { - if (unionkey(base, GETENTRY(entryvec, i))) + if (unionkey(base, GETENTRY(entryvec, i), siglen)) { - flag = ALLISTRUE; + result->flag = ALLISTRUE; + SET_VARSIZE(result, CALCGTSIZE(ALLISTRUE, siglen)); break; } } - flag |= SIGNKEY; - len = CALCGTSIZE(flag, 0); - result = (TRGM *) palloc(len); - SET_VARSIZE(result, len); - result->flag = flag; - if (!ISALLTRUE(result)) - memcpy((void *) GETSIGN(result), (void *) base, sizeof(BITVEC)); - *size = len; + *size = VARSIZE(result); PG_RETURN_POINTER(result); } @@ -558,6 +583,7 @@ gtrgm_same(PG_FUNCTION_ARGS) TRGM *a = (TRGM *) PG_GETARG_POINTER(0); TRGM *b = (TRGM *) PG_GETARG_POINTER(1); bool *result = (bool *) PG_GETARG_POINTER(2); + int siglen = LTREE_GET_ASIGLEN(); if (ISSIGNKEY(a)) { /* then b also ISSIGNKEY */ @@ -574,7 +600,7 @@ gtrgm_same(PG_FUNCTION_ARGS) sb = GETSIGN(b); *result = true; - LOOPBYTE + LOOPBYTE(siglen) { if (sa[i] != sb[i]) { @@ -611,19 +637,19 @@ gtrgm_same(PG_FUNCTION_ARGS) } static int32 -sizebitvec(BITVECP sign) +sizebitvec(BITVECP sign, int siglen) { - return pg_popcount(sign, SIGLEN); + return pg_popcount(sign, siglen); } static int -hemdistsign(BITVECP a, BITVECP b) +hemdistsign(BITVECP a, BITVECP b, int siglen) { int i, diff, dist = 0; - LOOPBYTE + LOOPBYTE(siglen) { diff = (unsigned char) (a[i] ^ b[i]); /* Using the popcount functions here isn't likely to win */ @@ -633,19 +659,19 @@ hemdistsign(BITVECP a, BITVECP b) } static int -hemdist(TRGM *a, TRGM *b) +hemdist(TRGM *a, TRGM *b, int siglen) { if (ISALLTRUE(a)) { if (ISALLTRUE(b)) return 0; else - return SIGLENBIT - sizebitvec(GETSIGN(b)); + return SIGLENBIT(siglen) - sizebitvec(GETSIGN(b), siglen); } else if (ISALLTRUE(b)) - return SIGLENBIT - sizebitvec(GETSIGN(a)); + return SIGLENBIT(siglen) - sizebitvec(GETSIGN(a), siglen); - return hemdistsign(GETSIGN(a), GETSIGN(b)); + return hemdistsign(GETSIGN(a), GETSIGN(b), siglen); } Datum @@ -654,6 +680,7 @@ gtrgm_penalty(PG_FUNCTION_ARGS) GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */ GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1); float *penalty = (float *) PG_GETARG_POINTER(2); + int siglen = LTREE_GET_ASIGLEN(); TRGM *origval = (TRGM *) DatumGetPointer(origentry->key); TRGM *newval = (TRGM *) DatumGetPointer(newentry->key); BITVECP orig = GETSIGN(origval); @@ -663,7 +690,7 @@ gtrgm_penalty(PG_FUNCTION_ARGS) if (ISARRKEY(newval)) { char *cache = (char *) fcinfo->flinfo->fn_extra; - TRGM *cachedVal = (TRGM *) (cache + MAXALIGN(sizeof(BITVEC))); + TRGM *cachedVal = (TRGM *) (cache + MAXALIGN(siglen)); Size newvalsize = VARSIZE(newval); BITVECP sign; @@ -677,12 +704,12 @@ gtrgm_penalty(PG_FUNCTION_ARGS) char *newcache; newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - MAXALIGN(sizeof(BITVEC)) + + MAXALIGN(siglen) + newvalsize); - makesign((BITVECP) newcache, newval); + makesign((BITVECP) newcache, newval, siglen); - cachedVal = (TRGM *) (newcache + MAXALIGN(sizeof(BITVEC))); + cachedVal = (TRGM *) (newcache + MAXALIGN(siglen)); memcpy(cachedVal, newval, newvalsize); if (cache) @@ -694,31 +721,32 @@ gtrgm_penalty(PG_FUNCTION_ARGS) sign = (BITVECP) cache; if (ISALLTRUE(origval)) - *penalty = ((float) (SIGLENBIT - sizebitvec(sign))) / (float) (SIGLENBIT + 1); + *penalty = ((float) (SIGLENBIT(siglen) - sizebitvec(sign, siglen))) / (float) (SIGLENBIT(siglen) + 1); else - *penalty = hemdistsign(sign, orig); + *penalty = hemdistsign(sign, orig, siglen); } else - *penalty = hemdist(origval, newval); + *penalty = hemdist(origval, newval, siglen); PG_RETURN_POINTER(penalty); } typedef struct { bool allistrue; - BITVEC sign; + BITVECP sign; } CACHESIGN; static void -fillcache(CACHESIGN *item, TRGM *key) +fillcache(CACHESIGN *item, TRGM *key, BITVECP sign, int siglen) { item->allistrue = false; + item->sign = sign; if (ISARRKEY(key)) - makesign(item->sign, key); + makesign(item->sign, key, siglen); else if (ISALLTRUE(key)) item->allistrue = true; else - memcpy((void *) item->sign, (void *) GETSIGN(key), sizeof(BITVEC)); + memcpy((void *) item->sign, (void *) GETSIGN(key), siglen); } #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) ) @@ -739,19 +767,19 @@ comparecost(const void *a, const void *b) static int -hemdistcache(CACHESIGN *a, CACHESIGN *b) +hemdistcache(CACHESIGN *a, CACHESIGN *b, int siglen) { if (a->allistrue) { if (b->allistrue) return 0; else - return SIGLENBIT - sizebitvec(b->sign); + return SIGLENBIT(siglen) - sizebitvec(b->sign, siglen); } else if (b->allistrue) - return SIGLENBIT - sizebitvec(a->sign); + return SIGLENBIT(siglen) - sizebitvec(a->sign, siglen); - return hemdistsign(a->sign, b->sign); + return hemdistsign(a->sign, b->sign, siglen); } Datum @@ -760,6 +788,7 @@ gtrgm_picksplit(PG_FUNCTION_ARGS) GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0); OffsetNumber maxoff = entryvec->n - 2; GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1); + int siglen = LTREE_GET_ASIGLEN(); OffsetNumber k, j; TRGM *datum_l, @@ -778,19 +807,23 @@ gtrgm_picksplit(PG_FUNCTION_ARGS) BITVECP ptr; int i; CACHESIGN *cache; + char *cache_sign; SPLITCOST *costvector; /* cache the sign data for each existing item */ cache = (CACHESIGN *) palloc(sizeof(CACHESIGN) * (maxoff + 2)); + cache_sign = palloc(siglen * (maxoff + 2)); + for (k = FirstOffsetNumber; k <= maxoff; k = OffsetNumberNext(k)) - fillcache(&cache[k], GETENTRY(entryvec, k)); + fillcache(&cache[k], GETENTRY(entryvec, k), &cache_sign[siglen * k], + siglen); /* now find the two furthest-apart items */ for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k)) { for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) { - size_waste = hemdistcache(&(cache[j]), &(cache[k])); + size_waste = hemdistcache(&(cache[j]), &(cache[k]), siglen); if (size_waste > waste) { waste = size_waste; @@ -815,44 +848,22 @@ gtrgm_picksplit(PG_FUNCTION_ARGS) v->spl_nright = 0; /* form initial .. */ - if (cache[seed_1].allistrue) - { - datum_l = (TRGM *) palloc(CALCGTSIZE(SIGNKEY | ALLISTRUE, 0)); - SET_VARSIZE(datum_l, CALCGTSIZE(SIGNKEY | ALLISTRUE, 0)); - datum_l->flag = SIGNKEY | ALLISTRUE; - } - else - { - datum_l = (TRGM *) palloc(CALCGTSIZE(SIGNKEY, 0)); - SET_VARSIZE(datum_l, CALCGTSIZE(SIGNKEY, 0)); - datum_l->flag = SIGNKEY; - memcpy((void *) GETSIGN(datum_l), (void *) cache[seed_1].sign, sizeof(BITVEC)); - } - if (cache[seed_2].allistrue) - { - datum_r = (TRGM *) palloc(CALCGTSIZE(SIGNKEY | ALLISTRUE, 0)); - SET_VARSIZE(datum_r, CALCGTSIZE(SIGNKEY | ALLISTRUE, 0)); - datum_r->flag = SIGNKEY | ALLISTRUE; - } - else - { - datum_r = (TRGM *) palloc(CALCGTSIZE(SIGNKEY, 0)); - SET_VARSIZE(datum_r, CALCGTSIZE(SIGNKEY, 0)); - datum_r->flag = SIGNKEY; - memcpy((void *) GETSIGN(datum_r), (void *) cache[seed_2].sign, sizeof(BITVEC)); - } + datum_l = gtrgm_alloc(cache[seed_1].allistrue, siglen, cache[seed_1].sign); + datum_r = gtrgm_alloc(cache[seed_2].allistrue, siglen, cache[seed_2].sign); union_l = GETSIGN(datum_l); union_r = GETSIGN(datum_r); maxoff = OffsetNumberNext(maxoff); - fillcache(&cache[maxoff], GETENTRY(entryvec, maxoff)); + fillcache(&cache[maxoff], GETENTRY(entryvec, maxoff), + &cache_sign[siglen * maxoff], siglen); + /* sort before ... */ costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff); for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j)) { costvector[j - 1].pos = j; - size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j])); - size_beta = hemdistcache(&(cache[seed_2]), &(cache[j])); + size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j]), siglen); + size_beta = hemdistcache(&(cache[seed_2]), &(cache[j]), siglen); costvector[j - 1].cost = abs(size_alpha - size_beta); } qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost); @@ -878,36 +889,38 @@ gtrgm_picksplit(PG_FUNCTION_ARGS) if (ISALLTRUE(datum_l) && cache[j].allistrue) size_alpha = 0; else - size_alpha = SIGLENBIT - + size_alpha = SIGLENBIT(siglen) - sizebitvec((cache[j].allistrue) ? GETSIGN(datum_l) : - GETSIGN(cache[j].sign)); + GETSIGN(cache[j].sign), + siglen); } else - size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l)); + size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l), siglen); if (ISALLTRUE(datum_r) || cache[j].allistrue) { if (ISALLTRUE(datum_r) && cache[j].allistrue) size_beta = 0; else - size_beta = SIGLENBIT - + size_beta = SIGLENBIT(siglen) - sizebitvec((cache[j].allistrue) ? GETSIGN(datum_r) : - GETSIGN(cache[j].sign)); + GETSIGN(cache[j].sign), + siglen); } else - size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r)); + size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r), siglen); if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1)) { if (ISALLTRUE(datum_l) || cache[j].allistrue) { if (!ISALLTRUE(datum_l)) - MemSet((void *) GETSIGN(datum_l), 0xff, sizeof(BITVEC)); + MemSet((void *) GETSIGN(datum_l), 0xff, siglen); } else { ptr = cache[j].sign; - LOOPBYTE + LOOPBYTE(siglen) union_l[i] |= ptr[i]; } *left++ = j; @@ -918,12 +931,12 @@ gtrgm_picksplit(PG_FUNCTION_ARGS) if (ISALLTRUE(datum_r) || cache[j].allistrue) { if (!ISALLTRUE(datum_r)) - MemSet((void *) GETSIGN(datum_r), 0xff, sizeof(BITVEC)); + MemSet((void *) GETSIGN(datum_r), 0xff, siglen); } else { ptr = cache[j].sign; - LOOPBYTE + LOOPBYTE(siglen) union_r[i] |= ptr[i]; } *right++ = j; @@ -937,3 +950,17 @@ gtrgm_picksplit(PG_FUNCTION_ARGS) PG_RETURN_POINTER(v); } + +Datum +gtrgm_options(PG_FUNCTION_ARGS) +{ + local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0); + + init_local_reloptions(relopts, sizeof(TrgmGistOptions)); + add_local_int_reloption(relopts, "siglen", + "signature length in bytes", + SIGLEN_DEFAULT, 1, SIGLEN_MAX, + offsetof(TrgmGistOptions, siglen)); + + PG_RETURN_VOID(); +} |
