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-19 08:16:11 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       646861 : ginarrayextract(PG_FUNCTION_ARGS)
      34              : {
      35              :     /* Make copy of array input to ensure it doesn't disappear while in use */
      36       646861 :     ArrayType  *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
      37       646861 :     int32      *nkeys = (int32 *) PG_GETARG_POINTER(1);
      38       646861 :     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       646861 :     get_typlenbyvalalign(ARR_ELEMTYPE(array),
      47              :                          &elmlen, &elmbyval, &elmalign);
      48              : 
      49       646861 :     deconstruct_array(array,
      50              :                       ARR_ELEMTYPE(array),
      51              :                       elmlen, elmbyval, elmalign,
      52              :                       &elems, &nulls, &nelems);
      53              : 
      54       646861 :     *nkeys = nelems;
      55       646861 :     *nullFlags = nulls;
      56              : 
      57              :     /* we should not free array, elems[i] points into it */
      58       646861 :     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          977 : ginqueryarrayextract(PG_FUNCTION_ARGS)
      80              : {
      81              :     /* Make copy of array input to ensure it doesn't disappear while in use */
      82          977 :     ArrayType  *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
      83          977 :     int32      *nkeys = (int32 *) PG_GETARG_POINTER(1);
      84          977 :     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          977 :     bool      **nullFlags = (bool **) PG_GETARG_POINTER(5);
      90          977 :     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          977 :     get_typlenbyvalalign(ARR_ELEMTYPE(array),
      99              :                          &elmlen, &elmbyval, &elmalign);
     100              : 
     101          977 :     deconstruct_array(array,
     102              :                       ARR_ELEMTYPE(array),
     103              :                       elmlen, elmbyval, elmalign,
     104              :                       &elems, &nulls, &nelems);
     105              : 
     106          977 :     *nkeys = nelems;
     107          977 :     *nullFlags = nulls;
     108              : 
     109          977 :     switch (strategy)
     110              :     {
     111          118 :         case GinOverlapStrategy:
     112          118 :             *searchMode = GIN_SEARCH_MODE_DEFAULT;
     113          118 :             break;
     114          778 :         case GinContainsStrategy:
     115          778 :             if (nelems > 0)
     116          484 :                 *searchMode = GIN_SEARCH_MODE_DEFAULT;
     117              :             else                /* everything contains the empty set */
     118          294 :                 *searchMode = GIN_SEARCH_MODE_ALL;
     119          778 :             break;
     120           36 :         case GinContainedStrategy:
     121              :             /* empty set is contained in everything */
     122           36 :             *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
     123           36 :             break;
     124           45 :         case GinEqualStrategy:
     125           45 :             if (nelems > 0)
     126           18 :                 *searchMode = GIN_SEARCH_MODE_DEFAULT;
     127              :             else
     128           27 :                 *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
     129           45 :             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          977 :     PG_RETURN_POINTER(elems);
     137              : }
     138              : 
     139              : /*
     140              :  * consistent support function
     141              :  */
     142              : Datum
     143          540 : ginarrayconsistent(PG_FUNCTION_ARGS)
     144              : {
     145          540 :     bool       *check = (bool *) PG_GETARG_POINTER(0);
     146          540 :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     147              : #ifdef NOT_USED
     148              :     ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2);
     149              : #endif
     150          540 :     int32       nkeys = PG_GETARG_INT32(3);
     151              : #ifdef NOT_USED
     152              :     Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4);
     153              : #endif
     154          540 :     bool       *recheck = (bool *) PG_GETARG_POINTER(5);
     155              : #ifdef NOT_USED
     156              :     Datum      *queryKeys = (Datum *) PG_GETARG_POINTER(6);
     157              : #endif
     158          540 :     bool       *nullFlags = (bool *) PG_GETARG_POINTER(7);
     159              :     bool        res;
     160              :     int32       i;
     161              : 
     162          540 :     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          540 :         case GinContainsStrategy:
     179              :             /* result is not lossy */
     180          540 :             *recheck = false;
     181              :             /* must have all elements in check[] true, and no nulls */
     182          540 :             res = true;
     183          740 :             for (i = 0; i < nkeys; i++)
     184              :             {
     185          200 :                 if (!check[i] || nullFlags[i])
     186              :                 {
     187            0 :                     res = false;
     188            0 :                     break;
     189              :                 }
     190              :             }
     191          540 :             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          540 :     PG_RETURN_BOOL(res);
     224              : }
     225              : 
     226              : /*
     227              :  * triconsistent support function
     228              :  */
     229              : Datum
     230       508359 : ginarraytriconsistent(PG_FUNCTION_ARGS)
     231              : {
     232       508359 :     GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
     233       508359 :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     234              : #ifdef NOT_USED
     235              :     ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2);
     236              : #endif
     237       508359 :     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       508359 :     bool       *nullFlags = (bool *) PG_GETARG_POINTER(6);
     243              :     GinTernaryValue res;
     244              :     int32       i;
     245              : 
     246       508359 :     switch (strategy)
     247              :     {
     248         1808 :         case GinOverlapStrategy:
     249              :             /* must have a match for at least one non-null element */
     250         1808 :             res = GIN_FALSE;
     251       461140 :             for (i = 0; i < nkeys; i++)
     252              :             {
     253       459637 :                 if (!nullFlags[i])
     254              :                 {
     255       459637 :                     if (check[i] == GIN_TRUE)
     256              :                     {
     257          305 :                         res = GIN_TRUE;
     258          305 :                         break;
     259              :                     }
     260       459332 :                     else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
     261              :                     {
     262         1503 :                         res = GIN_MAYBE;
     263              :                     }
     264              :                 }
     265              :             }
     266         1808 :             break;
     267       506279 :         case GinContainsStrategy:
     268              :             /* must have all elements in check[] true, and no nulls */
     269       506279 :             res = GIN_TRUE;
     270       931718 :             for (i = 0; i < nkeys; i++)
     271              :             {
     272       425471 :                 if (check[i] == GIN_FALSE || nullFlags[i])
     273              :                 {
     274           32 :                     res = GIN_FALSE;
     275           32 :                     break;
     276              :                 }
     277       425439 :                 if (check[i] == GIN_MAYBE)
     278              :                 {
     279            8 :                     res = GIN_MAYBE;
     280              :                 }
     281              :             }
     282       506279 :             break;
     283          224 :         case GinContainedStrategy:
     284              :             /* can't do anything else useful here */
     285          224 :             res = GIN_MAYBE;
     286          224 :             break;
     287           48 :         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           48 :             res = GIN_MAYBE;
     295           88 :             for (i = 0; i < nkeys; i++)
     296              :             {
     297           68 :                 if (check[i] == GIN_FALSE)
     298              :                 {
     299           28 :                     res = GIN_FALSE;
     300           28 :                     break;
     301              :                 }
     302              :             }
     303           48 :             break;
     304            0 :         default:
     305            0 :             elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
     306              :                  strategy);
     307              :             res = false;
     308              :     }
     309              : 
     310       508359 :     PG_RETURN_GIN_TERNARY_VALUE(res);
     311              : }
        

Generated by: LCOV version 2.0-1