LCOV - code coverage report
Current view: top level - src/backend/access/gin - ginarrayproc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 87 119 73.1 %
Date: 2024-02-28 22:11:00 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-2024, 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     1056214 : ginarrayextract(PG_FUNCTION_ARGS)
      34             : {
      35             :     /* Make copy of array input to ensure it doesn't disappear while in use */
      36     1056214 :     ArrayType  *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
      37     1056214 :     int32      *nkeys = (int32 *) PG_GETARG_POINTER(1);
      38     1056214 :     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     1056214 :     get_typlenbyvalalign(ARR_ELEMTYPE(array),
      47             :                          &elmlen, &elmbyval, &elmalign);
      48             : 
      49     1056214 :     deconstruct_array(array,
      50             :                       ARR_ELEMTYPE(array),
      51             :                       elmlen, elmbyval, elmalign,
      52             :                       &elems, &nulls, &nelems);
      53             : 
      54     1056214 :     *nkeys = nelems;
      55     1056214 :     *nullFlags = nulls;
      56             : 
      57             :     /* we should not free array, elems[i] points into it */
      58     1056214 :     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        1312 : ginqueryarrayextract(PG_FUNCTION_ARGS)
      80             : {
      81             :     /* Make copy of array input to ensure it doesn't disappear while in use */
      82        1312 :     ArrayType  *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
      83        1312 :     int32      *nkeys = (int32 *) PG_GETARG_POINTER(1);
      84        1312 :     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        1312 :     bool      **nullFlags = (bool **) PG_GETARG_POINTER(5);
      89        1312 :     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        1312 :     get_typlenbyvalalign(ARR_ELEMTYPE(array),
      98             :                          &elmlen, &elmbyval, &elmalign);
      99             : 
     100        1312 :     deconstruct_array(array,
     101             :                       ARR_ELEMTYPE(array),
     102             :                       elmlen, elmbyval, elmalign,
     103             :                       &elems, &nulls, &nelems);
     104             : 
     105        1312 :     *nkeys = nelems;
     106        1312 :     *nullFlags = nulls;
     107             : 
     108        1312 :     switch (strategy)
     109             :     {
     110         144 :         case GinOverlapStrategy:
     111         144 :             *searchMode = GIN_SEARCH_MODE_DEFAULT;
     112         144 :             break;
     113        1060 :         case GinContainsStrategy:
     114        1060 :             if (nelems > 0)
     115         676 :                 *searchMode = GIN_SEARCH_MODE_DEFAULT;
     116             :             else                /* everything contains the empty set */
     117         384 :                 *searchMode = GIN_SEARCH_MODE_ALL;
     118        1060 :             break;
     119          48 :         case GinContainedStrategy:
     120             :             /* empty set is contained in everything */
     121          48 :             *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
     122          48 :             break;
     123          60 :         case GinEqualStrategy:
     124          60 :             if (nelems > 0)
     125          24 :                 *searchMode = GIN_SEARCH_MODE_DEFAULT;
     126             :             else
     127          36 :                 *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
     128          60 :             break;
     129           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        1312 :     PG_RETURN_POINTER(elems);
     136             : }
     137             : 
     138             : /*
     139             :  * consistent support function
     140             :  */
     141             : Datum
     142         810 : ginarrayconsistent(PG_FUNCTION_ARGS)
     143             : {
     144         810 :     bool       *check = (bool *) PG_GETARG_POINTER(0);
     145         810 :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     146             : 
     147             :     /* ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2); */
     148         810 :     int32       nkeys = PG_GETARG_INT32(3);
     149             : 
     150             :     /* Pointer     *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
     151         810 :     bool       *recheck = (bool *) PG_GETARG_POINTER(5);
     152             : 
     153             :     /* Datum       *queryKeys = (Datum *) PG_GETARG_POINTER(6); */
     154         810 :     bool       *nullFlags = (bool *) PG_GETARG_POINTER(7);
     155             :     bool        res;
     156             :     int32       i;
     157             : 
     158         810 :     switch (strategy)
     159             :     {
     160           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         810 :         case GinContainsStrategy:
     175             :             /* result is not lossy */
     176         810 :             *recheck = false;
     177             :             /* must have all elements in check[] true, and no nulls */
     178         810 :             res = true;
     179        1110 :             for (i = 0; i < nkeys; i++)
     180             :             {
     181         300 :                 if (!check[i] || nullFlags[i])
     182             :                 {
     183           0 :                     res = false;
     184           0 :                     break;
     185             :                 }
     186             :             }
     187         810 :             break;
     188           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         810 :     PG_RETURN_BOOL(res);
     220             : }
     221             : 
     222             : /*
     223             :  * triconsistent support function
     224             :  */
     225             : Datum
     226      805352 : ginarraytriconsistent(PG_FUNCTION_ARGS)
     227             : {
     228      805352 :     GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
     229      805352 :     StrategyNumber strategy = PG_GETARG_UINT16(1);
     230             : 
     231             :     /* ArrayType  *query = PG_GETARG_ARRAYTYPE_P(2); */
     232      805352 :     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      805352 :     bool       *nullFlags = (bool *) PG_GETARG_POINTER(6);
     237             :     GinTernaryValue res;
     238             :     int32       i;
     239             : 
     240      805352 :     switch (strategy)
     241             :     {
     242         372 :         case GinOverlapStrategy:
     243             :             /* must have a match for at least one non-null element */
     244         372 :             res = GIN_FALSE;
     245         438 :             for (i = 0; i < nkeys; i++)
     246             :             {
     247         426 :                 if (!nullFlags[i])
     248             :                 {
     249         426 :                     if (check[i] == GIN_TRUE)
     250             :                     {
     251         360 :                         res = GIN_TRUE;
     252         360 :                         break;
     253             :                     }
     254          66 :                     else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
     255             :                     {
     256          12 :                         res = GIN_MAYBE;
     257             :                     }
     258             :                 }
     259             :             }
     260         372 :             break;
     261      804572 :         case GinContainsStrategy:
     262             :             /* must have all elements in check[] true, and no nulls */
     263      804572 :             res = GIN_TRUE;
     264     1487884 :             for (i = 0; i < nkeys; i++)
     265             :             {
     266      683360 :                 if (check[i] == GIN_FALSE || nullFlags[i])
     267             :                 {
     268          48 :                     res = GIN_FALSE;
     269          48 :                     break;
     270             :                 }
     271      683312 :                 if (check[i] == GIN_MAYBE)
     272             :                 {
     273          12 :                     res = GIN_MAYBE;
     274             :                 }
     275             :             }
     276      804572 :             break;
     277         336 :         case GinContainedStrategy:
     278             :             /* can't do anything else useful here */
     279         336 :             res = GIN_MAYBE;
     280         336 :             break;
     281          72 :         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          72 :             res = GIN_MAYBE;
     289         132 :             for (i = 0; i < nkeys; i++)
     290             :             {
     291         102 :                 if (check[i] == GIN_FALSE)
     292             :                 {
     293          42 :                     res = GIN_FALSE;
     294          42 :                     break;
     295             :                 }
     296             :             }
     297          72 :             break;
     298           0 :         default:
     299           0 :             elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
     300             :                  strategy);
     301             :             res = false;
     302             :     }
     303             : 
     304      805352 :     PG_RETURN_GIN_TERNARY_VALUE(res);
     305             : }

Generated by: LCOV version 1.14