⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pg_operator.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * pg_operator.c *	  routines to support manipulation of the pg_operator relation * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.94 2005/10/15 02:49:14 momjian Exp $ * * NOTES *	  these routines moved here from commands/define.c and somewhat cleaned up. * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/dependency.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_namespace.h"#include "catalog/pg_operator.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.h"#include "miscadmin.h"#include "parser/parse_func.h"#include "parser/parse_oper.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/syscache.h"static Oid OperatorGet(const char *operatorName,			Oid operatorNamespace,			Oid leftObjectId,			Oid rightObjectId,			bool *defined);static Oid OperatorLookup(List *operatorName,			   Oid leftObjectId,			   Oid rightObjectId,			   bool *defined);static Oid OperatorShellMake(const char *operatorName,				  Oid operatorNamespace,				  Oid leftTypeId,				  Oid rightTypeId);static void OperatorUpd(Oid baseId, Oid commId, Oid negId);static Oid get_other_operator(List *otherOp,				   Oid otherLeftTypeId, Oid otherRightTypeId,				   const char *operatorName, Oid operatorNamespace,				   Oid leftTypeId, Oid rightTypeId,				   bool isCommutator);static void makeOperatorDependencies(HeapTuple tuple);/* * Check whether a proposed operator name is legal * * This had better match the behavior of parser/scan.l! * * We need this because the parser is not smart enough to check that * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses * are operator names rather than some other lexical entity. */static boolvalidOperatorName(const char *name){	size_t		len = strlen(name);	/* Can't be empty or too long */	if (len == 0 || len >= NAMEDATALEN)		return false;	/* Can't contain any invalid characters */	/* Test string here should match op_chars in scan.l */	if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)		return false;	/* Can't contain slash-star or dash-dash (comment starts) */	if (strstr(name, "/*") || strstr(name, "--"))		return false;	/*	 * For SQL92 compatibility, '+' and '-' cannot be the last char of a	 * multi-char operator unless the operator contains chars that are not in	 * SQL92 operators. The idea is to lex '=-' as two operators, but not to	 * forbid operator names like '?-' that could not be sequences of SQL92	 * operators.	 */	if (len > 1 &&		(name[len - 1] == '+' ||		 name[len - 1] == '-'))	{		int			ic;		for (ic = len - 2; ic >= 0; ic--)		{			if (strchr("~!@#^&|`?%", name[ic]))				break;		}		if (ic < 0)			return false;		/* nope, not valid */	}	/* != isn't valid either, because parser will convert it to <> */	if (strcmp(name, "!=") == 0)		return false;	return true;}/* * OperatorGet * *		finds an operator given an exact specification (name, namespace, *		left and right type IDs). * *		*defined is set TRUE if defined (not a shell) */static OidOperatorGet(const char *operatorName,			Oid operatorNamespace,			Oid leftObjectId,			Oid rightObjectId,			bool *defined){	HeapTuple	tup;	Oid			operatorObjectId;	tup = SearchSysCache(OPERNAMENSP,						 PointerGetDatum(operatorName),						 ObjectIdGetDatum(leftObjectId),						 ObjectIdGetDatum(rightObjectId),						 ObjectIdGetDatum(operatorNamespace));	if (HeapTupleIsValid(tup))	{		RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;		operatorObjectId = HeapTupleGetOid(tup);		*defined = RegProcedureIsValid(oprcode);		ReleaseSysCache(tup);	}	else	{		operatorObjectId = InvalidOid;		*defined = false;	}	return operatorObjectId;}/* * OperatorLookup * *		looks up an operator given a possibly-qualified name and *		left and right type IDs. * *		*defined is set TRUE if defined (not a shell) */static OidOperatorLookup(List *operatorName,			   Oid leftObjectId,			   Oid rightObjectId,			   bool *defined){	Oid			operatorObjectId;	RegProcedure oprcode;	operatorObjectId = LookupOperName(operatorName, leftObjectId,									  rightObjectId, true);	if (!OidIsValid(operatorObjectId))	{		*defined = false;		return InvalidOid;	}	oprcode = get_opcode(operatorObjectId);	*defined = RegProcedureIsValid(oprcode);	return operatorObjectId;}/* * OperatorShellMake *		Make a "shell" entry for a not-yet-existing operator. */static OidOperatorShellMake(const char *operatorName,				  Oid operatorNamespace,				  Oid leftTypeId,				  Oid rightTypeId){	Relation	pg_operator_desc;	Oid			operatorObjectId;	int			i;	HeapTuple	tup;	Datum		values[Natts_pg_operator];	char		nulls[Natts_pg_operator];	NameData	oname;	TupleDesc	tupDesc;	/*	 * validate operator name	 */	if (!validOperatorName(operatorName))		ereport(ERROR,				(errcode(ERRCODE_INVALID_NAME),				 errmsg("\"%s\" is not a valid operator name",						operatorName)));	/*	 * initialize our *nulls and *values arrays	 */	for (i = 0; i < Natts_pg_operator; ++i)	{		nulls[i] = ' ';		values[i] = (Datum) NULL;		/* redundant, but safe */	}	/*	 * initialize values[] with the operator name and input data types. Note	 * that oprcode is set to InvalidOid, indicating it's a shell.	 */	i = 0;	namestrcpy(&oname, operatorName);	values[i++] = NameGetDatum(&oname); /* oprname */	values[i++] = ObjectIdGetDatum(operatorNamespace);	/* oprnamespace */	values[i++] = ObjectIdGetDatum(GetUserId());		/* oprowner */	values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');	/* oprkind */	values[i++] = BoolGetDatum(false);	/* oprcanhash */	values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */	values[i++] = ObjectIdGetDatum(rightTypeId);		/* oprright */	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprresult */	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcom */	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprnegate */	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprlsortop */	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrsortop */	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprltcmpop */	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprgtcmpop */	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcode */	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrest */	values[i++] = ObjectIdGetDatum(InvalidOid); /* oprjoin */	/*	 * open pg_operator	 */	pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);	tupDesc = pg_operator_desc->rd_att;	/*	 * create a new operator tuple	 */	tup = heap_formtuple(tupDesc, values, nulls);	/*	 * insert our "shell" operator tuple	 */	operatorObjectId = simple_heap_insert(pg_operator_desc, tup);	CatalogUpdateIndexes(pg_operator_desc, tup);	/* Add dependencies for the entry */	makeOperatorDependencies(tup);	heap_freetuple(tup);	/*	 * close the operator relation and return the oid.	 */	heap_close(pg_operator_desc, RowExclusiveLock);	return operatorObjectId;}/* * OperatorCreate * * "X" indicates an optional argument (i.e. one that can be NULL or 0) *		operatorName			name for new operator *		operatorNamespace		namespace for new operator *		leftTypeId				X left type ID *		rightTypeId				X right type ID *		procedureName			procedure for operator *		commutatorName			X commutator operator *		negatorName				X negator operator *		restrictionName			X restriction sel. procedure *		joinName				X join sel. procedure *		canHash					hash join can be used with this operator *		leftSortName			X left sort operator (for merge join) *		rightSortName			X right sort operator (for merge join) *		ltCompareName			X L<R compare operator (for merge join) *		gtCompareName			X L>R compare operator (for merge join) * * This routine gets complicated because it allows the user to * specify operators that do not exist.  For example, if operator * "op" is being defined, the negator operator "negop" and the * commutator "commop" can also be defined without specifying * any information other than their names.	Since in order to * add "op" to the PG_OPERATOR catalog, all the Oid's for these * operators must be placed in the fields of "op", a forward * declaration is done on the commutator and negator operators. * This is called creating a shell, and its main effect is to * create a tuple in the PG_OPERATOR catalog with minimal * information about the operator (just its name and types). * Forward declaration is used only for this purpose, it is * not available to the user as it is for type definition. * * Algorithm: * * check if operator already defined *	  if so, but oprcode is null, save the Oid -- we are filling in a shell *	  otherwise error * get the attribute types from relation descriptor for pg_operator * assign values to the fields of the operator: *	 operatorName *	 owner id (simply the user id of the caller) *	 operator "kind" either "b" for binary or "l" for left unary *	 canHash boolean *	 leftTypeObjectId -- type must already be defined *	 rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified *	 resultType -- defer this, since it must be determined from *				   the pg_procedure catalog *	 commutatorObjectId -- if this is NULL, enter ObjectId=0 *					  else if this already exists, enter its ObjectId *					  else if this does not yet exist, and is not *						the same as the main operatorName, then create *						a shell and enter the new ObjectId *					  else if this does not exist but IS the same *						name & types as the main operator, set the ObjectId=0. *						(We are creating a self-commutating operator.) *						The link will be fixed later by OperatorUpd. *	 negatorObjectId   -- same as for commutatorObjectId *	 leftSortObjectId  -- same as for commutatorObjectId *	 rightSortObjectId -- same as for commutatorObjectId *	 operatorProcedure -- must access the pg_procedure catalog to get the *				   ObjectId of the procedure that actually does the operator *				   actions this is required.  Do a lookup to find out the *				   return type of the procedure *	 restrictionProcedure -- must access the pg_procedure catalog to get *				   the ObjectId but this is optional *	 joinProcedure -- same as restrictionProcedure * now either insert or replace the operator into the pg_operator catalog * if the operator shell is being filled in *	 access the catalog in order to get a valid buffer *	 create a tuple using ModifyHeapTuple *	 get the t_self from the modified tuple and call RelationReplaceHeapTuple * else if a new operator is being created *	 create a tuple using heap_formtuple *	 call simple_heap_insert */voidOperatorCreate(const char *operatorName,			   Oid operatorNamespace,			   Oid leftTypeId,			   Oid rightTypeId,			   List *procedureName,			   List *commutatorName,			   List *negatorName,			   List *restrictionName,			   List *joinName,			   bool canHash,			   List *leftSortName,			   List *rightSortName,			   List *ltCompareName,			   List *gtCompareName){	Relation	pg_operator_desc;	HeapTuple	tup;	char		nulls[Natts_pg_operator];	char		replaces[Natts_pg_operator];	Datum		values[Natts_pg_operator];	Oid			operatorObjectId;	bool		operatorAlreadyDefined;	Oid			procOid;	Oid			operResultType;	Oid			commutatorId,				negatorId,				leftSortId,				rightSortId,				ltCompareId,				gtCompareId,				restOid,				joinOid;	bool		selfCommutator = false;	Oid			typeId[4];		/* only need up to 4 args here */	int			nargs;	NameData	oname;	TupleDesc	tupDesc;	int			i;	/*	 * Sanity checks	 */	if (!validOperatorName(operatorName))		ereport(ERROR,				(errcode(ERRCODE_INVALID_NAME),				 errmsg("\"%s\" is not a valid operator name",						operatorName)));	if (!OidIsValid(leftTypeId) && !OidIsValid(rightTypeId))		ereport(ERROR,				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),		   errmsg("at least one of leftarg or rightarg must be specified")));	if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))	{		/* If it's not a binary op, these things mustn't be set: */		if (commutatorName)			ereport(ERROR,					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					 errmsg("only binary operators can have commutators")));		if (joinName)			ereport(ERROR,					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),				 errmsg("only binary operators can have join selectivity")));		if (canHash)			ereport(ERROR,					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					 errmsg("only binary operators can hash")));		if (leftSortName || rightSortName || ltCompareName || gtCompareName)			ereport(ERROR,					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),					 errmsg("only binary operators can merge join")));	}	operatorObjectId = OperatorGet(operatorName,								   operatorNamespace,								   leftTypeId,								   rightTypeId,								   &operatorAlreadyDefined);	if (operatorAlreadyDefined)		ereport(ERROR,				(errcode(ERRCODE_DUPLICATE_FUNCTION),				 errmsg("operator %s already exists",						operatorName)));	/*	 * At this point, if operatorObjectId is not InvalidOid then we are	 * filling in a previously-created shell.	 */	/*	 * Look up registered procedures -- find the return type of procedureName	 * to place in "result" field. Do this before shells are created so we	 * don't have to worry about deleting them later.	 */	if (!OidIsValid(leftTypeId))	{		typeId[0] = rightTypeId;		nargs = 1;	}	else if (!OidIsValid(rightTypeId))	{		typeId[0] = leftTypeId;		nargs = 1;	}	else	{		typeId[0] = leftTypeId;		typeId[1] = rightTypeId;		nargs = 2;	}	procOid = LookupFuncName(procedureName, nargs, typeId, false);	operResultType = get_func_rettype(procOid);	/*	 * find restriction estimator	 */	if (restrictionName)	{		typeId[0] = INTERNALOID;	/* Query */		typeId[1] = OIDOID;		/* operator OID */		typeId[2] = INTERNALOID;	/* args list */		typeId[3] = INT4OID;	/* varRelid */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -