LCOV - code coverage report
Current view: top level - contrib/bloom - blvalidate.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 70.0 % 70 49
Test Date: 2026-07-21 22:15:42 Functions: 100.0 % 1 1
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 45.9 % 61 28

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * blvalidate.c
       4                 :             :  *    Opclass validator for bloom.
       5                 :             :  *
       6                 :             :  * Copyright (c) 2016-2026, PostgreSQL Global Development Group
       7                 :             :  *
       8                 :             :  * IDENTIFICATION
       9                 :             :  *    contrib/bloom/blvalidate.c
      10                 :             :  *
      11                 :             :  *-------------------------------------------------------------------------
      12                 :             :  */
      13                 :             : #include "postgres.h"
      14                 :             : 
      15                 :             : #include "access/amvalidate.h"
      16                 :             : #include "access/htup_details.h"
      17                 :             : #include "bloom.h"
      18                 :             : #include "catalog/pg_amop.h"
      19                 :             : #include "catalog/pg_amproc.h"
      20                 :             : #include "catalog/pg_opclass.h"
      21                 :             : #include "catalog/pg_type.h"
      22                 :             : #include "utils/lsyscache.h"
      23                 :             : #include "utils/regproc.h"
      24                 :             : #include "utils/syscache.h"
      25                 :             : 
      26                 :             : /*
      27                 :             :  * Validator for a bloom opclass.
      28                 :             :  */
      29                 :             : bool
      30                 :           2 : blvalidate(Oid opclassoid)
      31                 :             : {
      32                 :           2 :     bool        result = true;
      33                 :             :     HeapTuple   classtup;
      34                 :             :     Form_pg_opclass classform;
      35                 :             :     Oid         opfamilyoid;
      36                 :             :     Oid         opcintype;
      37                 :             :     Oid         opckeytype;
      38                 :             :     char       *opclassname;
      39                 :             :     char       *opfamilyname;
      40                 :             :     CatCList   *proclist,
      41                 :             :                *oprlist;
      42                 :             :     List       *grouplist;
      43                 :             :     OpFamilyOpFuncGroup *opclassgroup;
      44                 :             :     int         i;
      45                 :             :     ListCell   *lc;
      46                 :             : 
      47                 :             :     /* Fetch opclass information */
      48                 :           2 :     classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
      49         [ -  + ]:           2 :     if (!HeapTupleIsValid(classtup))
      50         [ #  # ]:           0 :         elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
      51                 :           2 :     classform = (Form_pg_opclass) GETSTRUCT(classtup);
      52                 :             : 
      53                 :           2 :     opfamilyoid = classform->opcfamily;
      54                 :           2 :     opcintype = classform->opcintype;
      55                 :           2 :     opckeytype = classform->opckeytype;
      56         [ +  - ]:           2 :     if (!OidIsValid(opckeytype))
      57                 :           2 :         opckeytype = opcintype;
      58                 :           2 :     opclassname = NameStr(classform->opcname);
      59                 :             : 
      60                 :             :     /* Fetch opfamily information */
      61                 :           2 :     opfamilyname = get_opfamily_name(opfamilyoid, false);
      62                 :             : 
      63                 :             :     /* Fetch all operators and support functions of the opfamily */
      64                 :           2 :     oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
      65                 :           2 :     proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
      66                 :             : 
      67                 :             :     /* Check individual support functions */
      68         [ +  + ]:           4 :     for (i = 0; i < proclist->n_members; i++)
      69                 :             :     {
      70                 :           2 :         HeapTuple   proctup = &proclist->members[i]->tuple;
      71                 :           2 :         Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
      72                 :             :         bool        ok;
      73                 :             : 
      74                 :             :         /*
      75                 :             :          * All bloom support functions should be registered with matching
      76                 :             :          * left/right types
      77                 :             :          */
      78         [ -  + ]:           2 :         if (procform->amproclefttype != procform->amprocrighttype)
      79                 :             :         {
      80         [ #  # ]:           0 :             ereport(INFO,
      81                 :             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
      82                 :             :                      errmsg("bloom opfamily %s contains support procedure %s with cross-type registration",
      83                 :             :                             opfamilyname,
      84                 :             :                             format_procedure(procform->amproc))));
      85                 :           0 :             result = false;
      86                 :             :         }
      87                 :             : 
      88                 :             :         /*
      89                 :             :          * We can't check signatures except within the specific opclass, since
      90                 :             :          * we need to know the associated opckeytype in many cases.
      91                 :             :          */
      92         [ -  + ]:           2 :         if (procform->amproclefttype != opcintype)
      93                 :           0 :             continue;
      94                 :             : 
      95                 :             :         /* Check procedure numbers and function signatures */
      96      [ +  -  - ]:           2 :         switch (procform->amprocnum)
      97                 :             :         {
      98                 :           2 :             case BLOOM_HASH_PROC:
      99                 :           2 :                 ok = check_amproc_signature(procform->amproc, INT4OID, false,
     100                 :             :                                             1, 1, opckeytype);
     101                 :           2 :                 break;
     102                 :           0 :             case BLOOM_OPTIONS_PROC:
     103                 :           0 :                 ok = check_amoptsproc_signature(procform->amproc);
     104                 :           0 :                 break;
     105                 :           0 :             default:
     106         [ #  # ]:           0 :                 ereport(INFO,
     107                 :             :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     108                 :             :                          errmsg("bloom opfamily %s contains function %s with invalid support number %d",
     109                 :             :                                 opfamilyname,
     110                 :             :                                 format_procedure(procform->amproc),
     111                 :             :                                 procform->amprocnum)));
     112                 :           0 :                 result = false;
     113                 :           0 :                 continue;       /* don't want additional message */
     114                 :             :         }
     115                 :             : 
     116         [ -  + ]:           2 :         if (!ok)
     117                 :             :         {
     118         [ #  # ]:           0 :             ereport(INFO,
     119                 :             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     120                 :             :                      errmsg("bloom opfamily %s contains function %s with wrong signature for support number %d",
     121                 :             :                             opfamilyname,
     122                 :             :                             format_procedure(procform->amproc),
     123                 :             :                             procform->amprocnum)));
     124                 :           0 :             result = false;
     125                 :             :         }
     126                 :             :     }
     127                 :             : 
     128                 :             :     /* Check individual operators */
     129         [ +  + ]:           4 :     for (i = 0; i < oprlist->n_members; i++)
     130                 :             :     {
     131                 :           2 :         HeapTuple   oprtup = &oprlist->members[i]->tuple;
     132                 :           2 :         Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
     133                 :             : 
     134                 :             :         /* Check it's allowed strategy for bloom */
     135         [ +  - ]:           2 :         if (oprform->amopstrategy < 1 ||
     136         [ -  + ]:           2 :             oprform->amopstrategy > BLOOM_NSTRATEGIES)
     137                 :             :         {
     138         [ #  # ]:           0 :             ereport(INFO,
     139                 :             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     140                 :             :                      errmsg("bloom opfamily %s contains operator %s with invalid strategy number %d",
     141                 :             :                             opfamilyname,
     142                 :             :                             format_operator(oprform->amopopr),
     143                 :             :                             oprform->amopstrategy)));
     144                 :           0 :             result = false;
     145                 :             :         }
     146                 :             : 
     147                 :             :         /* bloom doesn't support ORDER BY operators */
     148         [ +  - ]:           2 :         if (oprform->amoppurpose != AMOP_SEARCH ||
     149         [ -  + ]:           2 :             OidIsValid(oprform->amopsortfamily))
     150                 :             :         {
     151         [ #  # ]:           0 :             ereport(INFO,
     152                 :             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     153                 :             :                      errmsg("bloom opfamily %s contains invalid ORDER BY specification for operator %s",
     154                 :             :                             opfamilyname,
     155                 :             :                             format_operator(oprform->amopopr))));
     156                 :           0 :             result = false;
     157                 :             :         }
     158                 :             : 
     159                 :             :         /* Check operator signature --- same for all bloom strategies */
     160         [ -  + ]:           2 :         if (!check_amop_signature(oprform->amopopr, BOOLOID,
     161                 :             :                                   oprform->amoplefttype,
     162                 :             :                                   oprform->amoprighttype))
     163                 :             :         {
     164         [ #  # ]:           0 :             ereport(INFO,
     165                 :             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     166                 :             :                      errmsg("bloom opfamily %s contains operator %s with wrong signature",
     167                 :             :                             opfamilyname,
     168                 :             :                             format_operator(oprform->amopopr))));
     169                 :           0 :             result = false;
     170                 :             :         }
     171                 :             :     }
     172                 :             : 
     173                 :             :     /* Now check for inconsistent groups of operators/functions */
     174                 :           2 :     grouplist = identify_opfamily_groups(oprlist, proclist);
     175                 :           2 :     opclassgroup = NULL;
     176   [ +  -  +  +  :           4 :     foreach(lc, grouplist)
                   +  + ]
     177                 :             :     {
     178                 :           2 :         OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
     179                 :             : 
     180                 :             :         /* Remember the group exactly matching the test opclass */
     181         [ +  - ]:           2 :         if (thisgroup->lefttype == opcintype &&
     182         [ +  - ]:           2 :             thisgroup->righttype == opcintype)
     183                 :           2 :             opclassgroup = thisgroup;
     184                 :             : 
     185                 :             :         /*
     186                 :             :          * There is not a lot we can do to check the operator sets, since each
     187                 :             :          * bloom opclass is more or less a law unto itself, and some contain
     188                 :             :          * only operators that are binary-compatible with the opclass datatype
     189                 :             :          * (meaning that empty operator sets can be OK).  That case also means
     190                 :             :          * that we shouldn't insist on nonempty function sets except for the
     191                 :             :          * opclass's own group.
     192                 :             :          */
     193                 :             :     }
     194                 :             : 
     195                 :             :     /* Check that the originally-named opclass is complete */
     196         [ +  + ]:           6 :     for (i = 1; i <= BLOOM_NPROC; i++)
     197                 :             :     {
     198         [ +  - ]:           4 :         if (opclassgroup &&
     199         [ +  + ]:           4 :             (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
     200                 :           2 :             continue;           /* got it */
     201         [ +  - ]:           2 :         if (i == BLOOM_OPTIONS_PROC)
     202                 :           2 :             continue;           /* optional method */
     203         [ #  # ]:           0 :         ereport(INFO,
     204                 :             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     205                 :             :                  errmsg("bloom opclass %s is missing support function %d",
     206                 :             :                         opclassname, i)));
     207                 :           0 :         result = false;
     208                 :             :     }
     209                 :             : 
     210                 :           2 :     ReleaseCatCacheList(proclist);
     211                 :           2 :     ReleaseCatCacheList(oprlist);
     212                 :           2 :     ReleaseSysCache(classtup);
     213                 :             : 
     214                 :           2 :     return result;
     215                 :             : }
        

Generated by: LCOV version 2.0-1