LCOV - code coverage report
Current view: top level - src/backend/access/gin - ginarrayproc.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 73.1 % 119 87
Test Date: 2026-03-01 19:14:57 Functions: 80.0 % 5 4
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * ginarrayproc.c
       4              :  *    support functions for GIN's indexing of any array
       5              :  *
       6              :  *
       7              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       8              :  * Portions Copyright (c) 1994, Regents of the University of California
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/backend/access/gin/ginarrayproc.c
      12              :  *-------------------------------------------------------------------------
      13              :  */
      14              : #include "postgres.h"
      15              : 
      16              : #include "access/gin.h"
      17              : #include "access/stratnum.h"
      18              : #include "utils/array.h"
      19              : #include "utils/fmgrprotos.h"
      20              : #include "utils/lsyscache.h"
      21              : 
      22              : 
      23              : #define GinOverlapStrategy      1
      24              : #define GinContainsStrategy     2
      25              : #define GinContainedStrategy    3
      26              : #define GinEqualStrategy        4
      27              : 
      28              : 
      29              : /*
      30              :  * extractValue support function
      31              :  */
      32              : Datum
      33       569364 : ginarrayextract(PG_FUNCTION_ARGS)
      34              : {
      35              :     /* Make copy of array input to ensure it doesn't disappear while in use */
      36       569364 :     ArrayType  *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
      37       569364 :     int32      *nkeys = (int32 *) PG_GETARG_POINTER(1);
      38       569364 :     bool      **nullFlags = (bool **) PG_GETARG_POINTER(2);
      39              :     int16       elmlen;
      40              :     bool        elmbyval;
      41              :     char        elmalign;
      42              :     Datum      *elems;
      43              :     bool       *nulls;
      44              :     int         nelems;
      45              : 
      46       569364 :     get_typlenbyvalalign(ARR_ELEMTYPE(array),
      47              :                          &elmlen, &elmbyval, &elmalign);
      48              : 
      49       569364 :     deconstruct_array(array,
      50              :                       ARR_ELEMTYPE(array),
      51              :                       elmlen, elmbyval, elmalign,
      52              :                       &elems, &nulls, &nelems);
      53              : 
      54       569364 :     *nkeys = nelems;
      55       569364 :     *nullFlags = nulls;
      56              : 
      57              :     /* we should not free array, elems[i] points into it */
      58       569364 :     PG_RETURN_POINTER(elems);
      59              : }
      60              : 
      61              : /*
      62              :  * Formerly, ginarrayextract had only two arguments.  Now it has three,
      63              :  * but we still need a pg_proc entry with two args to support reloading
      64              :  * pre-9.1 contrib/intarray opclass declarations.  This compatibility
      65              :  * function should go away eventually.
      66              :  */
      67              : Datum
      68            0 : ginarrayextract_2args(PG_FUNCTION_ARGS)
      69              : {
      70            0 :     if (PG_NARGS() < 3)          /* should not happen */
      71            0 :         elog(ERROR, "ginarrayextract requires three arguments");
      72            0 :     return ginarrayextract(fcinfo);
      73              : }
      74              : 
      75              : /*
      76              :  * extractQuery support function
      77              :  */
      78              : Datum
      79          666 : ginqueryarrayextract(PG_FUNCTION_ARGS)
      80              : {
      81              :     /* Make copy of array input to ensure it doesn't disappear while in use */
      82          666 :     ArrayType  *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
      83          666 :     int32      *nkeys = (int32 *) PG_GETARG_POINTER(1);
      84          666 :     StrategyNumber strategy = PG_GETARG_UINT16(2);
      85              : #ifdef NOT_USED
      86              :     bool      **pmatch = (bool **) PG_GETARG_POINTER(3);
      87              :     Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4);
      88              : #endif
      89          666 :     bool      **nullFlags = (bool **) PG_GETARG_POINTER(5);
      90          666 :     int32      *searchMode = (int32 *) PG_GETARG_POINTER(6);
      91              :     int16       elmlen;
      92              :     bool        elmbyval;
      93              :     char        elmalign;
      94              :     Datum      *elems;
      95              :     bool       *nulls;
      96              :     int         nelems;
      97              : 
      98          666 :     get_typlenbyvalalign(ARR_ELEMTYPE(array),
      99              :                          &elmlen, &elmbyval, &elmalign);
     100              : 
     101          666 :     deconstruct_array(array,
     102              :                       ARR_ELEMTYPE(array),
     103              :                       elmlen, elmbyval, elmalign,
     104              :                       &elems, &nulls, &nelems);
     105              : 
     106          666 :     *nkeys = nelems;
     107          666 :     *nullFlags = nulls;
     108              : 
     109          666 :     switch (strategy)
     110              :     {
     111           82 :         case GinOverlapStrategy:
     112           82 :             *searchMode = GIN_SEARCH_MODE_DEFAULT;
     113           82 :             break;
     114          530 :         case GinContainsStrategy:
     115          530 :             if (nelems > 0)
     116          338 :                 *searchMode = GIN_SEARCH_MODE_DEFAULT;
     117              :             else                /* everything contains the empty set */
     118          192 :                 *searchMode = GIN_SEARCH_MODE_ALL;
     119          530 :             break;
     120           24 :         case GinContainedStrategy:
     121              :             /* empty set is contained in everything */
     122           24 :             *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
     123           24 :             break;
     124           30 :         case GinEqualStrategy:
     125           30 :             if (nelems > 0)
     126           12 :                 *searchMode = GIN_SEARCH_MODE_DEFAULT;
     127              :             else
     128           18 :                 *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
     129           30 :             break;
     130            0 :         default:
     131            0 :             elog(ERROR, "ginqueryarrayextract: unknown strategy number: %d",
     132              :                  strategy);
     133              :     }
     134              : 
     135              :     /* we should not free array, elems[i] points into it */
     136          666 :     PG_RETURN_POINTER(elems);
     137              : }
     138              : 
     139              : /*
     140              :  * consistent support function
     141              :  */
     142              : Datum
     143          405 : ginarrayconsistent(PG_FUNCTION_ARGS)
     144              : {
     145          405 :     bool       *check = (bool *) PG_GETARG_POINTER(0);
     146          405 :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     147              : #ifdef NOT_USED
     148              :     ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2);
     149              : #endif
     150          405 :     int32       nkeys = PG_GETARG_INT32(3);
     151              : #ifdef NOT_USED
     152              :     Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4);
     153              : #endif
     154          405 :     bool       *recheck = (bool *) PG_GETARG_POINTER(5);
     155              : #ifdef NOT_USED
     156              :     Datum      *queryKeys = (Datum *) PG_GETARG_POINTER(6);
     157              : #endif
     158          405 :     bool       *nullFlags = (bool *) PG_GETARG_POINTER(7);
     159              :     bool        res;
     160              :     int32       i;
     161              : 
     162          405 :     switch (strategy)
     163              :     {
     164            0 :         case GinOverlapStrategy:
     165              :             /* result is not lossy */
     166            0 :             *recheck = false;
     167              :             /* must have a match for at least one non-null element */
     168            0 :             res = false;
     169            0 :             for (i = 0; i < nkeys; i++)
     170              :             {
     171            0 :                 if (check[i] && !nullFlags[i])
     172              :                 {
     173            0 :                     res = true;
     174            0 :                     break;
     175              :                 }
     176              :             }
     177            0 :             break;
     178          405 :         case GinContainsStrategy:
     179              :             /* result is not lossy */
     180          405 :             *recheck = false;
     181              :             /* must have all elements in check[] true, and no nulls */
     182          405 :             res = true;
     183          555 :             for (i = 0; i < nkeys; i++)
     184              :             {
     185          150 :                 if (!check[i] || nullFlags[i])
     186              :                 {
     187            0 :                     res = false;
     188            0 :                     break;
     189              :                 }
     190              :             }
     191          405 :             break;
     192            0 :         case GinContainedStrategy:
     193              :             /* we will need recheck */
     194            0 :             *recheck = true;
     195              :             /* can't do anything else useful here */
     196            0 :             res = true;
     197            0 :             break;
     198            0 :         case GinEqualStrategy:
     199              :             /* we will need recheck */
     200            0 :             *recheck = true;
     201              : 
     202              :             /*
     203              :              * Must have all elements in check[] true; no discrimination
     204              :              * against nulls here.  This is because array_contain_compare and
     205              :              * array_eq handle nulls differently ...
     206              :              */
     207            0 :             res = true;
     208            0 :             for (i = 0; i < nkeys; i++)
     209              :             {
     210            0 :                 if (!check[i])
     211              :                 {
     212            0 :                     res = false;
     213            0 :                     break;
     214              :                 }
     215              :             }
     216            0 :             break;
     217            0 :         default:
     218            0 :             elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
     219              :                  strategy);
     220              :             res = false;
     221              :     }
     222              : 
     223          405 :     PG_RETURN_BOOL(res);
     224              : }
     225              : 
     226              : /*
     227              :  * triconsistent support function
     228              :  */
     229              : Datum
     230       404295 : ginarraytriconsistent(PG_FUNCTION_ARGS)
     231              : {
     232       404295 :     GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
     233       404295 :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     234              : #ifdef NOT_USED
     235              :     ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2);
     236              : #endif
     237       404295 :     int32       nkeys = PG_GETARG_INT32(3);
     238              : #ifdef NOT_USED
     239              :     Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4);
     240              :     Datum      *queryKeys = (Datum *) PG_GETARG_POINTER(5);
     241              : #endif
     242       404295 :     bool       *nullFlags = (bool *) PG_GETARG_POINTER(6);
     243              :     GinTernaryValue res;
     244              :     int32       i;
     245              : 
     246       404295 :     switch (strategy)
     247              :     {
     248         1746 :         case GinOverlapStrategy:
     249              :             /* must have a match for at least one non-null element */
     250         1746 :             res = GIN_FALSE;
     251       461067 :             for (i = 0; i < nkeys; i++)
     252              :             {
     253       459566 :                 if (!nullFlags[i])
     254              :                 {
     255       459566 :                     if (check[i] == GIN_TRUE)
     256              :                     {
     257          245 :                         res = GIN_TRUE;
     258          245 :                         break;
     259              :                     }
     260       459321 :                     else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
     261              :                     {
     262         1501 :                         res = GIN_MAYBE;
     263              :                     }
     264              :                 }
     265              :             }
     266         1746 :             break;
     267       402345 :         case GinContainsStrategy:
     268              :             /* must have all elements in check[] true, and no nulls */
     269       402345 :             res = GIN_TRUE;
     270       744060 :             for (i = 0; i < nkeys; i++)
     271              :             {
     272       341739 :                 if (check[i] == GIN_FALSE || nullFlags[i])
     273              :                 {
     274           24 :                     res = GIN_FALSE;
     275           24 :                     break;
     276              :                 }
     277       341715 :                 if (check[i] == GIN_MAYBE)
     278              :                 {
     279            6 :                     res = GIN_MAYBE;
     280              :                 }
     281              :             }
     282       402345 :             break;
     283          168 :         case GinContainedStrategy:
     284              :             /* can't do anything else useful here */
     285          168 :             res = GIN_MAYBE;
     286          168 :             break;
     287           36 :         case GinEqualStrategy:
     288              : 
     289              :             /*
     290              :              * Must have all elements in check[] true; no discrimination
     291              :              * against nulls here.  This is because array_contain_compare and
     292              :              * array_eq handle nulls differently ...
     293              :              */
     294           36 :             res = GIN_MAYBE;
     295           66 :             for (i = 0; i < nkeys; i++)
     296              :             {
     297           51 :                 if (check[i] == GIN_FALSE)
     298              :                 {
     299           21 :                     res = GIN_FALSE;
     300           21 :                     break;
     301              :                 }
     302              :             }
     303           36 :             break;
     304            0 :         default:
     305            0 :             elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
     306              :                  strategy);
     307              :             res = false;
     308              :     }
     309              : 
     310       404295 :     PG_RETURN_GIN_TERNARY_VALUE(res);
     311              : }
        

Generated by: LCOV version 2.0-1