LCOV - differential code coverage report
Current view: top level - src/backend/access/gin - ginarrayproc.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 73.1 % 119 87 32 87
Current Date: 2023-04-08 15:15:32 Functions: 80.0 % 5 4 1 4
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, 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/builtins.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 CBC      528039 : ginarrayextract(PG_FUNCTION_ARGS)
      34                 : {
      35                 :     /* Make copy of array input to ensure it doesn't disappear while in use */
      36          528039 :     ArrayType  *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
      37          528039 :     int32      *nkeys = (int32 *) PG_GETARG_POINTER(1);
      38          528039 :     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          528039 :     get_typlenbyvalalign(ARR_ELEMTYPE(array),
      47                 :                          &elmlen, &elmbyval, &elmalign);
      48                 : 
      49          528039 :     deconstruct_array(array,
      50                 :                       ARR_ELEMTYPE(array),
      51                 :                       elmlen, elmbyval, elmalign,
      52                 :                       &elems, &nulls, &nelems);
      53                 : 
      54          528039 :     *nkeys = nelems;
      55          528039 :     *nullFlags = nulls;
      56                 : 
      57                 :     /* we should not free array, elems[i] points into it */
      58          528039 :     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 UBC           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 CBC         653 : ginqueryarrayextract(PG_FUNCTION_ARGS)
      80                 : {
      81                 :     /* Make copy of array input to ensure it doesn't disappear while in use */
      82             653 :     ArrayType  *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
      83             653 :     int32      *nkeys = (int32 *) PG_GETARG_POINTER(1);
      84             653 :     StrategyNumber strategy = PG_GETARG_UINT16(2);
      85                 : 
      86                 :     /* bool   **pmatch = (bool **) PG_GETARG_POINTER(3); */
      87                 :     /* Pointer     *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
      88             653 :     bool      **nullFlags = (bool **) PG_GETARG_POINTER(5);
      89             653 :     int32      *searchMode = (int32 *) PG_GETARG_POINTER(6);
      90                 :     int16       elmlen;
      91                 :     bool        elmbyval;
      92                 :     char        elmalign;
      93                 :     Datum      *elems;
      94                 :     bool       *nulls;
      95                 :     int         nelems;
      96                 : 
      97             653 :     get_typlenbyvalalign(ARR_ELEMTYPE(array),
      98                 :                          &elmlen, &elmbyval, &elmalign);
      99                 : 
     100             653 :     deconstruct_array(array,
     101                 :                       ARR_ELEMTYPE(array),
     102                 :                       elmlen, elmbyval, elmalign,
     103                 :                       &elems, &nulls, &nelems);
     104                 : 
     105             653 :     *nkeys = nelems;
     106             653 :     *nullFlags = nulls;
     107                 : 
     108             653 :     switch (strategy)
     109                 :     {
     110              72 :         case GinOverlapStrategy:
     111              72 :             *searchMode = GIN_SEARCH_MODE_DEFAULT;
     112              72 :             break;
     113             527 :         case GinContainsStrategy:
     114             527 :             if (nelems > 0)
     115             335 :                 *searchMode = GIN_SEARCH_MODE_DEFAULT;
     116                 :             else                /* everything contains the empty set */
     117             192 :                 *searchMode = GIN_SEARCH_MODE_ALL;
     118             527 :             break;
     119              24 :         case GinContainedStrategy:
     120                 :             /* empty set is contained in everything */
     121              24 :             *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
     122              24 :             break;
     123              30 :         case GinEqualStrategy:
     124              30 :             if (nelems > 0)
     125              12 :                 *searchMode = GIN_SEARCH_MODE_DEFAULT;
     126                 :             else
     127              18 :                 *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
     128              30 :             break;
     129 UBC           0 :         default:
     130               0 :             elog(ERROR, "ginqueryarrayextract: unknown strategy number: %d",
     131                 :                  strategy);
     132                 :     }
     133                 : 
     134                 :     /* we should not free array, elems[i] points into it */
     135 CBC         653 :     PG_RETURN_POINTER(elems);
     136                 : }
     137                 : 
     138                 : /*
     139                 :  * consistent support function
     140                 :  */
     141                 : Datum
     142             405 : ginarrayconsistent(PG_FUNCTION_ARGS)
     143                 : {
     144             405 :     bool       *check = (bool *) PG_GETARG_POINTER(0);
     145             405 :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     146                 : 
     147                 :     /* ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2); */
     148             405 :     int32       nkeys = PG_GETARG_INT32(3);
     149                 : 
     150                 :     /* Pointer     *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
     151             405 :     bool       *recheck = (bool *) PG_GETARG_POINTER(5);
     152                 : 
     153                 :     /* Datum       *queryKeys = (Datum *) PG_GETARG_POINTER(6); */
     154             405 :     bool       *nullFlags = (bool *) PG_GETARG_POINTER(7);
     155                 :     bool        res;
     156                 :     int32       i;
     157                 : 
     158             405 :     switch (strategy)
     159                 :     {
     160 UBC           0 :         case GinOverlapStrategy:
     161                 :             /* result is not lossy */
     162               0 :             *recheck = false;
     163                 :             /* must have a match for at least one non-null element */
     164               0 :             res = false;
     165               0 :             for (i = 0; i < nkeys; i++)
     166                 :             {
     167               0 :                 if (check[i] && !nullFlags[i])
     168                 :                 {
     169               0 :                     res = true;
     170               0 :                     break;
     171                 :                 }
     172                 :             }
     173               0 :             break;
     174 CBC         405 :         case GinContainsStrategy:
     175                 :             /* result is not lossy */
     176             405 :             *recheck = false;
     177                 :             /* must have all elements in check[] true, and no nulls */
     178             405 :             res = true;
     179             555 :             for (i = 0; i < nkeys; i++)
     180                 :             {
     181             150 :                 if (!check[i] || nullFlags[i])
     182                 :                 {
     183 UBC           0 :                     res = false;
     184               0 :                     break;
     185                 :                 }
     186                 :             }
     187 CBC         405 :             break;
     188 UBC           0 :         case GinContainedStrategy:
     189                 :             /* we will need recheck */
     190               0 :             *recheck = true;
     191                 :             /* can't do anything else useful here */
     192               0 :             res = true;
     193               0 :             break;
     194               0 :         case GinEqualStrategy:
     195                 :             /* we will need recheck */
     196               0 :             *recheck = true;
     197                 : 
     198                 :             /*
     199                 :              * Must have all elements in check[] true; no discrimination
     200                 :              * against nulls here.  This is because array_contain_compare and
     201                 :              * array_eq handle nulls differently ...
     202                 :              */
     203               0 :             res = true;
     204               0 :             for (i = 0; i < nkeys; i++)
     205                 :             {
     206               0 :                 if (!check[i])
     207                 :                 {
     208               0 :                     res = false;
     209               0 :                     break;
     210                 :                 }
     211                 :             }
     212               0 :             break;
     213               0 :         default:
     214               0 :             elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
     215                 :                  strategy);
     216                 :             res = false;
     217                 :     }
     218                 : 
     219 CBC         405 :     PG_RETURN_BOOL(res);
     220                 : }
     221                 : 
     222                 : /*
     223                 :  * triconsistent support function
     224                 :  */
     225                 : Datum
     226          402716 : ginarraytriconsistent(PG_FUNCTION_ARGS)
     227                 : {
     228          402716 :     GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
     229          402716 :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     230                 : 
     231                 :     /* ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2); */
     232          402716 :     int32       nkeys = PG_GETARG_INT32(3);
     233                 : 
     234                 :     /* Pointer     *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
     235                 :     /* Datum       *queryKeys = (Datum *) PG_GETARG_POINTER(5); */
     236          402716 :     bool       *nullFlags = (bool *) PG_GETARG_POINTER(6);
     237                 :     GinTernaryValue res;
     238                 :     int32       i;
     239                 : 
     240          402716 :     switch (strategy)
     241                 :     {
     242             186 :         case GinOverlapStrategy:
     243                 :             /* must have a match for at least one non-null element */
     244             186 :             res = GIN_FALSE;
     245             219 :             for (i = 0; i < nkeys; i++)
     246                 :             {
     247             213 :                 if (!nullFlags[i])
     248                 :                 {
     249             213 :                     if (check[i] == GIN_TRUE)
     250                 :                     {
     251             180 :                         res = GIN_TRUE;
     252             180 :                         break;
     253                 :                     }
     254              33 :                     else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
     255                 :                     {
     256               6 :                         res = GIN_MAYBE;
     257                 :                     }
     258                 :                 }
     259                 :             }
     260             186 :             break;
     261          402326 :         case GinContainsStrategy:
     262                 :             /* must have all elements in check[] true, and no nulls */
     263          402326 :             res = GIN_TRUE;
     264          744022 :             for (i = 0; i < nkeys; i++)
     265                 :             {
     266          341720 :                 if (check[i] == GIN_FALSE || nullFlags[i])
     267                 :                 {
     268              24 :                     res = GIN_FALSE;
     269              24 :                     break;
     270                 :                 }
     271          341696 :                 if (check[i] == GIN_MAYBE)
     272                 :                 {
     273               6 :                     res = GIN_MAYBE;
     274                 :                 }
     275                 :             }
     276          402326 :             break;
     277             168 :         case GinContainedStrategy:
     278                 :             /* can't do anything else useful here */
     279             168 :             res = GIN_MAYBE;
     280             168 :             break;
     281              36 :         case GinEqualStrategy:
     282                 : 
     283                 :             /*
     284                 :              * Must have all elements in check[] true; no discrimination
     285                 :              * against nulls here.  This is because array_contain_compare and
     286                 :              * array_eq handle nulls differently ...
     287                 :              */
     288              36 :             res = GIN_MAYBE;
     289              66 :             for (i = 0; i < nkeys; i++)
     290                 :             {
     291              51 :                 if (check[i] == GIN_FALSE)
     292                 :                 {
     293              21 :                     res = GIN_FALSE;
     294              21 :                     break;
     295                 :                 }
     296                 :             }
     297              36 :             break;
     298 UBC           0 :         default:
     299               0 :             elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
     300                 :                  strategy);
     301                 :             res = false;
     302                 :     }
     303                 : 
     304 CBC      402716 :     PG_RETURN_GIN_TERNARY_VALUE(res);
     305                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a