/*-------------------------------------------------------------------------
*
- * 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 <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
+#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,
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;
}
/* --------------------------------
* 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.
* 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);
}