LCOV - code coverage report
Current view: top level - contrib/hstore - hstore_gin.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 80 85 94.1 %
Date: 2024-04-19 18:11:10 Functions: 7 7 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * contrib/hstore/hstore_gin.c
       3             :  */
       4             : #include "postgres.h"
       5             : 
       6             : #include "access/gin.h"
       7             : #include "access/stratnum.h"
       8             : #include "catalog/pg_type.h"
       9             : 
      10             : #include "hstore.h"
      11             : 
      12             : 
      13             : /*
      14             :  * When using a GIN index for hstore, we choose to index both keys and values.
      15             :  * The storage format is "text" values, with K, V, or N prepended to the string
      16             :  * to indicate key, value, or null values.  (As of 9.1 it might be better to
      17             :  * store null values as nulls, but we'll keep it this way for on-disk
      18             :  * compatibility.)
      19             :  */
      20             : #define KEYFLAG     'K'
      21             : #define VALFLAG     'V'
      22             : #define NULLFLAG    'N'
      23             : 
      24          16 : PG_FUNCTION_INFO_V1(gin_extract_hstore);
      25             : 
      26             : /* Build an indexable text value */
      27             : static text *
      28       19176 : makeitem(char *str, int len, char flag)
      29             : {
      30             :     text       *item;
      31             : 
      32       19176 :     item = (text *) palloc(VARHDRSZ + len + 1);
      33       19176 :     SET_VARSIZE(item, VARHDRSZ + len + 1);
      34             : 
      35       19176 :     *VARDATA(item) = flag;
      36             : 
      37       19176 :     if (str && len > 0)
      38       19170 :         memcpy(VARDATA(item) + 1, str, len);
      39             : 
      40       19176 :     return item;
      41             : }
      42             : 
      43             : Datum
      44        2014 : gin_extract_hstore(PG_FUNCTION_ARGS)
      45             : {
      46        2014 :     HStore     *hs = PG_GETARG_HSTORE_P(0);
      47        2014 :     int32      *nentries = (int32 *) PG_GETARG_POINTER(1);
      48        2014 :     Datum      *entries = NULL;
      49        2014 :     HEntry     *hsent = ARRPTR(hs);
      50        2014 :     char       *ptr = STRPTR(hs);
      51        2014 :     int         count = HS_COUNT(hs);
      52             :     int         i;
      53             : 
      54        2014 :     *nentries = 2 * count;
      55        2014 :     if (count)
      56        1780 :         entries = (Datum *) palloc(sizeof(Datum) * 2 * count);
      57             : 
      58       11592 :     for (i = 0; i < count; ++i)
      59             :     {
      60             :         text       *item;
      61             : 
      62        9578 :         item = makeitem(HSTORE_KEY(hsent, ptr, i),
      63        9578 :                         HSTORE_KEYLEN(hsent, i),
      64             :                         KEYFLAG);
      65        9578 :         entries[2 * i] = PointerGetDatum(item);
      66             : 
      67        9578 :         if (HSTORE_VALISNULL(hsent, i))
      68           6 :             item = makeitem(NULL, 0, NULLFLAG);
      69             :         else
      70        9572 :             item = makeitem(HSTORE_VAL(hsent, ptr, i),
      71        9572 :                             HSTORE_VALLEN(hsent, i),
      72             :                             VALFLAG);
      73        9578 :         entries[2 * i + 1] = PointerGetDatum(item);
      74             :     }
      75             : 
      76        2014 :     PG_RETURN_POINTER(entries);
      77             : }
      78             : 
      79          16 : PG_FUNCTION_INFO_V1(gin_extract_hstore_query);
      80             : 
      81             : Datum
      82          24 : gin_extract_hstore_query(PG_FUNCTION_ARGS)
      83             : {
      84          24 :     int32      *nentries = (int32 *) PG_GETARG_POINTER(1);
      85          24 :     StrategyNumber strategy = PG_GETARG_UINT16(2);
      86          24 :     int32      *searchMode = (int32 *) PG_GETARG_POINTER(6);
      87             :     Datum      *entries;
      88             : 
      89          24 :     if (strategy == HStoreContainsStrategyNumber)
      90             :     {
      91             :         /* Query is an hstore, so just apply gin_extract_hstore... */
      92             :         entries = (Datum *)
      93          12 :             DatumGetPointer(DirectFunctionCall2(gin_extract_hstore,
      94             :                                                 PG_GETARG_DATUM(0),
      95             :                                                 PointerGetDatum(nentries)));
      96             :         /* ... except that "contains {}" requires a full index scan */
      97          12 :         if (entries == NULL)
      98           0 :             *searchMode = GIN_SEARCH_MODE_ALL;
      99             :     }
     100          12 :     else if (strategy == HStoreExistsStrategyNumber)
     101             :     {
     102           4 :         text       *query = PG_GETARG_TEXT_PP(0);
     103             :         text       *item;
     104             : 
     105           4 :         *nentries = 1;
     106           4 :         entries = (Datum *) palloc(sizeof(Datum));
     107           4 :         item = makeitem(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query), KEYFLAG);
     108           4 :         entries[0] = PointerGetDatum(item);
     109             :     }
     110           8 :     else if (strategy == HStoreExistsAnyStrategyNumber ||
     111             :              strategy == HStoreExistsAllStrategyNumber)
     112           8 :     {
     113           8 :         ArrayType  *query = PG_GETARG_ARRAYTYPE_P(0);
     114             :         Datum      *key_datums;
     115             :         bool       *key_nulls;
     116             :         int         key_count;
     117             :         int         i,
     118             :                     j;
     119             :         text       *item;
     120             : 
     121           8 :         deconstruct_array_builtin(query, TEXTOID, &key_datums, &key_nulls, &key_count);
     122             : 
     123           8 :         entries = (Datum *) palloc(sizeof(Datum) * key_count);
     124             : 
     125          24 :         for (i = 0, j = 0; i < key_count; ++i)
     126             :         {
     127             :             /* Nulls in the array are ignored, cf hstoreArrayToPairs */
     128          16 :             if (key_nulls[i])
     129           0 :                 continue;
     130          16 :             item = makeitem(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ, KEYFLAG);
     131          16 :             entries[j++] = PointerGetDatum(item);
     132             :         }
     133             : 
     134           8 :         *nentries = j;
     135             :         /* ExistsAll with no keys should match everything */
     136           8 :         if (j == 0 && strategy == HStoreExistsAllStrategyNumber)
     137           0 :             *searchMode = GIN_SEARCH_MODE_ALL;
     138             :     }
     139             :     else
     140             :     {
     141           0 :         elog(ERROR, "unrecognized strategy number: %d", strategy);
     142             :         entries = NULL;         /* keep compiler quiet */
     143             :     }
     144             : 
     145          24 :     PG_RETURN_POINTER(entries);
     146             : }
     147             : 
     148          16 : PG_FUNCTION_INFO_V1(gin_consistent_hstore);
     149             : 
     150             : Datum
     151        1910 : gin_consistent_hstore(PG_FUNCTION_ARGS)
     152             : {
     153        1910 :     bool       *check = (bool *) PG_GETARG_POINTER(0);
     154        1910 :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     155             : 
     156             :     /* HStore      *query = PG_GETARG_HSTORE_P(2); */
     157        1910 :     int32       nkeys = PG_GETARG_INT32(3);
     158             : 
     159             :     /* Pointer     *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
     160        1910 :     bool       *recheck = (bool *) PG_GETARG_POINTER(5);
     161        1910 :     bool        res = true;
     162             :     int32       i;
     163             : 
     164        1910 :     if (strategy == HStoreContainsStrategyNumber)
     165             :     {
     166             :         /*
     167             :          * Index doesn't have information about correspondence of keys and
     168             :          * values, so we need recheck.  However, if not all the keys are
     169             :          * present, we can fail at once.
     170             :          */
     171         470 :         *recheck = true;
     172         750 :         for (i = 0; i < nkeys; i++)
     173             :         {
     174         678 :             if (!check[i])
     175             :             {
     176         398 :                 res = false;
     177         398 :                 break;
     178             :             }
     179             :         }
     180             :     }
     181        1440 :     else if (strategy == HStoreExistsStrategyNumber)
     182             :     {
     183             :         /* Existence of key is guaranteed in default search mode */
     184         388 :         *recheck = false;
     185         388 :         res = true;
     186             :     }
     187        1052 :     else if (strategy == HStoreExistsAnyStrategyNumber)
     188             :     {
     189             :         /* Existence of key is guaranteed in default search mode */
     190         678 :         *recheck = false;
     191         678 :         res = true;
     192             :     }
     193         374 :     else if (strategy == HStoreExistsAllStrategyNumber)
     194             :     {
     195             :         /* Testing for all the keys being present gives an exact result */
     196         374 :         *recheck = false;
     197         544 :         for (i = 0; i < nkeys; i++)
     198             :         {
     199         460 :             if (!check[i])
     200             :             {
     201         290 :                 res = false;
     202         290 :                 break;
     203             :             }
     204             :         }
     205             :     }
     206             :     else
     207           0 :         elog(ERROR, "unrecognized strategy number: %d", strategy);
     208             : 
     209        1910 :     PG_RETURN_BOOL(res);
     210             : }

Generated by: LCOV version 1.14