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 >.
This commit is contained in:
Tom Lane 2002-04-16 23:08:12 +00:00
parent 4da51bfd6d
commit 6cef5d2549
39 changed files with 1953 additions and 1803 deletions

View File

@ -1,6 +1,6 @@
<!--
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>

View File

@ -1,5 +1,5 @@
<!--
$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>
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 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.
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>

View File

@ -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] =

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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;
Oid oid;
/* Attempt to fetch the left type oid, if specified */
if (typenode1 != NULL)
leftoid = typenameTypeId(typenode1);
/* Look up the operator */
/* 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 */
optuple = SearchSysCache(OPERNAME,
PointerGetDatum(opername),
ObjectIdGetDatum(leftoid),
ObjectIdGetDatum(rightoid),
CharGetDatum(oprtype));
if (!HeapTupleIsValid(optuple))
elog(ERROR, "operator '%s' does not exist", opername);
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 */

View File

@ -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"
@ -59,23 +60,26 @@ DefineOperator(List *names, List *parameters)
{
char *oprName;
Oid oprNamespace;
uint16 precedence = 0; /* operator precedence */
bool canHash = false; /* operator hashes */
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()))
elog(ERROR, "RemoveOperator: operator '%s': permission denied",
operatorName);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "RemoveOperator: failed to find tuple for operator '%s'",
NameListToString(operatorName));
/* Delete any comments associated with this operator */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
if (!pg_oper_ownercheck(operOid, GetUserId()))
elog(ERROR, "RemoveOperator: operator '%s': permission denied",
NameListToString(operatorName));
/* Delete any comments associated with this operator */
DeleteComments(operOid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self);
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);
}

View File

@ -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'",

View File

@ -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));

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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:

View File

@ -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));
}
/*

View File

@ -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))
{
/*

View File

@ -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);

View File

@ -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);
}

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.301 2002/04/09 20:35:51 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.302 2002/04/16 23:08:11 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -82,11 +82,10 @@ static int pfunc_num_args;
*/
/*#define __YYSCLASS*/
static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
static Node *makeTypeCast(Node *arg, TypeName *typename);
static Node *makeStringConst(char *str, TypeName *typename);
static Node *makeFloatConst(char *str);
static Node *makeRowExpr(char *opr, List *largs, List *rargs);
static Node *makeRowExpr(List *opr, List *largs, List *rargs);
static SelectStmt *findLeftmostSelect(SelectStmt *node);
static void insertSelectOptions(SelectStmt *stmt,
List *sortClause, List *forUpdate,
@ -177,13 +176,13 @@ static bool set_name_needs_quotes(const char *name);
database_name, access_method_clause, access_method, attr_name,
class, index_name, name, function_name, file_name
%type <list> func_name, handler_name
%type <list> func_name, handler_name, qual_Op, qual_all_Op, OptUseOp
%type <range> qualified_name, OptConstrFromTable
%type <str> opt_id,
all_Op, MathOp, opt_name,
OptUseOp, opt_class, SpecialRuleRelation
opt_class, SpecialRuleRelation
%type <str> opt_level, opt_encoding
%type <node> grantee
@ -202,7 +201,7 @@ static bool set_name_needs_quotes(const char *name);
opt_column_list, columnList, opt_name_list,
sort_clause, sortby_list, index_params, index_list, name_list,
from_clause, from_list, opt_array_bounds, qualified_name_list,
any_name, any_name_list, expr_list, dotted_name, attrs,
any_name, any_name_list, any_operator, expr_list, dotted_name, attrs,
target_list, update_target_list, insert_column_list,
insert_target_list,
def_list, opt_indirection, group_clause, TriggerFuncArgs,
@ -404,7 +403,7 @@ static bool set_name_needs_quotes(const char *name);
%nonassoc BETWEEN
%nonassoc IN
%left POSTFIXOP /* dummy for postfix Op rules */
%left Op /* multi-character ops and user-defined operators */
%left Op OPERATOR /* multi-character ops and user-defined operators */
%nonassoc NOTNULL
%nonassoc ISNULL
%nonassoc IS NULL_P TRUE_P FALSE_P UNKNOWN /* sets precedence for IS NULL, etc */
@ -2086,11 +2085,11 @@ DefineStmt: CREATE AGGREGATE func_name definition
n->definition = $4;
$$ = (Node *)n;
}
| CREATE OPERATOR all_Op definition
| CREATE OPERATOR any_operator definition
{
DefineStmt *n = makeNode(DefineStmt);
n->defType = OPERATOR;
n->defnames = makeList1(makeString($3)); /* XXX */
n->defnames = $3;
n->definition = $4;
$$ = (Node *)n;
}
@ -2227,11 +2226,11 @@ CommentStmt: COMMENT ON comment_type any_name IS comment_text
n->comment = $7;
$$ = (Node *) n;
}
| COMMENT ON OPERATOR all_Op '(' oper_argtypes ')' IS comment_text
| COMMENT ON OPERATOR any_operator '(' oper_argtypes ')' IS comment_text
{
CommentStmt *n = makeNode(CommentStmt);
n->objtype = OPERATOR;
n->objname = makeList1(makeString($4)); /* XXX */
n->objname = $4;
n->objargs = $6;
n->comment = $9;
$$ = (Node *) n;
@ -2812,7 +2811,7 @@ aggr_argtype: Typename { $$ = $1; }
| '*' { $$ = NULL; }
;
RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')'
RemoveOperStmt: DROP OPERATOR any_operator '(' oper_argtypes ')'
{
RemoveOperStmt *n = makeNode(RemoveOperStmt);
n->opname = $3;
@ -2833,6 +2832,12 @@ oper_argtypes: Typename
{ $$ = makeList2($1, NULL); }
;
any_operator: all_Op
{ $$ = makeList1(makeString($1)); }
| ColId '.' any_operator
{ $$ = lcons(makeString($1), $3); }
;
/*****************************************************************************
*
@ -3831,10 +3836,14 @@ sortby: a_expr OptUseOp
}
;
OptUseOp: USING all_Op { $$ = $2; }
| ASC { $$ = "<"; }
| DESC { $$ = ">"; }
| /*EMPTY*/ { $$ = "<"; /*default*/ }
OptUseOp: USING qual_all_Op
{ $$ = $2; }
| ASC
{ $$ = makeList1(makeString("<")); }
| DESC
{ $$ = makeList1(makeString(">")); }
| /*EMPTY*/
{ $$ = makeList1(makeString("<")); /*default*/ }
;
@ -4593,7 +4602,7 @@ row_expr: '(' row_descriptor ')' IN select_with_parens
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = (List *) makeA_Expr(OP, "=", NULL, NULL);
n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
n->useor = FALSE;
n->subLinkType = ANY_SUBLINK;
n->subselect = $5;
@ -4603,18 +4612,18 @@ row_expr: '(' row_descriptor ')' IN select_with_parens
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = (List *) makeA_Expr(OP, "<>", NULL, NULL);
n->oper = (List *) makeSimpleA_Expr(OP, "<>", NULL, NULL);
n->useor = TRUE;
n->subLinkType = ALL_SUBLINK;
n->subselect = $6;
$$ = (Node *)n;
}
| '(' row_descriptor ')' all_Op sub_type select_with_parens
| '(' row_descriptor ')' qual_all_Op sub_type select_with_parens %prec Op
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = (List *) makeA_Expr(OP, $4, NULL, NULL);
if (strcmp($4, "<>") == 0)
if (strcmp(strVal(llast($4)), "<>") == 0)
n->useor = TRUE;
else
n->useor = FALSE;
@ -4622,12 +4631,12 @@ row_expr: '(' row_descriptor ')' IN select_with_parens
n->subselect = $6;
$$ = (Node *)n;
}
| '(' row_descriptor ')' all_Op select_with_parens
| '(' row_descriptor ')' qual_all_Op select_with_parens %prec Op
{
SubLink *n = makeNode(SubLink);
n->lefthand = $2;
n->oper = (List *) makeA_Expr(OP, $4, NULL, NULL);
if (strcmp($4, "<>") == 0)
if (strcmp(strVal(llast($4)), "<>") == 0)
n->useor = TRUE;
else
n->useor = FALSE;
@ -4635,7 +4644,7 @@ row_expr: '(' row_descriptor ')' IN select_with_parens
n->subselect = $5;
$$ = (Node *)n;
}
| '(' row_descriptor ')' all_Op '(' row_descriptor ')'
| '(' row_descriptor ')' qual_all_Op '(' row_descriptor ')' %prec Op
{
$$ = makeRowExpr($4, $2, $6);
}
@ -4696,6 +4705,18 @@ MathOp: '+' { $$ = "+"; }
| '=' { $$ = "="; }
;
qual_Op: Op
{ $$ = makeList1(makeString($1)); }
| OPERATOR '(' any_operator ')'
{ $$ = $3; }
;
qual_all_Op: all_Op
{ $$ = makeList1(makeString($1)); }
| OPERATOR '(' any_operator ')'
{ $$ = $3; }
;
/*
* General expressions
* This is the heart of the expression syntax.
@ -4735,52 +4756,52 @@ a_expr: c_expr
* also to b_expr and to the MathOp list above.
*/
| '+' a_expr %prec UMINUS
{ $$ = makeA_Expr(OP, "+", NULL, $2); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "+", NULL, $2); }
| '-' a_expr %prec UMINUS
{ $$ = doNegate($2); }
| '%' a_expr
{ $$ = makeA_Expr(OP, "%", NULL, $2); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "%", NULL, $2); }
| '^' a_expr
{ $$ = makeA_Expr(OP, "^", NULL, $2); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "^", NULL, $2); }
| a_expr '%'
{ $$ = makeA_Expr(OP, "%", $1, NULL); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, NULL); }
| a_expr '^'
{ $$ = makeA_Expr(OP, "^", $1, NULL); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, NULL); }
| a_expr '+' a_expr
{ $$ = makeA_Expr(OP, "+", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "+", $1, $3); }
| a_expr '-' a_expr
{ $$ = makeA_Expr(OP, "-", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "-", $1, $3); }
| a_expr '*' a_expr
{ $$ = makeA_Expr(OP, "*", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "*", $1, $3); }
| a_expr '/' a_expr
{ $$ = makeA_Expr(OP, "/", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "/", $1, $3); }
| a_expr '%' a_expr
{ $$ = makeA_Expr(OP, "%", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, $3); }
| a_expr '^' a_expr
{ $$ = makeA_Expr(OP, "^", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, $3); }
| a_expr '<' a_expr
{ $$ = makeA_Expr(OP, "<", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "<", $1, $3); }
| a_expr '>' a_expr
{ $$ = makeA_Expr(OP, ">", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, ">", $1, $3); }
| a_expr '=' a_expr
{ $$ = makeA_Expr(OP, "=", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "=", $1, $3); }
| a_expr Op a_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
| Op a_expr
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
| a_expr Op %prec POSTFIXOP
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
| a_expr qual_Op a_expr %prec Op
{ $$ = (Node *) makeA_Expr(OP, $2, $1, $3); }
| qual_Op a_expr %prec Op
{ $$ = (Node *) makeA_Expr(OP, $1, NULL, $2); }
| a_expr qual_Op %prec POSTFIXOP
{ $$ = (Node *) makeA_Expr(OP, $2, $1, NULL); }
| a_expr AND a_expr
{ $$ = makeA_Expr(AND, NULL, $1, $3); }
{ $$ = (Node *) makeA_Expr(AND, NIL, $1, $3); }
| a_expr OR a_expr
{ $$ = makeA_Expr(OR, NULL, $1, $3); }
{ $$ = (Node *) makeA_Expr(OR, NIL, $1, $3); }
| NOT a_expr
{ $$ = makeA_Expr(NOT, NULL, NULL, $2); }
{ $$ = (Node *) makeA_Expr(NOT, NIL, NULL, $2); }
| a_expr LIKE a_expr
{ $$ = makeA_Expr(OP, "~~", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "~~", $1, $3); }
| a_expr LIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
@ -4788,10 +4809,10 @@ a_expr: c_expr
n->args = makeList2($3, $5);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = makeA_Expr(OP, "~~", $1, (Node *) n);
$$ = (Node *) makeSimpleA_Expr(OP, "~~", $1, (Node *) n);
}
| a_expr NOT LIKE a_expr
{ $$ = makeA_Expr(OP, "!~~", $1, $4); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "!~~", $1, $4); }
| a_expr NOT LIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
@ -4799,10 +4820,10 @@ a_expr: c_expr
n->args = makeList2($4, $6);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = makeA_Expr(OP, "!~~", $1, (Node *) n);
$$ = (Node *) makeSimpleA_Expr(OP, "!~~", $1, (Node *) n);
}
| a_expr ILIKE a_expr
{ $$ = makeA_Expr(OP, "~~*", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "~~*", $1, $3); }
| a_expr ILIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
@ -4810,10 +4831,10 @@ a_expr: c_expr
n->args = makeList2($3, $5);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = makeA_Expr(OP, "~~*", $1, (Node *) n);
$$ = (Node *) makeSimpleA_Expr(OP, "~~*", $1, (Node *) n);
}
| a_expr NOT ILIKE a_expr
{ $$ = makeA_Expr(OP, "!~~*", $1, $4); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "!~~*", $1, $4); }
| a_expr NOT ILIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
@ -4821,7 +4842,7 @@ a_expr: c_expr
n->args = makeList2($4, $6);
n->agg_star = FALSE;
n->agg_distinct = FALSE;
$$ = makeA_Expr(OP, "!~~*", $1, (Node *) n);
$$ = (Node *) makeSimpleA_Expr(OP, "!~~*", $1, (Node *) n);
}
/* NullTest clause
* Define SQL92-style Null test clause.
@ -4915,15 +4936,15 @@ a_expr: c_expr
}
| a_expr BETWEEN b_expr AND b_expr %prec BETWEEN
{
$$ = makeA_Expr(AND, NULL,
makeA_Expr(OP, ">=", $1, $3),
makeA_Expr(OP, "<=", $1, $5));
$$ = (Node *) makeA_Expr(AND, NIL,
(Node *) makeSimpleA_Expr(OP, ">=", $1, $3),
(Node *) makeSimpleA_Expr(OP, "<=", $1, $5));
}
| a_expr NOT BETWEEN b_expr AND b_expr %prec BETWEEN
{
$$ = makeA_Expr(OR, NULL,
makeA_Expr(OP, "<", $1, $4),
makeA_Expr(OP, ">", $1, $6));
$$ = (Node *) makeA_Expr(OR, NIL,
(Node *) makeSimpleA_Expr(OP, "<", $1, $4),
(Node *) makeSimpleA_Expr(OP, ">", $1, $6));
}
| a_expr IN in_expr
{
@ -4932,7 +4953,8 @@ a_expr: c_expr
{
SubLink *n = (SubLink *)$3;
n->lefthand = makeList1($1);
n->oper = (List *) makeA_Expr(OP, "=", NULL, NULL);
n->oper = (List *) makeSimpleA_Expr(OP, "=",
NULL, NULL);
n->useor = FALSE;
n->subLinkType = ANY_SUBLINK;
$$ = (Node *)n;
@ -4943,11 +4965,13 @@ a_expr: c_expr
List *l;
foreach(l, (List *) $3)
{
Node *cmp = makeA_Expr(OP, "=", $1, lfirst(l));
Node *cmp;
cmp = (Node *) makeSimpleA_Expr(OP, "=",
$1, lfirst(l));
if (n == NULL)
n = cmp;
else
n = makeA_Expr(OR, NULL, n, cmp);
n = (Node *) makeA_Expr(OR, NIL, n, cmp);
}
$$ = n;
}
@ -4959,7 +4983,8 @@ a_expr: c_expr
{
SubLink *n = (SubLink *)$4;
n->lefthand = makeList1($1);
n->oper = (List *) makeA_Expr(OP, "<>", NULL, NULL);
n->oper = (List *) makeSimpleA_Expr(OP, "<>",
NULL, NULL);
n->useor = FALSE;
n->subLinkType = ALL_SUBLINK;
$$ = (Node *)n;
@ -4970,16 +4995,18 @@ a_expr: c_expr
List *l;
foreach(l, (List *) $4)
{
Node *cmp = makeA_Expr(OP, "<>", $1, lfirst(l));
Node *cmp;
cmp = (Node *) makeSimpleA_Expr(OP, "<>",
$1, lfirst(l));
if (n == NULL)
n = cmp;
else
n = makeA_Expr(AND, NULL, n, cmp);
n = (Node *) makeA_Expr(AND, NIL, n, cmp);
}
$$ = n;
}
}
| a_expr all_Op sub_type select_with_parens %prec Op
| a_expr qual_all_Op sub_type select_with_parens %prec Op
{
SubLink *n = makeNode(SubLink);
n->lefthand = makeList1($1);
@ -5007,42 +5034,42 @@ b_expr: c_expr
| b_expr TYPECAST Typename
{ $$ = makeTypeCast($1, $3); }
| '+' b_expr %prec UMINUS
{ $$ = makeA_Expr(OP, "+", NULL, $2); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "+", NULL, $2); }
| '-' b_expr %prec UMINUS
{ $$ = doNegate($2); }
| '%' b_expr
{ $$ = makeA_Expr(OP, "%", NULL, $2); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "%", NULL, $2); }
| '^' b_expr
{ $$ = makeA_Expr(OP, "^", NULL, $2); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "^", NULL, $2); }
| b_expr '%'
{ $$ = makeA_Expr(OP, "%", $1, NULL); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, NULL); }
| b_expr '^'
{ $$ = makeA_Expr(OP, "^", $1, NULL); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, NULL); }
| b_expr '+' b_expr
{ $$ = makeA_Expr(OP, "+", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "+", $1, $3); }
| b_expr '-' b_expr
{ $$ = makeA_Expr(OP, "-", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "-", $1, $3); }
| b_expr '*' b_expr
{ $$ = makeA_Expr(OP, "*", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "*", $1, $3); }
| b_expr '/' b_expr
{ $$ = makeA_Expr(OP, "/", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "/", $1, $3); }
| b_expr '%' b_expr
{ $$ = makeA_Expr(OP, "%", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, $3); }
| b_expr '^' b_expr
{ $$ = makeA_Expr(OP, "^", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, $3); }
| b_expr '<' b_expr
{ $$ = makeA_Expr(OP, "<", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "<", $1, $3); }
| b_expr '>' b_expr
{ $$ = makeA_Expr(OP, ">", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, ">", $1, $3); }
| b_expr '=' b_expr
{ $$ = makeA_Expr(OP, "=", $1, $3); }
{ $$ = (Node *) makeSimpleA_Expr(OP, "=", $1, $3); }
| b_expr Op b_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
| Op b_expr
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
| b_expr Op %prec POSTFIXOP
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
| b_expr qual_Op b_expr %prec Op
{ $$ = (Node *) makeA_Expr(OP, $2, $1, $3); }
| qual_Op b_expr %prec Op
{ $$ = (Node *) makeA_Expr(OP, $1, NULL, $2); }
| b_expr qual_Op %prec POSTFIXOP
{ $$ = (Node *) makeA_Expr(OP, $2, $1, NULL); }
;
/*
@ -5539,12 +5566,9 @@ case_expr: CASE case_arg when_clause_list case_default END_TRANS
{
CaseExpr *c = makeNode(CaseExpr);
CaseWhen *w = makeNode(CaseWhen);
/*
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
w->result = (Node *)n;
*/
w->expr = makeA_Expr(OP, "=", $3, $5);
w->expr = (Node *) makeSimpleA_Expr(OP, "=", $3, $5);
/* w->result is left NULL */
c->args = makeList1(w);
c->defresult = $3;
$$ = (Node *)c;
@ -6243,17 +6267,6 @@ SpecialRuleRelation: OLD
%%
static Node *
makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr)
{
A_Expr *a = makeNode(A_Expr);
a->oper = oper;
a->opname = opname;
a->lexpr = lexpr;
a->rexpr = rexpr;
return (Node *)a;
}
static Node *
makeTypeCast(Node *arg, TypeName *typename)
{
@ -6308,41 +6321,49 @@ makeFloatConst(char *str)
* - thomas 1997-12-22
*/
static Node *
makeRowExpr(char *opr, List *largs, List *rargs)
makeRowExpr(List *opr, List *largs, List *rargs)
{
Node *expr = NULL;
Node *larg, *rarg;
char *oprname;
if (length(largs) != length(rargs))
elog(ERROR,"Unequal number of entries in row expression");
elog(ERROR, "Unequal number of entries in row expression");
if (lnext(largs) != NIL)
expr = makeRowExpr(opr,lnext(largs),lnext(rargs));
expr = makeRowExpr(opr, lnext(largs), lnext(rargs));
larg = lfirst(largs);
rarg = lfirst(rargs);
if ((strcmp(opr, "=") == 0)
|| (strcmp(opr, "<") == 0)
|| (strcmp(opr, "<=") == 0)
|| (strcmp(opr, ">") == 0)
|| (strcmp(opr, ">=") == 0))
oprname = strVal(llast(opr));
if ((strcmp(oprname, "=") == 0) ||
(strcmp(oprname, "<") == 0) ||
(strcmp(oprname, "<=") == 0) ||
(strcmp(oprname, ">") == 0) ||
(strcmp(oprname, ">=") == 0))
{
if (expr == NULL)
expr = makeA_Expr(OP, opr, larg, rarg);
expr = (Node *) makeA_Expr(OP, opr, larg, rarg);
else
expr = makeA_Expr(AND, NULL, expr, makeA_Expr(OP, opr, larg, rarg));
expr = (Node *) makeA_Expr(AND, NIL, expr,
(Node *) makeA_Expr(OP, opr,
larg, rarg));
}
else if (strcmp(opr, "<>") == 0)
else if (strcmp(oprname, "<>") == 0)
{
if (expr == NULL)
expr = makeA_Expr(OP, opr, larg, rarg);
expr = (Node *) makeA_Expr(OP, opr, larg, rarg);
else
expr = makeA_Expr(OR, NULL, expr, makeA_Expr(OP, opr, larg, rarg));
expr = (Node *) makeA_Expr(OR, NIL, expr,
(Node *) makeA_Expr(OP, opr,
larg, rarg));
}
else
{
elog(ERROR,"Operator '%s' not implemented for row expressions",opr);
elog(ERROR, "Operator '%s' not implemented for row expressions",
oprname);
}
return expr;
@ -6557,7 +6578,7 @@ doNegate(Node *n)
}
}
return makeA_Expr(OP, "-", NULL, n);
return (Node *) makeSimpleA_Expr(OP, "-", NULL, n);
}
static void

View File

@ -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))

View File

@ -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);

View File

@ -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 */

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.54 2002/04/11 20:00:02 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.55 2002/04/16 23:08:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -19,6 +19,7 @@
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_operator.h"
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
@ -28,17 +29,106 @@
#include "utils/fmgroids.h"
#include "utils/syscache.h"
static Oid *oper_select_candidate(int nargs, Oid *input_typeids,
CandidateList candidates);
static Operator oper_exact(char *op, Oid arg1, Oid arg2);
static Operator oper_inexact(char *op, Oid arg1, Oid arg2);
static int binary_oper_get_candidates(char *opname,
CandidateList *candidates);
static int unary_oper_get_candidates(char *opname,
CandidateList *candidates,
char rightleft);
static void op_error(char *op, Oid arg1, Oid arg2);
static void unary_op_error(char *op, Oid arg, bool is_left_op);
static Oid binary_oper_exact(Oid arg1, Oid arg2,
FuncCandidateList candidates);
static Oid oper_select_candidate(int nargs, Oid *input_typeids,
FuncCandidateList candidates);
static void op_error(List *op, Oid arg1, Oid arg2);
static void unary_op_error(List *op, Oid arg, bool is_left_op);
/*
* LookupOperName
* Given a possibly-qualified operator name and exact input datatypes,
* look up the operator. Returns InvalidOid if no such operator.
*
* Pass oprleft = InvalidOid for a prefix op, oprright = InvalidOid for
* a postfix op.
*
* If the operator name is not schema-qualified, it is sought in the current
* namespace search path.
*/
Oid
LookupOperName(List *opername, Oid oprleft, Oid oprright)
{
FuncCandidateList clist;
char oprkind;
if (!OidIsValid(oprleft))
oprkind = 'l';
else if (!OidIsValid(oprright))
oprkind = 'r';
else
oprkind = 'b';
clist = OpernameGetCandidates(opername, oprkind);
while (clist)
{
if (clist->args[0] == oprleft && clist->args[1] == oprright)
return clist->oid;
clist = clist->next;
}
return InvalidOid;
}
/*
* LookupOperNameTypeNames
* Like LookupOperName, but the argument types are specified by
* TypeName nodes. Also, if we fail to find the operator
* and caller is not NULL, then an error is reported.
*
* Pass oprleft = NULL for a prefix op, oprright = NULL for a postfix op.
*/
Oid
LookupOperNameTypeNames(List *opername, TypeName *oprleft,
TypeName *oprright, const char *caller)
{
Oid operoid;
Oid leftoid,
rightoid;
if (oprleft == NULL)
leftoid = InvalidOid;
else
{
leftoid = LookupTypeName(oprleft);
if (!OidIsValid(leftoid))
elog(ERROR, "Type \"%s\" does not exist",
TypeNameToString(oprleft));
}
if (oprright == NULL)
rightoid = InvalidOid;
else
{
rightoid = LookupTypeName(oprright);
if (!OidIsValid(rightoid))
elog(ERROR, "Type \"%s\" does not exist",
TypeNameToString(oprright));
}
operoid = LookupOperName(opername, leftoid, rightoid);
if (!OidIsValid(operoid) && caller != NULL)
{
if (oprleft == NULL)
elog(ERROR, "%s: Prefix operator '%s' for type '%s' does not exist",
caller, NameListToString(opername),
TypeNameToString(oprright));
else if (oprright == NULL)
elog(ERROR, "%s: Postfix operator '%s' for type '%s' does not exist",
caller, NameListToString(opername),
TypeNameToString(oprleft));
else
elog(ERROR, "%s: Operator '%s' for types '%s' and '%s' does not exist",
caller, NameListToString(opername),
TypeNameToString(oprleft),
TypeNameToString(oprright));
}
return operoid;
}
/* Select an ordering operator for the given datatype */
@ -47,7 +137,8 @@ any_ordering_op(Oid argtype)
{
Oid order_opid;
order_opid = compatible_oper_opid("<", argtype, argtype, true);
order_opid = compatible_oper_opid(makeList1(makeString("<")),
argtype, argtype, true);
if (!OidIsValid(order_opid))
elog(ERROR, "Unable to identify an ordering operator '%s' for type '%s'"
"\n\tUse an explicit ordering operator or modify the query",
@ -72,116 +163,32 @@ oprfuncid(Operator op)
}
/* binary_oper_get_candidates()
* given opname, find all possible input type pairs for which an operator
* named opname exists.
* Build a list of the candidate input types.
* Returns number of candidates found.
/* binary_oper_exact()
* Check for an "exact" match to the specified operand types.
*
* If one operand is an unknown literal, assume it should be taken to be
* the same type as the other operand for this purpose.
*/
static int
binary_oper_get_candidates(char *opname,
CandidateList *candidates)
static Oid
binary_oper_exact(Oid arg1, Oid arg2,
FuncCandidateList candidates)
{
Relation pg_operator_desc;
SysScanDesc pg_operator_scan;
HeapTuple tup;
int ncandidates = 0;
ScanKeyData opKey[1];
/* Unspecified type for one of the arguments? then use the other */
if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid))
arg1 = arg2;
else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))
arg2 = arg1;
*candidates = NULL;
ScanKeyEntryInitialize(&opKey[0], 0,
Anum_pg_operator_oprname,
F_NAMEEQ,
NameGetDatum(opname));
pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
pg_operator_scan = systable_beginscan(pg_operator_desc,
OperatorNameIndex, true,
SnapshotNow,
1, opKey);
while (HeapTupleIsValid(tup = systable_getnext(pg_operator_scan)))
while (candidates != NULL)
{
Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tup);
if (oper->oprkind == 'b')
{
CandidateList current_candidate;
current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
current_candidate->args = (Oid *) palloc(2 * sizeof(Oid));
current_candidate->args[0] = oper->oprleft;
current_candidate->args[1] = oper->oprright;
current_candidate->next = *candidates;
*candidates = current_candidate;
ncandidates++;
}
if (arg1 == candidates->args[0] &&
arg2 == candidates->args[1])
return candidates->oid;
candidates = candidates->next;
}
systable_endscan(pg_operator_scan);
heap_close(pg_operator_desc, AccessShareLock);
return ncandidates;
} /* binary_oper_get_candidates() */
/* unary_oper_get_candidates()
* given opname, find all possible types for which
* a right/left unary operator named opname exists.
* Build a list of the candidate input types.
* Returns number of candidates found.
*/
static int
unary_oper_get_candidates(char *opname,
CandidateList *candidates,
char rightleft)
{
Relation pg_operator_desc;
SysScanDesc pg_operator_scan;
HeapTuple tup;
int ncandidates = 0;
ScanKeyData opKey[1];
*candidates = NULL;
ScanKeyEntryInitialize(&opKey[0], 0,
Anum_pg_operator_oprname,
F_NAMEEQ,
NameGetDatum(opname));
pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
pg_operator_scan = systable_beginscan(pg_operator_desc,
OperatorNameIndex, true,
SnapshotNow,
1, opKey);
while (HeapTupleIsValid(tup = systable_getnext(pg_operator_scan)))
{
Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tup);
if (oper->oprkind == rightleft)
{
CandidateList current_candidate;
current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
current_candidate->args = (Oid *) palloc(sizeof(Oid));
if (rightleft == 'r')
current_candidate->args[0] = oper->oprleft;
else
current_candidate->args[0] = oper->oprright;
current_candidate->next = *candidates;
*candidates = current_candidate;
ncandidates++;
}
}
systable_endscan(pg_operator_scan);
heap_close(pg_operator_desc, AccessShareLock);
return ncandidates;
} /* unary_oper_get_candidates() */
return InvalidOid;
}
/* oper_select_candidate()
@ -234,13 +241,13 @@ unary_oper_get_candidates(char *opname,
* some sense. (see equivalentOpersAfterPromotion for details.)
* - ay 6/95
*/
static Oid *
static Oid
oper_select_candidate(int nargs,
Oid *input_typeids,
CandidateList candidates)
FuncCandidateList candidates)
{
CandidateList current_candidate;
CandidateList last_candidate;
FuncCandidateList current_candidate;
FuncCandidateList last_candidate;
Oid *current_typeids;
Oid current_type;
int unknownOids;
@ -289,9 +296,9 @@ oper_select_candidate(int nargs,
/* Done if no candidate or only one candidate survives */
if (ncandidates == 0)
return NULL;
return InvalidOid;
if (ncandidates == 1)
return candidates->args;
return candidates->oid;
/*
* Run through all candidates and keep those with the most matches on
@ -335,7 +342,7 @@ oper_select_candidate(int nargs,
last_candidate->next = NULL;
if (ncandidates == 1)
return candidates->args;
return candidates->oid;
/*
* Still too many candidates? Run through all candidates and keep
@ -382,7 +389,7 @@ oper_select_candidate(int nargs,
last_candidate->next = NULL;
if (ncandidates == 1)
return candidates->args;
return candidates->oid;
/*
* Still too many candidates? Now look for candidates which are
@ -428,7 +435,7 @@ oper_select_candidate(int nargs,
last_candidate->next = NULL;
if (ncandidates == 1)
return candidates->args;
return candidates->oid;
/*
* Still too many candidates? Try assigning types for the unknown
@ -467,7 +474,7 @@ oper_select_candidate(int nargs,
nmatch++;
}
if (nmatch == nargs)
return current_typeids;
return current_candidate->oid;
}
}
@ -602,87 +609,12 @@ oper_select_candidate(int nargs,
}
if (ncandidates == 1)
return candidates->args;
return candidates->oid;
return NULL; /* failed to determine a unique candidate */
return InvalidOid; /* failed to determine a unique candidate */
} /* oper_select_candidate() */
/* oper_exact()
* Given operator, types of arg1 and arg2, return oper struct or NULL.
*
* NOTE: on success, the returned object is a syscache entry. The caller
* must ReleaseSysCache() the entry when done with it.
*/
static Operator
oper_exact(char *op, Oid arg1, Oid arg2)
{
HeapTuple tup;
/* Unspecified type for one of the arguments? then use the other */
if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid))
arg1 = arg2;
else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))
arg2 = arg1;
tup = SearchSysCache(OPERNAME,
PointerGetDatum(op),
ObjectIdGetDatum(arg1),
ObjectIdGetDatum(arg2),
CharGetDatum('b'));
return (Operator) tup;
}
/* oper_inexact()
* Given operator, types of arg1 and arg2, return oper struct or NULL.
*
* NOTE: on success, the returned object is a syscache entry. The caller
* must ReleaseSysCache() the entry when done with it.
*/
static Operator
oper_inexact(char *op, Oid arg1, Oid arg2)
{
HeapTuple tup;
CandidateList candidates;
int ncandidates;
Oid *targetOids;
Oid inputOids[2];
/* Unspecified type for one of the arguments? then use the other */
if (arg2 == InvalidOid)
arg2 = arg1;
if (arg1 == InvalidOid)
arg1 = arg2;
ncandidates = binary_oper_get_candidates(op, &candidates);
/* No operators found? Then return null... */
if (ncandidates == 0)
return NULL;
/*
* Otherwise, check for compatible datatypes, and then try to resolve
* the conflict if more than one candidate remains.
*/
inputOids[0] = arg1;
inputOids[1] = arg2;
targetOids = oper_select_candidate(2, inputOids, candidates);
if (targetOids != NULL)
{
tup = SearchSysCache(OPERNAME,
PointerGetDatum(op),
ObjectIdGetDatum(targetOids[0]),
ObjectIdGetDatum(targetOids[1]),
CharGetDatum('b'));
}
else
tup = NULL;
return (Operator) tup;
}
/* oper() -- search for a binary operator
* Given operator name, types of arg1 and arg2, return oper struct.
*
@ -697,22 +629,48 @@ oper_inexact(char *op, Oid arg1, Oid arg2)
* must ReleaseSysCache() the entry when done with it.
*/
Operator
oper(char *opname, Oid ltypeId, Oid rtypeId, bool noError)
oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError)
{
HeapTuple tup;
FuncCandidateList clist;
Oid operOid;
Oid inputOids[2];
HeapTuple tup = NULL;
/* check for exact match on this operator... */
if (HeapTupleIsValid(tup = oper_exact(opname, ltypeId, rtypeId)))
return (Operator) tup;
/* Get binary operators of given name */
clist = OpernameGetCandidates(opname, 'b');
/* try to find a match on likely candidates... */
if (HeapTupleIsValid(tup = oper_inexact(opname, ltypeId, rtypeId)))
return (Operator) tup;
/* No operators found? Then fail... */
if (clist != NULL)
{
/*
* Check for an "exact" match.
*/
operOid = binary_oper_exact(ltypeId, rtypeId, clist);
if (!OidIsValid(operOid))
{
/*
* Otherwise, search for the most suitable candidate.
*/
if (!noError)
/* Unspecified type for one of the arguments? then use the other */
if (rtypeId == InvalidOid)
rtypeId = ltypeId;
else if (ltypeId == InvalidOid)
ltypeId = rtypeId;
inputOids[0] = ltypeId;
inputOids[1] = rtypeId;
operOid = oper_select_candidate(2, inputOids, clist);
}
if (OidIsValid(operOid))
tup = SearchSysCache(OPEROID,
ObjectIdGetDatum(operOid),
0, 0, 0);
}
if (!HeapTupleIsValid(tup) && !noError)
op_error(opname, ltypeId, rtypeId);
return (Operator) NULL;
return (Operator) tup;
}
/* compatible_oper()
@ -723,7 +681,7 @@ oper(char *opname, Oid ltypeId, Oid rtypeId, bool noError)
* are accepted). Otherwise, the semantics are the same.
*/
Operator
compatible_oper(char *op, Oid arg1, Oid arg2, bool noError)
compatible_oper(List *op, Oid arg1, Oid arg2, bool noError)
{
Operator optup;
Form_pg_operator opform;
@ -755,7 +713,7 @@ compatible_oper(char *op, Oid arg1, Oid arg2, bool noError)
* lookup fails and noError is true.
*/
Oid
compatible_oper_opid(char *op, Oid arg1, Oid arg2, bool noError)
compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
{
Operator optup;
Oid result;
@ -777,7 +735,7 @@ compatible_oper_opid(char *op, Oid arg1, Oid arg2, bool noError)
* lookup fails and noError is true.
*/
Oid
compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError)
compatible_oper_funcid(List *op, Oid arg1, Oid arg2, bool noError)
{
Operator optup;
Oid result;
@ -805,46 +763,50 @@ compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError)
* must ReleaseSysCache() the entry when done with it.
*/
Operator
right_oper(char *op, Oid arg)
right_oper(List *op, Oid arg)
{
HeapTuple tup;
CandidateList candidates;
int ncandidates;
Oid *targetOid;
FuncCandidateList clist;
Oid operOid = InvalidOid;
HeapTuple tup = NULL;
/* Try for exact match */
tup = SearchSysCache(OPERNAME,
PointerGetDatum(op),
ObjectIdGetDatum(arg),
ObjectIdGetDatum(InvalidOid),
CharGetDatum('r'));
/* Find candidates */
clist = OpernameGetCandidates(op, 'r');
if (!HeapTupleIsValid(tup))
if (clist != NULL)
{
/* Try for inexact matches */
ncandidates = unary_oper_get_candidates(op, &candidates, 'r');
if (ncandidates == 0)
unary_op_error(op, arg, FALSE);
else
/*
* First, quickly check to see if there is an exactly matching
* operator (there can be only one such entry in the list).
*/
FuncCandidateList clisti;
for (clisti = clist; clisti != NULL; clisti = clisti->next)
{
if (arg == clisti->args[0])
{
operOid = clisti->oid;
break;
}
}
if (!OidIsValid(operOid))
{
/*
* We must run oper_select_candidate even if only one
* candidate, otherwise we may falsely return a
* non-type-compatible operator.
*/
targetOid = oper_select_candidate(1, &arg, candidates);
if (targetOid != NULL)
tup = SearchSysCache(OPERNAME,
PointerGetDatum(op),
ObjectIdGetDatum(targetOid[0]),
ObjectIdGetDatum(InvalidOid),
CharGetDatum('r'));
operOid = oper_select_candidate(1, &arg, clist);
}
if (!HeapTupleIsValid(tup))
unary_op_error(op, arg, FALSE);
if (OidIsValid(operOid))
tup = SearchSysCache(OPEROID,
ObjectIdGetDatum(operOid),
0, 0, 0);
}
if (!HeapTupleIsValid(tup))
unary_op_error(op, arg, FALSE);
return (Operator) tup;
} /* right_oper() */
@ -861,46 +823,55 @@ right_oper(char *op, Oid arg)
* must ReleaseSysCache() the entry when done with it.
*/
Operator
left_oper(char *op, Oid arg)
left_oper(List *op, Oid arg)
{
HeapTuple tup;
CandidateList candidates;
int ncandidates;
Oid *targetOid;
FuncCandidateList clist;
Oid operOid = InvalidOid;
HeapTuple tup = NULL;
/* Try for exact match */
tup = SearchSysCache(OPERNAME,
PointerGetDatum(op),
ObjectIdGetDatum(InvalidOid),
ObjectIdGetDatum(arg),
CharGetDatum('l'));
/* Find candidates */
clist = OpernameGetCandidates(op, 'l');
if (!HeapTupleIsValid(tup))
if (clist != NULL)
{
/* Try for inexact matches */
ncandidates = unary_oper_get_candidates(op, &candidates, 'l');
if (ncandidates == 0)
unary_op_error(op, arg, TRUE);
else
/*
* First, quickly check to see if there is an exactly matching
* operator (there can be only one such entry in the list).
*
* The returned list has args in the form (0, oprright). Move the
* useful data into args[0] to keep oper_select_candidate simple.
* XXX we are assuming here that we may scribble on the list!
*/
FuncCandidateList clisti;
for (clisti = clist; clisti != NULL; clisti = clisti->next)
{
clisti->args[0] = clisti->args[1];
if (arg == clisti->args[0])
{
operOid = clisti->oid;
break;
}
}
if (!OidIsValid(operOid))
{
/*
* We must run oper_select_candidate even if only one
* candidate, otherwise we may falsely return a
* non-type-compatible operator.
*/
targetOid = oper_select_candidate(1, &arg, candidates);
if (targetOid != NULL)
tup = SearchSysCache(OPERNAME,
PointerGetDatum(op),
ObjectIdGetDatum(InvalidOid),
ObjectIdGetDatum(targetOid[0]),
CharGetDatum('l'));
operOid = oper_select_candidate(1, &arg, clist);
}
if (!HeapTupleIsValid(tup))
unary_op_error(op, arg, TRUE);
if (OidIsValid(operOid))
tup = SearchSysCache(OPEROID,
ObjectIdGetDatum(operOid),
0, 0, 0);
}
if (!HeapTupleIsValid(tup))
unary_op_error(op, arg, TRUE);
return (Operator) tup;
} /* left_oper() */
@ -910,19 +881,22 @@ left_oper(char *op, Oid arg)
* is not found.
*/
static void
op_error(char *op, Oid arg1, Oid arg2)
op_error(List *op, Oid arg1, Oid arg2)
{
if (!typeidIsValid(arg1))
elog(ERROR, "Left hand side of operator '%s' has an unknown type"
"\n\tProbably a bad attribute name", op);
"\n\tProbably a bad attribute name",
NameListToString(op));
if (!typeidIsValid(arg2))
elog(ERROR, "Right hand side of operator %s has an unknown type"
"\n\tProbably a bad attribute name", op);
"\n\tProbably a bad attribute name",
NameListToString(op));
elog(ERROR, "Unable to identify an operator '%s' for types '%s' and '%s'"
"\n\tYou will have to retype this query using an explicit cast",
op, format_type_be(arg1), format_type_be(arg2));
NameListToString(op),
format_type_be(arg1), format_type_be(arg2));
}
/* unary_op_error()
@ -930,28 +904,28 @@ op_error(char *op, Oid arg1, Oid arg2)
* is not found.
*/
static void
unary_op_error(char *op, Oid arg, bool is_left_op)
unary_op_error(List *op, Oid arg, bool is_left_op)
{
if (!typeidIsValid(arg))
{
if (is_left_op)
elog(ERROR, "operand of prefix operator '%s' has an unknown type"
"\n\t(probably an invalid column reference)",
op);
NameListToString(op));
else
elog(ERROR, "operand of postfix operator '%s' has an unknown type"
"\n\t(probably an invalid column reference)",
op);
NameListToString(op));
}
else
{
if (is_left_op)
elog(ERROR, "Unable to identify a prefix operator '%s' for type '%s'"
"\n\tYou may need to add parentheses or an explicit cast",
op, format_type_be(arg));
NameListToString(op), format_type_be(arg));
else
elog(ERROR, "Unable to identify a postfix operator '%s' for type '%s'"
"\n\tYou may need to add parentheses or an explicit cast",
op, format_type_be(arg));
NameListToString(op), format_type_be(arg));
}
}

View File

@ -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",
"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

View File

@ -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));
}
/*

View File

@ -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);
}
/*

View File

@ -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,

View File

@ -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

View File

@ -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 */

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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
{

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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)