Commit 6cef5d25 authored by Tom Lane's avatar Tom Lane

Operators live in namespaces. CREATE/DROP/COMMENT ON OPERATOR take

qualified operator names directly, for example CREATE OPERATOR myschema.+
( ... ).  To qualify an operator name in an expression you need to write
OPERATOR(myschema.+) (thanks to Peter for suggesting an escape hatch).
I also took advantage of having to reformat pg_operator to fix something
that'd been bugging me for a while: mergejoinable operators should have
explicit links to the associated cross-data-type comparison operators,
rather than hardwiring an assumption that they are named < and >.
parent 4da51bfd
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.41 2002/04/11 19:59:54 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.42 2002/04/16 23:08:09 tgl Exp $
-->
<chapter id="catalogs">
......@@ -1482,6 +1482,15 @@
<entry>Name of the operator</entry>
</row>
<row>
<entry>oprnamespace</entry>
<entry><type>oid</type></entry>
<entry>pg_namespace.oid</entry>
<entry>
The OID of the namespace that contains this operator
</entry>
</row>
<row>
<entry>oprowner</entry>
<entry><type>int4</type></entry>
......@@ -1493,7 +1502,8 @@
<entry>oprprec</entry>
<entry><type>int2</type></entry>
<entry></entry>
<entry>unused</entry>
<entry>precedence (currently unused, as precedences are hard-wired
in the grammar)</entry>
</row>
<row>
......@@ -1510,7 +1520,8 @@
<entry>oprisleft</entry>
<entry><type>bool</type></entry>
<entry></entry>
<entry>unused</entry>
<entry>left-associativity (currently unused, as this is hard-wired
in the grammar)</entry>
</row>
<row>
......@@ -1561,7 +1572,7 @@
<entry>pg_operator.oid</entry>
<entry>
If this operator supports merge joins, the operator that sorts
the type of the left-hand operand
the type of the left-hand operand (<literal>L&lt;L</>)
</entry>
</row>
......@@ -1571,28 +1582,48 @@
<entry>pg_operator.oid</entry>
<entry>
If this operator supports merge joins, the operator that sorts
the type of the right-hand operand
the type of the right-hand operand (<literal>R&lt;R</>)
</entry>
</row>
<row>
<entry>oprltcmpop</entry>
<entry><type>oid</type></entry>
<entry>pg_operator.oid</entry>
<entry>
If this operator supports merge joins, the less-than operator that
compares the left and right operand types (<literal>L&lt;R</>)
</entry>
</row>
<row>
<entry>oprgtcmpop</entry>
<entry><type>oid</type></entry>
<entry>pg_operator.oid</entry>
<entry>
If this operator supports merge joins, the greater-than operator that
compares the left and right operand types (<literal>L&gt;R</>)
</entry>
</row>
<row>
<entry>oprcode</entry>
<entry><type>regproc</type></entry>
<entry></entry>
<entry>pg_proc.oid</entry>
<entry>Function that implements this operator</entry>
</row>
<row>
<entry>oprrest</entry>
<entry><type>regproc</type></entry>
<entry></entry>
<entry>pg_proc.oid</entry>
<entry>Restriction selectivity estimation function for this operator</entry>
</row>
<row>
<entry>oprjoin</entry>
<entry><type>regproc</type></entry>
<entry></entry>
<entry>pg_proc.oid</entry>
<entry>Join selectivity estimation function for this operator</entry>
</row>
</tbody>
......@@ -2498,28 +2529,28 @@
<row>
<entry>typinput</entry>
<entry><type>regproc</type></entry>
<entry></entry>
<entry>pg_proc.oid</entry>
<entry>Input function</entry>
</row>
<row>
<entry>typoutput</entry>
<entry><type>regproc</type></entry>
<entry></entry>
<entry>pg_proc.oid</entry>
<entry>Output function</entry>
</row>
<row>
<entry>typreceive</entry>
<entry><type>regproc</type></entry>
<entry></entry>
<entry>pg_proc.oid</entry>
<entry>unused</entry>
</row>
<row>
<entry>typsend</entry>
<entry><type>regproc</type></entry>
<entry></entry>
<entry>pg_proc.oid</entry>
<entry>unused</entry>
</row>
......
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_operator.sgml,v 1.25 2002/03/22 19:20:39 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_operator.sgml,v 1.26 2002/04/16 23:08:10 tgl Exp $
PostgreSQL documentation
-->
......@@ -28,7 +28,9 @@ CREATE OPERATOR <replaceable>name</replaceable> ( PROCEDURE = <replaceable class
] [, RIGHTARG = <replaceable class="parameter">righttype</replaceable> ]
[, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ] [, NEGATOR = <replaceable class="parameter">neg_op</replaceable> ]
[, RESTRICT = <replaceable class="parameter">res_proc</replaceable> ] [, JOIN = <replaceable class="parameter">join_proc</replaceable> ]
[, HASHES ] [, SORT1 = <replaceable class="parameter">left_sort_op</replaceable> ] [, SORT2 = <replaceable class="parameter">right_sort_op</replaceable> ] )
[, HASHES ] [, MERGES ]
[, SORT1 = <replaceable class="parameter">left_sort_op</replaceable> ] [, SORT2 = <replaceable class="parameter">right_sort_op</replaceable> ]
[, LTCMP = <replaceable class="parameter">less_than_op</replaceable> ] [, GTCMP = <replaceable class="parameter">greater_than_op</replaceable> ] )
</synopsis>
<refsect2 id="R2-SQL-CREATEOPERATOR-1">
......@@ -115,11 +117,19 @@ CREATE OPERATOR <replaceable>name</replaceable> ( PROCEDURE = <replaceable class
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>MERGES</term>
<listitem>
<para>
Indicates this operator can support a merge join.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">left_sort_op</replaceable></term>
<listitem>
<para>
If this operator can support a merge join, the
If this operator can support a merge join, the less-than
operator that sorts the left-hand data type of this operator.
</para>
</listitem>
......@@ -128,11 +138,29 @@ CREATE OPERATOR <replaceable>name</replaceable> ( PROCEDURE = <replaceable class
<term><replaceable class="parameter">right_sort_op</replaceable></term>
<listitem>
<para>
If this operator can support a merge join, the
If this operator can support a merge join, the less-than
operator that sorts the right-hand data type of this operator.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">less_than_op</replaceable></term>
<listitem>
<para>
If this operator can support a merge join, the less-than
operator that compares the input data types of this operator.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">greater_than_op</replaceable></term>
<listitem>
<para>
If this operator can support a merge join, the greater-than
operator that compares the input data types of this operator.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>
......@@ -295,30 +323,39 @@ MYBOXES.description !== box '((0,0), (1,1))'
it also works to just have both operators refer to each other.)
</para>
<para>
The HASHES, SORT1, and SORT2 options are present to support the
query optimizer in performing joins.
<productname>PostgreSQL</productname> can always
evaluate a join (i.e., processing a clause with two tuple
variables separated by an operator that returns a <type>boolean</type>)
by iterative substitution [WONG76].
In addition, <productname>PostgreSQL</productname>
can use a hash-join algorithm along
the lines of [SHAP86]; however, it must know whether this
strategy is applicable. The current hash-join algorithm
is only correct for operators that represent equality tests;
furthermore, equality of the data type must mean bitwise equality
of the representation of the type. (For example, a data type that
contains unused bits that don't matter for equality tests could
not be hash-joined.)
The HASHES flag indicates to the query optimizer that a hash join
may safely be used with this operator.</para>
<para>
Similarly, the two sort operators indicate to the query
optimizer whether merge-sort is a usable join strategy and
which operators should be used to sort the two operand
classes. Sort operators should only be provided for an equality
operator, and they should refer to less-than operators for the
left and right side data types respectively.
The HASHES, MERGES, SORT1, SORT2, LTCMP, and GTCMP options are present to
support the query optimizer in performing joins.
<productname>PostgreSQL</productname> can always evaluate a join (i.e.,
processing a clause with two tuple variables separated by an operator that
returns a <type>boolean</type>) by iterative substitution [WONG76]. In
addition, <productname>PostgreSQL</productname> can use a hash-join
algorithm along the lines of [SHAP86]; however, it must know whether this
strategy is applicable. The current hash-join algorithm is only correct
for operators that represent equality tests; furthermore, equality of the
data type must mean bitwise equality of the representation of the type.
(For example, a data type that contains unused bits that don't matter for
equality tests could not be hash-joined.) The HASHES flag indicates to the
query optimizer that a hash join may safely be used with this
operator.
</para>
<para>
Similarly, the MERGES flag indicates whether merge-sort is a usable join
strategy for this operator. A merge join requires that the two input
datatypes have consistent orderings, and that the mergejoin operator
behave like equality with respect to that ordering. For example, it is
possible to merge-join equality between an integer and a float variable by
sorting both inputs in ordinary
numeric order. Execution of a merge join requires that the system be
able to identify four operators related to the mergejoin equality operator:
less-than comparison for the left input datatype,
less-than comparison for the right input datatype,
less-than comparison between the two datatypes, and
greater-than comparison between the two datatypes. It is possible to
specify these by name, as the SORT1, SORT2, LTCMP, and GTCMP options
respectively. The system will fill in the default names <literal>&lt;</>,
<literal>&lt;</>, <literal>&lt;</>, <literal>&gt;</> respectively if
any of these are omitted when MERGES is specified. Also, MERGES will
be assumed to be implied if any of these four operator options appear.
</para>
<para>
If other join strategies are found to be practical,
......@@ -408,8 +445,10 @@ CREATE OPERATOR === (
RESTRICT = area_restriction_procedure,
JOIN = area_join_procedure,
HASHES,
SORT1 = <<<,
SORT2 = <<<
SORT1 = &lt;&lt;&lt;,
SORT2 = &lt;&lt;&lt;
-- Since sort operators were given, MERGES is implied.
-- LTCMP and GTCMP are assumed to be &lt; and &gt; respectively
);
</programlisting>
</refsect1>
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.88 2002/04/11 19:59:57 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.89 2002/04/16 23:08:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -62,7 +62,7 @@ char *Name_pg_namespace_indices[Num_pg_namespace_indices] =
char *Name_pg_opclass_indices[Num_pg_opclass_indices] =
{OpclassAmNameIndex, OpclassOidIndex};
char *Name_pg_operator_indices[Num_pg_operator_indices] =
{OperatorOidIndex, OperatorNameIndex};
{OperatorOidIndex, OperatorNameNspIndex};
char *Name_pg_proc_indices[Num_pg_proc_indices] =
{ProcedureOidIndex, ProcedureNameNspIndex};
char *Name_pg_relcheck_indices[Num_pg_relcheck_indices] =
......
......@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.9 2002/04/15 22:33:21 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.10 2002/04/16 23:08:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -27,6 +27,7 @@
#include "catalog/namespace.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
#include "lib/stringinfo.h"
......@@ -478,6 +479,179 @@ FuncnameGetCandidates(List *names, int nargs)
return resultList;
}
/*
* OpernameGetCandidates
* Given a possibly-qualified operator name and operator kind,
* retrieve a list of the possible matches.
*
* We search a single namespace if the operator name is qualified, else
* all namespaces in the search path. The return list will never contain
* multiple entries with identical argument types --- in the multiple-
* namespace case, we arrange for entries in earlier namespaces to mask
* identical entries in later namespaces.
*
* The returned items always have two args[] entries --- one or the other
* will be InvalidOid for a prefix or postfix oprkind.
*/
FuncCandidateList
OpernameGetCandidates(List *names, char oprkind)
{
FuncCandidateList resultList = NULL;
char *catalogname;
char *schemaname = NULL;
char *opername = NULL;
Oid namespaceId;
CatCList *catlist;
int i;
/* deconstruct the name list */
switch (length(names))
{
case 1:
opername = strVal(lfirst(names));
break;
case 2:
schemaname = strVal(lfirst(names));
opername = strVal(lsecond(names));
break;
case 3:
catalogname = strVal(lfirst(names));
schemaname = strVal(lsecond(names));
opername = strVal(lfirst(lnext(lnext(names))));
/*
* We check the catalog name and then ignore it.
*/
if (strcmp(catalogname, DatabaseName) != 0)
elog(ERROR, "Cross-database references are not implemented");
break;
default:
elog(ERROR, "Improper qualified name (too many dotted names)");
break;
}
if (schemaname)
{
/* use exact schema given */
namespaceId = GetSysCacheOid(NAMESPACENAME,
CStringGetDatum(schemaname),
0, 0, 0);
if (!OidIsValid(namespaceId))
elog(ERROR, "Namespace \"%s\" does not exist",
schemaname);
}
else
{
/* flag to indicate we need namespace search */
namespaceId = InvalidOid;
}
/* Search syscache by name only */
catlist = SearchSysCacheList(OPERNAMENSP, 1,
CStringGetDatum(opername),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
HeapTuple opertup = &catlist->members[i]->tuple;
Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
int pathpos = 0;
FuncCandidateList newResult;
/* Ignore operators of wrong kind */
if (operform->oprkind != oprkind)
continue;
if (OidIsValid(namespaceId))
{
/* Consider only opers in specified namespace */
if (operform->oprnamespace != namespaceId)
continue;
/* No need to check args, they must all be different */
}
else
{
/* Consider only opers that are in the search path */
if (pathContainsSystemNamespace ||
!IsSystemNamespace(operform->oprnamespace))
{
List *nsp;
foreach(nsp, namespaceSearchPath)
{
pathpos++;
if (operform->oprnamespace == (Oid) lfirsti(nsp))
break;
}
if (nsp == NIL)
continue; /* oper is not in search path */
}
/*
* Okay, it's in the search path, but does it have the same
* arguments as something we already accepted? If so, keep
* only the one that appears earlier in the search path.
*
* If we have an ordered list from SearchSysCacheList (the
* normal case), then any conflicting oper must immediately
* adjoin this one in the list, so we only need to look at
* the newest result item. If we have an unordered list,
* we have to scan the whole result list.
*/
if (resultList)
{
FuncCandidateList prevResult;
if (catlist->ordered)
{
if (operform->oprleft == resultList->args[0] &&
operform->oprright == resultList->args[1])
prevResult = resultList;
else
prevResult = NULL;
}
else
{
for (prevResult = resultList;
prevResult;
prevResult = prevResult->next)
{
if (operform->oprleft == prevResult->args[0] &&
operform->oprright == prevResult->args[1])
break;
}
}
if (prevResult)
{
/* We have a match with a previous result */
Assert(pathpos != prevResult->pathpos);
if (pathpos > prevResult->pathpos)
continue; /* keep previous result */
/* replace previous result */
prevResult->pathpos = pathpos;
prevResult->oid = opertup->t_data->t_oid;
continue; /* args are same, of course */
}
}
}
/*
* Okay to add it to result list
*/
newResult = (FuncCandidateList)
palloc(sizeof(struct _FuncCandidateList) + sizeof(Oid));
newResult->pathpos = pathpos;
newResult->oid = opertup->t_data->t_oid;
newResult->args[0] = operform->oprleft;
newResult->args[1] = operform->oprright;
newResult->next = resultList;
resultList = newResult;
}
ReleaseSysCacheList(catlist);
return resultList;
}
/*
* QualifiedNameGetCreationNamespace
* Given a possibly-qualified name for an object (in List-of-Values
......
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.31 2002/04/12 20:38:20 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.32 2002/04/16 23:08:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -398,7 +398,7 @@ examine_attribute(Relation onerel, int attnum)
return NULL;
/* If column has no "=" operator, we can't do much of anything */
func_operator = compatible_oper("=",
func_operator = compatible_oper(makeList1(makeString("=")),
attr->atttypid,
attr->atttypid,
true);
......@@ -436,7 +436,7 @@ examine_attribute(Relation onerel, int attnum)
stats->eqfunc = eqfunc;
/* Is there a "<" operator with suitable semantics? */
func_operator = compatible_oper("<",
func_operator = compatible_oper(makeList1(makeString("<")),
attr->atttypid,
attr->atttypid,
true);
......
......@@ -7,7 +7,7 @@
* Copyright (c) 1999-2001, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.40 2002/04/11 19:59:57 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.41 2002/04/16 23:08:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -28,6 +28,7 @@
#include "commands/comment.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "parser/parse.h"
#include "utils/acl.h"
......@@ -53,7 +54,7 @@ static void CommentRule(List *qualname, char *comment);
static void CommentType(List *typename, char *comment);
static void CommentAggregate(List *aggregate, List *arguments, char *comment);
static void CommentProc(List *function, List *arguments, char *comment);
static void CommentOperator(List *qualname, List *arguments, char *comment);
static void CommentOperator(List *opername, List *arguments, char *comment);
static void CommentTrigger(List *qualname, char *comment);
......@@ -643,63 +644,29 @@ CommentProc(List *function, List *arguments, char *comment)
* to be visible for both operator and function.
*/
static void
CommentOperator(List *qualname, List *arguments, char *comment)
CommentOperator(List *opername, List *arguments, char *comment)
{
char *opername = strVal(lfirst(qualname)); /* XXX */
TypeName *typenode1 = (TypeName *) lfirst(arguments);
TypeName *typenode2 = (TypeName *) lsecond(arguments);
char oprtype = 0;
Form_pg_operator data;
HeapTuple optuple;
Oid oid,
leftoid = InvalidOid,
rightoid = InvalidOid;
/* Attempt to fetch the left type oid, if specified */
if (typenode1 != NULL)
leftoid = typenameTypeId(typenode1);
/* Attempt to fetch the right type oid, if specified */
if (typenode2 != NULL)
rightoid = typenameTypeId(typenode2);
/* Determine operator type */
if (OidIsValid(leftoid) && (OidIsValid(rightoid)))
oprtype = 'b';
else if (OidIsValid(leftoid))
oprtype = 'r';
else if (OidIsValid(rightoid))
oprtype = 'l';
else
elog(ERROR, "operator '%s' is of an illegal type'", opername);
/* Attempt to fetch the operator oid */
Oid oid;
optuple = SearchSysCache(OPERNAME,
PointerGetDatum(opername),
ObjectIdGetDatum(leftoid),
ObjectIdGetDatum(rightoid),
CharGetDatum(oprtype));
if (!HeapTupleIsValid(optuple))
elog(ERROR, "operator '%s' does not exist", opername);
/* Look up the operator */
oid = optuple->t_data->t_oid;
oid = LookupOperNameTypeNames(opername, typenode1, typenode2,
"CommentOperator");
/* Valid user's ability to comment on this operator */
if (!pg_oper_ownercheck(oid, GetUserId()))
elog(ERROR, "you are not permitted to comment on operator '%s'",
opername);
NameListToString(opername));
/* Get the procedure associated with the operator */
data = (Form_pg_operator) GETSTRUCT(optuple);
oid = data->oprcode;
oid = get_opcode(oid);
if (oid == InvalidOid)
elog(ERROR, "operator '%s' does not have an underlying function", opername);
ReleaseSysCache(optuple);
elog(ERROR, "operator '%s' does not have an underlying function",
NameListToString(opername));
/* Call CreateComments() to create/drop the comments */
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/operatorcmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/operatorcmds.c,v 1.2 2002/04/16 23:08:10 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
......@@ -41,6 +41,7 @@
#include "commands/comment.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/syscache.h"
......@@ -61,21 +62,24 @@ DefineOperator(List *names, List *parameters)
Oid oprNamespace;
uint16 precedence = 0; /* operator precedence */
bool canHash = false; /* operator hashes */
bool canMerge = false; /* operator merges */
bool isLeftAssociative = true; /* operator is left
* associative */
char *functionName = NULL; /* function for operator */
List *functionName = NIL; /* function for operator */
TypeName *typeName1 = NULL; /* first type name */
TypeName *typeName2 = NULL; /* second type name */
Oid typeId1 = InvalidOid; /* types converted to OID */
Oid typeId2 = InvalidOid;
char *commutatorName = NULL; /* optional commutator operator
List *commutatorName = NIL; /* optional commutator operator
* name */
char *negatorName = NULL; /* optional negator operator name */
char *restrictionName = NULL; /* optional restrict. sel.
List *negatorName = NIL; /* optional negator operator name */
List *restrictionName = NIL; /* optional restrict. sel.
* procedure */
char *joinName = NULL; /* optional join sel. procedure name */
char *sortName1 = NULL; /* optional first sort operator */
char *sortName2 = NULL; /* optional second sort operator */
List *joinName = NIL; /* optional join sel. procedure */
List *leftSortName = NIL; /* optional left sort operator */
List *rightSortName = NIL; /* optional right sort operator */
List *ltCompareName = NIL; /* optional < compare operator */
List *gtCompareName = NIL; /* optional > compare operator */
List *pl;
/* Convert list of names to a name and namespace */
......@@ -101,7 +105,7 @@ DefineOperator(List *names, List *parameters)
elog(ERROR, "setof type not implemented for rightarg");
}
else if (strcasecmp(defel->defname, "procedure") == 0)
functionName = defGetString(defel);
functionName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "precedence") == 0)
{
/* NOT IMPLEMENTED (never worked in v4.2) */
......@@ -113,19 +117,25 @@ DefineOperator(List *names, List *parameters)
elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
}
else if (strcasecmp(defel->defname, "commutator") == 0)
commutatorName = defGetString(defel);
commutatorName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "negator") == 0)
negatorName = defGetString(defel);
negatorName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "restrict") == 0)
restrictionName = defGetString(defel);
restrictionName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "join") == 0)
joinName = defGetString(defel);
joinName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "hashes") == 0)
canHash = TRUE;
else if (strcasecmp(defel->defname, "merges") == 0)
canMerge = TRUE;
else if (strcasecmp(defel->defname, "sort1") == 0)
sortName1 = defGetString(defel);
leftSortName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "sort2") == 0)
sortName2 = defGetString(defel);
rightSortName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "ltcmp") == 0)
ltCompareName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "gtcmp") == 0)
gtCompareName = defGetQualifiedName(defel);
else
{
elog(WARNING, "DefineOperator: attribute \"%s\" not recognized",
......@@ -136,7 +146,7 @@ DefineOperator(List *names, List *parameters)
/*
* make sure we have our required definitions
*/
if (functionName == NULL)
if (functionName == NIL)
elog(ERROR, "Define: \"procedure\" unspecified");
/* Transform type names to type OIDs */
......@@ -145,10 +155,31 @@ DefineOperator(List *names, List *parameters)
if (typeName2)
typeId2 = typenameTypeId(typeName2);
/*
* If any of the mergejoin support operators were given, then canMerge
* is implicit. If canMerge is specified or implicit, fill in default
* operator names for any missing mergejoin support operators.
*/
if (leftSortName || rightSortName || ltCompareName || gtCompareName)
canMerge = true;
if (canMerge)
{
if (!leftSortName)
leftSortName = makeList1(makeString("<"));
if (!rightSortName)
rightSortName = makeList1(makeString("<"));
if (!ltCompareName)
ltCompareName = makeList1(makeString("<"));
if (!gtCompareName)
gtCompareName = makeList1(makeString(">"));
}
/*
* now have OperatorCreate do all the work..
*/
OperatorCreate(oprName, /* operator name */
oprNamespace, /* namespace */
typeId1, /* left type id */
typeId2, /* right type id */
functionName, /* function for operator */
......@@ -161,9 +192,10 @@ DefineOperator(List *names, List *parameters)
* procedure */
joinName, /* optional join sel. procedure name */
canHash, /* operator hashes */
sortName1, /* optional first sort operator */
sortName2); /* optional second sort operator */
leftSortName, /* optional left sort operator */
rightSortName, /* optional right sort operator */
ltCompareName, /* optional < comparison op */
gtCompareName); /* optional < comparison op */
}
......@@ -178,70 +210,36 @@ DefineOperator(List *names, List *parameters)
* ...
*/
void
RemoveOperator(char *operatorName, /* operator name */
RemoveOperator(List *operatorName, /* operator name */
TypeName *typeName1, /* left argument type name */
TypeName *typeName2) /* right argument type name */
{
Oid operOid;
Relation relation;
HeapTuple tup;
Oid typeId1 = InvalidOid;
Oid typeId2 = InvalidOid;
char oprtype;
if (typeName1)
typeId1 = typenameTypeId(typeName1);
if (typeName2)
typeId2 = typenameTypeId(typeName2);
if (OidIsValid(typeId1) && OidIsValid(typeId2))
oprtype = 'b';
else if (OidIsValid(typeId1))
oprtype = 'r';
else
oprtype = 'l';
operOid = LookupOperNameTypeNames(operatorName, typeName1, typeName2,
"RemoveOperator");
relation = heap_openr(OperatorRelationName, RowExclusiveLock);
tup = SearchSysCacheCopy(OPERNAME,
PointerGetDatum(operatorName),
ObjectIdGetDatum(typeId1),
ObjectIdGetDatum(typeId2),
CharGetDatum(oprtype));
tup = SearchSysCacheCopy(OPEROID,
ObjectIdGetDatum(operOid),
0, 0, 0);
if (HeapTupleIsValid(tup))
{
if (!pg_oper_ownercheck(tup->t_data->t_oid, GetUserId()))
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "RemoveOperator: failed to find tuple for operator '%s'",
NameListToString(operatorName));
if (!pg_oper_ownercheck(operOid, GetUserId()))
elog(ERROR, "RemoveOperator: operator '%s': permission denied",
operatorName);
NameListToString(operatorName));
/* Delete any comments associated with this operator */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
DeleteComments(operOid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
}
else
{
if (OidIsValid(typeId1) && OidIsValid(typeId2))
{
elog(ERROR, "RemoveOperator: binary operator '%s' taking '%s' and '%s' does not exist",
operatorName,
TypeNameToString(typeName1),
TypeNameToString(typeName2));
}
else if (OidIsValid(typeId1))
{
elog(ERROR, "RemoveOperator: right unary operator '%s' taking '%s' does not exist",
operatorName,
TypeNameToString(typeName1));
}
else
{
elog(ERROR, "RemoveOperator: left unary operator '%s' taking '%s' does not exist",
operatorName,
TypeNameToString(typeName2));
}
}
heap_freetuple(tup);
heap_close(relation, RowExclusiveLock);
}
......@@ -46,7 +46,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.81 2002/04/11 19:59:58 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.82 2002/04/16 23:08:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -925,7 +925,8 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
&peraggstate->inputtypeLen,
&peraggstate->inputtypeByVal);
eq_function = compatible_oper_funcid("=", inputType, inputType,
eq_function = compatible_oper_funcid(makeList1(makeString("=")),
inputType, inputType,
true);
if (!OidIsValid(eq_function))
elog(ERROR, "Unable to identify an equality operator for type '%s'",
......
......@@ -15,7 +15,7 @@
* locate group boundaries.
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.44 2001/10/25 05:49:28 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.45 2002/04/16 23:08:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -490,7 +490,8 @@ execTuplesMatchPrepare(TupleDesc tupdesc,
Oid typid = tupdesc->attrs[att - 1]->atttypid;
Oid eq_function;
eq_function = compatible_oper_funcid("=", typid, typid, true);
eq_function = compatible_oper_funcid(makeList1(makeString("=")),
typid, typid, true);
if (!OidIsValid(eq_function))
elog(ERROR, "Unable to identify an equality operator for type '%s'",
typeidTypeName(typid));
......
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.177 2002/04/11 19:59:59 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.178 2002/04/16 23:08:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1526,8 +1526,7 @@ _copyAExpr(A_Expr *from)
A_Expr *newnode = makeNode(A_Expr);
newnode->oper = from->oper;
if (from->opname)
newnode->opname = pstrdup(from->opname);
Node_Copy(from, newnode, name);
Node_Copy(from, newnode, lexpr);
Node_Copy(from, newnode, rexpr);
......@@ -1648,8 +1647,7 @@ _copySortGroupBy(SortGroupBy *from)
{
SortGroupBy *newnode = makeNode(SortGroupBy);
if (from->useOp)
newnode->useOp = pstrdup(from->useOp);
Node_Copy(from, newnode, useOp);
Node_Copy(from, newnode, node);
return newnode;
......@@ -2128,7 +2126,7 @@ _copyRemoveOperStmt(RemoveOperStmt *from)
{
RemoveOperStmt *newnode = makeNode(RemoveOperStmt);
newnode->opname = pstrdup(from->opname);
Node_Copy(from, newnode, opname);
Node_Copy(from, newnode, args);
return newnode;
......
......@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.125 2002/04/11 19:59:59 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.126 2002/04/16 23:08:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -969,7 +969,7 @@ _equalRemoveFuncStmt(RemoveFuncStmt *a, RemoveFuncStmt *b)
static bool
_equalRemoveOperStmt(RemoveOperStmt *a, RemoveOperStmt *b)
{
if (!equalstr(a->opname, b->opname))
if (!equal(a->opname, b->opname))
return false;
if (!equal(a->args, b->args))
return false;
......@@ -1400,7 +1400,7 @@ _equalAExpr(A_Expr *a, A_Expr *b)
{
if (a->oper != b->oper)
return false;
if (!equalstr(a->opname, b->opname))
if (!equal(a->name, b->name))
return false;
if (!equal(a->lexpr, b->lexpr))
return false;
......@@ -1520,7 +1520,7 @@ _equalTypeCast(TypeCast *a, TypeCast *b)
static bool
_equalSortGroupBy(SortGroupBy *a, SortGroupBy *b)
{
if (!equalstr(a->useOp, b->useOp))
if (!equal(a->useOp, b->useOp))
return false;
if (!equal(a->node, b->node))
return false;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.30 2002/03/29 19:06:09 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.31 2002/04/16 23:08:10 tgl Exp $
*/
#include "postgres.h"
......@@ -16,6 +16,39 @@
#include "utils/lsyscache.h"
/*
* makeA_Expr -
* makes an A_Expr node
*/
A_Expr *
makeA_Expr(int oper, List *name, Node *lexpr, Node *rexpr)
{
A_Expr *a = makeNode(A_Expr);
a->oper = oper;
a->name = name;
a->lexpr = lexpr;
a->rexpr = rexpr;
return a;
}
/*
* makeSimpleA_Expr -
* As above, given a simple (unqualified) operator name
*/
A_Expr *
makeSimpleA_Expr(int oper, const char *name,
Node *lexpr, Node *rexpr)
{
A_Expr *a = makeNode(A_Expr);
a->oper = oper;
a->name = makeList1(makeString((char *) name));
a->lexpr = lexpr;
a->rexpr = rexpr;
return a;
}
/*
* makeOper -
* creates an Oper node
......
......@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.154 2002/04/11 19:59:59 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.155 2002/04/16 23:08:10 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
......@@ -1285,7 +1285,7 @@ _outAExpr(StringInfo str, A_Expr *node)
appendStringInfo(str, "NOT ");
break;
case OP:
_outToken(str, node->opname);
_outNode(str, node->name);
appendStringInfo(str, " ");
break;
default:
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.115 2002/04/05 00:31:26 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.116 2002/04/16 23:08:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -21,6 +21,7 @@
#include "access/nbtree.h"
#include "catalog/catname.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
#include "executor/executor.h"
#include "nodes/makefuncs.h"
......@@ -911,7 +912,8 @@ indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
* operator, but in practice that seems pretty unlikely for
* binary-compatible types.)
*/
new_op = compatible_oper_opid(opname, indexkeytype, indexkeytype, true);
new_op = compatible_oper_opid(makeList1(makeString(opname)),
indexkeytype, indexkeytype, true);
if (OidIsValid(new_op))
{
......@@ -2143,14 +2145,15 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop)
*/
/* See if there is a binary op of the given name for the given datatype */
/* NB: we assume that only built-in system operators are searched for */
static Oid
find_operator(const char *opname, Oid datatype)
{
return GetSysCacheOid(OPERNAME,
return GetSysCacheOid(OPERNAMENSP,
PointerGetDatum(opname),
ObjectIdGetDatum(datatype),
ObjectIdGetDatum(datatype),
CharGetDatum('b'));
ObjectIdGetDatum(PG_CATALOG_NAMESPACE));
}
/*
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.67 2002/03/12 00:51:45 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.68 2002/04/16 23:08:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -740,7 +740,8 @@ process_implied_equality(Query *root, Node *item1, Node *item2,
*/
ltype = exprType(item1);
rtype = exprType(item2);
eq_operator = compatible_oper("=", ltype, rtype, true);
eq_operator = compatible_oper(makeList1(makeString("=")),
ltype, rtype, true);
if (!HeapTupleIsValid(eq_operator))
{
/*
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.50 2001/11/30 19:24:15 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.51 2002/04/16 23:08:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -284,9 +284,9 @@ make_subplan(SubLink *slink)
* Note: we use make_operand in case runtime type conversion
* function calls must be inserted for this operator!
*/
left = make_operand("", lefthand,
left = make_operand(lefthand,
exprType(lefthand), opform->oprleft);
right = make_operand("", (Node *) prm,
right = make_operand((Node *) prm,
prm->paramtype, opform->oprright);
ReleaseSysCache(tup);
......@@ -433,9 +433,9 @@ make_subplan(SubLink *slink)
* Note: we use make_operand in case runtime type conversion
* function calls must be inserted for this operator!
*/
left = make_operand("", lefthand,
left = make_operand(lefthand,
exprType(lefthand), opform->oprleft);
right = make_operand("", (Node *) con,
right = make_operand((Node *) con,
con->consttype, opform->oprright);
ReleaseSysCache(tup);
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.229 2002/04/12 19:11:49 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.230 2002/04/16 23:08:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1460,11 +1460,13 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
{
/*
* fktypoid[i] is the foreign key table's i'th element's type
* oid pktypoid[i] is the primary key table's i'th element's
* type oid We let oper() do our work for us, including
* elog(ERROR) if the types don't compare with =
* pktypoid[i] is the primary key table's i'th element's type
*
* We let oper() do our work for us, including elog(ERROR) if
* the types don't compare with =
*/
Operator o = oper("=", fktypoid[i], pktypoid[i], false);
Operator o = oper(makeList1(makeString("=")),
fktypoid[i], pktypoid[i], false);
ReleaseSysCache(o);
}
......
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.88 2002/04/15 06:05:49 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.89 2002/04/16 23:08:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -54,7 +54,7 @@ static Node *transformFromClauseItem(ParseState *pstate, Node *n,
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
List *tlist, int clause);
static List *addTargetToSortList(TargetEntry *tle, List *sortlist,
List *targetlist, char *opname);
List *targetlist, List *opname);
static bool exprIsInSortList(Node *expr, List *sortList, List *targetList);
......@@ -257,22 +257,15 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
Node *rvar = (Node *) lfirst(rvars);
A_Expr *e;
e = makeNode(A_Expr);
e->oper = OP;
e->opname = "=";
e->lexpr = copyObject(lvar);
e->rexpr = copyObject(rvar);
e = makeSimpleA_Expr(OP, "=", copyObject(lvar), copyObject(rvar));
if (result == NULL)
result = (Node *) e;
else
{
A_Expr *a = makeNode(A_Expr);
A_Expr *a;
a->oper = AND;
a->opname = NULL;
a->lexpr = result;
a->rexpr = (Node *) e;
a = makeA_Expr(AND, NIL, result, (Node *) e);
result = (Node *) a;
}
......@@ -1117,7 +1110,7 @@ transformDistinctClause(ParseState *pstate, List *distinctlist,
else
{
*sortClause = addTargetToSortList(tle, *sortClause,
targetlist, NULL);
targetlist, NIL);
/*
* Probably, the tle should always have been added at the
......@@ -1160,7 +1153,7 @@ addAllTargetsToSortList(List *sortlist, List *targetlist)
TargetEntry *tle = (TargetEntry *) lfirst(i);
if (!tle->resdom->resjunk)
sortlist = addTargetToSortList(tle, sortlist, targetlist, NULL);
sortlist = addTargetToSortList(tle, sortlist, targetlist, NIL);
}
return sortlist;
}
......@@ -1169,13 +1162,13 @@ addAllTargetsToSortList(List *sortlist, List *targetlist)
* addTargetToSortList
* If the given targetlist entry isn't already in the ORDER BY list,
* add it to the end of the list, using the sortop with given name
* or any available sort operator if opname == NULL.
* or any available sort operator if opname == NIL.
*
* Returns the updated ORDER BY list.
*/
static List *
addTargetToSortList(TargetEntry *tle, List *sortlist, List *targetlist,
char *opname)
List *opname)
{
/* avoid making duplicate sortlist entries */
if (!exprIsInSortList(tle->expr, sortlist, targetlist))
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.114 2002/04/11 20:00:00 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.115 2002/04/16 23:08:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -192,7 +192,8 @@ transformExpr(ParseState *pstate, Node *expr)
* into IS NULL exprs.
*/
if (Transform_null_equals &&
strcmp(a->opname, "=") == 0 &&
length(a->name) == 1 &&
strcmp(strVal(lfirst(a->name)), "=") == 0 &&
(exprIsNullConstant(a->lexpr) ||
exprIsNullConstant(a->rexpr)))
{
......@@ -215,7 +216,7 @@ transformExpr(ParseState *pstate, Node *expr)
Node *rexpr = transformExpr(pstate,
a->rexpr);
result = (Node *) make_op(a->opname,
result = (Node *) make_op(a->name,
lexpr,
rexpr);
}
......@@ -366,21 +367,23 @@ transformExpr(ParseState *pstate, Node *expr)
/* ALL, ANY, or MULTIEXPR: generate operator list */
List *left_list = sublink->lefthand;
List *right_list = qtree->targetList;
char *op;
List *op;
char *opname;
List *elist;
foreach(elist, left_list)
lfirst(elist) = transformExpr(pstate, lfirst(elist));
Assert(IsA(sublink->oper, A_Expr));
op = ((A_Expr *) sublink->oper)->opname;
op = ((A_Expr *) sublink->oper)->name;
opname = strVal(llast(op));
sublink->oper = NIL;
/* Combining operators other than =/<> is dubious... */
if (length(left_list) != 1 &&
strcmp(op, "=") != 0 && strcmp(op, "<>") != 0)
strcmp(opname, "=") != 0 && strcmp(opname, "<>") != 0)
elog(ERROR, "Row comparison cannot use '%s'",
op);
opname);
/*
* Scan subquery's targetlist to find values that will
......@@ -420,7 +423,7 @@ transformExpr(ParseState *pstate, Node *expr)
if (opform->oprresult != BOOLOID)
elog(ERROR, "'%s' result type of '%s' must return '%s'"
" to be used with quantified predicate subquery",
op, typeidTypeName(opform->oprresult),
opname, typeidTypeName(opform->oprresult),
typeidTypeName(BOOLOID));
newop = makeOper(oprid(optup), /* opno */
......@@ -459,13 +462,8 @@ transformExpr(ParseState *pstate, Node *expr)
if (c->arg != NULL)
{
/* shorthand form was specified, so expand... */
A_Expr *a = makeNode(A_Expr);
a->oper = OP;
a->opname = "=";
a->lexpr = c->arg;
a->rexpr = warg;
warg = (Node *) a;
warg = (Node *) makeSimpleA_Expr(OP, "=",
c->arg, warg);
}
neww->expr = transformExpr(pstate, warg);
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.61 2002/04/11 20:00:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.62 2002/04/16 23:08:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -62,10 +62,7 @@ make_parsestate(ParseState *parentParseState)
* Ensure argument type match by forcing conversion of constants.
*/
Node *
make_operand(char *opname,
Node *tree,
Oid orig_typeId,
Oid target_typeId)
make_operand(Node *tree, Oid orig_typeId, Oid target_typeId)
{
Node *result;
......@@ -95,7 +92,7 @@ make_operand(char *opname,
* This is where some type conversion happens.
*/
Expr *
make_op(char *opname, Node *ltree, Node *rtree)
make_op(List *opname, Node *ltree, Node *rtree)
{
Oid ltypeId,
rtypeId;
......@@ -114,7 +111,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
{
tup = right_oper(opname, ltypeId);
opform = (Form_pg_operator) GETSTRUCT(tup);
left = make_operand(opname, ltree, ltypeId, opform->oprleft);
left = make_operand(ltree, ltypeId, opform->oprleft);
right = NULL;
}
......@@ -123,7 +120,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
{
tup = left_oper(opname, rtypeId);
opform = (Form_pg_operator) GETSTRUCT(tup);
right = make_operand(opname, rtree, rtypeId, opform->oprright);
right = make_operand(rtree, rtypeId, opform->oprright);
left = NULL;
}
......@@ -132,8 +129,8 @@ make_op(char *opname, Node *ltree, Node *rtree)
{
tup = oper(opname, ltypeId, rtypeId, false);
opform = (Form_pg_operator) GETSTRUCT(tup);
left = make_operand(opname, ltree, ltypeId, opform->oprleft);
right = make_operand(opname, rtree, rtypeId, opform->oprright);
left = make_operand(ltree, ltypeId, opform->oprleft);
right = make_operand(rtree, rtypeId, opform->oprright);
}
newop = makeOper(oprid(tup), /* opno */
......
This diff is collapsed.
......@@ -18,7 +18,7 @@
* Portions Copyright (c) 2000-2001, PostgreSQL Global Development Group
* Copyright 1999 Jan Wieck
*
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.36 2002/04/02 01:03:07 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.37 2002/04/16 23:08:11 tgl Exp $
*
* ----------
*/
......@@ -36,6 +36,7 @@
#include "catalog/pg_operator.h"
#include "commands/trigger.h"
#include "executor/spi_priv.h"
#include "parser/parse_oper.h"
#include "utils/lsyscache.h"
#include "miscadmin.h"
......@@ -3338,27 +3339,20 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
HASH_FIND, NULL);
/*
* If not found, lookup the OPERNAME system cache for it to get the
* func OID, then do the function manager lookup, and remember that
* info.
* If not found, lookup the operator, then do the function manager
* lookup, and remember that info.
*/
if (!entry)
{
HeapTuple opr_tup;
Oid opr_proc;
FmgrInfo finfo;
opr_tup = SearchSysCache(OPERNAME,
PointerGetDatum("="),
ObjectIdGetDatum(typeid),
ObjectIdGetDatum(typeid),
CharGetDatum('b'));
if (!HeapTupleIsValid(opr_tup))
opr_proc = compatible_oper_funcid(makeList1(makeString("=")),
typeid, typeid, true);
if (!OidIsValid(opr_proc))
elog(ERROR,
"ri_AttributesEqual(): cannot find '=' operator for type %u",
typeid);
opr_proc = ((Form_pg_operator) GETSTRUCT(opr_tup))->oprcode;
ReleaseSysCache(opr_tup);
/*
* Since fmgr_info could fail, call it *before* creating the
......
......@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.107 2002/04/03 05:39:31 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.108 2002/04/16 23:08:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -74,6 +74,7 @@
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_statistic.h"
......@@ -3285,14 +3286,15 @@ string_lessthan(const char *str1, const char *str2, Oid datatype)
}
/* See if there is a binary op of the given name for the given datatype */
/* NB: we assume that only built-in system operators are searched for */
static Oid
find_operator(const char *opname, Oid datatype)
{
return GetSysCacheOid(OPERNAME,
return GetSysCacheOid(OPERNAMENSP,
PointerGetDatum(opname),
ObjectIdGetDatum(datatype),
ObjectIdGetDatum(datatype),
CharGetDatum('b'));
ObjectIdGetDatum(PG_CATALOG_NAMESPACE));
}
/*
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.69 2002/04/05 00:31:30 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.70 2002/04/16 23:08:11 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
......@@ -378,10 +378,6 @@ op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
* ltype ">" rtype) for an operator previously determined to be
* mergejoinable. Optionally, fetches the regproc ids of these
* operators, as well as their operator OIDs.
*
* Raises error if operators cannot be found. Assuming that the operator
* had indeed been marked mergejoinable, this indicates that whoever marked
* it so was mistaken.
*/
void
op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
......@@ -389,11 +385,9 @@ op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
{
HeapTuple tp;
Form_pg_operator optup;
Oid oprleft,
oprright;
/*
* Get the declared left and right operand types of the operator.
* Get the declared comparison operators of the operator.
*/
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
......@@ -401,44 +395,23 @@ op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
if (!HeapTupleIsValid(tp)) /* shouldn't happen */
elog(ERROR, "op_mergejoin_crossops: operator %u not found", opno);
optup = (Form_pg_operator) GETSTRUCT(tp);
oprleft = optup->oprleft;
oprright = optup->oprright;
*ltop = optup->oprltcmpop;
*gtop = optup->oprgtcmpop;
ReleaseSysCache(tp);
/*
* Look up the "<" operator with the same input types. If there isn't
* one, whoever marked the "=" operator mergejoinable was a loser.
*/
tp = SearchSysCache(OPERNAME,
PointerGetDatum("<"),
ObjectIdGetDatum(oprleft),
ObjectIdGetDatum(oprright),
CharGetDatum('b'));
if (!HeapTupleIsValid(tp))
/* Check < op provided */
if (!OidIsValid(*ltop))
elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching < operator",
opno);
optup = (Form_pg_operator) GETSTRUCT(tp);
*ltop = tp->t_data->t_oid;
if (ltproc)
*ltproc = optup->oprcode;
ReleaseSysCache(tp);
*ltproc = get_opcode(*ltop);
/*
* And the same for the ">" operator.
*/
tp = SearchSysCache(OPERNAME,
PointerGetDatum(">"),
ObjectIdGetDatum(oprleft),
ObjectIdGetDatum(oprright),
CharGetDatum('b'));
if (!HeapTupleIsValid(tp))
/* Check > op provided */
if (!OidIsValid(*gtop))
elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching > operator",
opno);
optup = (Form_pg_operator) GETSTRUCT(tp);
*gtop = tp->t_data->t_oid;
if (gtproc)
*gtproc = optup->oprcode;
ReleaseSysCache(tp);
*gtproc = get_opcode(*gtop);
}
/*
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.76 2002/04/11 20:00:06 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.77 2002/04/16 23:08:11 tgl Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
......@@ -273,15 +273,15 @@ static const struct cachedesc cacheinfo[] = {
0,
0
}},
{OperatorRelationName, /* OPERNAME */
OperatorNameIndex,
{OperatorRelationName, /* OPERNAMENSP */
OperatorNameNspIndex,
0,
4,
{
Anum_pg_operator_oprname,
Anum_pg_operator_oprleft,
Anum_pg_operator_oprright,
Anum_pg_operator_oprkind
Anum_pg_operator_oprnamespace
}},
{OperatorRelationName, /* OPEROID */
OperatorOidIndex,
......
......@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: catversion.h,v 1.115 2002/04/15 23:45:07 momjian Exp $
* $Id: catversion.h,v 1.116 2002/04/16 23:08:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200204151
#define CATALOG_VERSION_NO 200204161
#endif
......@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: indexing.h,v 1.62 2002/04/11 20:00:10 tgl Exp $
* $Id: indexing.h,v 1.63 2002/04/16 23:08:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -74,7 +74,7 @@
#define NamespaceOidIndex "pg_namespace_oid_index"
#define OpclassAmNameIndex "pg_opclass_am_name_index"
#define OpclassOidIndex "pg_opclass_oid_index"
#define OperatorNameIndex "pg_operator_oprname_l_r_k_index"
#define OperatorNameNspIndex "pg_operator_oprname_l_r_n_index"
#define OperatorOidIndex "pg_operator_oid_index"
#define ProcedureNameNspIndex "pg_proc_proname_args_nsp_index"
#define ProcedureOidIndex "pg_proc_oid_index"
......@@ -172,7 +172,7 @@ DECLARE_UNIQUE_INDEX(pg_namespace_oid_index on pg_namespace using btree(oid oid_
DECLARE_UNIQUE_INDEX(pg_opclass_am_name_index on pg_opclass using btree(opcamid oid_ops, opcname name_ops));
DECLARE_UNIQUE_INDEX(pg_opclass_oid_index on pg_opclass using btree(oid oid_ops));
DECLARE_UNIQUE_INDEX(pg_operator_oid_index on pg_operator using btree(oid oid_ops));
DECLARE_UNIQUE_INDEX(pg_operator_oprname_l_r_k_index on pg_operator using btree(oprname name_ops, oprleft oid_ops, oprright oid_ops, oprkind char_ops));
DECLARE_UNIQUE_INDEX(pg_operator_oprname_l_r_n_index on pg_operator using btree(oprname name_ops, oprleft oid_ops, oprright oid_ops, oprnamespace oid_ops));
DECLARE_UNIQUE_INDEX(pg_proc_oid_index on pg_proc using btree(oid oid_ops));
DECLARE_UNIQUE_INDEX(pg_proc_proname_args_nsp_index on pg_proc using btree(proname name_ops, pronargs int2_ops, proargtypes oidvector_ops, pronamespace oid_ops));
/* This following index is not used for a cache and is not unique */
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: namespace.h,v 1.7 2002/04/09 20:35:54 tgl Exp $
* $Id: namespace.h,v 1.8 2002/04/16 23:08:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -43,6 +43,8 @@ extern Oid TypenameGetTypid(const char *typname);
extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs);
extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind);
extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p);
extern RangeVar *makeRangeVarFromNameList(List *names);
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: defrem.h,v 1.35 2002/04/15 05:22:03 tgl Exp $
* $Id: defrem.h,v 1.36 2002/04/16 23:08:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -42,7 +42,7 @@ extern void CreateFunction(ProcedureStmt *stmt);
extern void RemoveFunction(List *functionName, List *argTypes);
extern void DefineOperator(List *names, List *parameters);
extern void RemoveOperator(char *operatorName,
extern void RemoveOperator(List *operatorName,
TypeName *typeName1, TypeName *typeName2);
extern void DefineAggregate(List *names, List *parameters);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: makefuncs.h,v 1.34 2002/03/29 19:06:23 tgl Exp $
* $Id: makefuncs.h,v 1.35 2002/04/16 23:08:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -16,6 +16,11 @@
#include "nodes/parsenodes.h"
extern A_Expr *makeA_Expr(int oper, List *name, Node *lexpr, Node *rexpr);
extern A_Expr *makeSimpleA_Expr(int oper, const char *name,
Node *lexpr, Node *rexpr);
extern Oper *makeOper(Oid opno,
Oid opid,
Oid opresulttype);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.169 2002/04/09 20:35:54 tgl Exp $
* $Id: parsenodes.h,v 1.170 2002/04/16 23:08:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -158,7 +158,7 @@ typedef struct A_Expr
{
NodeTag type;
int oper; /* type of operation (OP,OR,AND,NOT) */
char *opname; /* name of operator */
List *name; /* possibly-qualified name of operator */
Node *lexpr; /* left argument */
Node *rexpr; /* right argument */
} A_Expr;
......@@ -373,7 +373,7 @@ typedef struct InsertDefault
typedef struct SortGroupBy
{
NodeTag type;
char *useOp; /* operator to use */
List *useOp; /* operator to use */
Node *node; /* Expression */
} SortGroupBy;
......@@ -1189,7 +1189,7 @@ typedef struct RemoveFuncStmt
typedef struct RemoveOperStmt
{
NodeTag type;
char *opname; /* operator to drop */
List *opname; /* operator to drop */
List *args; /* types of the arguments */
} RemoveOperStmt;
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_func.h,v 1.39 2002/04/11 20:00:15 tgl Exp $
* $Id: parse_func.h,v 1.40 2002/04/16 23:08:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -28,16 +28,6 @@ typedef struct _InhPaths
Oid *supervec; /* vector of superclasses */
} InhPaths;
/*
* This structure holds a list of possible functions or operators that
* agree with the known name and argument types of the function/operator.
*/
typedef struct _CandidateList
{
Oid *args;
struct _CandidateList *next;
} *CandidateList;
/* Result codes for func_get_detail */
typedef enum
{
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_node.h,v 1.29 2001/11/05 17:46:35 momjian Exp $
* $Id: parse_node.h,v 1.30 2002/04/16 23:08:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -51,9 +51,8 @@ typedef struct ParseState
} ParseState;
extern ParseState *make_parsestate(ParseState *parentParseState);
extern Expr *make_op(char *opname, Node *ltree, Node *rtree);
extern Node *make_operand(char *opname, Node *tree,
Oid orig_typeId, Oid target_typeId);
extern Expr *make_op(List *opname, Node *ltree, Node *rtree);
extern Node *make_operand(Node *tree, Oid orig_typeId, Oid target_typeId);
extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno);
extern ArrayRef *transformArraySubscripts(ParseState *pstate,
Node *arrayBase,
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_oper.h,v 1.18 2001/11/05 17:46:35 momjian Exp $
* $Id: parse_oper.h,v 1.19 2002/04/16 23:08:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -15,25 +15,31 @@
#define PARSE_OPER_H
#include "access/htup.h"
#include "nodes/parsenodes.h"
typedef HeapTuple Operator;
/* Routines to look up an operator given name and exact input type(s) */
extern Oid LookupOperName(List *opername, Oid oprleft, Oid oprright);
extern Oid LookupOperNameTypeNames(List *opername, TypeName *oprleft,
TypeName *oprright, const char *caller);
/* Routines to find operators matching a name and given input types */
/* NB: the selected operator may require coercion of the input types! */
extern Operator oper(char *op, Oid arg1, Oid arg2, bool noError);
extern Operator right_oper(char *op, Oid arg);
extern Operator left_oper(char *op, Oid arg);
extern Operator oper(List *op, Oid arg1, Oid arg2, bool noError);
extern Operator right_oper(List *op, Oid arg);
extern Operator left_oper(List *op, Oid arg);
/* Routines to find operators that DO NOT require coercion --- ie, their */
/* input types are either exactly as given, or binary-compatible */
extern Operator compatible_oper(char *op, Oid arg1, Oid arg2, bool noError);
extern Operator compatible_oper(List *op, Oid arg1, Oid arg2, bool noError);
/* currently no need for compatible_left_oper/compatible_right_oper */
/* Convenience routines that call compatible_oper() and return either */
/* the operator OID or the underlying function OID, or InvalidOid if fail */
extern Oid compatible_oper_opid(char *op, Oid arg1, Oid arg2, bool noError);
extern Oid compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError);
extern Oid compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError);
extern Oid compatible_oper_funcid(List *op, Oid arg1, Oid arg2, bool noError);
/* Convenience routine that packages a specific call on compatible_oper */
extern Oid any_ordering_op(Oid argtype);
......
......@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: syscache.h,v 1.44 2002/04/11 20:00:17 tgl Exp $
* $Id: syscache.h,v 1.45 2002/04/16 23:08:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -46,7 +46,7 @@
#define LANGOID 15
#define NAMESPACENAME 16
#define NAMESPACEOID 17
#define OPERNAME 18
#define OPERNAMENSP 18
#define OPEROID 19
#define PROCNAMENSP 20
#define PROCOID 21
......
......@@ -173,13 +173,13 @@ drop operator;
ERROR: parser: parse error at or near ";"
-- bad operator name
drop operator equals;
ERROR: parser: parse error at or near "equals"
ERROR: parser: parse error at or near ";"
-- missing type list
drop operator ===;
ERROR: parser: parse error at or near ";"
-- missing parentheses
drop operator int4, int4;
ERROR: parser: parse error at or near "int4"
ERROR: parser: parse error at or near ","
-- missing operator name
drop operator (int4, int4);
ERROR: parser: parse error at or near "("
......@@ -191,7 +191,7 @@ drop operator === (int4);
ERROR: parser: argument type missing (use NONE for unary operators)
-- no such operator by that name
drop operator === (int4, int4);
ERROR: RemoveOperator: binary operator '===' taking 'int4' and 'int4' does not exist
ERROR: RemoveOperator: Operator '===' for types 'int4' and 'int4' does not exist
-- no such type1
drop operator = (nonesuch);
ERROR: parser: argument type missing (use NONE for unary operators)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment