aboutsummaryrefslogtreecommitdiff
path: root/src/backend/catalog/pg_operator.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/catalog/pg_operator.c')
-rw-r--r--src/backend/catalog/pg_operator.c737
1 files changed, 338 insertions, 399 deletions
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 41023b7edc8..3a4bb1bba34 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.65 2002/04/09 20:35:47 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.66 2002/04/16 23:08:10 tgl Exp $
*
* NOTES
* these routines moved here from commands/define.c and somewhat cleaned up.
@@ -20,42 +20,41 @@
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
+#include "catalog/namespace.h"
#include "catalog/pg_operator.h"
-#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
+#include "parser/parse_oper.h"
#include "utils/builtins.h"
-#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
static Oid OperatorGet(const char *operatorName,
+ Oid operatorNamespace,
Oid leftObjectId,
Oid rightObjectId,
bool *defined);
+static Oid OperatorLookup(List *operatorName,
+ Oid leftObjectId,
+ Oid rightObjectId,
+ bool *defined);
+
static Oid OperatorShellMake(const char *operatorName,
+ Oid operatorNamespace,
Oid leftTypeId,
Oid rightTypeId);
-static void OperatorDef(const char *operatorName,
- Oid leftTypeId,
- Oid rightTypeId,
- List *procedureName,
- uint16 precedence,
- bool isLeftAssociative,
- const char *commutatorName,
- const char *negatorName,
- List *restrictionName,
- List *joinName,
- bool canHash,
- const char *leftSortName,
- const char *rightSortName);
-
static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
+static Oid get_other_operator(List *otherOp,
+ Oid otherLeftTypeId, Oid otherRightTypeId,
+ const char *operatorName, Oid operatorNamespace,
+ Oid leftTypeId, Oid rightTypeId,
+ bool isCommutator);
+
/*
* Check whether a proposed operator name is legal
@@ -114,76 +113,36 @@ validOperatorName(const char *name)
}
-/* ----------------------------------------------------------------
- * OperatorGet
+/*
+ * OperatorGet
*
- * finds the operator associated with the specified name
- * and left and right type IDs.
+ * finds an operator given an exact specification (name, namespace,
+ * left and right type IDs).
*
- * 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)
- * ----------------------------------------------------------------
+ * *defined is set TRUE if defined (not a shell)
*/
static Oid
OperatorGet(const char *operatorName,
+ Oid operatorNamespace,
Oid leftObjectId,
Oid rightObjectId,
bool *defined)
{
- Relation pg_operator_desc;
- HeapScanDesc pg_operator_scan;
HeapTuple tup;
- ScanKeyData opKey[3];
Oid operatorObjectId;
- if (!(OidIsValid(leftObjectId) || OidIsValid(rightObjectId)))
- elog(ERROR, "operator %s must have at least one operand type",
- operatorName);
-
- /*
- * open the pg_operator relation
- */
- pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
-
- /*
- * form scan key
- */
- 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
- */
- 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);
-
+ tup = SearchSysCache(OPERNAMENSP,
+ PointerGetDatum(operatorName),
+ ObjectIdGetDatum(leftObjectId),
+ ObjectIdGetDatum(rightObjectId),
+ ObjectIdGetDatum(operatorNamespace));
if (HeapTupleIsValid(tup))
{
regproc oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
operatorObjectId = tup->t_data->t_oid;
*defined = RegProcedureIsValid(oprcode);
+ ReleaseSysCache(tup);
}
else
{
@@ -191,21 +150,48 @@ OperatorGet(const char *operatorName,
*defined = false;
}
- /*
- * close the scan and return the oid.
- */
- heap_endscan(pg_operator_scan);
- heap_close(pg_operator_desc, AccessShareLock);
+ return operatorObjectId;
+}
+
+/*
+ * OperatorLookup
+ *
+ * looks up an operator given a possibly-qualified name and
+ * left and right type IDs.
+ *
+ * *defined is set TRUE if defined (not a shell)
+ */
+static Oid
+OperatorLookup(List *operatorName,
+ Oid leftObjectId,
+ Oid rightObjectId,
+ bool *defined)
+{
+ Oid operatorObjectId;
+ regproc oprcode;
+
+ operatorObjectId = LookupOperName(operatorName, leftObjectId,
+ rightObjectId);
+ if (!OidIsValid(operatorObjectId))
+ {
+ *defined = false;
+ return InvalidOid;
+ }
+
+ oprcode = get_opcode(operatorObjectId);
+ *defined = RegProcedureIsValid(oprcode);
return operatorObjectId;
}
+
/*
* OperatorShellMake
* Make a "shell" entry for a not-yet-existing operator.
*/
static Oid
OperatorShellMake(const char *operatorName,
+ Oid operatorNamespace,
Oid leftTypeId,
Oid rightTypeId)
{
@@ -225,11 +211,6 @@ OperatorShellMake(const char *operatorName,
elog(ERROR, "\"%s\" is not a valid operator name", operatorName);
/*
- * open pg_operator
- */
- pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
-
- /*
* initialize our *nulls and *values arrays
*/
for (i = 0; i < Natts_pg_operator; ++i)
@@ -244,28 +225,35 @@ OperatorShellMake(const char *operatorName,
*/
i = 0;
namestrcpy(&oname, operatorName);
- values[i++] = NameGetDatum(&oname);
- values[i++] = Int32GetDatum(GetUserId());
- values[i++] = UInt16GetDatum(0);
- values[i++] = CharGetDatum('b'); /* assume it's binary */
- values[i++] = BoolGetDatum(false);
- values[i++] = BoolGetDatum(false);
- values[i++] = ObjectIdGetDatum(leftTypeId);
- values[i++] = ObjectIdGetDatum(rightTypeId);
- 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);
+ values[i++] = NameGetDatum(&oname); /* oprname */
+ values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */
+ values[i++] = Int32GetDatum(GetUserId()); /* oprowner */
+ values[i++] = UInt16GetDatum(0); /* oprprec */
+ values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */
+ values[i++] = BoolGetDatum(false); /* oprisleft */
+ values[i++] = BoolGetDatum(false); /* oprcanhash */
+ values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
+ values[i++] = ObjectIdGetDatum(rightTypeId); /* oprright */
+ values[i++] = ObjectIdGetDatum(InvalidOid); /* oprresult */
+ values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcom */
+ values[i++] = ObjectIdGetDatum(InvalidOid); /* oprnegate */
+ values[i++] = ObjectIdGetDatum(InvalidOid); /* oprlsortop */
+ values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrsortop */
+ values[i++] = ObjectIdGetDatum(InvalidOid); /* oprltcmpop */
+ values[i++] = ObjectIdGetDatum(InvalidOid); /* oprgtcmpop */
+ values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcode */
+ values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrest */
+ values[i++] = ObjectIdGetDatum(InvalidOid); /* oprjoin */
/*
- * create a new operator tuple
+ * open pg_operator
*/
+ pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
tupDesc = pg_operator_desc->rd_att;
+ /*
+ * create a new operator tuple
+ */
tup = heap_formtuple(tupDesc, values, nulls);
/*
@@ -293,8 +281,26 @@ OperatorShellMake(const char *operatorName,
return operatorObjectId;
}
-/* --------------------------------
- * OperatorDef
+/*
+ * OperatorCreate
+ *
+ * "X" indicates an optional argument (i.e. one that can be NULL or 0)
+ * operatorName name for new operator
+ * operatorNamespace namespace for new operator
+ * leftTypeId X left type ID
+ * rightTypeId X right type ID
+ * procedureName procedure for operator
+ * precedence operator precedence
+ * isLeftAssociative operator is left associative
+ * commutatorName X commutator operator
+ * negatorName X negator operator
+ * restrictionName X restriction sel. procedure
+ * joinName X join sel. procedure
+ * canHash hash join can be used with this operator
+ * leftSortName X left sort operator (for merge join)
+ * rightSortName X right sort operator (for merge join)
+ * ltCompareName X L<R compare operator (for merge join)
+ * gtCompareName X L>R compare operator (for merge join)
*
* This routine gets complicated because it allows the user to
* specify operators that do not exist. For example, if operator
@@ -354,68 +360,73 @@ OperatorShellMake(const char *operatorName,
* 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
- * leftTypeId; -- X left type id
- * rightTypeId; -- X right type id
- * 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(const char *operatorName,
- Oid leftTypeId,
- Oid rightTypeId,
- List *procedureName,
- uint16 precedence,
- bool isLeftAssociative,
- const char *commutatorName,
- const char *negatorName,
- List *restrictionName,
- List *joinName,
- bool canHash,
- const char *leftSortName,
- const char *rightSortName)
+void
+OperatorCreate(const char *operatorName,
+ Oid operatorNamespace,
+ Oid leftTypeId,
+ Oid rightTypeId,
+ List *procedureName,
+ uint16 precedence,
+ bool isLeftAssociative,
+ List *commutatorName,
+ List *negatorName,
+ List *restrictionName,
+ List *joinName,
+ bool canHash,
+ List *leftSortName,
+ List *rightSortName,
+ List *ltCompareName,
+ List *gtCompareName)
{
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 commutatorId = InvalidOid;
- Oid negatorId = InvalidOid;
+ Oid procOid;
+ Oid operResultType;
+ Oid commutatorId,
+ negatorId,
+ leftSortId,
+ rightSortId,
+ ltCompareId,
+ gtCompareId,
+ restOid,
+ joinOid;
bool selfCommutator = false;
- const char *name[4];
Oid typeId[FUNC_MAX_ARGS];
int nargs;
- Oid procOid;
NameData oname;
TupleDesc tupDesc;
- ScanKeyData opKey[3];
- int i,
- j;
+ int i;
/*
- * validate operator name
+ * Sanity checks
*/
if (!validOperatorName(operatorName))
elog(ERROR, "\"%s\" is not a valid operator name", operatorName);
- if (!(OidIsValid(leftTypeId) || OidIsValid(rightTypeId)))
- elog(ERROR, "operator must have at least one operand type");
+ if (!OidIsValid(leftTypeId) && !OidIsValid(rightTypeId))
+ elog(ERROR, "at least one of leftarg or rightarg must be specified");
+
+ if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
+ {
+ /* If it's not a binary op, these things mustn't be set: */
+ if (commutatorName)
+ 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 || ltCompareName || gtCompareName)
+ elog(ERROR, "only binary operators can mergejoin");
+ }
operatorObjectId = OperatorGet(operatorName,
+ operatorNamespace,
leftTypeId,
rightTypeId,
&operatorAlreadyDefined);
@@ -429,13 +440,6 @@ OperatorDef(const char *operatorName,
* filling in a previously-created shell.
*/
- 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
@@ -461,17 +465,13 @@ OperatorDef(const char *operatorName,
procOid = LookupFuncName(procedureName, nargs, typeId);
if (!OidIsValid(procOid))
func_error("OperatorDef", procedureName, nargs, typeId, NULL);
-
- values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procOid);
- values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(get_func_rettype(procOid));
+ operResultType = get_func_rettype(procOid);
/*
* find restriction estimator
*/
if (restrictionName)
- { /* optional */
- Oid restOid;
-
+ {
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
typeId[0] = 0; /* Query (opaque type) */
typeId[1] = OIDOID; /* operator OID */
@@ -481,19 +481,15 @@ OperatorDef(const char *operatorName,
restOid = LookupFuncName(restrictionName, 4, typeId);
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);
+ restOid = InvalidOid;
/*
* find join estimator
*/
if (joinName)
- { /* optional */
- Oid joinOid;
-
+ {
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
typeId[0] = 0; /* Query (opaque type) */
typeId[1] = OIDOID; /* operator OID */
@@ -502,170 +498,148 @@ OperatorDef(const char *operatorName,
joinOid = LookupFuncName(joinName, 3, typeId);
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);
+ joinOid = InvalidOid;
/*
* set up values in the operator tuple
*/
+
+ for (i = 0; i < Natts_pg_operator; ++i)
+ {
+ values[i] = (Datum) NULL;
+ replaces[i] = 'r';
+ nulls[i] = ' ';
+ }
+
i = 0;
namestrcpy(&oname, operatorName);
- values[i++] = NameGetDatum(&oname);
- values[i++] = Int32GetDatum(GetUserId());
- values[i++] = UInt16GetDatum(precedence);
- values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
- values[i++] = BoolGetDatum(isLeftAssociative);
- values[i++] = BoolGetDatum(canHash);
- values[i++] = ObjectIdGetDatum(leftTypeId);
- values[i++] = ObjectIdGetDatum(rightTypeId);
-
- ++i; /* Skip "oprresult", it was filled in
- * above */
+ values[i++] = NameGetDatum(&oname); /* oprname */
+ values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */
+ values[i++] = Int32GetDatum(GetUserId()); /* oprowner */
+ values[i++] = UInt16GetDatum(precedence); /* oprprec */
+ values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */
+ values[i++] = BoolGetDatum(isLeftAssociative); /* oprisleft */
+ values[i++] = BoolGetDatum(canHash); /* oprcanhash */
+ values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
+ values[i++] = ObjectIdGetDatum(rightTypeId); /* oprright */
+ values[i++] = ObjectIdGetDatum(operResultType); /* oprresult */
/*
* 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 (commutatorName)
{
- if (name[j])
- {
- Oid otherLeftTypeId = InvalidOid;
- Oid otherRightTypeId = InvalidOid;
- Oid other_oid = InvalidOid;
- bool otherDefined = false;
+ /* commutator has reversed arg types */
+ commutatorId = get_other_operator(commutatorName,
+ rightTypeId, leftTypeId,
+ operatorName, operatorNamespace,
+ leftTypeId, rightTypeId,
+ true);
+ /*
+ * self-linkage to this operator; will fix below. Note
+ * that only self-linkage for commutation makes sense.
+ */
+ if (!OidIsValid(commutatorId))
+ selfCommutator = true;
+ }
+ else
+ commutatorId = InvalidOid;
+ values[i++] = ObjectIdGetDatum(commutatorId); /* oprcom */
- switch (j)
- {
- case 0: /* commutator has reversed arg types */
- otherLeftTypeId = rightTypeId;
- otherRightTypeId = leftTypeId;
- other_oid = OperatorGet(name[j],
- otherLeftTypeId,
- otherRightTypeId,
- &otherDefined);
- commutatorId = other_oid;
- break;
- case 1: /* negator has same arg types */
- otherLeftTypeId = leftTypeId;
- otherRightTypeId = rightTypeId;
- other_oid = OperatorGet(name[j],
- otherLeftTypeId,
- otherRightTypeId,
- &otherDefined);
- negatorId = other_oid;
- break;
- case 2: /* left sort op takes left-side data type */
- otherLeftTypeId = leftTypeId;
- otherRightTypeId = leftTypeId;
- other_oid = OperatorGet(name[j],
- otherLeftTypeId,
- otherRightTypeId,
- &otherDefined);
- break;
- case 3: /* right sort op takes right-side data type */
- otherLeftTypeId = rightTypeId;
- otherRightTypeId = rightTypeId;
- other_oid = OperatorGet(name[j],
- otherLeftTypeId,
- otherRightTypeId,
- &otherDefined);
- break;
- }
+ if (negatorName)
+ {
+ /* negator has same arg types */
+ negatorId = get_other_operator(negatorName,
+ leftTypeId, rightTypeId,
+ operatorName, operatorNamespace,
+ leftTypeId, rightTypeId,
+ false);
+ }
+ else
+ negatorId = InvalidOid;
+ values[i++] = ObjectIdGetDatum(negatorId); /* oprnegate */
- 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],
- otherLeftTypeId,
- otherRightTypeId);
- 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,
- "operator cannot be its own negator or sort operator");
- selfCommutator = true;
- values[i++] = ObjectIdGetDatum(InvalidOid);
- }
- }
- else
- {
- /* other operator is omitted */
- values[i++] = ObjectIdGetDatum(InvalidOid);
- }
+ if (leftSortName)
+ {
+ /* left sort op takes left-side data type */
+ leftSortId = get_other_operator(leftSortName,
+ leftTypeId, leftTypeId,
+ operatorName, operatorNamespace,
+ leftTypeId, rightTypeId,
+ false);
}
+ else
+ leftSortId = InvalidOid;
+ values[i++] = ObjectIdGetDatum(leftSortId); /* oprlsortop */
- /* last three fields were filled in above */
+ if (rightSortName)
+ {
+ /* right sort op takes right-side data type */
+ rightSortId = get_other_operator(rightSortName,
+ rightTypeId, rightTypeId,
+ operatorName, operatorNamespace,
+ leftTypeId, rightTypeId,
+ false);
+ }
+ else
+ rightSortId = InvalidOid;
+ values[i++] = ObjectIdGetDatum(rightSortId); /* oprrsortop */
+
+ if (ltCompareName)
+ {
+ /* comparator has same arg types */
+ ltCompareId = get_other_operator(ltCompareName,
+ leftTypeId, rightTypeId,
+ operatorName, operatorNamespace,
+ leftTypeId, rightTypeId,
+ false);
+ }
+ else
+ ltCompareId = InvalidOid;
+ values[i++] = ObjectIdGetDatum(ltCompareId); /* oprltcmpop */
+
+ if (gtCompareName)
+ {
+ /* comparator has same arg types */
+ gtCompareId = get_other_operator(gtCompareName,
+ leftTypeId, rightTypeId,
+ operatorName, operatorNamespace,
+ leftTypeId, rightTypeId,
+ false);
+ }
+ else
+ gtCompareId = InvalidOid;
+ values[i++] = ObjectIdGetDatum(gtCompareId); /* oprgtcmpop */
+
+ values[i++] = ObjectIdGetDatum(procOid); /* oprcode */
+ values[i++] = ObjectIdGetDatum(restOid); /* oprrest */
+ values[i++] = ObjectIdGetDatum(joinOid); /* oprjoin */
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
/*
- * If we are adding to an operator shell, get its t_self
+ * If we are adding to an operator shell, update; else insert
*/
if (operatorObjectId)
{
- /* 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,
- 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);
+ tup = SearchSysCacheCopy(OPEROID,
+ ObjectIdGetDatum(operatorObjectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "OperatorDef: operator %u not found",
+ operatorObjectId);
- simple_heap_update(pg_operator_desc, &tup->t_self, tup);
- }
- else
- elog(ERROR, "OperatorDef: operator %u not found", operatorObjectId);
+ tup = heap_modifytuple(tup,
+ pg_operator_desc,
+ values,
+ nulls,
+ replaces);
- heap_endscan(pg_operator_scan);
+ simple_heap_update(pg_operator_desc, &tup->t_self, tup);
}
else
{
@@ -676,6 +650,7 @@ OperatorDef(const char *operatorName,
operatorObjectId = tup->t_data->t_oid;
}
+ /* Must update the indexes in either case */
if (RelationGetForm(pg_operator_desc)->relhasindex)
{
Relation idescs[Num_pg_operator_indices];
@@ -705,7 +680,65 @@ OperatorDef(const char *operatorName,
OperatorUpd(operatorObjectId, commutatorId, negatorId);
}
-/* ----------------------------------------------------------------
+/*
+ * Try to lookup another operator (commutator, etc)
+ *
+ * If not found, check to see if it is exactly the operator we are trying
+ * to define; if so, return InvalidOid. (Note that this case is only
+ * sensible for a commutator, so we error out otherwise.) If it is not
+ * the same operator, create a shell operator.
+ */
+static Oid
+get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
+ const char *operatorName, Oid operatorNamespace,
+ Oid leftTypeId, Oid rightTypeId, bool isCommutator)
+{
+ Oid other_oid;
+ bool otherDefined;
+ char *otherName;
+ Oid otherNamespace;
+
+ other_oid = OperatorLookup(otherOp,
+ otherLeftTypeId,
+ otherRightTypeId,
+ &otherDefined);
+
+ if (OidIsValid(other_oid))
+ {
+ /* other op already in catalogs */
+ return other_oid;
+ }
+
+ otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
+ &otherName);
+
+ if (strcmp(otherName, operatorName) == 0 &&
+ otherNamespace == operatorNamespace &&
+ otherLeftTypeId == leftTypeId &&
+ otherRightTypeId == rightTypeId)
+ {
+ /*
+ * self-linkage to this operator; caller will fix later. Note
+ * that only self-linkage for commutation makes sense.
+ */
+ if (!isCommutator)
+ elog(ERROR, "operator cannot be its own negator or sort operator");
+ return InvalidOid;
+ }
+
+ /* not in catalogs, different from operator, so make shell */
+ other_oid = OperatorShellMake(otherName,
+ otherNamespace,
+ otherLeftTypeId,
+ otherRightTypeId);
+ if (!OidIsValid(other_oid))
+ elog(ERROR,
+ "OperatorDef: can't create operator shell \"%s\"",
+ NameListToString(otherOp));
+ return other_oid;
+}
+
+/*
* OperatorUpd
*
* For a given operator, look up its negator and commutator operators.
@@ -713,19 +746,16 @@ OperatorDef(const char *operatorName,
* (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)
{
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];
- ScanKeyData opKey[1];
for (i = 0; i < Natts_pg_operator; ++i)
{
@@ -734,8 +764,6 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
nulls[i] = ' ';
}
- pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
-
/*
* check and update the commutator & negator, if necessary
*
@@ -743,18 +771,11 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
*/
CommandCounterIncrement();
- ScanKeyEntryInitialize(&opKey[0], 0x0,
- ObjectIdAttributeNumber,
- F_OIDEQ,
- ObjectIdGetDatum(commId));
-
- pg_operator_scan = heap_beginscan(pg_operator_desc,
- 0,
- SnapshotSelf, /* no cache? */
- 1,
- opKey);
+ pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
- tup = heap_getnext(pg_operator_scan, 0);
+ tup = SearchSysCacheCopy(OPEROID,
+ ObjectIdGetDatum(commId),
+ 0, 0, 0);
/*
* if the commutator and negator are the same operator, do one update.
@@ -765,13 +786,10 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
{
if (HeapTupleIsValid(tup))
{
- Form_pg_operator t;
+ Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
- t = (Form_pg_operator) GETSTRUCT(tup);
- if (!OidIsValid(t->oprcom)
- || !OidIsValid(t->oprnegate))
+ if (!OidIsValid(t->oprcom) || !OidIsValid(t->oprnegate))
{
-
if (!OidIsValid(t->oprnegate))
{
values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
@@ -802,7 +820,6 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
}
}
}
- heap_endscan(pg_operator_scan);
heap_close(pg_operator_desc, RowExclusiveLock);
@@ -816,6 +833,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
{
values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
replaces[Anum_pg_operator_oprcom - 1] = 'r';
+
tup = heap_modifytuple(tup,
pg_operator_desc,
values,
@@ -837,23 +855,18 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
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 = SearchSysCacheCopy(OPEROID,
+ ObjectIdGetDatum(negId),
+ 0, 0, 0);
- 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,
@@ -872,79 +885,5 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
}
}
- heap_endscan(pg_operator_scan);
-
heap_close(pg_operator_desc, RowExclusiveLock);
}
-
-
-/* ----------------------------------------------------------------
- * OperatorCreate
- *
- * This is now just an interface procedure for OperatorDef ...
- *
- * "X" indicates an optional argument (i.e. one that can be NULL or 0)
- * operatorName; -- operator name
- * leftTypeId; -- X left type ID
- * rightTypeId; -- X right type ID
- * 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(const char *operatorName,
- Oid leftTypeId,
- Oid rightTypeId,
- const char *procedureName,
- uint16 precedence,
- bool isLeftAssociative,
- const char *commutatorName,
- const char *negatorName,
- const char *restrictionName,
- const char *joinName,
- bool canHash,
- const char *leftSortName,
- const char *rightSortName)
-{
- if (!OidIsValid(leftTypeId) && !OidIsValid(rightTypeId))
- elog(ERROR, "at least one of leftarg or rightarg must be specified");
-
- if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
- {
- /* If it's not a binary op, these things mustn't be set: */
- if (commutatorName)
- 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.
- */
- OperatorDef(operatorName,
- leftTypeId,
- rightTypeId,
- makeList1(makeString((char*) procedureName)), /* XXX */
- precedence,
- isLeftAssociative,
- commutatorName,
- negatorName,
- restrictionName ? makeList1(makeString((char*) restrictionName)) : NIL, /* XXX */
- joinName ? makeList1(makeString((char*) joinName)) : NIL, /* XXX */
- canHash,
- leftSortName,
- rightSortName);
-}