mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +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;
 | 
						|
}
 |