PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
hashvalidate.c File Reference
#include "postgres.h"
#include "access/amvalidate.h"
#include "access/hash.h"
#include "access/htup_details.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "parser/parse_coerce.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/regproc.h"
#include "utils/syscache.h"
Include dependency graph for hashvalidate.c:

Go to the source code of this file.

Functions

static bool check_hash_func_signature (Oid funcid, Oid restype, Oid argtype)
 
bool hashvalidate (Oid opclassoid)
 

Function Documentation

static bool check_hash_func_signature ( Oid  funcid,
Oid  restype,
Oid  argtype 
)
static

Definition at line 267 of file hashvalidate.c.

References ABSTIMEOID, BOOLOID, BYTEAOID, CIDOID, DATEOID, elog, ERROR, GETSTRUCT, HeapTupleIsValid, IsBinaryCoercible(), ObjectIdGetDatum, PROCOID, ReleaseSysCache(), RELTIMEOID, result, SearchSysCache1, TIMESTAMPTZOID, and XIDOID.

Referenced by hashvalidate().

268 {
269  bool result = true;
270  HeapTuple tp;
271  Form_pg_proc procform;
272 
274  if (!HeapTupleIsValid(tp))
275  elog(ERROR, "cache lookup failed for function %u", funcid);
276  procform = (Form_pg_proc) GETSTRUCT(tp);
277 
278  if (procform->prorettype != restype || procform->proretset ||
279  procform->pronargs != 1)
280  result = false;
281 
282  if (!IsBinaryCoercible(argtype, procform->proargtypes.values[0]))
283  {
284  /*
285  * Some of the built-in hash opclasses cheat by using hash functions
286  * that are different from but physically compatible with the opclass
287  * datatype. In some of these cases, even a "binary coercible" check
288  * fails because there's no relevant cast. For the moment, fix it by
289  * having a whitelist of allowed cases. Test the specific function
290  * identity, not just its input type, because hashvarlena() takes
291  * INTERNAL and allowing any such function seems too scary.
292  */
293  if (funcid == F_HASHINT4 &&
294  (argtype == DATEOID ||
295  argtype == ABSTIMEOID || argtype == RELTIMEOID ||
296  argtype == XIDOID || argtype == CIDOID))
297  /* okay, allowed use of hashint4() */ ;
298  else if (funcid == F_TIMESTAMP_HASH &&
299  argtype == TIMESTAMPTZOID)
300  /* okay, allowed use of timestamp_hash() */ ;
301  else if (funcid == F_HASHCHAR &&
302  argtype == BOOLOID)
303  /* okay, allowed use of hashchar() */ ;
304  else if (funcid == F_HASHVARLENA &&
305  argtype == BYTEAOID)
306  /* okay, allowed use of hashvarlena() */ ;
307  else
308  result = false;
309  }
310 
311  ReleaseSysCache(tp);
312  return result;
313 }
#define TIMESTAMPTZOID
Definition: pg_type.h:525
#define DATEOID
Definition: pg_type.h:511
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
return result
Definition: formatting.c:1633
#define XIDOID
Definition: pg_type.h:336
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
bool IsBinaryCoercible(Oid srctype, Oid targettype)
#define CIDOID
Definition: pg_type.h:340
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:83
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define BOOLOID
Definition: pg_type.h:288
#define BYTEAOID
Definition: pg_type.h:292
#define elog
Definition: elog.h:219
#define ABSTIMEOID
Definition: pg_type.h:422
#define RELTIMEOID
Definition: pg_type.h:425
bool hashvalidate ( Oid  opclassoid)

Definition at line 44 of file hashvalidate.c.

References AMOP_SEARCH, AMOPSTRATEGY, AMPROCNUM, BOOLOID, check_amop_signature(), check_hash_func_signature(), CLAOID, elog, ereport, errcode(), errmsg(), ERROR, format_operator(), format_procedure(), format_type_be(), GETSTRUCT, HASHPROC, HeapTupleIsValid, HTEqualStrategyNumber, HTMaxStrategyNumber, i, identify_opfamily_groups(), INFO, INT4OID, OpFamilyOpFuncGroup::lefttype, lfirst, list_append_unique_oid(), list_length(), list_member_oid(), catclist::members, catclist::n_members, NameStr, NIL, NULL, ObjectIdGetDatum, OidIsValid, OpFamilyOpFuncGroup::operatorset, OPFAMILYOID, ReleaseCatCacheList(), ReleaseSysCache(), result, OpFamilyOpFuncGroup::righttype, SearchSysCache1, SearchSysCacheList1, and catctup::tuple.

Referenced by hashhandler().

45 {
46  bool result = true;
47  HeapTuple classtup;
48  Form_pg_opclass classform;
49  Oid opfamilyoid;
50  Oid opcintype;
51  char *opclassname;
52  HeapTuple familytup;
53  Form_pg_opfamily familyform;
54  char *opfamilyname;
55  CatCList *proclist,
56  *oprlist;
57  List *grouplist;
58  OpFamilyOpFuncGroup *opclassgroup;
59  List *hashabletypes = NIL;
60  int i;
61  ListCell *lc;
62 
63  /* Fetch opclass information */
64  classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
65  if (!HeapTupleIsValid(classtup))
66  elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
67  classform = (Form_pg_opclass) GETSTRUCT(classtup);
68 
69  opfamilyoid = classform->opcfamily;
70  opcintype = classform->opcintype;
71  opclassname = NameStr(classform->opcname);
72 
73  /* Fetch opfamily information */
74  familytup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyoid));
75  if (!HeapTupleIsValid(familytup))
76  elog(ERROR, "cache lookup failed for operator family %u", opfamilyoid);
77  familyform = (Form_pg_opfamily) GETSTRUCT(familytup);
78 
79  opfamilyname = NameStr(familyform->opfname);
80 
81  /* Fetch all operators and support functions of the opfamily */
82  oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
83  proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
84 
85  /* Check individual support functions */
86  for (i = 0; i < proclist->n_members; i++)
87  {
88  HeapTuple proctup = &proclist->members[i]->tuple;
89  Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
90 
91  /*
92  * All hash functions should be registered with matching left/right
93  * types
94  */
95  if (procform->amproclefttype != procform->amprocrighttype)
96  {
97  ereport(INFO,
98  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
99  errmsg("operator family \"%s\" of access method %s contains support procedure %s with different left and right input types",
100  opfamilyname, "hash",
101  format_procedure(procform->amproc))));
102  result = false;
103  }
104 
105  /* Check procedure numbers and function signatures */
106  switch (procform->amprocnum)
107  {
108  case HASHPROC:
109  if (!check_hash_func_signature(procform->amproc, INT4OID,
110  procform->amproclefttype))
111  {
112  ereport(INFO,
113  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
114  errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
115  opfamilyname, "hash",
116  format_procedure(procform->amproc),
117  procform->amprocnum)));
118  result = false;
119  }
120  else
121  {
122  /* Remember which types we can hash */
123  hashabletypes =
124  list_append_unique_oid(hashabletypes,
125  procform->amproclefttype);
126  }
127  break;
128  default:
129  ereport(INFO,
130  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
131  errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
132  opfamilyname, "hash",
133  format_procedure(procform->amproc),
134  procform->amprocnum)));
135  result = false;
136  break;
137  }
138  }
139 
140  /* Check individual operators */
141  for (i = 0; i < oprlist->n_members; i++)
142  {
143  HeapTuple oprtup = &oprlist->members[i]->tuple;
144  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
145 
146  /* Check that only allowed strategy numbers exist */
147  if (oprform->amopstrategy < 1 ||
148  oprform->amopstrategy > HTMaxStrategyNumber)
149  {
150  ereport(INFO,
151  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
152  errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
153  opfamilyname, "hash",
154  format_operator(oprform->amopopr),
155  oprform->amopstrategy)));
156  result = false;
157  }
158 
159  /* hash doesn't support ORDER BY operators */
160  if (oprform->amoppurpose != AMOP_SEARCH ||
161  OidIsValid(oprform->amopsortfamily))
162  {
163  ereport(INFO,
164  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
165  errmsg("operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s",
166  opfamilyname, "hash",
167  format_operator(oprform->amopopr))));
168  result = false;
169  }
170 
171  /* Check operator signature --- same for all hash strategies */
172  if (!check_amop_signature(oprform->amopopr, BOOLOID,
173  oprform->amoplefttype,
174  oprform->amoprighttype))
175  {
176  ereport(INFO,
177  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
178  errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
179  opfamilyname, "hash",
180  format_operator(oprform->amopopr))));
181  result = false;
182  }
183 
184  /* There should be relevant hash procedures for each datatype */
185  if (!list_member_oid(hashabletypes, oprform->amoplefttype) ||
186  !list_member_oid(hashabletypes, oprform->amoprighttype))
187  {
188  ereport(INFO,
189  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
190  errmsg("operator family \"%s\" of access method %s lacks support function for operator %s",
191  opfamilyname, "hash",
192  format_operator(oprform->amopopr))));
193  result = false;
194  }
195  }
196 
197  /* Now check for inconsistent groups of operators/functions */
198  grouplist = identify_opfamily_groups(oprlist, proclist);
199  opclassgroup = NULL;
200  foreach(lc, grouplist)
201  {
202  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
203 
204  /* Remember the group exactly matching the test opclass */
205  if (thisgroup->lefttype == opcintype &&
206  thisgroup->righttype == opcintype)
207  opclassgroup = thisgroup;
208 
209  /*
210  * Complain if there seems to be an incomplete set of operators for
211  * this datatype pair (implying that we have a hash function but no
212  * operator).
213  */
214  if (thisgroup->operatorset != (1 << HTEqualStrategyNumber))
215  {
216  ereport(INFO,
217  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
218  errmsg("operator family \"%s\" of access method %s is missing operator(s) for types %s and %s",
219  opfamilyname, "hash",
220  format_type_be(thisgroup->lefttype),
221  format_type_be(thisgroup->righttype))));
222  result = false;
223  }
224  }
225 
226  /* Check that the originally-named opclass is supported */
227  /* (if group is there, we already checked it adequately above) */
228  if (!opclassgroup)
229  {
230  ereport(INFO,
231  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
232  errmsg("operator class \"%s\" of access method %s is missing operator(s)",
233  opclassname, "hash")));
234  result = false;
235  }
236 
237  /*
238  * Complain if the opfamily doesn't have entries for all possible
239  * combinations of its supported datatypes. While missing cross-type
240  * operators are not fatal, it seems reasonable to insist that all
241  * built-in hash opfamilies be complete.
242  */
243  if (list_length(grouplist) !=
244  list_length(hashabletypes) * list_length(hashabletypes))
245  {
246  ereport(INFO,
247  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
248  errmsg("operator family \"%s\" of access method %s is missing cross-type operator(s)",
249  opfamilyname, "hash")));
250  result = false;
251  }
252 
253  ReleaseCatCacheList(proclist);
254  ReleaseCatCacheList(oprlist);
255  ReleaseSysCache(familytup);
256  ReleaseSysCache(classtup);
257 
258  return result;
259 }
#define NIL
Definition: pg_list.h:69
int n_members
Definition: catcache.h:154
List * list_append_unique_oid(List *list, Oid datum)
Definition: list.c:999
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define AMOP_SEARCH
Definition: pg_amop.h:69
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:59
#define HTEqualStrategyNumber
Definition: hash.h:289
#define INT4OID
Definition: pg_type.h:316
int errcode(int sqlerrcode)
Definition: elog.c:575
#define INFO
Definition: elog.h:33
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
return result
Definition: formatting.c:1633
char * format_operator(Oid operator_oid)
Definition: regproc.c:820
#define HTMaxStrategyNumber
Definition: hash.h:290
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:156
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1651
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:155
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:41
static bool check_hash_func_signature(Oid funcid, Oid restype, Oid argtype)
Definition: hashvalidate.c:267
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:201
#define ereport(elevel, rest)
Definition: elog.h:122
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:44
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:323
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:505
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:194
#define BOOLOID
Definition: pg_type.h:288
int errmsg(const char *fmt,...)
Definition: elog.c:797
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:77
#define HASHPROC
Definition: hash.h:297
int i
#define NameStr(name)
Definition: c.h:499
HeapTupleData tuple
Definition: catcache.h:116
#define elog
Definition: elog.h:219
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
Definition: pg_list.h:45