Header And Logo

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

hstore_gin.c

Go to the documentation of this file.
00001 /*
00002  * contrib/hstore/hstore_gin.c
00003  */
00004 #include "postgres.h"
00005 
00006 #include "access/gin.h"
00007 #include "access/skey.h"
00008 #include "catalog/pg_type.h"
00009 
00010 #include "hstore.h"
00011 
00012 
00013 /*
00014  * When using a GIN index for hstore, we choose to index both keys and values.
00015  * The storage format is "text" values, with K, V, or N prepended to the string
00016  * to indicate key, value, or null values.  (As of 9.1 it might be better to
00017  * store null values as nulls, but we'll keep it this way for on-disk
00018  * compatibility.)
00019  */
00020 #define KEYFLAG     'K'
00021 #define VALFLAG     'V'
00022 #define NULLFLAG    'N'
00023 
00024 PG_FUNCTION_INFO_V1(gin_extract_hstore);
00025 Datum       gin_extract_hstore(PG_FUNCTION_ARGS);
00026 
00027 /* Build an indexable text value */
00028 static text *
00029 makeitem(char *str, int len, char flag)
00030 {
00031     text       *item;
00032 
00033     item = (text *) palloc(VARHDRSZ + len + 1);
00034     SET_VARSIZE(item, VARHDRSZ + len + 1);
00035 
00036     *VARDATA(item) = flag;
00037 
00038     if (str && len > 0)
00039         memcpy(VARDATA(item) + 1, str, len);
00040 
00041     return item;
00042 }
00043 
00044 Datum
00045 gin_extract_hstore(PG_FUNCTION_ARGS)
00046 {
00047     HStore     *hs = PG_GETARG_HS(0);
00048     int32      *nentries = (int32 *) PG_GETARG_POINTER(1);
00049     Datum      *entries = NULL;
00050     HEntry     *hsent = ARRPTR(hs);
00051     char       *ptr = STRPTR(hs);
00052     int         count = HS_COUNT(hs);
00053     int         i;
00054 
00055     *nentries = 2 * count;
00056     if (count)
00057         entries = (Datum *) palloc(sizeof(Datum) * 2 * count);
00058 
00059     for (i = 0; i < count; ++i)
00060     {
00061         text       *item;
00062 
00063         item = makeitem(HS_KEY(hsent, ptr, i), HS_KEYLEN(hsent, i),
00064                         KEYFLAG);
00065         entries[2 * i] = PointerGetDatum(item);
00066 
00067         if (HS_VALISNULL(hsent, i))
00068             item = makeitem(NULL, 0, NULLFLAG);
00069         else
00070             item = makeitem(HS_VAL(hsent, ptr, i), HS_VALLEN(hsent, i),
00071                             VALFLAG);
00072         entries[2 * i + 1] = PointerGetDatum(item);
00073     }
00074 
00075     PG_RETURN_POINTER(entries);
00076 }
00077 
00078 PG_FUNCTION_INFO_V1(gin_extract_hstore_query);
00079 Datum       gin_extract_hstore_query(PG_FUNCTION_ARGS);
00080 
00081 Datum
00082 gin_extract_hstore_query(PG_FUNCTION_ARGS)
00083 {
00084     int32      *nentries = (int32 *) PG_GETARG_POINTER(1);
00085     StrategyNumber strategy = PG_GETARG_UINT16(2);
00086     int32      *searchMode = (int32 *) PG_GETARG_POINTER(6);
00087     Datum      *entries;
00088 
00089     if (strategy == HStoreContainsStrategyNumber)
00090     {
00091         /* Query is an hstore, so just apply gin_extract_hstore... */
00092         entries = (Datum *)
00093             DatumGetPointer(DirectFunctionCall2(gin_extract_hstore,
00094                                                 PG_GETARG_DATUM(0),
00095                                                 PointerGetDatum(nentries)));
00096         /* ... except that "contains {}" requires a full index scan */
00097         if (entries == NULL)
00098             *searchMode = GIN_SEARCH_MODE_ALL;
00099     }
00100     else if (strategy == HStoreExistsStrategyNumber)
00101     {
00102         text       *query = PG_GETARG_TEXT_PP(0);
00103         text       *item;
00104 
00105         *nentries = 1;
00106         entries = (Datum *) palloc(sizeof(Datum));
00107         item = makeitem(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query), KEYFLAG);
00108         entries[0] = PointerGetDatum(item);
00109     }
00110     else if (strategy == HStoreExistsAnyStrategyNumber ||
00111              strategy == HStoreExistsAllStrategyNumber)
00112     {
00113         ArrayType  *query = PG_GETARG_ARRAYTYPE_P(0);
00114         Datum      *key_datums;
00115         bool       *key_nulls;
00116         int         key_count;
00117         int         i,
00118                     j;
00119         text       *item;
00120 
00121         deconstruct_array(query,
00122                           TEXTOID, -1, false, 'i',
00123                           &key_datums, &key_nulls, &key_count);
00124 
00125         entries = (Datum *) palloc(sizeof(Datum) * key_count);
00126 
00127         for (i = 0, j = 0; i < key_count; ++i)
00128         {
00129             /* Nulls in the array are ignored, cf hstoreArrayToPairs */
00130             if (key_nulls[i])
00131                 continue;
00132             item = makeitem(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ, KEYFLAG);
00133             entries[j++] = PointerGetDatum(item);
00134         }
00135 
00136         *nentries = j;
00137         /* ExistsAll with no keys should match everything */
00138         if (j == 0 && strategy == HStoreExistsAllStrategyNumber)
00139             *searchMode = GIN_SEARCH_MODE_ALL;
00140     }
00141     else
00142     {
00143         elog(ERROR, "unrecognized strategy number: %d", strategy);
00144         entries = NULL;         /* keep compiler quiet */
00145     }
00146 
00147     PG_RETURN_POINTER(entries);
00148 }
00149 
00150 PG_FUNCTION_INFO_V1(gin_consistent_hstore);
00151 Datum       gin_consistent_hstore(PG_FUNCTION_ARGS);
00152 
00153 Datum
00154 gin_consistent_hstore(PG_FUNCTION_ARGS)
00155 {
00156     bool       *check = (bool *) PG_GETARG_POINTER(0);
00157     StrategyNumber strategy = PG_GETARG_UINT16(1);
00158 
00159     /* HStore      *query = PG_GETARG_HS(2); */
00160     int32       nkeys = PG_GETARG_INT32(3);
00161 
00162     /* Pointer     *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
00163     bool       *recheck = (bool *) PG_GETARG_POINTER(5);
00164     bool        res = true;
00165     int32       i;
00166 
00167     if (strategy == HStoreContainsStrategyNumber)
00168     {
00169         /*
00170          * Index doesn't have information about correspondence of keys and
00171          * values, so we need recheck.  However, if not all the keys are
00172          * present, we can fail at once.
00173          */
00174         *recheck = true;
00175         for (i = 0; i < nkeys; i++)
00176         {
00177             if (!check[i])
00178             {
00179                 res = false;
00180                 break;
00181             }
00182         }
00183     }
00184     else if (strategy == HStoreExistsStrategyNumber)
00185     {
00186         /* Existence of key is guaranteed in default search mode */
00187         *recheck = false;
00188         res = true;
00189     }
00190     else if (strategy == HStoreExistsAnyStrategyNumber)
00191     {
00192         /* Existence of key is guaranteed in default search mode */
00193         *recheck = false;
00194         res = true;
00195     }
00196     else if (strategy == HStoreExistsAllStrategyNumber)
00197     {
00198         /* Testing for all the keys being present gives an exact result */
00199         *recheck = false;
00200         for (i = 0; i < nkeys; i++)
00201         {
00202             if (!check[i])
00203             {
00204                 res = false;
00205                 break;
00206             }
00207         }
00208     }
00209     else
00210         elog(ERROR, "unrecognized strategy number: %d", strategy);
00211 
00212     PG_RETURN_BOOL(res);
00213 }