diff options
Diffstat (limited to 'contrib/pg_trgm/trgm_gist.c')
-rw-r--r-- | contrib/pg_trgm/trgm_gist.c | 95 |
1 files changed, 83 insertions, 12 deletions
diff --git a/contrib/pg_trgm/trgm_gist.c b/contrib/pg_trgm/trgm_gist.c index d9f3d40c179..d83265c11c3 100644 --- a/contrib/pg_trgm/trgm_gist.c +++ b/contrib/pg_trgm/trgm_gist.c @@ -195,31 +195,61 @@ gtrgm_consistent(PG_FUNCTION_ARGS) TRGM *key = (TRGM *) DatumGetPointer(entry->key); TRGM *qtrg; bool res; - char *cache = (char *) fcinfo->flinfo->fn_extra; - - /* All cases served by this function are exact */ - *recheck = false; - - if (cache == NULL || VARSIZE(cache) != VARSIZE(query) || memcmp(cache, query, VARSIZE(query)) != 0) + char *cache = (char *) fcinfo->flinfo->fn_extra, + *cacheContents = cache + MAXALIGN(sizeof(StrategyNumber)); + + /* + * Store both the strategy number and extracted trigrams in cache, because + * trigram extraction is relatively CPU-expensive. We must include + * strategy number because trigram extraction depends on strategy. + */ + if (cache == NULL || strategy != *((StrategyNumber *) cache) || + VARSIZE(cacheContents) != VARSIZE(query) || + memcmp(cacheContents, query, VARSIZE(query)) != 0) { - qtrg = generate_trgm(VARDATA(query), VARSIZE(query) - VARHDRSZ); + switch (strategy) + { + case SimilarityStrategyNumber: + qtrg = generate_trgm(VARDATA(query), VARSIZE(query) - VARHDRSZ); + break; + case ILikeStrategyNumber: +#ifndef IGNORECASE + elog(ERROR, "cannot handle ~~* with case-sensitive trigrams"); +#endif + /* FALL THRU */ + case LikeStrategyNumber: + qtrg = generate_wildcard_trgm(VARDATA(query), VARSIZE(query) - VARHDRSZ); + break; + default: + elog(ERROR, "unrecognized strategy number: %d", strategy); + qtrg = NULL; /* keep compiler quiet */ + break; + } if (cache) pfree(cache); - fcinfo->flinfo->fn_extra = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, - MAXALIGN(VARSIZE(query)) + VARSIZE(qtrg)); + fcinfo->flinfo->fn_extra = + MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, + MAXALIGN(sizeof(StrategyNumber)) + + MAXALIGN(VARSIZE(query)) + + VARSIZE(qtrg)); cache = (char *) fcinfo->flinfo->fn_extra; + cacheContents = cache + MAXALIGN(sizeof(StrategyNumber)); - memcpy(cache, query, VARSIZE(query)); - memcpy(cache + MAXALIGN(VARSIZE(query)), qtrg, VARSIZE(qtrg)); + *((StrategyNumber *) cache) = strategy; + memcpy(cacheContents, query, VARSIZE(query)); + memcpy(cacheContents + MAXALIGN(VARSIZE(query)), qtrg, VARSIZE(qtrg)); } - qtrg = (TRGM *) (cache + MAXALIGN(VARSIZE(query))); + qtrg = (TRGM *) (cacheContents + MAXALIGN(VARSIZE(query))); switch (strategy) { case SimilarityStrategyNumber: + /* Similarity search is exact */ + *recheck = false; + if (GIST_LEAF(entry)) { /* all leafs contains orig trgm */ float4 tmpsml = cnt_sml(key, qtrg); @@ -242,6 +272,47 @@ gtrgm_consistent(PG_FUNCTION_ARGS) res = (((((float8) count) / ((float8) len))) >= trgm_limit) ? true : false; } break; + case ILikeStrategyNumber: +#ifndef IGNORECASE + elog(ERROR, "cannot handle ~~* with case-sensitive trigrams"); +#endif + /* FALL THRU */ + case LikeStrategyNumber: + /* Wildcard search is inexact */ + *recheck = true; + + /* + * Check if all the extracted trigrams can be present in child + * nodes. + */ + if (GIST_LEAF(entry)) + { /* all leafs contains orig trgm */ + res = trgm_contained_by(qtrg, key); + } + else if (ISALLTRUE(key)) + { /* non-leaf contains signature */ + res = true; + } + else + { /* non-leaf contains signature */ + int32 k, + tmp = 0, + len = ARRNELEM(qtrg); + trgm *ptr = GETARR(qtrg); + BITVECP sign = GETSIGN(key); + + res = true; + for (k = 0; k < len; k++) + { + CPTRGM(((char *) &tmp), ptr + k); + if (!GETBIT(sign, HASHVAL(tmp))) + { + res = false; + break; + } + } + } + break; default: elog(ERROR, "unrecognized strategy number: %d", strategy); res = false; /* keep compiler quiet */ |