LCOV - code coverage report
Current view: top level - src/backend/access/gin - ginarrayproc.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 35.9 % 142 51
Test Date: 2026-01-26 10:56:24 Functions: 40.0 % 5 2
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 10.7 % 75 8

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

Generated by: LCOV version 2.3.2-1