LCOV - code coverage report
Current view: top level - src/backend/access/gin - ginarrayproc.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 73.1 % 119 87
Test Date: 2026-07-03 19:57:34 Functions: 80.0 % 5 4
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 55.2 % 67 37

             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                 :      646781 : ginarrayextract(PG_FUNCTION_ARGS)
      34                 :             : {
      35                 :             :     /* Make copy of array input to ensure it doesn't disappear while in use */
      36                 :      646781 :     ArrayType  *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
      37                 :      646781 :     int32      *nkeys = (int32 *) PG_GETARG_POINTER(1);
      38                 :      646781 :     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                 :      646781 :     get_typlenbyvalalign(ARR_ELEMTYPE(array),
      47                 :             :                          &elmlen, &elmbyval, &elmalign);
      48                 :             : 
      49                 :      646781 :     deconstruct_array(array,
      50                 :             :                       ARR_ELEMTYPE(array),
      51                 :             :                       elmlen, elmbyval, elmalign,
      52                 :             :                       &elems, &nulls, &nelems);
      53                 :             : 
      54                 :      646781 :     *nkeys = nelems;
      55                 :      646781 :     *nullFlags = nulls;
      56                 :             : 
      57                 :             :     /* we should not free array, elems[i] points into it */
      58                 :      646781 :     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                 :      508392 : ginarraytriconsistent(PG_FUNCTION_ARGS)
     231                 :             : {
     232                 :      508392 :     GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
     233                 :      508392 :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     234                 :             : #ifdef NOT_USED
     235                 :             :     ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2);
     236                 :             : #endif
     237                 :      508392 :     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                 :      508392 :     bool       *nullFlags = (bool *) PG_GETARG_POINTER(6);
     243                 :             :     GinTernaryValue res;
     244                 :             :     int32       i;
     245                 :             : 
     246   [ +  +  +  +  :      508392 :     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                 :      506312 :         case GinContainsStrategy:
     268                 :             :             /* must have all elements in check[] true, and no nulls */
     269                 :      506312 :             res = GIN_TRUE;
     270         [ +  + ]:      931784 :             for (i = 0; i < nkeys; i++)
     271                 :             :             {
     272   [ +  +  -  + ]:      425504 :                 if (check[i] == GIN_FALSE || nullFlags[i])
     273                 :             :                 {
     274                 :          32 :                     res = GIN_FALSE;
     275                 :          32 :                     break;
     276                 :             :                 }
     277         [ +  + ]:      425472 :                 if (check[i] == GIN_MAYBE)
     278                 :             :                 {
     279                 :           8 :                     res = GIN_MAYBE;
     280                 :             :                 }
     281                 :             :             }
     282                 :      506312 :             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                 :      508392 :     PG_RETURN_GIN_TERNARY_VALUE(res);
     311                 :             : }
        

Generated by: LCOV version 2.0-1