Header And Logo

PostgreSQL
| The world's most advanced open source database.

trgm_gin.c

Go to the documentation of this file.
00001 /*
00002  * contrib/pg_trgm/trgm_gin.c
00003  */
00004 #include "postgres.h"
00005 
00006 #include "trgm.h"
00007 
00008 #include "access/gin.h"
00009 #include "access/skey.h"
00010 
00011 
00012 PG_FUNCTION_INFO_V1(gin_extract_trgm);
00013 Datum       gin_extract_trgm(PG_FUNCTION_ARGS);
00014 
00015 PG_FUNCTION_INFO_V1(gin_extract_value_trgm);
00016 Datum       gin_extract_value_trgm(PG_FUNCTION_ARGS);
00017 
00018 PG_FUNCTION_INFO_V1(gin_extract_query_trgm);
00019 Datum       gin_extract_query_trgm(PG_FUNCTION_ARGS);
00020 
00021 PG_FUNCTION_INFO_V1(gin_trgm_consistent);
00022 Datum       gin_trgm_consistent(PG_FUNCTION_ARGS);
00023 
00024 /*
00025  * This function can only be called if a pre-9.1 version of the GIN operator
00026  * class definition is present in the catalogs (probably as a consequence
00027  * of upgrade-in-place).  Cope.
00028  */
00029 Datum
00030 gin_extract_trgm(PG_FUNCTION_ARGS)
00031 {
00032     if (PG_NARGS() == 3)
00033         return gin_extract_value_trgm(fcinfo);
00034     if (PG_NARGS() == 7)
00035         return gin_extract_query_trgm(fcinfo);
00036     elog(ERROR, "unexpected number of arguments to gin_extract_trgm");
00037     PG_RETURN_NULL();
00038 }
00039 
00040 Datum
00041 gin_extract_value_trgm(PG_FUNCTION_ARGS)
00042 {
00043     text       *val = (text *) PG_GETARG_TEXT_P(0);
00044     int32      *nentries = (int32 *) PG_GETARG_POINTER(1);
00045     Datum      *entries = NULL;
00046     TRGM       *trg;
00047     int32       trglen;
00048 
00049     *nentries = 0;
00050 
00051     trg = generate_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ);
00052     trglen = ARRNELEM(trg);
00053 
00054     if (trglen > 0)
00055     {
00056         trgm       *ptr;
00057         int32       i;
00058 
00059         *nentries = trglen;
00060         entries = (Datum *) palloc(sizeof(Datum) * trglen);
00061 
00062         ptr = GETARR(trg);
00063         for (i = 0; i < trglen; i++)
00064         {
00065             int32       item = trgm2int(ptr);
00066 
00067             entries[i] = Int32GetDatum(item);
00068             ptr++;
00069         }
00070     }
00071 
00072     PG_RETURN_POINTER(entries);
00073 }
00074 
00075 Datum
00076 gin_extract_query_trgm(PG_FUNCTION_ARGS)
00077 {
00078     text       *val = (text *) PG_GETARG_TEXT_P(0);
00079     int32      *nentries = (int32 *) PG_GETARG_POINTER(1);
00080     StrategyNumber strategy = PG_GETARG_UINT16(2);
00081 
00082     /* bool   **pmatch = (bool **) PG_GETARG_POINTER(3); */
00083     Pointer   **extra_data = (Pointer **) PG_GETARG_POINTER(4);
00084 
00085     /* bool   **nullFlags = (bool **) PG_GETARG_POINTER(5); */
00086     int32      *searchMode = (int32 *) PG_GETARG_POINTER(6);
00087     Datum      *entries = NULL;
00088     TRGM       *trg;
00089     int32       trglen;
00090     trgm       *ptr;
00091     TrgmPackedGraph *graph;
00092     int32       i;
00093 
00094     switch (strategy)
00095     {
00096         case SimilarityStrategyNumber:
00097             trg = generate_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ);
00098             break;
00099         case ILikeStrategyNumber:
00100 #ifndef IGNORECASE
00101             elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
00102 #endif
00103             /* FALL THRU */
00104         case LikeStrategyNumber:
00105 
00106             /*
00107              * For wildcard search we extract all the trigrams that every
00108              * potentially-matching string must include.
00109              */
00110             trg = generate_wildcard_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ);
00111             break;
00112         case RegExpICaseStrategyNumber:
00113 #ifndef IGNORECASE
00114             elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
00115 #endif
00116             /* FALL THRU */
00117         case RegExpStrategyNumber:
00118             trg = createTrgmNFA(val, PG_GET_COLLATION(),
00119                                 &graph, CurrentMemoryContext);
00120             if (trg && ARRNELEM(trg) > 0)
00121             {
00122                 /*
00123                  * Successful regex processing: store NFA-like graph as
00124                  * extra_data.  GIN API requires an array of nentries
00125                  * Pointers, but we just put the same value in each element.
00126                  */
00127                 trglen = ARRNELEM(trg);
00128                 *extra_data = (Pointer *) palloc(sizeof(Pointer) * trglen);
00129                 for (i = 0; i < trglen; i++)
00130                     (*extra_data)[i] = (Pointer) graph;
00131             }
00132             else
00133             {
00134                 /* No result: have to do full index scan. */
00135                 *nentries = 0;
00136                 *searchMode = GIN_SEARCH_MODE_ALL;
00137                 PG_RETURN_POINTER(entries);
00138             }
00139             break;
00140         default:
00141             elog(ERROR, "unrecognized strategy number: %d", strategy);
00142             trg = NULL;         /* keep compiler quiet */
00143             break;
00144     }
00145 
00146     trglen = ARRNELEM(trg);
00147     *nentries = trglen;
00148 
00149     if (trglen > 0)
00150     {
00151         entries = (Datum *) palloc(sizeof(Datum) * trglen);
00152         ptr = GETARR(trg);
00153         for (i = 0; i < trglen; i++)
00154         {
00155             int32       item = trgm2int(ptr);
00156 
00157             entries[i] = Int32GetDatum(item);
00158             ptr++;
00159         }
00160     }
00161 
00162     /*
00163      * If no trigram was extracted then we have to scan all the index.
00164      */
00165     if (trglen == 0)
00166         *searchMode = GIN_SEARCH_MODE_ALL;
00167 
00168     PG_RETURN_POINTER(entries);
00169 }
00170 
00171 Datum
00172 gin_trgm_consistent(PG_FUNCTION_ARGS)
00173 {
00174     bool       *check = (bool *) PG_GETARG_POINTER(0);
00175     StrategyNumber strategy = PG_GETARG_UINT16(1);
00176 
00177     /* text    *query = PG_GETARG_TEXT_P(2); */
00178     int32       nkeys = PG_GETARG_INT32(3);
00179     Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4);
00180     bool       *recheck = (bool *) PG_GETARG_POINTER(5);
00181     bool        res;
00182     int32       i,
00183                 ntrue;
00184 
00185     /* All cases served by this function are inexact */
00186     *recheck = true;
00187 
00188     switch (strategy)
00189     {
00190         case SimilarityStrategyNumber:
00191             /* Count the matches */
00192             ntrue = 0;
00193             for (i = 0; i < nkeys; i++)
00194             {
00195                 if (check[i])
00196                     ntrue++;
00197             }
00198 #ifdef DIVUNION
00199             res = (nkeys == ntrue) ? true : ((((((float4) ntrue) / ((float4) (nkeys - ntrue)))) >= trgm_limit) ? true : false);
00200 #else
00201             res = (nkeys == 0) ? false : ((((((float4) ntrue) / ((float4) nkeys))) >= trgm_limit) ? true : false);
00202 #endif
00203             break;
00204         case ILikeStrategyNumber:
00205 #ifndef IGNORECASE
00206             elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
00207 #endif
00208             /* FALL THRU */
00209         case LikeStrategyNumber:
00210             /* Check if all extracted trigrams are presented. */
00211             res = true;
00212             for (i = 0; i < nkeys; i++)
00213             {
00214                 if (!check[i])
00215                 {
00216                     res = false;
00217                     break;
00218                 }
00219             }
00220             break;
00221         case RegExpICaseStrategyNumber:
00222 #ifndef IGNORECASE
00223             elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
00224 #endif
00225             /* FALL THRU */
00226         case RegExpStrategyNumber:
00227             if (nkeys < 1)
00228             {
00229                 /* Regex processing gave no result: do full index scan */
00230                 res = true;
00231             }
00232             else
00233                 res = trigramsMatchGraph((TrgmPackedGraph *) extra_data[0],
00234                                          check);
00235             break;
00236         default:
00237             elog(ERROR, "unrecognized strategy number: %d", strategy);
00238             res = false;        /* keep compiler quiet */
00239             break;
00240     }
00241 
00242     PG_RETURN_BOOL(res);
00243 }