]> granicus.if.org Git - postgresql/blobdiff - src/backend/catalog/pg_operator.c
message refinements
[postgresql] / src / backend / catalog / pg_operator.c
index 422c212811f003c47d276e749d50d0dda5680bcb..a72565e9709d284ed723a72a69cabe149ba8276b 100644 (file)
@@ -1,59 +1,56 @@
 /*-------------------------------------------------------------------------
  *
- * pg_operator.c--
+ * pg_operator.c
  *       routines to support manipulation of the pg_operator relation
  *
- * Copyright (c) 1994, Regents of the University of California
+ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.13 1997/09/08 02:21:48 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.61 2001/08/10 15:49:39 petere Exp $
  *
  * NOTES
  *       these routines moved here from commands/define.c and somewhat cleaned up.
  *
  *-------------------------------------------------------------------------
  */
-#include <postgres.h>
-
-#include <catalog/pg_proc.h>
-#include <utils/syscache.h>
-#include <access/heapam.h>
-#include <parser/catalog_utils.h>
-#include <catalog/catname.h>
-#include <catalog/pg_operator.h>
-#include <storage/bufmgr.h>
-#include <fmgr.h>
-#include <miscadmin.h>
-#ifndef HAVE_MEMMOVE
-#include <regex/utils.h>
-#else
-#include <string.h>
-#endif
-
-static Oid
-OperatorGetWithOpenRelation(Relation pg_operator_desc,
+#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/fmgroids.h"
+#include "utils/syscache.h"
+
+
+static Oid OperatorGetWithOpenRelation(Relation pg_operator_desc,
                                                        const char *operatorName,
                                                        Oid leftObjectId,
-                                                       Oid rightObjectId);
-static Oid
-OperatorGet(char *operatorName,
+                                                       Oid rightObjectId,
+                                                       bool *defined);
+
+static Oid OperatorGet(char *operatorName,
                        char *leftTypeName,
-                       char *rightTypeName);
+                       char *rightTypeName,
+                       bool *defined);
 
-static Oid
-OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
+static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
                                                                  char *operatorName,
                                                                  Oid leftObjectId,
                                                                  Oid rightObjectId);
-static Oid
-OperatorShellMake(char *operatorName,
+
+static Oid OperatorShellMake(char *operatorName,
                                  char *leftTypeName,
                                  char *rightTypeName);
 
-static void
-OperatorDef(char *operatorName,
-                       int definedOK,
+static void OperatorDef(char *operatorName,
                        char *leftTypeName,
                        char *rightTypeName,
                        char *procedureName,
@@ -66,76 +63,84 @@ OperatorDef(char *operatorName,
                        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
+ *             performs 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
+ *       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)
+                                                       Oid rightObjectId,
+                                                       bool *defined)
 {
        HeapScanDesc pg_operator_scan;
        Oid                     operatorObjectId;
        HeapTuple       tup;
+       ScanKeyData     opKey[3];
 
-       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
-        * ----------------
+       /*
+        * form scan key
         */
-       opKey[0].sk_argument = PointerGetDatum(operatorName);
-       opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
-       opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
+       ScanKeyEntryInitialize(&opKey[0], 0x0,
+                                                  Anum_pg_operator_oprname,
+                                                  F_NAMEEQ,
+                                                  PointerGetDatum(operatorName));
+       ScanKeyEntryInitialize(&opKey[1], 0x0,
+                                                  Anum_pg_operator_oprleft,
+                                                  F_OIDEQ,
+                                                  ObjectIdGetDatum(leftObjectId));
+       ScanKeyEntryInitialize(&opKey[2], 0x0,
+                                                  Anum_pg_operator_oprright,
+                                                  F_OIDEQ,
+                                                  ObjectIdGetDatum(rightObjectId));
 
-       /* ----------------
-        *      begin the scan
-        * ----------------
+       /*
+        * begin the scan
         */
        pg_operator_scan = heap_beginscan(pg_operator_desc,
                                                                          0,
-                                                                         SelfTimeQual,
+                                                                         SnapshotSelf,         /* no cache? */
                                                                          3,
                                                                          opKey);
 
-       /* ----------------
-        *      fetch the operator tuple, if it exists, and determine
-        *      the proper return oid value.
-        * ----------------
+       /*
+        * 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;
+       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.
-        * ----------------
+       /*
+        * close the scan and return the oid.
         */
        heap_endscan(pg_operator_scan);
 
-       return
-               operatorObjectId;
+       return operatorObjectId;
 }
 
 /* ----------------------------------------------------------------
@@ -148,7 +153,8 @@ OperatorGetWithOpenRelation(Relation pg_operator_desc,
 static Oid
 OperatorGet(char *operatorName,
                        char *leftTypeName,
-                       char *rightTypeName)
+                       char *rightTypeName,
+                       bool *defined)
 {
        Relation        pg_operator_desc;
 
@@ -158,18 +164,18 @@ OperatorGet(char *operatorName,
        bool            leftDefined = false;
        bool            rightDefined = false;
 
-       /* ----------------
-        *      look up the operator types.
+       /*
+        * look up the operator data types.
         *
-        *      Note: types must be defined before operators
-        * ----------------
+        * 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);
+                       elog(ERROR, "left type \"%s\" of operator %s does not exist",
+                                leftTypeName, operatorName);
        }
 
        if (rightTypeName)
@@ -177,38 +183,35 @@ OperatorGet(char *operatorName,
                rightObjectId = TypeGet(rightTypeName, &rightDefined);
 
                if (!OidIsValid(rightObjectId) || !rightDefined)
-                       elog(WARN, "OperatorGet: right type '%s' nonexistent",
-                                rightTypeName);
+                       elog(ERROR, "right type \"%s\" of operator %s does not exist",
+                                rightTypeName, operatorName);
        }
 
        if (!((OidIsValid(leftObjectId) && leftDefined) ||
                  (OidIsValid(rightObjectId) && rightDefined)))
-               elog(WARN, "OperatorGet: no argument types??");
+               elog(ERROR, "operator %s must have at least one operand type", operatorName);
 
-       /* ----------------
-        *      open the pg_operator relation
-        * ----------------
+       /*
+        * open the pg_operator relation
         */
-       pg_operator_desc = heap_openr(OperatorRelationName);
+       pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
 
-       /* ----------------
-        *      get the oid for the operator with the appropriate name
-        *      and left/right types.
-        * ----------------
+       /*
+        * get the oid for the operator with the appropriate name and
+        * left/right types.
         */
        operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
                                                                                                   operatorName,
                                                                                                   leftObjectId,
-                                                                                                  rightObjectId);
+                                                                                                  rightObjectId,
+                                                                                                  defined);
 
-       /* ----------------
-        *      close the relation and return the operator oid.
-        * ----------------
+       /*
+        * close the relation and return the operator oid.
         */
-       heap_close(pg_operator_desc);
+       heap_close(pg_operator_desc, AccessShareLock);
 
-       return
-               operatorObjectId;
+       return operatorObjectId;
 }
 
 /* ----------------------------------------------------------------
@@ -222,16 +225,16 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
                                                                  Oid leftObjectId,
                                                                  Oid rightObjectId)
 {
-       register int i;
+       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
-        * ----------------
+       /*
+        * initialize our *nulls and *values arrays
         */
        for (i = 0; i < Natts_pg_operator; ++i)
        {
@@ -239,19 +242,18 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
                values[i] = (Datum) NULL;               /* redundant, but safe */
        }
 
-       /* ----------------
-        *      initialize values[] with the type name and
-        * ----------------
+       /*
+        * initialize *values with the operator name and input data types.
+        * Note that oprcode is set to InvalidOid, indicating it's a shell.
         */
        i = 0;
-       values[i++] = PointerGetDatum(operatorName);
+       namestrcpy(&oname, operatorName);
+       values[i++] = NameGetDatum(&oname);
        values[i++] = Int32GetDatum(GetUserId());
-       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++] = UInt16GetDatum(0);
+       values[i++] = CharGetDatum('b');        /* assume it's binary */
+       values[i++] = BoolGetDatum(false);
+       values[i++] = BoolGetDatum(false);
        values[i++] = ObjectIdGetDatum(leftObjectId);           /* <-- left oid */
        values[i++] = ObjectIdGetDatum(rightObjectId);          /* <-- right oid */
        values[i++] = ObjectIdGetDatum(InvalidOid);
@@ -263,9 +265,8 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
        values[i++] = ObjectIdGetDatum(InvalidOid);
        values[i++] = ObjectIdGetDatum(InvalidOid);
 
-       /* ----------------
-        *      create a new operator tuple
-        * ----------------
+       /*
+        * create a new operator tuple
         */
        tupDesc = pg_operator_desc->rd_att;
 
@@ -273,22 +274,27 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
                                                 values,
                                                 nulls);
 
-       /* ----------------
-        *      insert our "shell" operator tuple and
-        *      close the relation
-        * ----------------
+       /*
+        * insert our "shell" operator tuple and close the relation
         */
        heap_insert(pg_operator_desc, tup);
-       operatorObjectId = tup->t_oid;
+       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
-        * ----------------
+       /*
+        * free the tuple and return the operator oid
         */
-       pfree(tup);
+       heap_freetuple(tup);
 
-       return
-               operatorObjectId;
+       return operatorObjectId;
 }
 
 /* ----------------------------------------------------------------
@@ -313,9 +319,8 @@ OperatorShellMake(char *operatorName,
        bool            leftDefined = false;
        bool            rightDefined = false;
 
-       /* ----------------
-        *      get the left and right type oid's for this operator
-        * ----------------
+       /*
+        * get the left and right type oid's for this operator
         */
        if (leftTypeName)
                leftObjectId = TypeGet(leftTypeName, &leftDefined);
@@ -325,32 +330,28 @@ OperatorShellMake(char *operatorName,
 
        if (!((OidIsValid(leftObjectId) && leftDefined) ||
                  (OidIsValid(rightObjectId) && rightDefined)))
-               elog(WARN, "OperatorShellMake: no valid argument types??");
+               elog(ERROR, "OperatorShellMake: the operand types are not valid");
 
-       /* ----------------
-        *      open pg_operator
-        * ----------------
+       /*
+        * open pg_operator
         */
-       pg_operator_desc = heap_openr(OperatorRelationName);
+       pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
 
-       /* ----------------
-        *      add a "shell" operator tuple to the operator relation
-        *      and recover the shell tuple's oid.
-        * ----------------
+       /*
+        * 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.
-        * ----------------
+       operatorObjectId = OperatorShellMakeWithOpenRelation(pg_operator_desc,
+                                                                                                                operatorName,
+                                                                                                                leftObjectId,
+                                                                                                                rightObjectId);
+
+       /*
+        * close the operator relation and return the oid.
         */
-       heap_close(pg_operator_desc);
+       heap_close(pg_operator_desc, RowExclusiveLock);
 
-       return
-               operatorObjectId;
+       return operatorObjectId;
 }
 
 /* --------------------------------
@@ -373,8 +374,8 @@ OperatorShellMake(char *operatorName,
  * 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
+ *       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
@@ -388,23 +389,20 @@ OperatorShellMake(char *operatorName,
  *      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 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 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)
+ *                                             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
+ *                                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
@@ -413,30 +411,28 @@ OperatorShellMake(char *operatorName,
  * 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
+ *      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
- *             definedOK;                              -- operator can already have an oid?
  *             leftTypeName;                   -- X left type name
  *             rightTypeName;                  -- X right type name
- *             procedureName;                  -- procedure oid for operator code
+ *             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;                                -- possible hash operator?
- *             leftSortName;                   -- X left sort operator
- *             rightSortName;                  -- X right sort operator
+ *             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,
@@ -450,60 +446,70 @@ OperatorDef(char *operatorName,
                        char *leftSortName,
                        char *rightSortName)
 {
-       register        i,
+       int                     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 = 0;
        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];
+       Oid                     typeId[FUNC_MAX_ARGS];
        int                     nargs;
+       NameData        oname;
        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);
+       ScanKeyData     opKey[3];
 
        operatorObjectId = OperatorGet(operatorName,
                                                                   leftTypeName,
-                                                                  rightTypeName);
+                                                                  rightTypeName,
+                                                                  &operatorAlreadyDefined);
 
-       if (OidIsValid(operatorObjectId) && !definedOK)
-               elog(WARN, "OperatorDef: operator \"%s\" already defined",
+       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, "left type \"%s\" does not exist",
+                                leftTypeName);
+       }
+
        if (rightTypeName)
+       {
                rightTypeId = TypeGet(rightTypeName, &rightDefined);
 
-       if (!((OidIsValid(leftTypeId && leftDefined)) ||
-                 (OidIsValid(rightTypeId && rightDefined))))
-               elog(WARN, "OperatorGet: no argument types??");
+               if (!OidIsValid(rightTypeId) || !rightDefined)
+                       elog(ERROR, "right type \"%s\" does not exist",
+                                rightTypeName);
+       }
+
+       if (!((OidIsValid(leftTypeId) && leftDefined) ||
+                 (OidIsValid(rightTypeId) && rightDefined)))
+               elog(ERROR, "operator must have at least one operand type");
 
        for (i = 0; i < Natts_pg_operator; ++i)
        {
@@ -512,14 +518,12 @@ OperatorDef(char *operatorName,
                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.
-        * ----------------
+       /*
+        * 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));
+       MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
        if (!leftTypeName)
        {
                typeId[0] = rightTypeId;
@@ -536,91 +540,91 @@ OperatorDef(char *operatorName,
                typeId[1] = rightTypeId;
                nargs = 2;
        }
-       tup = SearchSysCacheTuple(PRONAME,
-                                                         PointerGetDatum(procedureName),
-                                                         Int32GetDatum(nargs),
-                                                         PointerGetDatum(typeId),
-                                                         0);
-
-       if (!PointerIsValid(tup))
-               func_error("OperatorDef", procedureName, nargs, 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
-        * ----------------
+       tup = SearchSysCache(PROCNAME,
+                                                PointerGetDatum(procedureName),
+                                                Int32GetDatum(nargs),
+                                                PointerGetDatum(typeId),
+                                                0);
+       if (!HeapTupleIsValid(tup))
+               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);
+
+       ReleaseSysCache(tup);
+
+       /*
+        * find restriction estimator
         */
        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),
-                                                                 PointerGetDatum(typeId),
-                                                                 0);
-               if (!HeapTupleIsValid(tup))
-                       func_error("OperatorDef", restrictionName, 5, typeId);
-
-               values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_oid);
+               Oid                     restOid;
+
+               MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
+               typeId[0] = 0;                  /* Query (opaque type) */
+               typeId[1] = OIDOID;             /* operator OID */
+               typeId[2] = 0;                  /* args list (opaque type) */
+               typeId[3] = INT4OID;    /* varRelid */
+
+               restOid = GetSysCacheOid(PROCNAME,
+                                                                PointerGetDatum(restrictionName),
+                                                                Int32GetDatum(4),
+                                                                PointerGetDatum(typeId),
+                                                                0);
+               if (!OidIsValid(restOid))
+                       func_error("OperatorDef", restrictionName, 4, typeId, NULL);
+
+               values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restOid);
        }
        else
                values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
 
-       /* ----------------
-        *      find join - only valid for binary operators
-        * ----------------
+       /*
+        * find join estimator
         */
        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),
-                                                                 PointerGetDatum(typeId),
-                                                                 0);
-               if (!HeapTupleIsValid(tup))
-                       func_error("OperatorDef", joinName, 5, typeId);
-
-               values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_oid);
+               Oid                     joinOid;
+
+               MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
+               typeId[0] = 0;                  /* Query (opaque type) */
+               typeId[1] = OIDOID;             /* operator OID */
+               typeId[2] = 0;                  /* args list (opaque type) */
+
+               joinOid = GetSysCacheOid(PROCNAME,
+                                                                PointerGetDatum(joinName),
+                                                                Int32GetDatum(3),
+                                                                PointerGetDatum(typeId),
+                                                                0);
+               if (!OidIsValid(joinOid))
+                       func_error("OperatorDef", joinName, 3, typeId, NULL);
+
+               values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
        }
        else
                values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
 
-       /* ----------------
+       /*
         * set up values in the operator tuple
-        * ----------------
         */
        i = 0;
-       values[i++] = PointerGetDatum(operatorName);
+       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++] = CharGetDatum(leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l');
+       values[i++] = BoolGetDatum(isLeftAssociative);
+       values[i++] = BoolGetDatum(canHash);
        values[i++] = ObjectIdGetDatum(leftTypeId);
        values[i++] = ObjectIdGetDatum(rightTypeId);
 
-       ++i;                                            /* Skip "prorettype", this was done above */
+       ++i;                                            /* Skip "oprresult", it was filled in
+                                                                * 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.
+        * 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;
@@ -631,96 +635,146 @@ OperatorDef(char *operatorName,
        {
                if (name[j])
                {
-
-                       /* for the commutator, switch order of arguments */
-                       if (j == 0)
+                       char       *otherLeftTypeName = NULL;
+                       char       *otherRightTypeName = NULL;
+                       Oid                     otherLeftTypeId = InvalidOid;
+                       Oid                     otherRightTypeId = InvalidOid;
+                       Oid                     other_oid = InvalidOid;
+                       bool            otherDefined = false;
+
+                       switch (j)
                        {
-                               other_oid = OperatorGet(name[j], rightTypeName, leftTypeName);
-                               commutatorId = other_oid;
-                       }
-                       else
-                       {
-                               other_oid = OperatorGet(name[j], leftTypeName, rightTypeName);
-                               if (j == 1)
+                               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))      /* already in catalogs */
+                       if (OidIsValid(other_oid))
+                       {
+                               /* other op already in catalogs */
                                values[i++] = ObjectIdGetDatum(other_oid);
-                       else if (strcmp(operatorName, name[j]) != 0)
+                       }
+                       else if (strcmp(operatorName, name[j]) != 0 ||
+                                        otherLeftTypeId != leftTypeId ||
+                                        otherRightTypeId != rightTypeId)
                        {
                                /* 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);
-                               }
-
+                               other_oid = OperatorShellMake(name[j],
+                                                                                         otherLeftTypeName,
+                                                                                         otherRightTypeName);
                                if (!OidIsValid(other_oid))
-                                       elog(WARN,
-                                                "OperatorDef: can't create operator '%s'",
+                                       elog(ERROR,
+                                          "OperatorDef: can't create operator shell \"%s\"",
                                                 name[j]);
                                values[i++] = ObjectIdGetDatum(other_oid);
-
                        }
                        else
-/* not in catalogs, same as operator ??? */
-                               values[i++] = ObjectIdGetDatum(InvalidOid);
+                       {
 
+                               /*
+                                * self-linkage to this operator; will fix below. Note
+                                * that only self-linkage for commutation makes sense.
+                                */
+                               if (j != 0)
+                                       elog(ERROR,
+                                                "operator cannot be its own negator or sort operator");
+                               selfCommutator = true;
+                               values[i++] = ObjectIdGetDatum(InvalidOid);
+                       }
                }
                else
-/* new operator is optional */
+               {
+                       /* other operator is omitted */
                        values[i++] = ObjectIdGetDatum(InvalidOid);
+               }
        }
 
-       /* last three fields were filled in first */
+       /* 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_ctid and a buffer.
+        * If we are adding to an operator shell, get its t_self
         */
-       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);
+               /* Make sure we can see the shell even if it is new in current cmd */
+               CommandCounterIncrement();
+
+               ScanKeyEntryInitialize(&opKey[0], 0x0,
+                                                          Anum_pg_operator_oprname,
+                                                          F_NAMEEQ,
+                                                          PointerGetDatum(operatorName));
+               ScanKeyEntryInitialize(&opKey[1], 0x0,
+                                                          Anum_pg_operator_oprleft,
+                                                          F_OIDEQ,
+                                                          ObjectIdGetDatum(leftTypeId));
+               ScanKeyEntryInitialize(&opKey[2], 0x0,
+                                                          Anum_pg_operator_oprright,
+                                                          F_OIDEQ,
+                                                          ObjectIdGetDatum(rightTypeId));
 
                pg_operator_scan = heap_beginscan(pg_operator_desc,
                                                                                  0,
-                                                                                 SelfTimeQual,
+                                                                                 SnapshotSelf, /* no cache? */
                                                                                  3,
                                                                                  opKey);
 
-               tup = heap_getnext(pg_operator_scan, 0, &buffer);
+               tup = heap_getnext(pg_operator_scan, 0);
                if (HeapTupleIsValid(tup))
                {
                        tup = heap_modifytuple(tup,
-                                                                  buffer,
                                                                   pg_operator_desc,
                                                                   values,
                                                                   nulls,
                                                                   replaces);
 
-                       ItemPointerCopy(&tup->t_ctid, &itemPointerData);
-                       setheapoverride(true);
-                       heap_replace(pg_operator_desc, &itemPointerData, tup);
-                       setheapoverride(false);
+                       simple_heap_update(pg_operator_desc, &tup->t_self, tup);
                }
                else
-                       elog(WARN, "OperatorDef: no operator %d", other_oid);
+                       elog(ERROR, "OperatorDef: operator %u not found", operatorObjectId);
 
                heap_endscan(pg_operator_scan);
-
        }
        else
        {
@@ -728,27 +782,35 @@ OperatorDef(char *operatorName,
                tup = heap_formtuple(tupDesc, values, nulls);
 
                heap_insert(pg_operator_desc, tup);
-               operatorObjectId = tup->t_oid;
+               operatorObjectId = tup->t_data->t_oid;
        }
 
-       heap_close(pg_operator_desc);
+       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);
 
        /*
-        * 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 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 (!definedOK)
+       if (selfCommutator)
+               commutatorId = operatorObjectId;
+
+       if (OidIsValid(commutatorId) || OidIsValid(negatorId))
                OperatorUpd(operatorObjectId, commutatorId, negatorId);
 }
 
@@ -756,8 +818,8 @@ OperatorDef(char *operatorName,
  * 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.
+ *     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.
  * ----------------------------------------------------------------
@@ -765,194 +827,170 @@ OperatorDef(char *operatorName,
 static void
 OperatorUpd(Oid baseId, Oid commId, Oid negId)
 {
-       register        i;
+       int                     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);
+       ScanKeyData     opKey[1];
 
        for (i = 0; i < Natts_pg_operator; ++i)
        {
-               values[i] = (Datum) NULL;
+               values[i] = (Datum) 0;
                replaces[i] = ' ';
                nulls[i] = ' ';
        }
 
-       pg_operator_desc = heap_openr(OperatorRelationName);
+       pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
 
-       /* check and update the commutator, if necessary */
-       opKey[0].sk_argument = ObjectIdGetDatum(commId);
+       /*
+        * check and update the commutator & negator, if necessary
+        *
+        * First make sure we can see them...
+        */
+       CommandCounterIncrement();
+
+       ScanKeyEntryInitialize(&opKey[0], 0x0,
+                                                  ObjectIdAttributeNumber,
+                                                  F_OIDEQ,
+                                                  ObjectIdGetDatum(commId));
 
        pg_operator_scan = heap_beginscan(pg_operator_desc,
                                                                          0,
-                                                                         SelfTimeQual,
+                                                                         SnapshotSelf,         /* no cache? */
                                                                          1,
                                                                          opKey);
 
-       tup = heap_getnext(pg_operator_scan, 0, &buffer);
+       tup = heap_getnext(pg_operator_scan, 0);
 
-       /* if the commutator and negator are the same operator, do one update */
+       /*
+        * 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))
                {
-                       OperatorTupleForm t;
+                       Form_pg_operator t;
 
-                       t = (OperatorTupleForm) GETSTRUCT(tup);
+                       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);
+                                       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);
+                                       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);
+                               simple_heap_update(pg_operator_desc, &tup->t_self, tup);
 
-                               setheapoverride(true);
-                               heap_replace(pg_operator_desc, &itemPointerData, tup);
-                               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);
+                               }
                        }
                }
                heap_endscan(pg_operator_scan);
 
-               heap_close(pg_operator_desc);
-
-               /* release the buffer properly */
-               if (BufferIsValid(buffer))
-                       ReleaseBuffer(buffer);
+               heap_close(pg_operator_desc, RowExclusiveLock);
 
                return;
        }
 
        /* if commutator and negator are different, do two updates */
+
        if (HeapTupleIsValid(tup) &&
-               !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprcom)))
+               !(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);
-               setheapoverride(true);
-               heap_replace(pg_operator_desc, &itemPointerData, tup);
-               setheapoverride(false);
+               simple_heap_update(pg_operator_desc, &tup->t_self, tup);
 
-               values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
-               replaces[Anum_pg_operator_oprcom - 1] = ' ';
+               if (RelationGetForm(pg_operator_desc)->relhasindex)
+               {
+                       Relation        idescs[Num_pg_operator_indices];
 
-               /* release the buffer properly */
-               if (BufferIsValid(buffer))
-                       ReleaseBuffer(buffer);
+                       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,
-                                                                         SelfTimeQual,
+                                                                         SnapshotSelf,         /* no cache? */
                                                                          1,
                                                                          opKey);
 
-       tup = heap_getnext(pg_operator_scan, 0, &buffer);
+       tup = heap_getnext(pg_operator_scan, 0);
        if (HeapTupleIsValid(tup) &&
-               !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprnegate)))
+               !(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,
-                                                          buffer,
                                                           pg_operator_desc,
                                                           values,
                                                           nulls,
                                                           replaces);
 
-               ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+               simple_heap_update(pg_operator_desc, &tup->t_self, tup);
 
-               setheapoverride(true);
-               heap_replace(pg_operator_desc, &itemPointerData, tup);
-               setheapoverride(false);
-       }
+               if (RelationGetForm(pg_operator_desc)->relhasindex)
+               {
+                       Relation        idescs[Num_pg_operator_indices];
 
-       /* release the buffer properly */
-       if (BufferIsValid(buffer))
-               ReleaseBuffer(buffer);
+                       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);
+       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.
- *
- *     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.
- * ----------------------------------------------------------------
+ * This is now just an interface procedure for OperatorDef ...
  *
  * "X" indicates an optional argument (i.e. one that can be NULL)
  *             operatorName;                   -- operator name
@@ -964,11 +1002,10 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
  *             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
- *
+ *             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,
@@ -985,59 +1022,28 @@ OperatorCreate(char *operatorName,
                           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);
-       else
-               commObjectId = 0;
-
-       if (negatorName)
-               negObjectId = OperatorGet(negatorName,
-                                                                 leftTypeName,
-                                                                 rightTypeName);
-       else
-               negObjectId = 0;
-
-       if (leftSortName)
-               leftSortObjectId = OperatorGet(leftSortName,
-                                                                          leftTypeName,
-                                                                          rightTypeName);
-       else
-               leftSortObjectId = 0;
+               elog(ERROR, "at least one of leftarg or rightarg must be specified");
 
-       if (rightSortName)
-               rightSortObjectId = OperatorGet(rightSortName,
-                                                                               rightTypeName,
-                                                                               leftTypeName);
-       else
-               rightSortObjectId = 0;
+       if (!(leftTypeName && rightTypeName))
+       {
+               /* If it's not a binary op, these things mustn't be set: */
+               if (commutatorName)
+                       elog(ERROR, "only binary operators can have commutators");
+               if (joinName)
+                       elog(ERROR, "only binary operators can have join selectivity");
+               if (canHash)
+                       elog(ERROR, "only binary operators can hash");
+               if (leftSortName || rightSortName)
+                       elog(ERROR, "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.
-        *
-        *      This operator should not be defined yet.
-        * ----------------
+       /*
+        * Use OperatorDef() to define the specified operator and also create
+        * shells for the operator's associated operators if they don't
+        * already exist.
         */
-       definedOK = 0;
-
        OperatorDef(operatorName,
-                               definedOK,
                                leftTypeName,
                                rightTypeName,
                                procedureName,
@@ -1050,77 +1056,4 @@ OperatorCreate(char *operatorName,
                                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 */
 }