LCOV - code coverage report
Current view: top level - src/backend/access/index - amvalidate.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 85 93 91.4 %
Date: 2020-05-25 03:07:04 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * amvalidate.c
       4             :  *    Support routines for index access methods' amvalidate functions.
       5             :  *
       6             :  * Copyright (c) 2016-2020, PostgreSQL Global Development Group
       7             :  *
       8             :  *
       9             :  * IDENTIFICATION
      10             :  *    src/backend/access/index/amvalidate.c
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : #include "postgres.h"
      15             : 
      16             : #include "access/amvalidate.h"
      17             : #include "access/htup_details.h"
      18             : #include "catalog/pg_am.h"
      19             : #include "catalog/pg_amop.h"
      20             : #include "catalog/pg_amproc.h"
      21             : #include "catalog/pg_opclass.h"
      22             : #include "catalog/pg_operator.h"
      23             : #include "catalog/pg_proc.h"
      24             : #include "catalog/pg_type.h"
      25             : #include "parser/parse_coerce.h"
      26             : #include "utils/syscache.h"
      27             : 
      28             : 
      29             : /*
      30             :  * identify_opfamily_groups() returns a List of OpFamilyOpFuncGroup structs,
      31             :  * one for each combination of lefttype/righttype present in the family's
      32             :  * operator and support function lists.  If amopstrategy K is present for
      33             :  * this datatype combination, we set bit 1 << K in operatorset, and similarly
      34             :  * for the support functions.  With uint64 fields we can handle operator and
      35             :  * function numbers up to 63, which is plenty for the foreseeable future.
      36             :  *
      37             :  * The given CatCLists are expected to represent a single opfamily fetched
      38             :  * from the AMOPSTRATEGY and AMPROCNUM caches, so that they will be in
      39             :  * order by those caches' second and third cache keys, namely the datatypes.
      40             :  */
      41             : List *
      42         702 : identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
      43             : {
      44         702 :     List       *result = NIL;
      45             :     OpFamilyOpFuncGroup *thisgroup;
      46             :     Form_pg_amop oprform;
      47             :     Form_pg_amproc procform;
      48             :     int         io,
      49             :                 ip;
      50             : 
      51             :     /* We need the lists to be ordered; should be true in normal operation */
      52         702 :     if (!oprlist->ordered || !proclist->ordered)
      53           0 :         elog(ERROR, "cannot validate operator family without ordered data");
      54             : 
      55             :     /*
      56             :      * Advance through the lists concurrently.  Thanks to the ordering, we
      57             :      * should see all operators and functions of a given datatype pair
      58             :      * consecutively.
      59             :      */
      60         702 :     thisgroup = NULL;
      61         702 :     io = ip = 0;
      62         702 :     if (io < oprlist->n_members)
      63             :     {
      64         702 :         oprform = (Form_pg_amop) GETSTRUCT(&oprlist->members[io]->tuple);
      65         702 :         io++;
      66             :     }
      67             :     else
      68           0 :         oprform = NULL;
      69         702 :     if (ip < proclist->n_members)
      70             :     {
      71         702 :         procform = (Form_pg_amproc) GETSTRUCT(&proclist->members[ip]->tuple);
      72         702 :         ip++;
      73             :     }
      74             :     else
      75           0 :         procform = NULL;
      76             : 
      77       16016 :     while (oprform || procform)
      78             :     {
      79       15314 :         if (oprform && thisgroup &&
      80       12264 :             oprform->amoplefttype == thisgroup->lefttype &&
      81       11304 :             oprform->amoprighttype == thisgroup->righttype)
      82             :         {
      83             :             /* Operator belongs to current group; include it and advance */
      84             : 
      85             :             /* Ignore strategy numbers outside supported range */
      86        8366 :             if (oprform->amopstrategy > 0 && oprform->amopstrategy < 64)
      87        8362 :                 thisgroup->operatorset |= ((uint64) 1) << oprform->amopstrategy;
      88             : 
      89        8366 :             if (io < oprlist->n_members)
      90             :             {
      91        7664 :                 oprform = (Form_pg_amop) GETSTRUCT(&oprlist->members[io]->tuple);
      92        7664 :                 io++;
      93             :             }
      94             :             else
      95         702 :                 oprform = NULL;
      96        8366 :             continue;
      97             :         }
      98             : 
      99        6948 :         if (procform && thisgroup &&
     100        6170 :             procform->amproclefttype == thisgroup->lefttype &&
     101        5558 :             procform->amprocrighttype == thisgroup->righttype)
     102             :         {
     103             :             /* Procedure belongs to current group; include it and advance */
     104             : 
     105             :             /* Ignore function numbers outside supported range */
     106        4578 :             if (procform->amprocnum > 0 && procform->amprocnum < 64)
     107        4578 :                 thisgroup->functionset |= ((uint64) 1) << procform->amprocnum;
     108             : 
     109        4578 :             if (ip < proclist->n_members)
     110             :             {
     111        3876 :                 procform = (Form_pg_amproc) GETSTRUCT(&proclist->members[ip]->tuple);
     112        3876 :                 ip++;
     113             :             }
     114             :             else
     115         702 :                 procform = NULL;
     116        4578 :             continue;
     117             :         }
     118             : 
     119             :         /* Time for a new group */
     120        2370 :         thisgroup = (OpFamilyOpFuncGroup *) palloc(sizeof(OpFamilyOpFuncGroup));
     121        2370 :         if (oprform &&
     122        2276 :             (!procform ||
     123        2276 :              (oprform->amoplefttype < procform->amproclefttype ||
     124        2056 :               (oprform->amoplefttype == procform->amproclefttype &&
     125        2028 :                oprform->amoprighttype < procform->amprocrighttype))))
     126             :         {
     127         568 :             thisgroup->lefttype = oprform->amoplefttype;
     128         568 :             thisgroup->righttype = oprform->amoprighttype;
     129             :         }
     130             :         else
     131             :         {
     132        1802 :             thisgroup->lefttype = procform->amproclefttype;
     133        1802 :             thisgroup->righttype = procform->amprocrighttype;
     134             :         }
     135        2370 :         thisgroup->operatorset = thisgroup->functionset = 0;
     136        2370 :         result = lappend(result, thisgroup);
     137             :     }
     138             : 
     139         702 :     return result;
     140             : }
     141             : 
     142             : /*
     143             :  * Validate the signature (argument and result types) of an opclass support
     144             :  * function.  Return true if OK, false if not.
     145             :  *
     146             :  * The "..." represents maxargs argument-type OIDs.  If "exact" is true, they
     147             :  * must match the function arg types exactly, else only binary-coercibly.
     148             :  * In any case the function result type must match restype exactly.
     149             :  */
     150             : bool
     151        4010 : check_amproc_signature(Oid funcid, Oid restype, bool exact,
     152             :                        int minargs, int maxargs,...)
     153             : {
     154        4010 :     bool        result = true;
     155             :     HeapTuple   tp;
     156             :     Form_pg_proc procform;
     157             :     va_list     ap;
     158             :     int         i;
     159             : 
     160        4010 :     tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
     161        4010 :     if (!HeapTupleIsValid(tp))
     162           0 :         elog(ERROR, "cache lookup failed for function %u", funcid);
     163        4010 :     procform = (Form_pg_proc) GETSTRUCT(tp);
     164             : 
     165        4010 :     if (procform->prorettype != restype || procform->proretset ||
     166        4010 :         procform->pronargs < minargs || procform->pronargs > maxargs)
     167           0 :         result = false;
     168             : 
     169        4010 :     va_start(ap, maxargs);
     170       14702 :     for (i = 0; i < maxargs; i++)
     171             :     {
     172       10692 :         Oid         argtype = va_arg(ap, Oid);
     173             : 
     174       10692 :         if (i >= procform->pronargs)
     175         302 :             continue;
     176       13258 :         if (exact ? (argtype != procform->proargtypes.values[i]) :
     177        2868 :             !IsBinaryCoercible(argtype, procform->proargtypes.values[i]))
     178           0 :             result = false;
     179             :     }
     180        4010 :     va_end(ap);
     181             : 
     182        4010 :     ReleaseSysCache(tp);
     183        4010 :     return result;
     184             : }
     185             : 
     186             : /*
     187             :  * Validate the signature of an opclass options support function, that should
     188             :  * be 'void(internal)'.
     189             :  */
     190             : bool
     191          16 : check_amoptsproc_signature(Oid funcid)
     192             : {
     193          16 :     return check_amproc_signature(funcid, VOIDOID, true, 1, 1, INTERNALOID);
     194             : }
     195             : 
     196             : /*
     197             :  * Validate the signature (argument and result types) of an opclass operator.
     198             :  * Return true if OK, false if not.
     199             :  *
     200             :  * Currently, we can hard-wire this as accepting only binary operators.  Also,
     201             :  * we can insist on exact type matches, since the given lefttype/righttype
     202             :  * come from pg_amop and should always match the operator exactly.
     203             :  */
     204             : bool
     205        8366 : check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
     206             : {
     207        8366 :     bool        result = true;
     208             :     HeapTuple   tp;
     209             :     Form_pg_operator opform;
     210             : 
     211        8366 :     tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
     212        8366 :     if (!HeapTupleIsValid(tp))  /* shouldn't happen */
     213           0 :         elog(ERROR, "cache lookup failed for operator %u", opno);
     214        8366 :     opform = (Form_pg_operator) GETSTRUCT(tp);
     215             : 
     216        8366 :     if (opform->oprresult != restype || opform->oprkind != 'b' ||
     217        8366 :         opform->oprleft != lefttype || opform->oprright != righttype)
     218           0 :         result = false;
     219             : 
     220        8366 :     ReleaseSysCache(tp);
     221        8366 :     return result;
     222             : }
     223             : 
     224             : /*
     225             :  * Is the datatype a legitimate input type for the btree opfamily?
     226             :  */
     227             : bool
     228          74 : opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
     229             : {
     230          74 :     bool        result = false;
     231             :     CatCList   *opclist;
     232             :     int         i;
     233             : 
     234             :     /*
     235             :      * We search through all btree opclasses to see if one matches.  This is a
     236             :      * bit inefficient but there is no better index available.  It also saves
     237             :      * making an explicit check that the opfamily belongs to btree.
     238             :      */
     239          74 :     opclist = SearchSysCacheList1(CLAAMNAMENSP, ObjectIdGetDatum(BTREE_AM_OID));
     240             : 
     241         994 :     for (i = 0; i < opclist->n_members; i++)
     242             :     {
     243         994 :         HeapTuple   classtup = &opclist->members[i]->tuple;
     244         994 :         Form_pg_opclass classform = (Form_pg_opclass) GETSTRUCT(classtup);
     245             : 
     246         994 :         if (classform->opcfamily == opfamilyoid &&
     247         128 :             classform->opcintype == datatypeoid)
     248             :         {
     249          74 :             result = true;
     250          74 :             break;
     251             :         }
     252             :     }
     253             : 
     254          74 :     ReleaseCatCacheList(opclist);
     255             : 
     256          74 :     return result;
     257             : }

Generated by: LCOV version 1.13