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

Generated by: LCOV version 1.13