mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-29 22:49:41 +03:00 
			
		
		
		
	This refactors and simplifies various existing code to make use of the new function. Reviewed-by: Mark Dilger <mark.dilger@enterprisedb.com> Discussion: https://www.postgresql.org/message-id/flat/E72EAA49-354D-4C2E-8EB9-255197F55330@enterprisedb.com
		
			
				
	
	
		
			216 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*-------------------------------------------------------------------------
 | |
|  *
 | |
|  * blvalidate.c
 | |
|  *	  Opclass validator for bloom.
 | |
|  *
 | |
|  * Copyright (c) 2016-2025, PostgreSQL Global Development Group
 | |
|  *
 | |
|  * IDENTIFICATION
 | |
|  *	  contrib/bloom/blvalidate.c
 | |
|  *
 | |
|  *-------------------------------------------------------------------------
 | |
|  */
 | |
| #include "postgres.h"
 | |
| 
 | |
| #include "access/amvalidate.h"
 | |
| #include "access/htup_details.h"
 | |
| #include "bloom.h"
 | |
| #include "catalog/pg_amop.h"
 | |
| #include "catalog/pg_amproc.h"
 | |
| #include "catalog/pg_opclass.h"
 | |
| #include "catalog/pg_type.h"
 | |
| #include "utils/lsyscache.h"
 | |
| #include "utils/regproc.h"
 | |
| #include "utils/syscache.h"
 | |
| 
 | |
| /*
 | |
|  * Validator for a bloom opclass.
 | |
|  */
 | |
| bool
 | |
| blvalidate(Oid opclassoid)
 | |
| {
 | |
| 	bool		result = true;
 | |
| 	HeapTuple	classtup;
 | |
| 	Form_pg_opclass classform;
 | |
| 	Oid			opfamilyoid;
 | |
| 	Oid			opcintype;
 | |
| 	Oid			opckeytype;
 | |
| 	char	   *opclassname;
 | |
| 	char	   *opfamilyname;
 | |
| 	CatCList   *proclist,
 | |
| 			   *oprlist;
 | |
| 	List	   *grouplist;
 | |
| 	OpFamilyOpFuncGroup *opclassgroup;
 | |
| 	int			i;
 | |
| 	ListCell   *lc;
 | |
| 
 | |
| 	/* Fetch opclass information */
 | |
| 	classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
 | |
| 	if (!HeapTupleIsValid(classtup))
 | |
| 		elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
 | |
| 	classform = (Form_pg_opclass) GETSTRUCT(classtup);
 | |
| 
 | |
| 	opfamilyoid = classform->opcfamily;
 | |
| 	opcintype = classform->opcintype;
 | |
| 	opckeytype = classform->opckeytype;
 | |
| 	if (!OidIsValid(opckeytype))
 | |
| 		opckeytype = opcintype;
 | |
| 	opclassname = NameStr(classform->opcname);
 | |
| 
 | |
| 	/* Fetch opfamily information */
 | |
| 	opfamilyname = get_opfamily_name(opfamilyoid, false);
 | |
| 
 | |
| 	/* Fetch all operators and support functions of the opfamily */
 | |
| 	oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
 | |
| 	proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
 | |
| 
 | |
| 	/* Check individual support functions */
 | |
| 	for (i = 0; i < proclist->n_members; i++)
 | |
| 	{
 | |
| 		HeapTuple	proctup = &proclist->members[i]->tuple;
 | |
| 		Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
 | |
| 		bool		ok;
 | |
| 
 | |
| 		/*
 | |
| 		 * All bloom support functions should be registered with matching
 | |
| 		 * left/right types
 | |
| 		 */
 | |
| 		if (procform->amproclefttype != procform->amprocrighttype)
 | |
| 		{
 | |
| 			ereport(INFO,
 | |
| 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 | |
| 					 errmsg("bloom opfamily %s contains support procedure %s with cross-type registration",
 | |
| 							opfamilyname,
 | |
| 							format_procedure(procform->amproc))));
 | |
| 			result = false;
 | |
| 		}
 | |
| 
 | |
| 		/*
 | |
| 		 * We can't check signatures except within the specific opclass, since
 | |
| 		 * we need to know the associated opckeytype in many cases.
 | |
| 		 */
 | |
| 		if (procform->amproclefttype != opcintype)
 | |
| 			continue;
 | |
| 
 | |
| 		/* Check procedure numbers and function signatures */
 | |
| 		switch (procform->amprocnum)
 | |
| 		{
 | |
| 			case BLOOM_HASH_PROC:
 | |
| 				ok = check_amproc_signature(procform->amproc, INT4OID, false,
 | |
| 											1, 1, opckeytype);
 | |
| 				break;
 | |
| 			case BLOOM_OPTIONS_PROC:
 | |
| 				ok = check_amoptsproc_signature(procform->amproc);
 | |
| 				break;
 | |
| 			default:
 | |
| 				ereport(INFO,
 | |
| 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 | |
| 						 errmsg("bloom opfamily %s contains function %s with invalid support number %d",
 | |
| 								opfamilyname,
 | |
| 								format_procedure(procform->amproc),
 | |
| 								procform->amprocnum)));
 | |
| 				result = false;
 | |
| 				continue;		/* don't want additional message */
 | |
| 		}
 | |
| 
 | |
| 		if (!ok)
 | |
| 		{
 | |
| 			ereport(INFO,
 | |
| 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 | |
| 					 errmsg("bloom opfamily %s contains function %s with wrong signature for support number %d",
 | |
| 							opfamilyname,
 | |
| 							format_procedure(procform->amproc),
 | |
| 							procform->amprocnum)));
 | |
| 			result = false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Check individual operators */
 | |
| 	for (i = 0; i < oprlist->n_members; i++)
 | |
| 	{
 | |
| 		HeapTuple	oprtup = &oprlist->members[i]->tuple;
 | |
| 		Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
 | |
| 
 | |
| 		/* Check it's allowed strategy for bloom */
 | |
| 		if (oprform->amopstrategy < 1 ||
 | |
| 			oprform->amopstrategy > BLOOM_NSTRATEGIES)
 | |
| 		{
 | |
| 			ereport(INFO,
 | |
| 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 | |
| 					 errmsg("bloom opfamily %s contains operator %s with invalid strategy number %d",
 | |
| 							opfamilyname,
 | |
| 							format_operator(oprform->amopopr),
 | |
| 							oprform->amopstrategy)));
 | |
| 			result = false;
 | |
| 		}
 | |
| 
 | |
| 		/* bloom doesn't support ORDER BY operators */
 | |
| 		if (oprform->amoppurpose != AMOP_SEARCH ||
 | |
| 			OidIsValid(oprform->amopsortfamily))
 | |
| 		{
 | |
| 			ereport(INFO,
 | |
| 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 | |
| 					 errmsg("bloom opfamily %s contains invalid ORDER BY specification for operator %s",
 | |
| 							opfamilyname,
 | |
| 							format_operator(oprform->amopopr))));
 | |
| 			result = false;
 | |
| 		}
 | |
| 
 | |
| 		/* Check operator signature --- same for all bloom strategies */
 | |
| 		if (!check_amop_signature(oprform->amopopr, BOOLOID,
 | |
| 								  oprform->amoplefttype,
 | |
| 								  oprform->amoprighttype))
 | |
| 		{
 | |
| 			ereport(INFO,
 | |
| 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 | |
| 					 errmsg("bloom opfamily %s contains operator %s with wrong signature",
 | |
| 							opfamilyname,
 | |
| 							format_operator(oprform->amopopr))));
 | |
| 			result = false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* Now check for inconsistent groups of operators/functions */
 | |
| 	grouplist = identify_opfamily_groups(oprlist, proclist);
 | |
| 	opclassgroup = NULL;
 | |
| 	foreach(lc, grouplist)
 | |
| 	{
 | |
| 		OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
 | |
| 
 | |
| 		/* Remember the group exactly matching the test opclass */
 | |
| 		if (thisgroup->lefttype == opcintype &&
 | |
| 			thisgroup->righttype == opcintype)
 | |
| 			opclassgroup = thisgroup;
 | |
| 
 | |
| 		/*
 | |
| 		 * There is not a lot we can do to check the operator sets, since each
 | |
| 		 * bloom opclass is more or less a law unto itself, and some contain
 | |
| 		 * only operators that are binary-compatible with the opclass datatype
 | |
| 		 * (meaning that empty operator sets can be OK).  That case also means
 | |
| 		 * that we shouldn't insist on nonempty function sets except for the
 | |
| 		 * opclass's own group.
 | |
| 		 */
 | |
| 	}
 | |
| 
 | |
| 	/* Check that the originally-named opclass is complete */
 | |
| 	for (i = 1; i <= BLOOM_NPROC; i++)
 | |
| 	{
 | |
| 		if (opclassgroup &&
 | |
| 			(opclassgroup->functionset & (((uint64) 1) << i)) != 0)
 | |
| 			continue;			/* got it */
 | |
| 		if (i == BLOOM_OPTIONS_PROC)
 | |
| 			continue;			/* optional method */
 | |
| 		ereport(INFO,
 | |
| 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 | |
| 				 errmsg("bloom opclass %s is missing support function %d",
 | |
| 						opclassname, i)));
 | |
| 		result = false;
 | |
| 	}
 | |
| 
 | |
| 	ReleaseCatCacheList(proclist);
 | |
| 	ReleaseCatCacheList(oprlist);
 | |
| 	ReleaseSysCache(classtup);
 | |
| 
 | |
| 	return result;
 | |
| }
 |