X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Fcatalog%2Fpg_operator.c;h=5ce7655edd47010bd9c30f8e19ff37885d15c7ca;hb=bb10bf319eb301cdb5d11a5fb1709348754ac6b3;hp=74db99fa0e583d3b6f6f30da1d4c47d7cef104d3;hpb=9e3d4c43a73e3670e60f04fab2625eed419307e5;p=postgresql diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index 74db99fa0e..5ce7655edd 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -1,54 +1,54 @@ /*------------------------------------------------------------------------- * - * pg_operator.c-- - * routines to support manipulation of the pg_operator relation + * pg_operator.c + * routines to support manipulation of the pg_operator relation * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.5 1996/11/06 07:31:24 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.44 1999/11/24 00:44:29 momjian Exp $ * * NOTES - * these routines moved here from commands/define.c and somewhat cleaned up. - * + * these routines moved here from commands/define.c and somewhat cleaned up. + * *------------------------------------------------------------------------- */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef HAVE_MEMMOVE -# include -#else -# include -#endif +#include "postgres.h" + +#include "access/heapam.h" +#include "catalog/catname.h" +#include "catalog/indexing.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 ); + const char *operatorName, + Oid leftObjectId, + Oid rightObjectId, + bool *defined); + static Oid OperatorGet(char *operatorName, - char *leftTypeName, - char *rightTypeName ); + char *leftTypeName, + char *rightTypeName, + bool *defined); static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc, - char *operatorName, - Oid leftObjectId, - Oid rightObjectId ); + char *operatorName, + Oid leftObjectId, + Oid rightObjectId); + static Oid OperatorShellMake(char *operatorName, - char *leftTypeName, - char *rightTypeName ); + char *leftTypeName, + char *rightTypeName); static void OperatorDef(char *operatorName, - int definedOK, char *leftTypeName, char *rightTypeName, char *procedureName, @@ -60,289 +60,315 @@ static void OperatorDef(char *operatorName, char *oinName, bool canHash, char *leftSortName, - char *rightSortName ); -static void OperatorUpd(Oid baseId , Oid commId , Oid negId ); - + char *rightSortName); + +static void OperatorUpd(Oid baseId, Oid commId, Oid negId); + /* ---------------------------------------------------------------- - * OperatorGetWithOpenRelation + * OperatorGetWithOpenRelation * - * preforms a scan on pg_operator for an operator tuple - * with given name and left/right type oids. + * 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 oid of operator to fetch - * rightObjectId -- right oid of operator to fetch + * 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 Oid OperatorGetWithOpenRelation(Relation pg_operator_desc, - const char *operatorName, - Oid leftObjectId, - Oid rightObjectId) + 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, NameEqualRegProcedure }, - { 0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure }, - { 0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure }, - }; - - fmgr_info(NameEqualRegProcedure, - &opKey[0].sk_func, &opKey[0].sk_nargs); - fmgr_info(ObjectIdEqualRegProcedure, - &opKey[1].sk_func, &opKey[1].sk_nargs); - fmgr_info(ObjectIdEqualRegProcedure, - &opKey[2].sk_func, &opKey[2].sk_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, - SelfTimeQual, - 3, - opKey); - - /* ---------------- - * fetch the operator tuple, if it exists, and determine - * the proper return oid value. - * ---------------- - */ - tup = heap_getnext(pg_operator_scan, 0, (Buffer *) 0); - operatorObjectId = HeapTupleIsValid(tup) ? tup->t_oid : InvalidOid; - - /* ---------------- - * close the scan and return the oid. - * ---------------- - */ - heap_endscan(pg_operator_scan); - - return - operatorObjectId; + 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 + * OperatorGet * - * finds the operator associated with the specified name - * and left and right type names. + * finds the operator associated with the specified name + * and left and right type names. * ---------------------------------------------------------------- */ static Oid OperatorGet(char *operatorName, - char *leftTypeName, - char *rightTypeName) + 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 types. - * - * Note: types must be defined before operators - * ---------------- - */ - if (leftTypeName) { - leftObjectId = TypeGet(leftTypeName, &leftDefined); - - if (!OidIsValid(leftObjectId) || !leftDefined) - elog(WARN, "OperatorGet: left type '%s' nonexistent",leftTypeName); - } - - if (rightTypeName) { - rightObjectId = TypeGet(rightTypeName, &rightDefined); - - if (!OidIsValid(rightObjectId) || !rightDefined) - elog(WARN, "OperatorGet: right type '%s' nonexistent", - rightTypeName); - } - - if (!((OidIsValid(leftObjectId) && leftDefined) || - (OidIsValid(rightObjectId) && rightDefined))) - elog(WARN, "OperatorGet: no argument types??"); - - /* ---------------- - * 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); - - /* ---------------- - * close the relation and return the operator oid. - * ---------------- - */ - heap_close(pg_operator_desc); - - return - operatorObjectId; + 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, AccessShareLock); + + /* ---------------- + * 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, AccessShareLock); + + return operatorObjectId; } /* ---------------------------------------------------------------- - * OperatorShellMakeWithOpenRelation + * OperatorShellMakeWithOpenRelation * * ---------------------------------------------------------------- */ static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc, - char *operatorName, - Oid leftObjectId, - Oid rightObjectId) + char *operatorName, + Oid leftObjectId, + Oid rightObjectId) { - register int i; - HeapTuple tup; - Datum values[ Natts_pg_operator ]; - char nulls[ Natts_pg_operator ]; - Oid operatorObjectId; - 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 type name and - * ---------------- - */ - i = 0; - values[i++] = PointerGetDatum(operatorName); - values[i++] = ObjectIdGetDatum(InvalidOid); - values[i++] = (Datum) (uint16) 0; - - values[i++] = (Datum)'b'; /* fill oprkind with a bogus value */ - - 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_oid; - - /* ---------------- - * free the tuple and return the operator oid - * ---------------- - */ - pfree(tup); - - return - operatorObjectId; + 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; + + if (RelationGetForm(pg_operator_desc)->relhasindex) + { + Relation idescs[Num_pg_operator_indices]; + + CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup); + CatalogCloseIndices(Num_pg_operator_indices, idescs); + } + + /* ---------------- + * free the tuple and return the operator oid + * ---------------- + */ + pfree(tup); + + return operatorObjectId; } /* ---------------------------------------------------------------- - * OperatorShellMake + * 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. + * 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 Oid OperatorShellMake(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(WARN, "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; + 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, RowExclusiveLock); + + /* ---------------- + * 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, RowExclusiveLock); + + return operatorObjectId; } /* -------------------------------- @@ -352,7 +378,7 @@ OperatorShellMake(char *operatorName, * 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 + * 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. @@ -363,712 +389,702 @@ OperatorShellMake(char *operatorName, * not available to the user as it is for type definition. * * Algorithm: - * - * check if operator already defined - * if so issue error if not definedOk, this is a duplicate - * but if definedOk, save the Oid -- filling in a shell + * + * 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 as the main operator, set the ObjectId=0. - * Later OperatorCreate will make another call - * to OperatorDef which will cause this field - * to be filled in (because even though the names - * will be switched, they are the same name and - * at this point this ObjectId will then be defined) - * 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 + * 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_ctid from the modified tuple and call RelationReplaceHeapTuple + * 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 + * create a tuple using heap_formtuple + * call heap_insert * -------------------------------- - * "X" indicates an optional argument (i.e. one that can be NULL) - * operatorName; -- operator name - * definedOK; -- operator can already have an oid? - * leftTypeName; -- X left type name - * rightTypeName; -- X right type name - * procedureName; -- procedure oid 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; -- possible hash operator? - * leftSortName; -- X left sort operator - * rightSortName; -- X right sort operator + * "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 void OperatorDef(char *operatorName, - int definedOK, - char *leftTypeName, - char *rightTypeName, - char *procedureName, - uint16 precedence, - bool isLeftAssociative, - char *commutatorName, - char *negatorName, - char *restrictionName, - char *joinName, - bool canHash, - char *leftSortName, - char *rightSortName) + char *leftTypeName, + char *rightTypeName, + char *procedureName, + uint16 precedence, + bool isLeftAssociative, + char *commutatorName, + char *negatorName, + char *restrictionName, + char *joinName, + bool canHash, + char *leftSortName, + char *rightSortName) { - register i, j; - Relation pg_operator_desc; - - HeapScanDesc pg_operator_scan; - HeapTuple tup; - Buffer buffer; - ItemPointerData itemPointerData; - char nulls[ Natts_pg_operator ]; - char replaces[ Natts_pg_operator ]; - Datum values[ Natts_pg_operator ]; - Oid other_oid; - Oid operatorObjectId; - Oid leftTypeId = InvalidOid; - Oid rightTypeId = InvalidOid; - Oid commutatorId = InvalidOid; - Oid negatorId = InvalidOid; - bool leftDefined = false; - bool rightDefined = false; - char *name[4]; - Oid typeId[8]; - int nargs; - TupleDesc tupDesc; - - static ScanKeyData opKey[3] = { - { 0, Anum_pg_operator_oprname, NameEqualRegProcedure }, - { 0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure }, - { 0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure }, - }; - - fmgr_info(NameEqualRegProcedure, - &opKey[0].sk_func, &opKey[0].sk_nargs); - fmgr_info(ObjectIdEqualRegProcedure, - &opKey[1].sk_func, &opKey[1].sk_nargs); - fmgr_info(ObjectIdEqualRegProcedure, - &opKey[2].sk_func, &opKey[2].sk_nargs); - - operatorObjectId = OperatorGet(operatorName, - leftTypeName, - rightTypeName); - - if (OidIsValid(operatorObjectId) && !definedOK) - elog(WARN, "OperatorDef: operator \"%-.*s\" already defined", - NAMEDATALEN, operatorName); - - if (leftTypeName) - leftTypeId = TypeGet(leftTypeName, &leftDefined); - - if (rightTypeName) - rightTypeId = TypeGet(rightTypeName, &rightDefined); - - if (!((OidIsValid(leftTypeId && leftDefined)) || - (OidIsValid(rightTypeId && rightDefined)))) - elog(WARN, "OperatorGet: no argument types??"); - - for (i = 0; i < Natts_pg_operator; ++i) { - values[i] = (Datum)NULL; - replaces[i] = 'r'; - nulls[i] = ' '; - } - - /* ---------------- - * 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. - * ---------------- - */ - memset(typeId, 0, 8 * sizeof(Oid)); - if (!leftTypeName) { - typeId[0] = rightTypeId; - nargs = 1; - } - else if (!rightTypeName) { - typeId[0] = leftTypeId; - nargs = 1; - } - else { - typeId[0] = leftTypeId; - typeId[1] = rightTypeId; - nargs = 2; - } - tup = SearchSysCacheTuple(PRONAME, - PointerGetDatum(procedureName), - Int32GetDatum(nargs), - PointerGetDatum(typeId), - 0); - - if (!PointerIsValid(tup)) - func_error("OperatorDef", procedureName, nargs, (int*)typeId); - - values[ Anum_pg_operator_oprcode-1 ] = ObjectIdGetDatum(tup->t_oid); - values[ Anum_pg_operator_oprresult-1 ] = - ObjectIdGetDatum(((Form_pg_proc) - GETSTRUCT(tup))->prorettype); - - /* ---------------- - * find restriction - * ---------------- - */ - if (restrictionName) { /* optional */ - memset(typeId, 0, 8 * sizeof(Oid)); - typeId[0] = OIDOID; /* operator OID */ - typeId[1] = OIDOID; /* relation OID */ - typeId[2] = INT2OID; /* attribute number */ - typeId[3] = 0; /* value - can be any type */ - typeId[4] = INT4OID; /* flags - left or right selectivity */ - tup = SearchSysCacheTuple(PRONAME, - PointerGetDatum(restrictionName), - Int32GetDatum(5), - ObjectIdGetDatum(typeId), - 0); - if (!HeapTupleIsValid(tup)) - func_error("OperatorDef", restrictionName, 5, (int*)typeId); - - values[ Anum_pg_operator_oprrest-1 ] = ObjectIdGetDatum(tup->t_oid); - } else - values[ Anum_pg_operator_oprrest-1 ] = ObjectIdGetDatum(InvalidOid); - - /* ---------------- - * find join - only valid for binary operators - * ---------------- - */ - if (joinName) { /* optional */ - memset(typeId, 0, 8 * sizeof(Oid)); - typeId[0] = OIDOID; /* operator OID */ - typeId[1] = OIDOID; /* relation OID 1 */ - typeId[2] = INT2OID; /* attribute number 1 */ - typeId[3] = OIDOID; /* relation OID 2 */ - typeId[4] = INT2OID; /* attribute number 2 */ - - tup = SearchSysCacheTuple(PRONAME, - PointerGetDatum(joinName), - Int32GetDatum(5), - Int32GetDatum(typeId), - 0); + 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) + { + rightTypeId = TypeGet(rightTypeName, &rightDefined); + + if (!OidIsValid(rightTypeId) || !rightDefined) + elog(ERROR, "OperatorDef: right type '%s' nonexistent", + rightTypeName); + } + + if (!((OidIsValid(leftTypeId) && leftDefined) || + (OidIsValid(rightTypeId) && rightDefined))) + elog(ERROR, "OperatorDef: must have at least one argument type"); + + for (i = 0; i < Natts_pg_operator; ++i) + { + values[i] = (Datum) NULL; + replaces[i] = 'r'; + nulls[i] = ' '; + } + + /* ---------------- + * 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. + * ---------------- + */ + MemSet(typeId, 0, 8 * sizeof(Oid)); + if (!leftTypeName) + { + typeId[0] = rightTypeId; + nargs = 1; + } + else if (!rightTypeName) + { + typeId[0] = leftTypeId; + nargs = 1; + } + else + { + typeId[0] = leftTypeId; + typeId[1] = rightTypeId; + nargs = 2; + } + tup = SearchSysCacheTuple(PROCNAME, + PointerGetDatum(procedureName), + Int32GetDatum(nargs), + PointerGetDatum(typeId), + 0); + if (!HeapTupleIsValid(tup)) - func_error("OperatorDef", joinName, 5, (int*)typeId); - - values[Anum_pg_operator_oprjoin-1] = ObjectIdGetDatum(tup->t_oid); - } else - values[Anum_pg_operator_oprjoin-1] = ObjectIdGetDatum(InvalidOid); - - /* ---------------- - * set up values in the operator tuple - * ---------------- - */ - i = 0; - values[i++] = PointerGetDatum(operatorName); - values[i++] = Int32GetDatum(GetUserId()); - values[i++] = UInt16GetDatum(precedence); - values[i++] = leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l'; - values[i++] = Int8GetDatum(isLeftAssociative); - values[i++] = Int8GetDatum(canHash); - values[i++] = ObjectIdGetDatum(leftTypeId); - values[i++] = ObjectIdGetDatum(rightTypeId); - - ++i; /* Skip "prorettype", this was done above */ - - /* - * Set up the other operators. If they do not currently exist, - * set up shells in order to get ObjectId's and call OperatorDef - * again later to fill in the shells. - */ - name[0] = commutatorName; - name[1] = negatorName; - name[2] = leftSortName; - name[3] = rightSortName; - - for (j = 0; j < 4; ++j) { - if (name[j]) { - - /* for the commutator, switch order of arguments */ - if (j == 0) { - other_oid = OperatorGet(name[j], rightTypeName,leftTypeName); - commutatorId = other_oid; - } else { - other_oid = OperatorGet(name[j], leftTypeName,rightTypeName); - if (j == 1) - negatorId = other_oid; - } - - if (OidIsValid(other_oid)) /* already in catalogs */ - values[i++] = ObjectIdGetDatum(other_oid); - else if (strcmp(operatorName, name[j]) != 0) { - /* not in catalogs, different from operator */ - - /* for the commutator, switch order of arguments */ - if (j == 0) { - other_oid = OperatorShellMake(name[j], - rightTypeName, - leftTypeName); - } else { - other_oid = OperatorShellMake(name[j], - leftTypeName, - rightTypeName); + func_error("OperatorDef", procedureName, nargs, typeId, NULL); + + values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_data->t_oid); + values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(((Form_pg_proc) + GETSTRUCT(tup))->prorettype); + + /* ---------------- + * find restriction + * ---------------- + */ + if (restrictionName) + { /* optional */ + MemSet(typeId, 0, 8 * sizeof(Oid)); + typeId[0] = OIDOID; /* operator OID */ + typeId[1] = OIDOID; /* relation OID */ + typeId[2] = INT2OID; /* attribute number */ + typeId[3] = 0; /* value - can be any type */ + typeId[4] = INT4OID; /* flags - left or right selectivity */ + tup = SearchSysCacheTuple(PROCNAME, + PointerGetDatum(restrictionName), + Int32GetDatum(5), + PointerGetDatum(typeId), + 0); + if (!HeapTupleIsValid(tup)) + func_error("OperatorDef", restrictionName, 5, typeId, NULL); + + values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_data->t_oid); + } + else + values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid); + + /* ---------------- + * find join - only valid for binary operators + * ---------------- + */ + if (joinName) + { /* optional */ + MemSet(typeId, 0, 8 * sizeof(Oid)); + typeId[0] = OIDOID; /* operator OID */ + typeId[1] = OIDOID; /* relation OID 1 */ + typeId[2] = INT2OID; /* attribute number 1 */ + typeId[3] = OIDOID; /* relation OID 2 */ + typeId[4] = INT2OID; /* attribute number 2 */ + + tup = SearchSysCacheTuple(PROCNAME, + PointerGetDatum(joinName), + Int32GetDatum(5), + PointerGetDatum(typeId), + 0); + if (!HeapTupleIsValid(tup)) + func_error("OperatorDef", joinName, 5, typeId, NULL); + + values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_data->t_oid); + } + else + values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid); + + /* ---------------- + * set up values in the operator tuple + * ---------------- + */ + i = 0; + namestrcpy(&oname, operatorName); + values[i++] = NameGetDatum(&oname); + values[i++] = Int32GetDatum(GetUserId()); + values[i++] = UInt16GetDatum(precedence); + values[i++] = leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l'; + values[i++] = Int8GetDatum(isLeftAssociative); + values[i++] = Int8GetDatum(canHash); + values[i++] = ObjectIdGetDatum(leftTypeId); + values[i++] = ObjectIdGetDatum(rightTypeId); + + ++i; /* Skip "oprresult", it was filled in + * above */ + + /* + * Set up the other operators. If they do not currently exist, create + * shells in order to get ObjectId's. + */ + name[0] = commutatorName; + name[1] = negatorName; + name[2] = leftSortName; + name[3] = rightSortName; + + for (j = 0; j < 4; ++j) + { + if (name[j]) + { + char *otherLeftTypeName = NULL; + char *otherRightTypeName = NULL; + Oid otherLeftTypeId = InvalidOid; + Oid otherRightTypeId = InvalidOid; + Oid other_oid = InvalidOid; + bool otherDefined = false; + + switch (j) + { + case 0: /* commutator has reversed arg types */ + otherLeftTypeName = rightTypeName; + otherRightTypeName = leftTypeName; + otherLeftTypeId = rightTypeId; + otherRightTypeId = leftTypeId; + other_oid = OperatorGet(name[j], + otherLeftTypeName, + otherRightTypeName, + &otherDefined); + commutatorId = other_oid; + break; + case 1: /* negator has same arg types */ + otherLeftTypeName = leftTypeName; + otherRightTypeName = rightTypeName; + otherLeftTypeId = leftTypeId; + otherRightTypeId = rightTypeId; + other_oid = OperatorGet(name[j], + otherLeftTypeName, + otherRightTypeName, + &otherDefined); + negatorId = other_oid; + break; + case 2: /* left sort op takes left-side data type */ + otherLeftTypeName = leftTypeName; + otherRightTypeName = leftTypeName; + otherLeftTypeId = leftTypeId; + otherRightTypeId = leftTypeId; + other_oid = OperatorGet(name[j], + otherLeftTypeName, + otherRightTypeName, + &otherDefined); + break; + case 3: /* right sort op takes right-side data + * type */ + otherLeftTypeName = rightTypeName; + otherRightTypeName = rightTypeName; + otherLeftTypeId = rightTypeId; + otherRightTypeId = rightTypeId; + other_oid = OperatorGet(name[j], + otherLeftTypeName, + otherRightTypeName, + &otherDefined); + break; + } + + if (OidIsValid(other_oid)) + { + /* other op already in catalogs */ + values[i++] = ObjectIdGetDatum(other_oid); + } + else if (strcmp(operatorName, name[j]) != 0 || + otherLeftTypeId != leftTypeId || + otherRightTypeId != rightTypeId) + { + /* not in catalogs, different from operator */ + other_oid = OperatorShellMake(name[j], + otherLeftTypeName, + otherRightTypeName); + if (!OidIsValid(other_oid)) + elog(ERROR, + "OperatorDef: can't create operator shell '%s'", + name[j]); + values[i++] = ObjectIdGetDatum(other_oid); + } + else + { + + /* + * self-linkage to this operator; will fix below. Note + * that only self-linkage for commutation makes sense. + */ + if (j != 0) + elog(ERROR, + "OperatorDef: operator can't be its own negator or sort op"); + selfCommutator = true; + values[i++] = ObjectIdGetDatum(InvalidOid); + } } - - if (!OidIsValid(other_oid)) - elog(WARN, - "OperatorDef: can't create operator '%s'", - name[j]); - values[i++] = ObjectIdGetDatum(other_oid); - - } else /* not in catalogs, same as operator ??? */ - values[i++] = ObjectIdGetDatum(InvalidOid); - - } else /* new operator is optional */ - values[i++] = ObjectIdGetDatum(InvalidOid); - } - - /* last three fields were filled in first */ - - /* - * If we are adding to an operator shell, get its t_ctid and a - * buffer. - */ - pg_operator_desc = heap_openr(OperatorRelationName); - - if (operatorObjectId) { - opKey[0].sk_argument = PointerGetDatum(operatorName); - opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId); - opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId); - - pg_operator_scan = heap_beginscan(pg_operator_desc, - 0, - SelfTimeQual, - 3, - opKey); - - tup = heap_getnext(pg_operator_scan, 0, &buffer); - if (HeapTupleIsValid(tup)) { - tup = heap_modifytuple(tup, - buffer, - pg_operator_desc, - values, - nulls, - replaces); - - ItemPointerCopy(&tup->t_ctid, &itemPointerData); - setheapoverride(true); - (void) heap_replace(pg_operator_desc, &itemPointerData, tup); - setheapoverride(false); - } else - elog(WARN, "OperatorDef: no operator %d", other_oid); - - heap_endscan(pg_operator_scan); - - } else { - tupDesc = pg_operator_desc->rd_att; - tup = heap_formtuple(tupDesc, values, nulls); - - heap_insert(pg_operator_desc, tup); - operatorObjectId = tup->t_oid; - } - - heap_close(pg_operator_desc); - - /* - * It's possible that we're creating a skeleton operator here for - * the commute or negate attributes of a real operator. If we are, - * then we're done. If not, we may need to update the negator and - * commutator for this attribute. The reason for this is that the - * user may want to create two operators (say < and >=). When he - * defines <, if he uses >= as the negator or commutator, he won't - * be able to insert it later, since (for some reason) define operator - * defines it for him. So what he does is to define > without a - * negator or commutator. Then he defines >= with < as the negator - * and commutator. As a side effect, this will update the > tuple - * if it has no commutator or negator defined. - * - * Alstublieft, Tom Vijlbrief. - */ - if (!definedOK) - OperatorUpd(operatorObjectId, commutatorId, negatorId); + else + { + /* other operator is omitted */ + values[i++] = ObjectIdGetDatum(InvalidOid); + } + } + + /* last three fields were filled in above */ + + pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock); + + /* + * If we are adding to an operator shell, get its t_self + */ + if (operatorObjectId) + { + opKey[0].sk_argument = PointerGetDatum(operatorName); + opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId); + opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId); + + pg_operator_scan = heap_beginscan(pg_operator_desc, + 0, + SnapshotSelf, /* no cache? */ + 3, + opKey); + + tup = heap_getnext(pg_operator_scan, 0); + if (HeapTupleIsValid(tup)) + { + tup = heap_modifytuple(tup, + pg_operator_desc, + values, + nulls, + replaces); + + setheapoverride(true); + heap_update(pg_operator_desc, &tup->t_self, tup, NULL); + setheapoverride(false); + } + else + elog(ERROR, "OperatorDef: no operator %u", operatorObjectId); + + heap_endscan(pg_operator_scan); + } + else + { + tupDesc = pg_operator_desc->rd_att; + tup = heap_formtuple(tupDesc, values, nulls); + + heap_insert(pg_operator_desc, tup); + operatorObjectId = tup->t_data->t_oid; + + } + + if (RelationGetForm(pg_operator_desc)->relhasindex) + { + Relation idescs[Num_pg_operator_indices]; + + CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup); + CatalogCloseIndices(Num_pg_operator_indices, idescs); + } + + heap_close(pg_operator_desc, RowExclusiveLock); + + /* + * If a commutator and/or negator link is provided, update the other + * operator(s) to point at this one, if they don't already have a + * link. This supports an alternate style of operator definition + * wherein the user first defines one operator without giving negator + * or commutator, then defines the other operator of the pair with the + * proper commutator or negator attribute. That style doesn't require + * creation of a shell, and it's the only style that worked right + * before Postgres version 6.5. This code also takes care of the + * situation where the new operator is its own commutator. + */ + if (selfCommutator) + commutatorId = operatorObjectId; + + if (OidIsValid(commutatorId) || OidIsValid(negatorId)) + OperatorUpd(operatorObjectId, commutatorId, negatorId); } /* ---------------------------------------------------------------- * OperatorUpd * - * For a given operator, look up its negator and commutator operators. - * If they are defined, but their negator and commutator operators - * (respectively) are not, then use the new operator for neg and comm. - * This solves a problem for users who need to insert two new operators - * which are the negator or commutator of each other. - * ---------------------------------------------------------------- + * For a given operator, look up its negator and commutator operators. + * If they are defined, but their negator and commutator fields + * (respectively) are empty, then use the new operator for neg or comm. + * This solves a problem for users who need to insert two new operators + * which are the negator or commutator of each other. + * ---------------------------------------------------------------- */ static void OperatorUpd(Oid baseId, Oid commId, Oid negId) { - register i; - Relation pg_operator_desc; - HeapScanDesc pg_operator_scan; - HeapTuple tup; - Buffer buffer; - ItemPointerData itemPointerData; - char nulls[ Natts_pg_operator ]; - char replaces[ Natts_pg_operator ]; - Datum values[ Natts_pg_operator ]; - - static ScanKeyData opKey[1] = { - { 0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure }, - }; - - fmgr_info(ObjectIdEqualRegProcedure, - &opKey[0].sk_func, &opKey[0].sk_nargs); - - for (i = 0; i < Natts_pg_operator; ++i) { - values[i] = (Datum)NULL; - replaces[i] = ' '; - nulls[i] = ' '; - } - - pg_operator_desc = heap_openr(OperatorRelationName); - - /* check and update the commutator, if necessary */ - opKey[0].sk_argument = ObjectIdGetDatum(commId); - - pg_operator_scan = heap_beginscan(pg_operator_desc, - 0, - SelfTimeQual, - 1, - opKey); - - tup = heap_getnext(pg_operator_scan, 0, &buffer); - - /* if the commutator and negator are the same operator, do one update */ - if (commId == negId) { - if (HeapTupleIsValid(tup)) { - OperatorTupleForm t; - - t = (OperatorTupleForm) GETSTRUCT(tup); - if (!OidIsValid(t->oprcom) - || !OidIsValid(t->oprnegate)) { - - if (!OidIsValid(t->oprnegate)) { - values[Anum_pg_operator_oprnegate - 1] = - ObjectIdGetDatum(baseId); - replaces[ Anum_pg_operator_oprnegate - 1 ] = 'r'; - } + int i; + 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]; + + static ScanKeyData opKey[1] = { + {0, ObjectIdAttributeNumber, F_OIDEQ}, + }; + + fmgr_info(F_OIDEQ, &opKey[0].sk_func); + opKey[0].sk_nargs = opKey[0].sk_func.fn_nargs; + + for (i = 0; i < Natts_pg_operator; ++i) + { + values[i] = (Datum) NULL; + replaces[i] = ' '; + nulls[i] = ' '; + } + + pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock); + + /* check and update the commutator, if necessary */ + opKey[0].sk_argument = ObjectIdGetDatum(commId); + + pg_operator_scan = heap_beginscan(pg_operator_desc, + 0, + SnapshotSelf, /* no cache? */ + 1, + opKey); + + tup = heap_getnext(pg_operator_scan, 0); + + /* + * if the commutator and negator are the same operator, do one update. + * XXX this is probably useless code --- I doubt it ever makes sense + * for commutator and negator to be the same thing... + */ + if (commId == negId) + { + if (HeapTupleIsValid(tup)) + { + Form_pg_operator t; + + t = (Form_pg_operator) GETSTRUCT(tup); + if (!OidIsValid(t->oprcom) + || !OidIsValid(t->oprnegate)) + { + + if (!OidIsValid(t->oprnegate)) + { + values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId); + replaces[Anum_pg_operator_oprnegate - 1] = 'r'; + } + + if (!OidIsValid(t->oprcom)) + { + values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId); + replaces[Anum_pg_operator_oprcom - 1] = 'r'; + } + + tup = heap_modifytuple(tup, + pg_operator_desc, + values, + nulls, + replaces); + + setheapoverride(true); + heap_update(pg_operator_desc, &tup->t_self, tup, NULL); + setheapoverride(false); - if (!OidIsValid(t->oprcom)) { - values[Anum_pg_operator_oprcom - 1] = - ObjectIdGetDatum(baseId); - replaces[ Anum_pg_operator_oprcom - 1 ] = 'r'; + if (RelationGetForm(pg_operator_desc)->relhasindex) + { + Relation idescs[Num_pg_operator_indices]; + + CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup); + CatalogCloseIndices(Num_pg_operator_indices, idescs); + } + } } - + heap_endscan(pg_operator_scan); + + heap_close(pg_operator_desc, RowExclusiveLock); + + return; + } + + /* if commutator and negator are different, do two updates */ + + if (HeapTupleIsValid(tup) && + !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom))) + { + values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId); + replaces[Anum_pg_operator_oprcom - 1] = 'r'; tup = heap_modifytuple(tup, - buffer, - pg_operator_desc, - values, - nulls, - replaces); - - ItemPointerCopy(&tup->t_ctid, &itemPointerData); - + pg_operator_desc, + values, + nulls, + replaces); + setheapoverride(true); - (void) heap_replace(pg_operator_desc, &itemPointerData, tup); + heap_update(pg_operator_desc, &tup->t_self, tup, NULL); setheapoverride(false); - } + if (RelationGetForm(pg_operator_desc)->relhasindex) + { + Relation idescs[Num_pg_operator_indices]; + + CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup); + CatalogCloseIndices(Num_pg_operator_indices, idescs); + } + + values[Anum_pg_operator_oprcom - 1] = (Datum) NULL; + replaces[Anum_pg_operator_oprcom - 1] = ' '; } + heap_endscan(pg_operator_scan); + + /* check and update the negator, if necessary */ + opKey[0].sk_argument = ObjectIdGetDatum(negId); + + pg_operator_scan = heap_beginscan(pg_operator_desc, + 0, + SnapshotSelf, /* no cache? */ + 1, + opKey); + + tup = heap_getnext(pg_operator_scan, 0); + if (HeapTupleIsValid(tup) && + !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate))) + { + values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId); + replaces[Anum_pg_operator_oprnegate - 1] = 'r'; + tup = heap_modifytuple(tup, + pg_operator_desc, + values, + nulls, + replaces); + + setheapoverride(true); + heap_update(pg_operator_desc, &tup->t_self, tup, NULL); + setheapoverride(false); + + if (RelationGetForm(pg_operator_desc)->relhasindex) + { + Relation idescs[Num_pg_operator_indices]; - heap_close(pg_operator_desc); - - /* release the buffer properly */ - if (BufferIsValid(buffer)) - ReleaseBuffer(buffer); - - return; - } - - /* if commutator and negator are different, do two updates */ - if (HeapTupleIsValid(tup) && - !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprcom))) { - values[ Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId); - replaces[ Anum_pg_operator_oprcom - 1] = 'r'; - tup = heap_modifytuple(tup, - buffer, - pg_operator_desc, - values, - nulls, - replaces); - - ItemPointerCopy(&tup->t_ctid, &itemPointerData); - setheapoverride(true); - (void) heap_replace(pg_operator_desc, &itemPointerData, tup); - setheapoverride(false); - - values[ Anum_pg_operator_oprcom - 1 ] = (Datum)NULL; - replaces[ Anum_pg_operator_oprcom - 1 ] = ' '; - - /* release the buffer properly */ - if (BufferIsValid(buffer)) - ReleaseBuffer(buffer); - - } - - /* check and update the negator, if necessary */ - opKey[0].sk_argument = ObjectIdGetDatum(negId); - - pg_operator_scan = heap_beginscan(pg_operator_desc, - 0, - SelfTimeQual, - 1, - opKey); - - tup = heap_getnext(pg_operator_scan, 0, &buffer); - if (HeapTupleIsValid(tup) && - !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprnegate))) { - values[Anum_pg_operator_oprnegate-1] = ObjectIdGetDatum(baseId); - replaces[ Anum_pg_operator_oprnegate - 1 ] = 'r'; - tup = heap_modifytuple(tup, - buffer, - pg_operator_desc, - values, - nulls, - replaces); - - ItemPointerCopy(&tup->t_ctid, &itemPointerData); - - setheapoverride(true); - (void) heap_replace(pg_operator_desc, &itemPointerData, tup); - setheapoverride(false); - } - - /* release the buffer properly */ - if (BufferIsValid(buffer)) - ReleaseBuffer(buffer); - - heap_endscan(pg_operator_scan); - - heap_close(pg_operator_desc); + CatalogOpenIndices(Num_pg_operator_indices, Name_pg_operator_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_operator_indices, pg_operator_desc, tup); + CatalogCloseIndices(Num_pg_operator_indices, idescs); + } + } + + heap_endscan(pg_operator_scan); + + + heap_close(pg_operator_desc, RowExclusiveLock); } /* ---------------------------------------------------------------- * OperatorCreate * - * Algorithm: - * - * Since the commutator, negator, leftsortoperator, and rightsortoperator - * can be defined implicitly through OperatorCreate, must check before - * the main operator is added to see if they already exist. If they - * do not already exist, OperatorDef makes a "shell" for each undefined - * one, and then OperatorCreate must call OperatorDef again to fill in - * each shell. All this is necessary in order to get the right ObjectId's - * filled into the right fields. + * This is now just an interface procedure for OperatorDef ... * - * The "definedOk" flag indicates that OperatorDef can be called on - * the operator even though it already has an entry in the PG_OPERATOR - * relation. This allows shells to be filled in. The user cannot - * forward declare operators, this is strictly an internal capability. - * - * When the shells are filled in by subsequent calls to OperatorDef, - * all the fields are the same as the definition of the original operator - * except that the target operator name and the original operatorName - * are switched. In the case of commutator and negator, special flags - * are set to indicate their status, telling the executor(?) that - * the operands are to be switched, or the outcome of the procedure - * negated. - * - * ************************* NOTE NOTE NOTE ****************************** - * - * If the execution of this utility is interrupted, the pg_operator - * catalog may be left in an inconsistent state. Similarly, if - * something is removed from the pg_operator, pg_type, or pg_procedure - * catalog while this is executing, the results may be inconsistent. - * ---------------------------------------------------------------- - * - * "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 for operator - * precedence; -- operator precedence - * isLeftAssociative; -- operator is left associative - * commutatorName; -- X commutator operator name - * negatorName; -- X negator operator name - * restrictionName; -- X restriction sel. procedure - * joinName; -- X join sel. procedure name - * canHash; -- operator hashes - * leftSortName; -- X left sort operator - * rightSortName; -- X right sort operator - * + * "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 for operator + * precedence; -- operator precedence + * isLeftAssociative; -- operator is left associative + * commutatorName; -- X commutator operator name + * negatorName; -- X negator operator name + * 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) */ void OperatorCreate(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) + char *leftTypeName, + char *rightTypeName, + char *procedureName, + uint16 precedence, + bool isLeftAssociative, + char *commutatorName, + char *negatorName, + char *restrictionName, + char *joinName, + bool canHash, + char *leftSortName, + char *rightSortName) { - Oid commObjectId, negObjectId; - Oid leftSortObjectId, rightSortObjectId; - int definedOK; - - if (!leftTypeName && !rightTypeName) - elog(WARN, "OperatorCreate : at least one of leftarg or rightarg must be defined"); - - /* ---------------- - * get the oid's of the operator's associated operators, if possible. - * ---------------- - */ - if (commutatorName) - commObjectId = OperatorGet(commutatorName, /* commute type order */ - rightTypeName, - leftTypeName); - - if (negatorName) - negObjectId = OperatorGet(negatorName, - leftTypeName, - rightTypeName); - - if (leftSortName) - leftSortObjectId = OperatorGet(leftSortName, - leftTypeName, - rightTypeName); - - if (rightSortName) - rightSortObjectId = OperatorGet(rightSortName, - rightTypeName, - leftTypeName); - - /* ---------------- - * Use OperatorDef() to define the specified operator and - * also create shells for the operator's associated operators - * if they don't already exist. - * - * This operator should not be defined yet. - * ---------------- - */ - definedOK = 0; - - OperatorDef(operatorName, - definedOK, - leftTypeName, - rightTypeName, - procedureName, - precedence, - isLeftAssociative, - commutatorName, - negatorName, - restrictionName, - joinName, - canHash, - leftSortName, - rightSortName); - - /* ---------------- - * Now fill in information in the operator's associated - * operators. - * - * These operators should be defined or have shells defined. - * ---------------- - */ - definedOK = 1; - - if (!OidIsValid(commObjectId) && commutatorName) - OperatorDef(commutatorName, - definedOK, - leftTypeName, /* should eventually */ - rightTypeName, /* commute order */ - procedureName, - precedence, - isLeftAssociative, - operatorName, /* commutator */ - negatorName, - restrictionName, - joinName, - canHash, - rightSortName, - leftSortName); - - if (negatorName && !OidIsValid(negObjectId)) - OperatorDef(negatorName, - definedOK, - leftTypeName, - rightTypeName, - procedureName, - precedence, - isLeftAssociative, - commutatorName, - operatorName, /* negator */ - restrictionName, - joinName, - canHash, - leftSortName, - rightSortName); - - if (leftSortName && !OidIsValid(leftSortObjectId)) - OperatorDef(leftSortName, - definedOK, - leftTypeName, - rightTypeName, - procedureName, - precedence, - isLeftAssociative, - commutatorName, - negatorName, - restrictionName, - joinName, - canHash, - operatorName, /* left sort */ - rightSortName); - - if (rightSortName && !OidIsValid(rightSortObjectId)) - OperatorDef(rightSortName, - definedOK, - leftTypeName, - rightTypeName, - procedureName, - precedence, - isLeftAssociative, - commutatorName, - negatorName, - restrictionName, - joinName, - canHash, - leftSortName, - operatorName); /* right sort */ + if (!leftTypeName && !rightTypeName) + elog(ERROR, "OperatorCreate: at least one of leftarg or rightarg must be defined"); + + if (!(leftTypeName && rightTypeName)) + { + /* If it's not a binary op, these things mustn't be set: */ + if (commutatorName) + elog(ERROR, "OperatorCreate: only binary operators can have commutators"); + if (negatorName) + elog(ERROR, "OperatorCreate: only binary operators can have negators"); + if (restrictionName || joinName) + elog(ERROR, "OperatorCreate: only binary operators can have selectivity"); + if (canHash) + elog(ERROR, "OperatorCreate: only binary operators can hash"); + if (leftSortName || rightSortName) + elog(ERROR, "OperatorCreate: only binary operators can have sort links"); + } + + /* ---------------- + * Use OperatorDef() to define the specified operator and + * also create shells for the operator's associated operators + * if they don't already exist. + * ---------------- + */ + OperatorDef(operatorName, + leftTypeName, + rightTypeName, + procedureName, + precedence, + isLeftAssociative, + commutatorName, + negatorName, + restrictionName, + joinName, + canHash, + leftSortName, + rightSortName); }