📄 pg_operator.c
字号:
/*------------------------------------------------------------------------- * * pg_operator.c * routines to support manipulation of the pg_operator relation * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.37.2.1 1999/08/02 05:56:55 scrappy Exp $ * * NOTES * these routines moved here from commands/define.c and somewhat cleaned up. * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/catname.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 "utils/builtins.h"#include "utils/syscache.h"static Oid OperatorGetWithOpenRelation(Relation pg_operator_desc, const char *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined);static Oid OperatorGet(char *operatorName, char *leftTypeName, char *rightTypeName, bool *defined);static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc, char *operatorName, Oid leftObjectId, Oid rightObjectId);static Oid OperatorShellMake(char *operatorName, char *leftTypeName, char *rightTypeName);static void OperatorDef(char *operatorName, char *leftTypeName, char *rightTypeName, char *procedureName, uint16 precedence, bool isLeftAssociative, char *commutatorName, char *negatorName, char *restrictionName, char *oinName, bool canHash, char *leftSortName, char *rightSortName);static void OperatorUpd(Oid baseId, Oid commId, Oid negId);/* ---------------------------------------------------------------- * OperatorGetWithOpenRelation * * preforms a scan on pg_operator for an operator tuple * with given name and left/right type oids. * ---------------------------------------------------------------- * pg_operator_desc -- reldesc for pg_operator * operatorName -- name of operator to fetch * leftObjectId -- left data type oid of operator to fetch * rightObjectId -- right data type oid of operator to fetch * defined -- set TRUE if defined (not a shell) */static OidOperatorGetWithOpenRelation(Relation pg_operator_desc, const char *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined){ HeapScanDesc pg_operator_scan; Oid operatorObjectId; HeapTuple tup; static ScanKeyData opKey[3] = { {0, Anum_pg_operator_oprname, F_NAMEEQ}, {0, Anum_pg_operator_oprleft, F_OIDEQ}, {0, Anum_pg_operator_oprright, F_OIDEQ}, }; fmgr_info(F_NAMEEQ, &opKey[0].sk_func); fmgr_info(F_OIDEQ, &opKey[1].sk_func); fmgr_info(F_OIDEQ, &opKey[2].sk_func); opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs; opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs; opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs; /* ---------------- * form scan key * ---------------- */ opKey[0].sk_argument = PointerGetDatum(operatorName); opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId); opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId); /* ---------------- * begin the scan * ---------------- */ pg_operator_scan = heap_beginscan(pg_operator_desc, 0, SnapshotSelf, /* no cache? */ 3, opKey); /* ---------------- * fetch the operator tuple, if it exists, and determine * the proper return oid value. * ---------------- */ tup = heap_getnext(pg_operator_scan, 0); if (HeapTupleIsValid(tup)) { regproc oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode; operatorObjectId = tup->t_data->t_oid; *defined = RegProcedureIsValid(oprcode); } else { operatorObjectId = InvalidOid; *defined = false; } /* ---------------- * close the scan and return the oid. * ---------------- */ heap_endscan(pg_operator_scan); return operatorObjectId;}/* ---------------------------------------------------------------- * OperatorGet * * finds the operator associated with the specified name * and left and right type names. * ---------------------------------------------------------------- */static OidOperatorGet(char *operatorName, char *leftTypeName, char *rightTypeName, bool *defined){ Relation pg_operator_desc; Oid operatorObjectId; Oid leftObjectId = InvalidOid; Oid rightObjectId = InvalidOid; bool leftDefined = false; bool rightDefined = false; /* ---------------- * look up the operator data types. * * Note: types must be defined before operators * ---------------- */ if (leftTypeName) { leftObjectId = TypeGet(leftTypeName, &leftDefined); if (!OidIsValid(leftObjectId) || !leftDefined) elog(ERROR, "OperatorGet: left type '%s' nonexistent", leftTypeName); } if (rightTypeName) { rightObjectId = TypeGet(rightTypeName, &rightDefined); if (!OidIsValid(rightObjectId) || !rightDefined) elog(ERROR, "OperatorGet: right type '%s' nonexistent", rightTypeName); } if (!((OidIsValid(leftObjectId) && leftDefined) || (OidIsValid(rightObjectId) && rightDefined))) elog(ERROR, "OperatorGet: must have at least one argument type"); /* ---------------- * open the pg_operator relation * ---------------- */ pg_operator_desc = heap_openr(OperatorRelationName); /* ---------------- * get the oid for the operator with the appropriate name * and left/right types. * ---------------- */ operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc, operatorName, leftObjectId, rightObjectId, defined); /* ---------------- * close the relation and return the operator oid. * ---------------- */ heap_close(pg_operator_desc); return operatorObjectId;}/* ---------------------------------------------------------------- * OperatorShellMakeWithOpenRelation * * ---------------------------------------------------------------- */static OidOperatorShellMakeWithOpenRelation(Relation pg_operator_desc, char *operatorName, Oid leftObjectId, Oid rightObjectId){ int i; HeapTuple tup; Datum values[Natts_pg_operator]; char nulls[Natts_pg_operator]; Oid operatorObjectId; NameData oname; TupleDesc tupDesc; /* ---------------- * 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); values[i++] = Int32GetDatum(GetUserId()); values[i++] = (Datum) (uint16) 0; values[i++] = (Datum) 'b'; /* assume it's binary */ values[i++] = (Datum) (bool) 0; values[i++] = (Datum) (bool) 0; values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */ values[i++] = ObjectIdGetDatum(rightObjectId); /* <-- right oid */ values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); /* ---------------- * create a new operator tuple * ---------------- */ tupDesc = pg_operator_desc->rd_att; tup = heap_formtuple(tupDesc, values, nulls); /* ---------------- * insert our "shell" operator tuple and * close the relation * ---------------- */ heap_insert(pg_operator_desc, tup); operatorObjectId = tup->t_data->t_oid; /* ---------------- * free the tuple and return the operator oid * ---------------- */ pfree(tup); return operatorObjectId;}/* ---------------------------------------------------------------- * OperatorShellMake * * Specify operator name and left and right type names, * fill an operator struct with this info and NULL's, * call heap_insert and return the Oid * to the caller. * ---------------------------------------------------------------- */static OidOperatorShellMake(char *operatorName, char *leftTypeName, char *rightTypeName){ Relation pg_operator_desc; Oid operatorObjectId; Oid leftObjectId = InvalidOid; Oid rightObjectId = InvalidOid; bool leftDefined = false; bool rightDefined = false; /* ---------------- * get the left and right type oid's for this operator * ---------------- */ if (leftTypeName) leftObjectId = TypeGet(leftTypeName, &leftDefined); if (rightTypeName) rightObjectId = TypeGet(rightTypeName, &rightDefined); if (!((OidIsValid(leftObjectId) && leftDefined) || (OidIsValid(rightObjectId) && rightDefined))) elog(ERROR, "OperatorShellMake: no valid argument types??"); /* ---------------- * open pg_operator * ---------------- */ pg_operator_desc = heap_openr(OperatorRelationName); /* ---------------- * add a "shell" operator tuple to the operator relation * and recover the shell tuple's oid. * ---------------- */ operatorObjectId = OperatorShellMakeWithOpenRelation(pg_operator_desc, operatorName, leftObjectId, rightObjectId); /* ---------------- * close the operator relation and return the oid. * ---------------- */ heap_close(pg_operator_desc); return operatorObjectId;}/* -------------------------------- * OperatorDef * * 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) * precedence * operator "kind" either "b" for binary or "l" for left unary * isLeftAssociative boolean * 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 it's 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 an amgetattr 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 heap_insert * -------------------------------- * "X" indicates an optional argument (i.e. one that can be NULL) * operatorName; -- operator name * leftTypeName; -- X left type name * rightTypeName; -- X right type name * procedureName; -- procedure name for operator code * precedence; -- operator precedence * isLeftAssociative; -- operator is left associative? * commutatorName; -- X commutator operator name * negatorName; -- X negator operator name * restrictionName; -- X restriction sel. procedure name * joinName; -- X join sel. procedure name * canHash; -- can hash join be used with operator? * leftSortName; -- X left sort operator (for merge join) * rightSortName; -- X right sort operator (for merge join) */static voidOperatorDef(char *operatorName, char *leftTypeName, char *rightTypeName, char *procedureName, uint16 precedence, bool isLeftAssociative, char *commutatorName, char *negatorName, char *restrictionName, char *joinName, bool canHash, char *leftSortName, char *rightSortName){ int i, j; Relation pg_operator_desc; HeapScanDesc pg_operator_scan; HeapTuple tup; char nulls[Natts_pg_operator]; char replaces[Natts_pg_operator]; Datum values[Natts_pg_operator]; Oid operatorObjectId; bool operatorAlreadyDefined; Oid leftTypeId = InvalidOid; Oid rightTypeId = InvalidOid; Oid commutatorId = InvalidOid; Oid negatorId = InvalidOid; bool leftDefined = false; bool rightDefined = false; bool selfCommutator = false; char *name[4]; Oid typeId[8]; int nargs; NameData oname; TupleDesc tupDesc; static ScanKeyData opKey[3] = { {0, Anum_pg_operator_oprname, F_NAMEEQ}, {0, Anum_pg_operator_oprleft, F_OIDEQ}, {0, Anum_pg_operator_oprright, F_OIDEQ}, }; fmgr_info(F_NAMEEQ, &opKey[0].sk_func); fmgr_info(F_OIDEQ, &opKey[1].sk_func); fmgr_info(F_OIDEQ, &opKey[2].sk_func); opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs; opKey[1].sk_nargs = opKey[1].sk_func.fn_nargs; opKey[2].sk_nargs = opKey[2].sk_func.fn_nargs; operatorObjectId = OperatorGet(operatorName, leftTypeName, rightTypeName, &operatorAlreadyDefined); if (operatorAlreadyDefined) elog(ERROR, "OperatorDef: operator \"%s\" already defined", operatorName); /* * At this point, if operatorObjectId is not InvalidOid then we are * filling in a previously-created shell. */ /* ---------------- * look up the operator data types. * * Note: types must be defined before operators * ---------------- */ if (leftTypeName) { leftTypeId = TypeGet(leftTypeName, &leftDefined); if (!OidIsValid(leftTypeId) || !leftDefined) elog(ERROR, "OperatorDef: left type '%s' nonexistent", leftTypeName); } if (rightTypeName)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -