mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
Restructure operator classes to allow improved handling of cross-data-type
cases. Operator classes now exist within "operator families". While most families are equivalent to a single class, related classes can be grouped into one family to represent the fact that they are semantically compatible. Cross-type operators are now naturally adjunct parts of a family, without having to wedge them into a particular opclass as we had done originally. This commit restructures the catalogs and cleans up enough of the fallout so that everything still works at least as well as before, but most of the work needed to actually improve the planner's behavior will come later. Also, there are not yet CREATE/DROP/ALTER OPERATOR FAMILY commands; the only way to create a new family right now is to allow CREATE OPERATOR CLASS to make one by default. I owe some more documentation work, too. But that can all be done in smaller pieces once this infrastructure is in place.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Makefile for backend/catalog
|
||||
#
|
||||
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.60 2006/07/31 01:16:36 tgl Exp $
|
||||
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.61 2006/12/23 00:43:09 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -28,8 +28,8 @@ SUBSYS.o: $(OBJS)
|
||||
|
||||
POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
|
||||
pg_proc.h pg_type.h pg_attribute.h pg_class.h pg_autovacuum.h \
|
||||
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h \
|
||||
pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
|
||||
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
|
||||
pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
|
||||
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
|
||||
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
|
||||
pg_namespace.h pg_conversion.h pg_depend.h \
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.60 2006/10/04 00:29:50 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.61 2006/12/23 00:43:09 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "catalog/index.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_amop.h"
|
||||
#include "catalog/pg_amproc.h"
|
||||
#include "catalog/pg_attrdef.h"
|
||||
#include "catalog/pg_authid.h"
|
||||
#include "catalog/pg_cast.h"
|
||||
@@ -33,6 +35,7 @@
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_opfamily.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_rewrite.h"
|
||||
#include "catalog/pg_tablespace.h"
|
||||
@@ -78,19 +81,25 @@ typedef struct
|
||||
* See also getObjectClass().
|
||||
*/
|
||||
static const Oid object_classes[MAX_OCLASS] = {
|
||||
RelationRelationId, /* OCLASS_CLASS */
|
||||
ProcedureRelationId, /* OCLASS_PROC */
|
||||
TypeRelationId, /* OCLASS_TYPE */
|
||||
CastRelationId, /* OCLASS_CAST */
|
||||
ConstraintRelationId, /* OCLASS_CONSTRAINT */
|
||||
ConversionRelationId, /* OCLASS_CONVERSION */
|
||||
AttrDefaultRelationId, /* OCLASS_DEFAULT */
|
||||
LanguageRelationId, /* OCLASS_LANGUAGE */
|
||||
OperatorRelationId, /* OCLASS_OPERATOR */
|
||||
OperatorClassRelationId, /* OCLASS_OPCLASS */
|
||||
RewriteRelationId, /* OCLASS_REWRITE */
|
||||
TriggerRelationId, /* OCLASS_TRIGGER */
|
||||
NamespaceRelationId /* OCLASS_SCHEMA */
|
||||
RelationRelationId, /* OCLASS_CLASS */
|
||||
ProcedureRelationId, /* OCLASS_PROC */
|
||||
TypeRelationId, /* OCLASS_TYPE */
|
||||
CastRelationId, /* OCLASS_CAST */
|
||||
ConstraintRelationId, /* OCLASS_CONSTRAINT */
|
||||
ConversionRelationId, /* OCLASS_CONVERSION */
|
||||
AttrDefaultRelationId, /* OCLASS_DEFAULT */
|
||||
LanguageRelationId, /* OCLASS_LANGUAGE */
|
||||
OperatorRelationId, /* OCLASS_OPERATOR */
|
||||
OperatorClassRelationId, /* OCLASS_OPCLASS */
|
||||
OperatorFamilyRelationId, /* OCLASS_OPFAMILY */
|
||||
AccessMethodOperatorRelationId, /* OCLASS_AMOP */
|
||||
AccessMethodProcedureRelationId, /* OCLASS_AMPROC */
|
||||
RewriteRelationId, /* OCLASS_REWRITE */
|
||||
TriggerRelationId, /* OCLASS_TRIGGER */
|
||||
NamespaceRelationId, /* OCLASS_SCHEMA */
|
||||
AuthIdRelationId, /* OCLASS_ROLE */
|
||||
DatabaseRelationId, /* OCLASS_DATABASE */
|
||||
TableSpaceRelationId /* OCLASS_TBLSPACE */
|
||||
};
|
||||
|
||||
|
||||
@@ -122,6 +131,7 @@ static int object_address_comparator(const void *a, const void *b);
|
||||
static void add_object_address(ObjectClass oclass, Oid objectId, int32 subId,
|
||||
ObjectAddresses *addrs);
|
||||
static void getRelationDescription(StringInfo buffer, Oid relid);
|
||||
static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
|
||||
|
||||
|
||||
/*
|
||||
@@ -185,7 +195,7 @@ performDeletion(const ObjectAddress *object,
|
||||
* filled with some objects. Also, the deleted objects are saved in the
|
||||
* alreadyDeleted list.
|
||||
*
|
||||
* XXX performDeletion could be refactored to be a thin wrapper to this
|
||||
* XXX performDeletion could be refactored to be a thin wrapper around this
|
||||
* function.
|
||||
*/
|
||||
static void
|
||||
@@ -954,6 +964,18 @@ doDeletion(const ObjectAddress *object)
|
||||
RemoveOpClassById(object->objectId);
|
||||
break;
|
||||
|
||||
case OCLASS_OPFAMILY:
|
||||
RemoveOpFamilyById(object->objectId);
|
||||
break;
|
||||
|
||||
case OCLASS_AMOP:
|
||||
RemoveAmOpEntryById(object->objectId);
|
||||
break;
|
||||
|
||||
case OCLASS_AMPROC:
|
||||
RemoveAmProcEntryById(object->objectId);
|
||||
break;
|
||||
|
||||
case OCLASS_REWRITE:
|
||||
RemoveRewriteRuleById(object->objectId);
|
||||
break;
|
||||
@@ -966,6 +988,8 @@ doDeletion(const ObjectAddress *object)
|
||||
RemoveSchemaById(object->objectId);
|
||||
break;
|
||||
|
||||
/* OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE not handled */
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized object class: %u",
|
||||
object->classId);
|
||||
@@ -1316,9 +1340,9 @@ find_expr_references_walker(Node *node,
|
||||
add_object_address(OCLASS_OPERATOR, lfirst_oid(l), 0,
|
||||
context->addrs);
|
||||
}
|
||||
foreach(l, rcexpr->opclasses)
|
||||
foreach(l, rcexpr->opfamilies)
|
||||
{
|
||||
add_object_address(OCLASS_OPCLASS, lfirst_oid(l), 0,
|
||||
add_object_address(OCLASS_OPFAMILY, lfirst_oid(l), 0,
|
||||
context->addrs);
|
||||
}
|
||||
/* fall through to examine arguments */
|
||||
@@ -1623,6 +1647,18 @@ getObjectClass(const ObjectAddress *object)
|
||||
Assert(object->objectSubId == 0);
|
||||
return OCLASS_OPCLASS;
|
||||
|
||||
case OperatorFamilyRelationId:
|
||||
Assert(object->objectSubId == 0);
|
||||
return OCLASS_OPFAMILY;
|
||||
|
||||
case AccessMethodOperatorRelationId:
|
||||
Assert(object->objectSubId == 0);
|
||||
return OCLASS_AMOP;
|
||||
|
||||
case AccessMethodProcedureRelationId:
|
||||
Assert(object->objectSubId == 0);
|
||||
return OCLASS_AMPROC;
|
||||
|
||||
case RewriteRelationId:
|
||||
Assert(object->objectSubId == 0);
|
||||
return OCLASS_REWRITE;
|
||||
@@ -1856,11 +1892,11 @@ getObjectDescription(const ObjectAddress *object)
|
||||
opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
|
||||
|
||||
amTup = SearchSysCache(AMOID,
|
||||
ObjectIdGetDatum(opcForm->opcamid),
|
||||
ObjectIdGetDatum(opcForm->opcmethod),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(amTup))
|
||||
elog(ERROR, "cache lookup failed for access method %u",
|
||||
opcForm->opcamid);
|
||||
opcForm->opcmethod);
|
||||
amForm = (Form_pg_am) GETSTRUCT(amTup);
|
||||
|
||||
/* Qualify the name if not visible in search path */
|
||||
@@ -1879,6 +1915,84 @@ getObjectDescription(const ObjectAddress *object)
|
||||
break;
|
||||
}
|
||||
|
||||
case OCLASS_OPFAMILY:
|
||||
getOpFamilyDescription(&buffer, object->objectId);
|
||||
break;
|
||||
|
||||
case OCLASS_AMOP:
|
||||
{
|
||||
Relation amopDesc;
|
||||
ScanKeyData skey[1];
|
||||
SysScanDesc amscan;
|
||||
HeapTuple tup;
|
||||
Form_pg_amop amopForm;
|
||||
|
||||
amopDesc = heap_open(AccessMethodOperatorRelationId,
|
||||
AccessShareLock);
|
||||
|
||||
ScanKeyInit(&skey[0],
|
||||
ObjectIdAttributeNumber,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(object->objectId));
|
||||
|
||||
amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
|
||||
SnapshotNow, 1, skey);
|
||||
|
||||
tup = systable_getnext(amscan);
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "could not find tuple for amop entry %u",
|
||||
object->objectId);
|
||||
|
||||
amopForm = (Form_pg_amop) GETSTRUCT(tup);
|
||||
|
||||
appendStringInfo(&buffer, _("operator %d %s of "),
|
||||
amopForm->amopstrategy,
|
||||
format_operator(amopForm->amopopr));
|
||||
getOpFamilyDescription(&buffer, amopForm->amopfamily);
|
||||
|
||||
systable_endscan(amscan);
|
||||
heap_close(amopDesc, AccessShareLock);
|
||||
break;
|
||||
}
|
||||
|
||||
case OCLASS_AMPROC:
|
||||
{
|
||||
Relation amprocDesc;
|
||||
ScanKeyData skey[1];
|
||||
SysScanDesc amscan;
|
||||
HeapTuple tup;
|
||||
Form_pg_amproc amprocForm;
|
||||
|
||||
amprocDesc = heap_open(AccessMethodProcedureRelationId,
|
||||
AccessShareLock);
|
||||
|
||||
ScanKeyInit(&skey[0],
|
||||
ObjectIdAttributeNumber,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(object->objectId));
|
||||
|
||||
amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
|
||||
SnapshotNow, 1, skey);
|
||||
|
||||
tup = systable_getnext(amscan);
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "could not find tuple for amproc entry %u",
|
||||
object->objectId);
|
||||
|
||||
amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
|
||||
|
||||
appendStringInfo(&buffer, _("function %d %s of "),
|
||||
amprocForm->amprocnum,
|
||||
format_procedure(amprocForm->amproc));
|
||||
getOpFamilyDescription(&buffer, amprocForm->amprocfamily);
|
||||
|
||||
systable_endscan(amscan);
|
||||
heap_close(amprocDesc, AccessShareLock);
|
||||
break;
|
||||
}
|
||||
|
||||
case OCLASS_REWRITE:
|
||||
{
|
||||
Relation ruleDesc;
|
||||
@@ -2068,3 +2182,45 @@ getRelationDescription(StringInfo buffer, Oid relid)
|
||||
|
||||
ReleaseSysCache(relTup);
|
||||
}
|
||||
|
||||
/*
|
||||
* subroutine for getObjectDescription: describe an operator family
|
||||
*/
|
||||
static void
|
||||
getOpFamilyDescription(StringInfo buffer, Oid opfid)
|
||||
{
|
||||
HeapTuple opfTup;
|
||||
Form_pg_opfamily opfForm;
|
||||
HeapTuple amTup;
|
||||
Form_pg_am amForm;
|
||||
char *nspname;
|
||||
|
||||
opfTup = SearchSysCache(OPFAMILYOID,
|
||||
ObjectIdGetDatum(opfid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(opfTup))
|
||||
elog(ERROR, "cache lookup failed for opfamily %u", opfid);
|
||||
opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
|
||||
|
||||
amTup = SearchSysCache(AMOID,
|
||||
ObjectIdGetDatum(opfForm->opfmethod),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(amTup))
|
||||
elog(ERROR, "cache lookup failed for access method %u",
|
||||
opfForm->opfmethod);
|
||||
amForm = (Form_pg_am) GETSTRUCT(amTup);
|
||||
|
||||
/* Qualify the name if not visible in search path */
|
||||
if (OpfamilyIsVisible(opfid))
|
||||
nspname = NULL;
|
||||
else
|
||||
nspname = get_namespace_name(opfForm->opfnamespace);
|
||||
|
||||
appendStringInfo(buffer, _("operator family %s for access method %s"),
|
||||
quote_qualified_identifier(nspname,
|
||||
NameStr(opfForm->opfname)),
|
||||
NameStr(amForm->amname));
|
||||
|
||||
ReleaseSysCache(amTup);
|
||||
ReleaseSysCache(opfTup);
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.88 2006/10/04 00:29:50 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.89 2006/12/23 00:43:09 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_opfamily.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/dbcommands.h"
|
||||
@@ -1062,7 +1063,7 @@ OpclassIsVisible(Oid opcid)
|
||||
*/
|
||||
char *opcname = NameStr(opcform->opcname);
|
||||
|
||||
visible = (OpclassnameGetOpcid(opcform->opcamid, opcname) == opcid);
|
||||
visible = (OpclassnameGetOpcid(opcform->opcmethod, opcname) == opcid);
|
||||
}
|
||||
|
||||
ReleaseSysCache(opctup);
|
||||
@@ -1070,6 +1071,89 @@ OpclassIsVisible(Oid opcid)
|
||||
return visible;
|
||||
}
|
||||
|
||||
/*
|
||||
* OpfamilynameGetOpfid
|
||||
* Try to resolve an unqualified index opfamily name.
|
||||
* Returns OID if opfamily found in search path, else InvalidOid.
|
||||
*
|
||||
* This is essentially the same as TypenameGetTypid, but we have to have
|
||||
* an extra argument for the index AM OID.
|
||||
*/
|
||||
Oid
|
||||
OpfamilynameGetOpfid(Oid amid, const char *opfname)
|
||||
{
|
||||
Oid opfid;
|
||||
ListCell *l;
|
||||
|
||||
recomputeNamespacePath();
|
||||
|
||||
foreach(l, namespaceSearchPath)
|
||||
{
|
||||
Oid namespaceId = lfirst_oid(l);
|
||||
|
||||
opfid = GetSysCacheOid(OPFAMILYAMNAMENSP,
|
||||
ObjectIdGetDatum(amid),
|
||||
PointerGetDatum(opfname),
|
||||
ObjectIdGetDatum(namespaceId),
|
||||
0);
|
||||
if (OidIsValid(opfid))
|
||||
return opfid;
|
||||
}
|
||||
|
||||
/* Not found in path */
|
||||
return InvalidOid;
|
||||
}
|
||||
|
||||
/*
|
||||
* OpfamilyIsVisible
|
||||
* Determine whether an opfamily (identified by OID) is visible in the
|
||||
* current search path. Visible means "would be found by searching
|
||||
* for the unqualified opfamily name".
|
||||
*/
|
||||
bool
|
||||
OpfamilyIsVisible(Oid opfid)
|
||||
{
|
||||
HeapTuple opftup;
|
||||
Form_pg_opfamily opfform;
|
||||
Oid opfnamespace;
|
||||
bool visible;
|
||||
|
||||
opftup = SearchSysCache(OPFAMILYOID,
|
||||
ObjectIdGetDatum(opfid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(opftup))
|
||||
elog(ERROR, "cache lookup failed for opfamily %u", opfid);
|
||||
opfform = (Form_pg_opfamily) GETSTRUCT(opftup);
|
||||
|
||||
recomputeNamespacePath();
|
||||
|
||||
/*
|
||||
* Quick check: if it ain't in the path at all, it ain't visible. Items in
|
||||
* the system namespace are surely in the path and so we needn't even do
|
||||
* list_member_oid() for them.
|
||||
*/
|
||||
opfnamespace = opfform->opfnamespace;
|
||||
if (opfnamespace != PG_CATALOG_NAMESPACE &&
|
||||
!list_member_oid(namespaceSearchPath, opfnamespace))
|
||||
visible = false;
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If it is in the path, it might still not be visible; it could be
|
||||
* hidden by another opfamily of the same name earlier in the path. So
|
||||
* we must do a slow check to see if this opfamily would be found by
|
||||
* OpfamilynameGetOpfid.
|
||||
*/
|
||||
char *opfname = NameStr(opfform->opfname);
|
||||
|
||||
visible = (OpfamilynameGetOpfid(opfform->opfmethod, opfname) == opfid);
|
||||
}
|
||||
|
||||
ReleaseSysCache(opftup);
|
||||
|
||||
return visible;
|
||||
}
|
||||
|
||||
/*
|
||||
* ConversionGetConid
|
||||
* Try to resolve an unqualified conversion name.
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.98 2006/07/14 14:52:18 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.99 2006/12/23 00:43:09 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* these routines moved here from commands/define.c and somewhat cleaned up.
|
||||
@@ -238,16 +238,13 @@ OperatorShellMake(const char *operatorName,
|
||||
values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */
|
||||
values[i++] = ObjectIdGetDatum(GetUserId()); /* oprowner */
|
||||
values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */
|
||||
values[i++] = BoolGetDatum(false); /* oprcanmerge */
|
||||
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 */
|
||||
@@ -296,11 +293,8 @@ OperatorShellMake(const char *operatorName,
|
||||
* negatorName X negator operator
|
||||
* restrictionName X restriction sel. procedure
|
||||
* joinName X join sel. procedure
|
||||
* canMerge merge join can be used with this operator
|
||||
* 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
|
||||
@@ -326,6 +320,7 @@ OperatorShellMake(const char *operatorName,
|
||||
* operatorName
|
||||
* owner id (simply the user id of the caller)
|
||||
* operator "kind" either "b" for binary or "l" for left unary
|
||||
* canMerge boolean
|
||||
* canHash boolean
|
||||
* leftTypeObjectId -- type must already be defined
|
||||
* rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
|
||||
@@ -341,8 +336,6 @@ OperatorShellMake(const char *operatorName,
|
||||
* (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 a lookup to find out the
|
||||
@@ -369,11 +362,8 @@ OperatorCreate(const char *operatorName,
|
||||
List *negatorName,
|
||||
List *restrictionName,
|
||||
List *joinName,
|
||||
bool canHash,
|
||||
List *leftSortName,
|
||||
List *rightSortName,
|
||||
List *ltCompareName,
|
||||
List *gtCompareName)
|
||||
bool canMerge,
|
||||
bool canHash)
|
||||
{
|
||||
Relation pg_operator_desc;
|
||||
HeapTuple tup;
|
||||
@@ -386,10 +376,6 @@ OperatorCreate(const char *operatorName,
|
||||
Oid operResultType;
|
||||
Oid commutatorId,
|
||||
negatorId,
|
||||
leftSortId,
|
||||
rightSortId,
|
||||
ltCompareId,
|
||||
gtCompareId,
|
||||
restOid,
|
||||
joinOid;
|
||||
bool selfCommutator = false;
|
||||
@@ -424,14 +410,14 @@ OperatorCreate(const char *operatorName,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("only binary operators can have join selectivity")));
|
||||
if (canMerge)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("only binary operators can merge join")));
|
||||
if (canHash)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("only binary operators can hash")));
|
||||
if (leftSortName || rightSortName || ltCompareName || gtCompareName)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("only binary operators can merge join")));
|
||||
}
|
||||
|
||||
operatorObjectId = OperatorGet(operatorName,
|
||||
@@ -522,6 +508,7 @@ OperatorCreate(const char *operatorName,
|
||||
values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */
|
||||
values[i++] = ObjectIdGetDatum(GetUserId()); /* oprowner */
|
||||
values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */
|
||||
values[i++] = BoolGetDatum(canMerge); /* oprcanmerge */
|
||||
values[i++] = BoolGetDatum(canHash); /* oprcanhash */
|
||||
values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
|
||||
values[i++] = ObjectIdGetDatum(rightTypeId); /* oprright */
|
||||
@@ -565,58 +552,6 @@ OperatorCreate(const char *operatorName,
|
||||
negatorId = InvalidOid;
|
||||
values[i++] = ObjectIdGetDatum(negatorId); /* oprnegate */
|
||||
|
||||
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 */
|
||||
|
||||
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 */
|
||||
@@ -930,12 +865,11 @@ makeOperatorDependencies(HeapTuple tuple)
|
||||
|
||||
/*
|
||||
* NOTE: we do not consider the operator to depend on the associated
|
||||
* operators oprcom, oprnegate, oprlsortop, oprrsortop, oprltcmpop,
|
||||
* oprgtcmpop. We would not want to delete this operator if those go
|
||||
* away, but only reset the link fields; which is not a function that the
|
||||
* dependency code can presently handle. (Something could perhaps be done
|
||||
* with objectSubId though.) For now, it's okay to let those links dangle
|
||||
* if a referenced operator is removed.
|
||||
* operators oprcom and oprnegate. We would not want to delete this
|
||||
* operator if those go away, but only reset the link fields; which is not
|
||||
* a function that the dependency code can presently handle. (Something
|
||||
* could perhaps be done with objectSubId though.) For now, it's okay to
|
||||
* let those links dangle if a referenced operator is removed.
|
||||
*/
|
||||
|
||||
/* Dependency on implementation function */
|
||||
|
Reference in New Issue
Block a user