postgresql/contrib/pg_trgm/trgm_gin.c
Tom Lane 4eb49db7ae Fix contrib/pg_trgm to have smoother updates from 9.0.
Take care of some loose ends in the update-from-unpackaged script, and
apply some ugly hacks to ensure that it produces the same catalog state
as the fresh-install script.  Per discussion, this seems like a safer
plan than having two different catalog states that both call themselves
"pg_trgm 1.0", even if it's not immediately clear that the subtle
differences would ever matter.

Also, fix the stub function gin_extract_trgm() so that it works instead
of just bleating.  Needed because this function will get called during a
regular dump and reload, if there are any indexes using its opclass.
The user won't have an opportunity to update the extension till later,
so telling him to do so is unhelpful.
2011-02-17 15:04:33 -05:00

201 lines
4.5 KiB
C

/*
* contrib/pg_trgm/trgm_gin.c
*/
#include "postgres.h"
#include "trgm.h"
#include "access/gin.h"
#include "access/itup.h"
#include "access/skey.h"
#include "access/tuptoaster.h"
#include "storage/bufpage.h"
#include "utils/array.h"
#include "utils/builtins.h"
PG_FUNCTION_INFO_V1(gin_extract_trgm);
Datum gin_extract_trgm(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(gin_extract_value_trgm);
Datum gin_extract_value_trgm(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(gin_extract_query_trgm);
Datum gin_extract_query_trgm(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(gin_trgm_consistent);
Datum gin_trgm_consistent(PG_FUNCTION_ARGS);
/*
* This function can only be called if a pre-9.1 version of the GIN operator
* class definition is present in the catalogs (probably as a consequence
* of upgrade-in-place). Cope.
*/
Datum
gin_extract_trgm(PG_FUNCTION_ARGS)
{
if (PG_NARGS() == 3)
return gin_extract_value_trgm(fcinfo);
if (PG_NARGS() == 7)
return gin_extract_query_trgm(fcinfo);
elog(ERROR, "unexpected number of arguments to gin_extract_trgm");
PG_RETURN_NULL();
}
Datum
gin_extract_value_trgm(PG_FUNCTION_ARGS)
{
text *val = (text *) PG_GETARG_TEXT_P(0);
int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL;
TRGM *trg;
int32 trglen;
*nentries = 0;
trg = generate_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ);
trglen = ARRNELEM(trg);
if (trglen > 0)
{
trgm *ptr;
int32 i;
*nentries = trglen;
entries = (Datum *) palloc(sizeof(Datum) * trglen);
ptr = GETARR(trg);
for (i = 0; i < trglen; i++)
{
int32 item = trgm2int(ptr);
entries[i] = Int32GetDatum(item);
ptr++;
}
}
PG_RETURN_POINTER(entries);
}
Datum
gin_extract_query_trgm(PG_FUNCTION_ARGS)
{
text *val = (text *) PG_GETARG_TEXT_P(0);
int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
StrategyNumber strategy = PG_GETARG_UINT16(2);
/* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
/* bool **nullFlags = (bool **) PG_GETARG_POINTER(5); */
int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
Datum *entries = NULL;
TRGM *trg;
int32 trglen;
trgm *ptr;
int32 i;
switch (strategy)
{
case SimilarityStrategyNumber:
trg = generate_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ);
break;
case ILikeStrategyNumber:
#ifndef IGNORECASE
elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
#endif
/* FALL THRU */
case LikeStrategyNumber:
/*
* For wildcard search we extract all the trigrams that every
* potentially-matching string must include.
*/
trg = generate_wildcard_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ);
break;
default:
elog(ERROR, "unrecognized strategy number: %d", strategy);
trg = NULL; /* keep compiler quiet */
break;
}
trglen = ARRNELEM(trg);
*nentries = trglen;
if (trglen > 0)
{
entries = (Datum *) palloc(sizeof(Datum) * trglen);
ptr = GETARR(trg);
for (i = 0; i < trglen; i++)
{
int32 item = trgm2int(ptr);
entries[i] = Int32GetDatum(item);
ptr++;
}
}
/*
* If no trigram was extracted then we have to scan all the index.
*/
if (trglen == 0)
*searchMode = GIN_SEARCH_MODE_ALL;
PG_RETURN_POINTER(entries);
}
Datum
gin_trgm_consistent(PG_FUNCTION_ARGS)
{
bool *check = (bool *) PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1);
/* text *query = PG_GETARG_TEXT_P(2); */
int32 nkeys = PG_GETARG_INT32(3);
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
bool *recheck = (bool *) PG_GETARG_POINTER(5);
bool res;
int32 i,
ntrue;
/* All cases served by this function are inexact */
*recheck = true;
switch (strategy)
{
case SimilarityStrategyNumber:
/* Count the matches */
ntrue = 0;
for (i = 0; i < nkeys; i++)
{
if (check[i])
ntrue++;
}
#ifdef DIVUNION
res = (nkeys == ntrue) ? true : ((((((float4) ntrue) / ((float4) (nkeys - ntrue)))) >= trgm_limit) ? true : false);
#else
res = (nkeys == 0) ? false : ((((((float4) ntrue) / ((float4) nkeys))) >= trgm_limit) ? true : false);
#endif
break;
case ILikeStrategyNumber:
#ifndef IGNORECASE
elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
#endif
/* FALL THRU */
case LikeStrategyNumber:
/* Check if all extracted trigrams are presented. */
res = true;
for (i = 0; i < nkeys; i++)
{
if (!check[i])
{
res = false;
break;
}
}
break;
default:
elog(ERROR, "unrecognized strategy number: %d", strategy);
res = false; /* keep compiler quiet */
break;
}
PG_RETURN_BOOL(res);
}