LCOV - code coverage report
Current view: top level - src/backend/access/gin - ginarrayproc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 87 119 73.1 %
Date: 2026-02-02 14:17:46 Functions: 4 5 80.0 %
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     1138728 : ginarrayextract(PG_FUNCTION_ARGS)
      34             : {
      35             :     /* Make copy of array input to ensure it doesn't disappear while in use */
      36     1138728 :     ArrayType  *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
      37     1138728 :     int32      *nkeys = (int32 *) PG_GETARG_POINTER(1);
      38     1138728 :     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     1138728 :     get_typlenbyvalalign(ARR_ELEMTYPE(array),
      47             :                          &elmlen, &elmbyval, &elmalign);
      48             : 
      49     1138728 :     deconstruct_array(array,
      50             :                       ARR_ELEMTYPE(array),
      51             :                       elmlen, elmbyval, elmalign,
      52             :                       &elems, &nulls, &nelems);
      53             : 
      54     1138728 :     *nkeys = nelems;
      55     1138728 :     *nullFlags = nulls;
      56             : 
      57             :     /* we should not free array, elems[i] points into it */
      58     1138728 :     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        1332 : ginqueryarrayextract(PG_FUNCTION_ARGS)
      80             : {
      81             :     /* Make copy of array input to ensure it doesn't disappear while in use */
      82        1332 :     ArrayType  *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
      83        1332 :     int32      *nkeys = (int32 *) PG_GETARG_POINTER(1);
      84        1332 :     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        1332 :     bool      **nullFlags = (bool **) PG_GETARG_POINTER(5);
      90        1332 :     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        1332 :     get_typlenbyvalalign(ARR_ELEMTYPE(array),
      99             :                          &elmlen, &elmbyval, &elmalign);
     100             : 
     101        1332 :     deconstruct_array(array,
     102             :                       ARR_ELEMTYPE(array),
     103             :                       elmlen, elmbyval, elmalign,
     104             :                       &elems, &nulls, &nelems);
     105             : 
     106        1332 :     *nkeys = nelems;
     107        1332 :     *nullFlags = nulls;
     108             : 
     109        1332 :     switch (strategy)
     110             :     {
     111         164 :         case GinOverlapStrategy:
     112         164 :             *searchMode = GIN_SEARCH_MODE_DEFAULT;
     113         164 :             break;
     114        1060 :         case GinContainsStrategy:
     115        1060 :             if (nelems > 0)
     116         676 :                 *searchMode = GIN_SEARCH_MODE_DEFAULT;
     117             :             else                /* everything contains the empty set */
     118         384 :                 *searchMode = GIN_SEARCH_MODE_ALL;
     119        1060 :             break;
     120          48 :         case GinContainedStrategy:
     121             :             /* empty set is contained in everything */
     122          48 :             *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
     123          48 :             break;
     124          60 :         case GinEqualStrategy:
     125          60 :             if (nelems > 0)
     126          24 :                 *searchMode = GIN_SEARCH_MODE_DEFAULT;
     127             :             else
     128          36 :                 *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
     129          60 :             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        1332 :     PG_RETURN_POINTER(elems);
     137             : }
     138             : 
     139             : /*
     140             :  * consistent support function
     141             :  */
     142             : Datum
     143         810 : ginarrayconsistent(PG_FUNCTION_ARGS)
     144             : {
     145         810 :     bool       *check = (bool *) PG_GETARG_POINTER(0);
     146         810 :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     147             : #ifdef NOT_USED
     148             :     ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2);
     149             : #endif
     150         810 :     int32       nkeys = PG_GETARG_INT32(3);
     151             : #ifdef NOT_USED
     152             :     Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4);
     153             : #endif
     154         810 :     bool       *recheck = (bool *) PG_GETARG_POINTER(5);
     155             : #ifdef NOT_USED
     156             :     Datum      *queryKeys = (Datum *) PG_GETARG_POINTER(6);
     157             : #endif
     158         810 :     bool       *nullFlags = (bool *) PG_GETARG_POINTER(7);
     159             :     bool        res;
     160             :     int32       i;
     161             : 
     162         810 :     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         810 :         case GinContainsStrategy:
     179             :             /* result is not lossy */
     180         810 :             *recheck = false;
     181             :             /* must have all elements in check[] true, and no nulls */
     182         810 :             res = true;
     183        1110 :             for (i = 0; i < nkeys; i++)
     184             :             {
     185         300 :                 if (!check[i] || nullFlags[i])
     186             :                 {
     187           0 :                     res = false;
     188           0 :                     break;
     189             :                 }
     190             :             }
     191         810 :             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         810 :     PG_RETURN_BOOL(res);
     224             : }
     225             : 
     226             : /*
     227             :  * triconsistent support function
     228             :  */
     229             : Datum
     230      808474 : ginarraytriconsistent(PG_FUNCTION_ARGS)
     231             : {
     232      808474 :     GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
     233      808474 :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     234             : #ifdef NOT_USED
     235             :     ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2);
     236             : #endif
     237      808474 :     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      808474 :     bool       *nullFlags = (bool *) PG_GETARG_POINTER(6);
     243             :     GinTernaryValue res;
     244             :     int32       i;
     245             : 
     246      808474 :     switch (strategy)
     247             :     {
     248        3492 :         case GinOverlapStrategy:
     249             :             /* must have a match for at least one non-null element */
     250        3492 :             res = GIN_FALSE;
     251      922134 :             for (i = 0; i < nkeys; i++)
     252             :             {
     253      919132 :                 if (!nullFlags[i])
     254             :                 {
     255      919132 :                     if (check[i] == GIN_TRUE)
     256             :                     {
     257         490 :                         res = GIN_TRUE;
     258         490 :                         break;
     259             :                     }
     260      918642 :                     else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
     261             :                     {
     262        3002 :                         res = GIN_MAYBE;
     263             :                     }
     264             :                 }
     265             :             }
     266        3492 :             break;
     267      804574 :         case GinContainsStrategy:
     268             :             /* must have all elements in check[] true, and no nulls */
     269      804574 :             res = GIN_TRUE;
     270     1487888 :             for (i = 0; i < nkeys; i++)
     271             :             {
     272      683362 :                 if (check[i] == GIN_FALSE || nullFlags[i])
     273             :                 {
     274          48 :                     res = GIN_FALSE;
     275          48 :                     break;
     276             :                 }
     277      683314 :                 if (check[i] == GIN_MAYBE)
     278             :                 {
     279          12 :                     res = GIN_MAYBE;
     280             :                 }
     281             :             }
     282      804574 :             break;
     283         336 :         case GinContainedStrategy:
     284             :             /* can't do anything else useful here */
     285         336 :             res = GIN_MAYBE;
     286         336 :             break;
     287          72 :         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          72 :             res = GIN_MAYBE;
     295         132 :             for (i = 0; i < nkeys; i++)
     296             :             {
     297         102 :                 if (check[i] == GIN_FALSE)
     298             :                 {
     299          42 :                     res = GIN_FALSE;
     300          42 :                     break;
     301             :                 }
     302             :             }
     303          72 :             break;
     304           0 :         default:
     305           0 :             elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
     306             :                  strategy);
     307             :             res = false;
     308             :     }
     309             : 
     310      808474 :     PG_RETURN_GIN_TERNARY_VALUE(res);
     311             : }

Generated by: LCOV version 1.16