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

Generated by: LCOV version 1.13