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

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

qualified operator names directly, for example CREATE OPERATOR myschema.+
( ... ).  To qualify an operator name in an expression you need to write
OPERATOR(myschema.+) (thanks to Peter for suggesting an escape hatch).
I also took advantage of having to reformat pg_operator to fix something
that'd been bugging me for a while: mergejoinable operators should have
explicit links to the associated cross-data-type comparison operators,
rather than hardwiring an assumption that they are named < and >.
parent 4da51bfd
<!-- <!--
Documentation of the system catalogs, directed toward PostgreSQL developers 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"> <chapter id="catalogs">
...@@ -1482,6 +1482,15 @@ ...@@ -1482,6 +1482,15 @@
<entry>Name of the operator</entry> <entry>Name of the operator</entry>
</row> </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> <row>
<entry>oprowner</entry> <entry>oprowner</entry>
<entry><type>int4</type></entry> <entry><type>int4</type></entry>
...@@ -1493,7 +1502,8 @@ ...@@ -1493,7 +1502,8 @@
<entry>oprprec</entry> <entry>oprprec</entry>
<entry><type>int2</type></entry> <entry><type>int2</type></entry>
<entry></entry> <entry></entry>
<entry>unused</entry> <entry>precedence (currently unused, as precedences are hard-wired
in the grammar)</entry>
</row> </row>
<row> <row>
...@@ -1510,7 +1520,8 @@ ...@@ -1510,7 +1520,8 @@
<entry>oprisleft</entry> <entry>oprisleft</entry>
<entry><type>bool</type></entry> <entry><type>bool</type></entry>
<entry></entry> <entry></entry>
<entry>unused</entry> <entry>left-associativity (currently unused, as this is hard-wired
in the grammar)</entry>
</row> </row>
<row> <row>
...@@ -1561,7 +1572,7 @@ ...@@ -1561,7 +1572,7 @@
<entry>pg_operator.oid</entry> <entry>pg_operator.oid</entry>
<entry> <entry>
If this operator supports merge joins, the operator that sorts 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> </entry>
</row> </row>
...@@ -1571,28 +1582,48 @@ ...@@ -1571,28 +1582,48 @@
<entry>pg_operator.oid</entry> <entry>pg_operator.oid</entry>
<entry> <entry>
If this operator supports merge joins, the operator that sorts 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> </entry>
</row> </row>
<row> <row>
<entry>oprcode</entry> <entry>oprcode</entry>
<entry><type>regproc</type></entry> <entry><type>regproc</type></entry>
<entry></entry> <entry>pg_proc.oid</entry>
<entry>Function that implements this operator</entry> <entry>Function that implements this operator</entry>
</row> </row>
<row> <row>
<entry>oprrest</entry> <entry>oprrest</entry>
<entry><type>regproc</type></entry> <entry><type>regproc</type></entry>
<entry></entry> <entry>pg_proc.oid</entry>
<entry>Restriction selectivity estimation function for this operator</entry> <entry>Restriction selectivity estimation function for this operator</entry>
</row> </row>
<row> <row>
<entry>oprjoin</entry> <entry>oprjoin</entry>
<entry><type>regproc</type></entry> <entry><type>regproc</type></entry>
<entry></entry> <entry>pg_proc.oid</entry>
<entry>Join selectivity estimation function for this operator</entry> <entry>Join selectivity estimation function for this operator</entry>
</row> </row>
</tbody> </tbody>
...@@ -2498,28 +2529,28 @@ ...@@ -2498,28 +2529,28 @@
<row> <row>
<entry>typinput</entry> <entry>typinput</entry>
<entry><type>regproc</type></entry> <entry><type>regproc</type></entry>
<entry></entry> <entry>pg_proc.oid</entry>
<entry>Input function</entry> <entry>Input function</entry>
</row> </row>
<row> <row>
<entry>typoutput</entry> <entry>typoutput</entry>
<entry><type>regproc</type></entry> <entry><type>regproc</type></entry>
<entry></entry> <entry>pg_proc.oid</entry>
<entry>Output function</entry> <entry>Output function</entry>
</row> </row>
<row> <row>
<entry>typreceive</entry> <entry>typreceive</entry>
<entry><type>regproc</type></entry> <entry><type>regproc</type></entry>
<entry></entry> <entry>pg_proc.oid</entry>
<entry>unused</entry> <entry>unused</entry>
</row> </row>
<row> <row>
<entry>typsend</entry> <entry>typsend</entry>
<entry><type>regproc</type></entry> <entry><type>regproc</type></entry>
<entry></entry> <entry>pg_proc.oid</entry>
<entry>unused</entry> <entry>unused</entry>
</row> </row>
......
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_operator.sgml,v 1.25 2002/03/22 19:20:39 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_operator.sgml,v 1.26 2002/04/16 23:08:10 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -28,7 +28,9 @@ CREATE OPERATOR <replaceable>name</replaceable> ( PROCEDURE = <replaceable class ...@@ -28,7 +28,9 @@ CREATE OPERATOR <replaceable>name</replaceable> ( PROCEDURE = <replaceable class
] [, RIGHTARG = <replaceable class="parameter">righttype</replaceable> ] ] [, RIGHTARG = <replaceable class="parameter">righttype</replaceable> ]
[, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ] [, NEGATOR = <replaceable class="parameter">neg_op</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> ] [, 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> </synopsis>
<refsect2 id="R2-SQL-CREATEOPERATOR-1"> <refsect2 id="R2-SQL-CREATEOPERATOR-1">
...@@ -115,11 +117,19 @@ CREATE OPERATOR <replaceable>name</replaceable> ( PROCEDURE = <replaceable class ...@@ -115,11 +117,19 @@ CREATE OPERATOR <replaceable>name</replaceable> ( PROCEDURE = <replaceable class
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>MERGES</term>
<listitem>
<para>
Indicates this operator can support a merge join.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="parameter">left_sort_op</replaceable></term> <term><replaceable class="parameter">left_sort_op</replaceable></term>
<listitem> <listitem>
<para> <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. operator that sorts the left-hand data type of this operator.
</para> </para>
</listitem> </listitem>
...@@ -128,11 +138,29 @@ CREATE OPERATOR <replaceable>name</replaceable> ( PROCEDURE = <replaceable class ...@@ -128,11 +138,29 @@ CREATE OPERATOR <replaceable>name</replaceable> ( PROCEDURE = <replaceable class
<term><replaceable class="parameter">right_sort_op</replaceable></term> <term><replaceable class="parameter">right_sort_op</replaceable></term>
<listitem> <listitem>
<para> <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. operator that sorts the right-hand data type of this operator.
</para> </para>
</listitem> </listitem>
</varlistentry> </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> </variablelist>
</para> </para>
</refsect2> </refsect2>
...@@ -295,30 +323,39 @@ MYBOXES.description !== box '((0,0), (1,1))' ...@@ -295,30 +323,39 @@ MYBOXES.description !== box '((0,0), (1,1))'
it also works to just have both operators refer to each other.) it also works to just have both operators refer to each other.)
</para> </para>
<para> <para>
The HASHES, SORT1, and SORT2 options are present to support the The HASHES, MERGES, SORT1, SORT2, LTCMP, and GTCMP options are present to
query optimizer in performing joins. support the query optimizer in performing joins.
<productname>PostgreSQL</productname> can always <productname>PostgreSQL</productname> can always evaluate a join (i.e.,
evaluate a join (i.e., processing a clause with two tuple processing a clause with two tuple variables separated by an operator that
variables separated by an operator that returns a <type>boolean</type>) returns a <type>boolean</type>) by iterative substitution [WONG76]. In
by iterative substitution [WONG76]. addition, <productname>PostgreSQL</productname> can use a hash-join
In addition, <productname>PostgreSQL</productname> algorithm along the lines of [SHAP86]; however, it must know whether this
can use a hash-join algorithm along strategy is applicable. The current hash-join algorithm is only correct
the lines of [SHAP86]; however, it must know whether this for operators that represent equality tests; furthermore, equality of the
strategy is applicable. The current hash-join algorithm data type must mean bitwise equality of the representation of the type.
is only correct for operators that represent equality tests; (For example, a data type that contains unused bits that don't matter for
furthermore, equality of the data type must mean bitwise equality equality tests could not be hash-joined.) The HASHES flag indicates to the
of the representation of the type. (For example, a data type that query optimizer that a hash join may safely be used with this
contains unused bits that don't matter for equality tests could operator.
not be hash-joined.) </para>
The HASHES flag indicates to the query optimizer that a hash join <para>
may safely be used with this operator.</para> Similarly, the MERGES flag indicates whether merge-sort is a usable join
<para> strategy for this operator. A merge join requires that the two input
Similarly, the two sort operators indicate to the query datatypes have consistent orderings, and that the mergejoin operator
optimizer whether merge-sort is a usable join strategy and behave like equality with respect to that ordering. For example, it is
which operators should be used to sort the two operand possible to merge-join equality between an integer and a float variable by
classes. Sort operators should only be provided for an equality sorting both inputs in ordinary
operator, and they should refer to less-than operators for the numeric order. Execution of a merge join requires that the system be
left and right side data types respectively. 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>
<para> <para>
If other join strategies are found to be practical, If other join strategies are found to be practical,
...@@ -408,8 +445,10 @@ CREATE OPERATOR === ( ...@@ -408,8 +445,10 @@ CREATE OPERATOR === (
RESTRICT = area_restriction_procedure, RESTRICT = area_restriction_procedure,
JOIN = area_join_procedure, JOIN = area_join_procedure,
HASHES, HASHES,
SORT1 = <<<, SORT1 = &lt;&lt;&lt;,
SORT2 = <<< SORT2 = &lt;&lt;&lt;
-- Since sort operators were given, MERGES is implied.
-- LTCMP and GTCMP are assumed to be &lt; and &gt; respectively
); );
</programlisting> </programlisting>
</refsect1> </refsect1>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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] = ...@@ -62,7 +62,7 @@ char *Name_pg_namespace_indices[Num_pg_namespace_indices] =
char *Name_pg_opclass_indices[Num_pg_opclass_indices] = char *Name_pg_opclass_indices[Num_pg_opclass_indices] =
{OpclassAmNameIndex, OpclassOidIndex}; {OpclassAmNameIndex, OpclassOidIndex};
char *Name_pg_operator_indices[Num_pg_operator_indices] = char *Name_pg_operator_indices[Num_pg_operator_indices] =
{OperatorOidIndex, OperatorNameIndex}; {OperatorOidIndex, OperatorNameNspIndex};
char *Name_pg_proc_indices[Num_pg_proc_indices] = char *Name_pg_proc_indices[Num_pg_proc_indices] =
{ProcedureOidIndex, ProcedureNameNspIndex}; {ProcedureOidIndex, ProcedureNameNspIndex};
char *Name_pg_relcheck_indices[Num_pg_relcheck_indices] = char *Name_pg_relcheck_indices[Num_pg_relcheck_indices] =
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 @@ ...@@ -27,6 +27,7 @@
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_inherits.h" #include "catalog/pg_inherits.h"
#include "catalog/pg_namespace.h" #include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
...@@ -478,6 +479,179 @@ FuncnameGetCandidates(List *names, int nargs) ...@@ -478,6 +479,179 @@ FuncnameGetCandidates(List *names, int nargs)
return resultList; 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 * QualifiedNameGetCreationNamespace
* Given a possibly-qualified name for an object (in List-of-Values * Given a possibly-qualified name for an object (in List-of-Values
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.65 2002/04/09 20:35:47 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.66 2002/04/16 23:08:10 tgl Exp $
* *
* NOTES * NOTES
* these routines moved here from commands/define.c and somewhat cleaned up. * these routines moved here from commands/define.c and somewhat cleaned up.
...@@ -20,42 +20,41 @@ ...@@ -20,42 +20,41 @@
#include "access/heapam.h" #include "access/heapam.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/parse_func.h" #include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
static Oid OperatorGet(const char *operatorName, static Oid OperatorGet(const char *operatorName,
Oid operatorNamespace,
Oid leftObjectId,
Oid rightObjectId,
bool *defined);
static Oid OperatorLookup(List *operatorName,
Oid leftObjectId, Oid leftObjectId,
Oid rightObjectId, Oid rightObjectId,
bool *defined); bool *defined);
static Oid OperatorShellMake(const char *operatorName, static Oid OperatorShellMake(const char *operatorName,
Oid operatorNamespace,
Oid leftTypeId, Oid leftTypeId,
Oid rightTypeId); Oid rightTypeId);
static void OperatorDef(const char *operatorName,
Oid leftTypeId,
Oid rightTypeId,
List *procedureName,
uint16 precedence,
bool isLeftAssociative,
const char *commutatorName,
const char *negatorName,
List *restrictionName,
List *joinName,
bool canHash,
const char *leftSortName,
const char *rightSortName);
static void OperatorUpd(Oid baseId, Oid commId, Oid negId); static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
static Oid get_other_operator(List *otherOp,
Oid otherLeftTypeId, Oid otherRightTypeId,
const char *operatorName, Oid operatorNamespace,
Oid leftTypeId, Oid rightTypeId,
bool isCommutator);
/* /*
* Check whether a proposed operator name is legal * Check whether a proposed operator name is legal
...@@ -114,76 +113,36 @@ validOperatorName(const char *name) ...@@ -114,76 +113,36 @@ validOperatorName(const char *name)
} }
/* ---------------------------------------------------------------- /*
* OperatorGet * OperatorGet
* *
* finds the operator associated with the specified name * finds an operator given an exact specification (name, namespace,
* and left and right type IDs. * left and right type IDs).
* *
* operatorName -- name of operator to fetch * *defined is set TRUE if defined (not a shell)
* leftObjectId -- left data type oid of operator to fetch
* rightObjectId -- right data type oid of operator to fetch
* defined -- set TRUE if defined (not a shell)
* ----------------------------------------------------------------
*/ */
static Oid static Oid
OperatorGet(const char *operatorName, OperatorGet(const char *operatorName,
Oid operatorNamespace,
Oid leftObjectId, Oid leftObjectId,
Oid rightObjectId, Oid rightObjectId,
bool *defined) bool *defined)
{ {
Relation pg_operator_desc;
HeapScanDesc pg_operator_scan;
HeapTuple tup; HeapTuple tup;
ScanKeyData opKey[3];
Oid operatorObjectId; Oid operatorObjectId;
if (!(OidIsValid(leftObjectId) || OidIsValid(rightObjectId))) tup = SearchSysCache(OPERNAMENSP,
elog(ERROR, "operator %s must have at least one operand type", PointerGetDatum(operatorName),
operatorName); ObjectIdGetDatum(leftObjectId),
ObjectIdGetDatum(rightObjectId),
/* ObjectIdGetDatum(operatorNamespace));
* open the pg_operator relation
*/
pg_operator_desc = heap_openr(OperatorRelationName, AccessShareLock);
/*
* form scan key
*/
ScanKeyEntryInitialize(&opKey[0], 0x0,
Anum_pg_operator_oprname,
F_NAMEEQ,
PointerGetDatum(operatorName));
ScanKeyEntryInitialize(&opKey[1], 0x0,
Anum_pg_operator_oprleft,
F_OIDEQ,
ObjectIdGetDatum(leftObjectId));
ScanKeyEntryInitialize(&opKey[2], 0x0,
Anum_pg_operator_oprright,
F_OIDEQ,
ObjectIdGetDatum(rightObjectId));
/*
* begin the scan
*/
pg_operator_scan = heap_beginscan(pg_operator_desc,
0,
SnapshotSelf, /* no cache? */
3,
opKey);
/*
* fetch the operator tuple, if it exists, and determine the proper
* return oid value.
*/
tup = heap_getnext(pg_operator_scan, 0);
if (HeapTupleIsValid(tup)) if (HeapTupleIsValid(tup))
{ {
regproc oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode; regproc oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
operatorObjectId = tup->t_data->t_oid; operatorObjectId = tup->t_data->t_oid;
*defined = RegProcedureIsValid(oprcode); *defined = RegProcedureIsValid(oprcode);
ReleaseSysCache(tup);
} }
else else
{ {
...@@ -191,21 +150,48 @@ OperatorGet(const char *operatorName, ...@@ -191,21 +150,48 @@ OperatorGet(const char *operatorName,
*defined = false; *defined = false;
} }
/* return operatorObjectId;
* close the scan and return the oid. }
/*
* OperatorLookup
*
* looks up an operator given a possibly-qualified name and
* left and right type IDs.
*
* *defined is set TRUE if defined (not a shell)
*/ */
heap_endscan(pg_operator_scan); static Oid
heap_close(pg_operator_desc, AccessShareLock); OperatorLookup(List *operatorName,
Oid leftObjectId,
Oid rightObjectId,
bool *defined)
{
Oid operatorObjectId;
regproc oprcode;
operatorObjectId = LookupOperName(operatorName, leftObjectId,
rightObjectId);
if (!OidIsValid(operatorObjectId))
{
*defined = false;
return InvalidOid;
}
oprcode = get_opcode(operatorObjectId);
*defined = RegProcedureIsValid(oprcode);
return operatorObjectId; return operatorObjectId;
} }
/* /*
* OperatorShellMake * OperatorShellMake
* Make a "shell" entry for a not-yet-existing operator. * Make a "shell" entry for a not-yet-existing operator.
*/ */
static Oid static Oid
OperatorShellMake(const char *operatorName, OperatorShellMake(const char *operatorName,
Oid operatorNamespace,
Oid leftTypeId, Oid leftTypeId,
Oid rightTypeId) Oid rightTypeId)
{ {
...@@ -224,11 +210,6 @@ OperatorShellMake(const char *operatorName, ...@@ -224,11 +210,6 @@ OperatorShellMake(const char *operatorName,
if (!validOperatorName(operatorName)) if (!validOperatorName(operatorName))
elog(ERROR, "\"%s\" is not a valid operator name", operatorName); elog(ERROR, "\"%s\" is not a valid operator name", operatorName);
/*
* open pg_operator
*/
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
/* /*
* initialize our *nulls and *values arrays * initialize our *nulls and *values arrays
*/ */
...@@ -244,28 +225,35 @@ OperatorShellMake(const char *operatorName, ...@@ -244,28 +225,35 @@ OperatorShellMake(const char *operatorName,
*/ */
i = 0; i = 0;
namestrcpy(&oname, operatorName); namestrcpy(&oname, operatorName);
values[i++] = NameGetDatum(&oname); values[i++] = NameGetDatum(&oname); /* oprname */
values[i++] = Int32GetDatum(GetUserId()); values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */
values[i++] = UInt16GetDatum(0); values[i++] = Int32GetDatum(GetUserId()); /* oprowner */
values[i++] = CharGetDatum('b'); /* assume it's binary */ values[i++] = UInt16GetDatum(0); /* oprprec */
values[i++] = BoolGetDatum(false); values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */
values[i++] = BoolGetDatum(false); values[i++] = BoolGetDatum(false); /* oprisleft */
values[i++] = ObjectIdGetDatum(leftTypeId); values[i++] = BoolGetDatum(false); /* oprcanhash */
values[i++] = ObjectIdGetDatum(rightTypeId); values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(rightTypeId); /* oprright */
values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); /* oprresult */
values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcom */
values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); /* oprnegate */
values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); /* oprlsortop */
values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrsortop */
values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); /* oprltcmpop */
values[i++] = ObjectIdGetDatum(InvalidOid); values[i++] = ObjectIdGetDatum(InvalidOid); /* oprgtcmpop */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcode */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrest */
values[i++] = ObjectIdGetDatum(InvalidOid); /* oprjoin */
/* /*
* create a new operator tuple * open pg_operator
*/ */
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
tupDesc = pg_operator_desc->rd_att; tupDesc = pg_operator_desc->rd_att;
/*
* create a new operator tuple
*/
tup = heap_formtuple(tupDesc, values, nulls); tup = heap_formtuple(tupDesc, values, nulls);
/* /*
...@@ -293,8 +281,26 @@ OperatorShellMake(const char *operatorName, ...@@ -293,8 +281,26 @@ OperatorShellMake(const char *operatorName,
return operatorObjectId; return operatorObjectId;
} }
/* -------------------------------- /*
* OperatorDef * OperatorCreate
*
* "X" indicates an optional argument (i.e. one that can be NULL or 0)
* operatorName name for new operator
* operatorNamespace namespace for new operator
* leftTypeId X left type ID
* rightTypeId X right type ID
* procedureName procedure for operator
* precedence operator precedence
* isLeftAssociative operator is left associative
* commutatorName X commutator operator
* negatorName X negator operator
* restrictionName X restriction sel. procedure
* joinName X join sel. procedure
* canHash hash join can be used with this operator
* leftSortName X left sort operator (for merge join)
* rightSortName X right sort operator (for merge join)
* ltCompareName X L<R compare operator (for merge join)
* gtCompareName X L>R compare operator (for merge join)
* *
* This routine gets complicated because it allows the user to * This routine gets complicated because it allows the user to
* specify operators that do not exist. For example, if operator * specify operators that do not exist. For example, if operator
...@@ -354,68 +360,73 @@ OperatorShellMake(const char *operatorName, ...@@ -354,68 +360,73 @@ OperatorShellMake(const char *operatorName,
* else if a new operator is being created * else if a new operator is being created
* create a tuple using heap_formtuple * create a tuple using heap_formtuple
* call heap_insert * call heap_insert
* --------------------------------
* "X" indicates an optional argument (i.e. one that can be NULL)
* operatorName; -- operator name
* leftTypeId; -- X left type id
* rightTypeId; -- X right type id
* procedureName; -- procedure name for operator code
* precedence; -- operator precedence
* isLeftAssociative; -- operator is left associative?
* commutatorName; -- X commutator operator name
* negatorName; -- X negator operator name
* restrictionName; -- X restriction sel. procedure name
* joinName; -- X join sel. procedure name
* canHash; -- can hash join be used with operator?
* leftSortName; -- X left sort operator (for merge join)
* rightSortName; -- X right sort operator (for merge join)
*/ */
static void void
OperatorDef(const char *operatorName, OperatorCreate(const char *operatorName,
Oid operatorNamespace,
Oid leftTypeId, Oid leftTypeId,
Oid rightTypeId, Oid rightTypeId,
List *procedureName, List *procedureName,
uint16 precedence, uint16 precedence,
bool isLeftAssociative, bool isLeftAssociative,
const char *commutatorName, List *commutatorName,
const char *negatorName, List *negatorName,
List *restrictionName, List *restrictionName,
List *joinName, List *joinName,
bool canHash, bool canHash,
const char *leftSortName, List *leftSortName,
const char *rightSortName) List *rightSortName,
List *ltCompareName,
List *gtCompareName)
{ {
Relation pg_operator_desc; Relation pg_operator_desc;
HeapScanDesc pg_operator_scan;
HeapTuple tup; HeapTuple tup;
char nulls[Natts_pg_operator]; char nulls[Natts_pg_operator];
char replaces[Natts_pg_operator]; char replaces[Natts_pg_operator];
Datum values[Natts_pg_operator]; Datum values[Natts_pg_operator];
Oid operatorObjectId; Oid operatorObjectId;
bool operatorAlreadyDefined; bool operatorAlreadyDefined;
Oid commutatorId = InvalidOid; Oid procOid;
Oid negatorId = InvalidOid; Oid operResultType;
Oid commutatorId,
negatorId,
leftSortId,
rightSortId,
ltCompareId,
gtCompareId,
restOid,
joinOid;
bool selfCommutator = false; bool selfCommutator = false;
const char *name[4];
Oid typeId[FUNC_MAX_ARGS]; Oid typeId[FUNC_MAX_ARGS];
int nargs; int nargs;
Oid procOid;
NameData oname; NameData oname;
TupleDesc tupDesc; TupleDesc tupDesc;
ScanKeyData opKey[3]; int i;
int i,
j;
/* /*
* validate operator name * Sanity checks
*/ */
if (!validOperatorName(operatorName)) if (!validOperatorName(operatorName))
elog(ERROR, "\"%s\" is not a valid operator name", operatorName); elog(ERROR, "\"%s\" is not a valid operator name", operatorName);
if (!(OidIsValid(leftTypeId) || OidIsValid(rightTypeId))) if (!OidIsValid(leftTypeId) && !OidIsValid(rightTypeId))
elog(ERROR, "operator must have at least one operand type"); elog(ERROR, "at least one of leftarg or rightarg must be specified");
if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
{
/* If it's not a binary op, these things mustn't be set: */
if (commutatorName)
elog(ERROR, "only binary operators can have commutators");
if (joinName)
elog(ERROR, "only binary operators can have join selectivity");
if (canHash)
elog(ERROR, "only binary operators can hash");
if (leftSortName || rightSortName || ltCompareName || gtCompareName)
elog(ERROR, "only binary operators can mergejoin");
}
operatorObjectId = OperatorGet(operatorName, operatorObjectId = OperatorGet(operatorName,
operatorNamespace,
leftTypeId, leftTypeId,
rightTypeId, rightTypeId,
&operatorAlreadyDefined); &operatorAlreadyDefined);
...@@ -429,13 +440,6 @@ OperatorDef(const char *operatorName, ...@@ -429,13 +440,6 @@ OperatorDef(const char *operatorName,
* filling in a previously-created shell. * filling in a previously-created shell.
*/ */
for (i = 0; i < Natts_pg_operator; ++i)
{
values[i] = (Datum) NULL;
replaces[i] = 'r';
nulls[i] = ' ';
}
/* /*
* Look up registered procedures -- find the return type of * Look up registered procedures -- find the return type of
* procedureName to place in "result" field. Do this before shells are * procedureName to place in "result" field. Do this before shells are
...@@ -461,17 +465,13 @@ OperatorDef(const char *operatorName, ...@@ -461,17 +465,13 @@ OperatorDef(const char *operatorName,
procOid = LookupFuncName(procedureName, nargs, typeId); procOid = LookupFuncName(procedureName, nargs, typeId);
if (!OidIsValid(procOid)) if (!OidIsValid(procOid))
func_error("OperatorDef", procedureName, nargs, typeId, NULL); func_error("OperatorDef", procedureName, nargs, typeId, NULL);
operResultType = get_func_rettype(procOid);
values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procOid);
values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(get_func_rettype(procOid));
/* /*
* find restriction estimator * find restriction estimator
*/ */
if (restrictionName) if (restrictionName)
{ /* optional */ {
Oid restOid;
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid)); MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
typeId[0] = 0; /* Query (opaque type) */ typeId[0] = 0; /* Query (opaque type) */
typeId[1] = OIDOID; /* operator OID */ typeId[1] = OIDOID; /* operator OID */
...@@ -481,19 +481,15 @@ OperatorDef(const char *operatorName, ...@@ -481,19 +481,15 @@ OperatorDef(const char *operatorName,
restOid = LookupFuncName(restrictionName, 4, typeId); restOid = LookupFuncName(restrictionName, 4, typeId);
if (!OidIsValid(restOid)) if (!OidIsValid(restOid))
func_error("OperatorDef", restrictionName, 4, typeId, NULL); func_error("OperatorDef", restrictionName, 4, typeId, NULL);
values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restOid);
} }
else else
values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid); restOid = InvalidOid;
/* /*
* find join estimator * find join estimator
*/ */
if (joinName) if (joinName)
{ /* optional */ {
Oid joinOid;
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid)); MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
typeId[0] = 0; /* Query (opaque type) */ typeId[0] = 0; /* Query (opaque type) */
typeId[1] = OIDOID; /* operator OID */ typeId[1] = OIDOID; /* operator OID */
...@@ -502,158 +498,141 @@ OperatorDef(const char *operatorName, ...@@ -502,158 +498,141 @@ OperatorDef(const char *operatorName,
joinOid = LookupFuncName(joinName, 3, typeId); joinOid = LookupFuncName(joinName, 3, typeId);
if (!OidIsValid(joinOid)) if (!OidIsValid(joinOid))
func_error("OperatorDef", joinName, 3, typeId, NULL); func_error("OperatorDef", joinName, 3, typeId, NULL);
values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
} }
else else
values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid); joinOid = InvalidOid;
/* /*
* set up values in the operator tuple * set up values in the operator tuple
*/ */
for (i = 0; i < Natts_pg_operator; ++i)
{
values[i] = (Datum) NULL;
replaces[i] = 'r';
nulls[i] = ' ';
}
i = 0; i = 0;
namestrcpy(&oname, operatorName); namestrcpy(&oname, operatorName);
values[i++] = NameGetDatum(&oname); values[i++] = NameGetDatum(&oname); /* oprname */
values[i++] = Int32GetDatum(GetUserId()); values[i++] = ObjectIdGetDatum(operatorNamespace); /* oprnamespace */
values[i++] = UInt16GetDatum(precedence); values[i++] = Int32GetDatum(GetUserId()); /* oprowner */
values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); values[i++] = UInt16GetDatum(precedence); /* oprprec */
values[i++] = BoolGetDatum(isLeftAssociative); values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l'); /* oprkind */
values[i++] = BoolGetDatum(canHash); values[i++] = BoolGetDatum(isLeftAssociative); /* oprisleft */
values[i++] = ObjectIdGetDatum(leftTypeId); values[i++] = BoolGetDatum(canHash); /* oprcanhash */
values[i++] = ObjectIdGetDatum(rightTypeId); values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
values[i++] = ObjectIdGetDatum(rightTypeId); /* oprright */
++i; /* Skip "oprresult", it was filled in values[i++] = ObjectIdGetDatum(operResultType); /* oprresult */
* above */
/* /*
* Set up the other operators. If they do not currently exist, create * Set up the other operators. If they do not currently exist, create
* shells in order to get ObjectId's. * shells in order to get ObjectId's.
*/ */
name[0] = commutatorName;
name[1] = negatorName;
name[2] = leftSortName;
name[3] = rightSortName;
for (j = 0; j < 4; ++j) if (commutatorName)
{
if (name[j])
{ {
Oid otherLeftTypeId = InvalidOid; /* commutator has reversed arg types */
Oid otherRightTypeId = InvalidOid; commutatorId = get_other_operator(commutatorName,
Oid other_oid = InvalidOid; rightTypeId, leftTypeId,
bool otherDefined = false; operatorName, operatorNamespace,
leftTypeId, rightTypeId,
true);
/*
* self-linkage to this operator; will fix below. Note
* that only self-linkage for commutation makes sense.
*/
if (!OidIsValid(commutatorId))
selfCommutator = true;
}
else
commutatorId = InvalidOid;
values[i++] = ObjectIdGetDatum(commutatorId); /* oprcom */
switch (j) if (negatorName)
{ {
case 0: /* commutator has reversed arg types */ /* negator has same arg types */
otherLeftTypeId = rightTypeId; negatorId = get_other_operator(negatorName,
otherRightTypeId = leftTypeId; leftTypeId, rightTypeId,
other_oid = OperatorGet(name[j], operatorName, operatorNamespace,
otherLeftTypeId, leftTypeId, rightTypeId,
otherRightTypeId, false);
&otherDefined);
commutatorId = other_oid;
break;
case 1: /* negator has same arg types */
otherLeftTypeId = leftTypeId;
otherRightTypeId = rightTypeId;
other_oid = OperatorGet(name[j],
otherLeftTypeId,
otherRightTypeId,
&otherDefined);
negatorId = other_oid;
break;
case 2: /* left sort op takes left-side data type */
otherLeftTypeId = leftTypeId;
otherRightTypeId = leftTypeId;
other_oid = OperatorGet(name[j],
otherLeftTypeId,
otherRightTypeId,
&otherDefined);
break;
case 3: /* right sort op takes right-side data type */
otherLeftTypeId = rightTypeId;
otherRightTypeId = rightTypeId;
other_oid = OperatorGet(name[j],
otherLeftTypeId,
otherRightTypeId,
&otherDefined);
break;
} }
else
negatorId = InvalidOid;
values[i++] = ObjectIdGetDatum(negatorId); /* oprnegate */
if (OidIsValid(other_oid)) if (leftSortName)
{ {
/* other op already in catalogs */ /* left sort op takes left-side data type */
values[i++] = ObjectIdGetDatum(other_oid); leftSortId = get_other_operator(leftSortName,
leftTypeId, leftTypeId,
operatorName, operatorNamespace,
leftTypeId, rightTypeId,
false);
} }
else if (strcmp(operatorName, name[j]) != 0 || else
otherLeftTypeId != leftTypeId || leftSortId = InvalidOid;
otherRightTypeId != rightTypeId) values[i++] = ObjectIdGetDatum(leftSortId); /* oprlsortop */
if (rightSortName)
{ {
/* not in catalogs, different from operator */ /* right sort op takes right-side data type */
other_oid = OperatorShellMake(name[j], rightSortId = get_other_operator(rightSortName,
otherLeftTypeId, rightTypeId, rightTypeId,
otherRightTypeId); operatorName, operatorNamespace,
if (!OidIsValid(other_oid)) leftTypeId, rightTypeId,
elog(ERROR, false);
"OperatorDef: can't create operator shell \"%s\"",
name[j]);
values[i++] = ObjectIdGetDatum(other_oid);
} }
else else
rightSortId = InvalidOid;
values[i++] = ObjectIdGetDatum(rightSortId); /* oprrsortop */
if (ltCompareName)
{ {
/* /* comparator has same arg types */
* self-linkage to this operator; will fix below. Note ltCompareId = get_other_operator(ltCompareName,
* that only self-linkage for commutation makes sense. leftTypeId, rightTypeId,
*/ operatorName, operatorNamespace,
if (j != 0) leftTypeId, rightTypeId,
elog(ERROR, false);
"operator cannot be its own negator or sort operator");
selfCommutator = true;
values[i++] = ObjectIdGetDatum(InvalidOid);
}
} }
else else
ltCompareId = InvalidOid;
values[i++] = ObjectIdGetDatum(ltCompareId); /* oprltcmpop */
if (gtCompareName)
{ {
/* other operator is omitted */ /* comparator has same arg types */
values[i++] = ObjectIdGetDatum(InvalidOid); gtCompareId = get_other_operator(gtCompareName,
} leftTypeId, rightTypeId,
operatorName, operatorNamespace,
leftTypeId, rightTypeId,
false);
} }
else
gtCompareId = InvalidOid;
values[i++] = ObjectIdGetDatum(gtCompareId); /* oprgtcmpop */
/* last three fields were filled in above */ values[i++] = ObjectIdGetDatum(procOid); /* oprcode */
values[i++] = ObjectIdGetDatum(restOid); /* oprrest */
values[i++] = ObjectIdGetDatum(joinOid); /* oprjoin */
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock); pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
/* /*
* If we are adding to an operator shell, get its t_self * If we are adding to an operator shell, update; else insert
*/ */
if (operatorObjectId) if (operatorObjectId)
{ {
/* Make sure we can see the shell even if it is new in current cmd */ tup = SearchSysCacheCopy(OPEROID,
CommandCounterIncrement(); ObjectIdGetDatum(operatorObjectId),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "OperatorDef: operator %u not found",
operatorObjectId);
ScanKeyEntryInitialize(&opKey[0], 0x0,
Anum_pg_operator_oprname,
F_NAMEEQ,
PointerGetDatum(operatorName));
ScanKeyEntryInitialize(&opKey[1], 0x0,
Anum_pg_operator_oprleft,
F_OIDEQ,
ObjectIdGetDatum(leftTypeId));
ScanKeyEntryInitialize(&opKey[2], 0x0,
Anum_pg_operator_oprright,
F_OIDEQ,
ObjectIdGetDatum(rightTypeId));
pg_operator_scan = heap_beginscan(pg_operator_desc,
0,
SnapshotSelf, /* no cache? */
3,
opKey);
tup = heap_getnext(pg_operator_scan, 0);
if (HeapTupleIsValid(tup))
{
tup = heap_modifytuple(tup, tup = heap_modifytuple(tup,
pg_operator_desc, pg_operator_desc,
values, values,
...@@ -662,11 +641,6 @@ OperatorDef(const char *operatorName, ...@@ -662,11 +641,6 @@ OperatorDef(const char *operatorName,
simple_heap_update(pg_operator_desc, &tup->t_self, tup); simple_heap_update(pg_operator_desc, &tup->t_self, tup);
} }
else
elog(ERROR, "OperatorDef: operator %u not found", operatorObjectId);
heap_endscan(pg_operator_scan);
}
else else
{ {
tupDesc = pg_operator_desc->rd_att; tupDesc = pg_operator_desc->rd_att;
...@@ -676,6 +650,7 @@ OperatorDef(const char *operatorName, ...@@ -676,6 +650,7 @@ OperatorDef(const char *operatorName,
operatorObjectId = tup->t_data->t_oid; operatorObjectId = tup->t_data->t_oid;
} }
/* Must update the indexes in either case */
if (RelationGetForm(pg_operator_desc)->relhasindex) if (RelationGetForm(pg_operator_desc)->relhasindex)
{ {
Relation idescs[Num_pg_operator_indices]; Relation idescs[Num_pg_operator_indices];
...@@ -705,7 +680,65 @@ OperatorDef(const char *operatorName, ...@@ -705,7 +680,65 @@ OperatorDef(const char *operatorName,
OperatorUpd(operatorObjectId, commutatorId, negatorId); OperatorUpd(operatorObjectId, commutatorId, negatorId);
} }
/* ---------------------------------------------------------------- /*
* Try to lookup another operator (commutator, etc)
*
* If not found, check to see if it is exactly the operator we are trying
* to define; if so, return InvalidOid. (Note that this case is only
* sensible for a commutator, so we error out otherwise.) If it is not
* the same operator, create a shell operator.
*/
static Oid
get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
const char *operatorName, Oid operatorNamespace,
Oid leftTypeId, Oid rightTypeId, bool isCommutator)
{
Oid other_oid;
bool otherDefined;
char *otherName;
Oid otherNamespace;
other_oid = OperatorLookup(otherOp,
otherLeftTypeId,
otherRightTypeId,
&otherDefined);
if (OidIsValid(other_oid))
{
/* other op already in catalogs */
return other_oid;
}
otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
&otherName);
if (strcmp(otherName, operatorName) == 0 &&
otherNamespace == operatorNamespace &&
otherLeftTypeId == leftTypeId &&
otherRightTypeId == rightTypeId)
{
/*
* self-linkage to this operator; caller will fix later. Note
* that only self-linkage for commutation makes sense.
*/
if (!isCommutator)
elog(ERROR, "operator cannot be its own negator or sort operator");
return InvalidOid;
}
/* not in catalogs, different from operator, so make shell */
other_oid = OperatorShellMake(otherName,
otherNamespace,
otherLeftTypeId,
otherRightTypeId);
if (!OidIsValid(other_oid))
elog(ERROR,
"OperatorDef: can't create operator shell \"%s\"",
NameListToString(otherOp));
return other_oid;
}
/*
* OperatorUpd * OperatorUpd
* *
* For a given operator, look up its negator and commutator operators. * For a given operator, look up its negator and commutator operators.
...@@ -713,19 +746,16 @@ OperatorDef(const char *operatorName, ...@@ -713,19 +746,16 @@ OperatorDef(const char *operatorName,
* (respectively) are empty, then use the new operator for neg or comm. * (respectively) are empty, then use the new operator for neg or comm.
* This solves a problem for users who need to insert two new operators * This solves a problem for users who need to insert two new operators
* which are the negator or commutator of each other. * which are the negator or commutator of each other.
* ----------------------------------------------------------------
*/ */
static void static void
OperatorUpd(Oid baseId, Oid commId, Oid negId) OperatorUpd(Oid baseId, Oid commId, Oid negId)
{ {
int i; int i;
Relation pg_operator_desc; Relation pg_operator_desc;
HeapScanDesc pg_operator_scan;
HeapTuple tup; HeapTuple tup;
char nulls[Natts_pg_operator]; char nulls[Natts_pg_operator];
char replaces[Natts_pg_operator]; char replaces[Natts_pg_operator];
Datum values[Natts_pg_operator]; Datum values[Natts_pg_operator];
ScanKeyData opKey[1];
for (i = 0; i < Natts_pg_operator; ++i) for (i = 0; i < Natts_pg_operator; ++i)
{ {
...@@ -734,8 +764,6 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) ...@@ -734,8 +764,6 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
nulls[i] = ' '; nulls[i] = ' ';
} }
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
/* /*
* check and update the commutator & negator, if necessary * check and update the commutator & negator, if necessary
* *
...@@ -743,18 +771,11 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) ...@@ -743,18 +771,11 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
*/ */
CommandCounterIncrement(); CommandCounterIncrement();
ScanKeyEntryInitialize(&opKey[0], 0x0, pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
ObjectIdAttributeNumber,
F_OIDEQ,
ObjectIdGetDatum(commId));
pg_operator_scan = heap_beginscan(pg_operator_desc,
0,
SnapshotSelf, /* no cache? */
1,
opKey);
tup = heap_getnext(pg_operator_scan, 0); tup = SearchSysCacheCopy(OPEROID,
ObjectIdGetDatum(commId),
0, 0, 0);
/* /*
* if the commutator and negator are the same operator, do one update. * if the commutator and negator are the same operator, do one update.
...@@ -765,13 +786,10 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) ...@@ -765,13 +786,10 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
{ {
if (HeapTupleIsValid(tup)) if (HeapTupleIsValid(tup))
{ {
Form_pg_operator t; Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
t = (Form_pg_operator) GETSTRUCT(tup); if (!OidIsValid(t->oprcom) || !OidIsValid(t->oprnegate))
if (!OidIsValid(t->oprcom)
|| !OidIsValid(t->oprnegate))
{ {
if (!OidIsValid(t->oprnegate)) if (!OidIsValid(t->oprnegate))
{ {
values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId); values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
...@@ -802,7 +820,6 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) ...@@ -802,7 +820,6 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
} }
} }
} }
heap_endscan(pg_operator_scan);
heap_close(pg_operator_desc, RowExclusiveLock); heap_close(pg_operator_desc, RowExclusiveLock);
...@@ -816,6 +833,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) ...@@ -816,6 +833,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
{ {
values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId); values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
replaces[Anum_pg_operator_oprcom - 1] = 'r'; replaces[Anum_pg_operator_oprcom - 1] = 'r';
tup = heap_modifytuple(tup, tup = heap_modifytuple(tup,
pg_operator_desc, pg_operator_desc,
values, values,
...@@ -837,23 +855,18 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) ...@@ -837,23 +855,18 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
replaces[Anum_pg_operator_oprcom - 1] = ' '; replaces[Anum_pg_operator_oprcom - 1] = ' ';
} }
heap_endscan(pg_operator_scan);
/* check and update the negator, if necessary */ /* check and update the negator, if necessary */
opKey[0].sk_argument = ObjectIdGetDatum(negId);
pg_operator_scan = heap_beginscan(pg_operator_desc, tup = SearchSysCacheCopy(OPEROID,
0, ObjectIdGetDatum(negId),
SnapshotSelf, /* no cache? */ 0, 0, 0);
1,
opKey);
tup = heap_getnext(pg_operator_scan, 0);
if (HeapTupleIsValid(tup) && if (HeapTupleIsValid(tup) &&
!(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate))) !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
{ {
values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId); values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
replaces[Anum_pg_operator_oprnegate - 1] = 'r'; replaces[Anum_pg_operator_oprnegate - 1] = 'r';
tup = heap_modifytuple(tup, tup = heap_modifytuple(tup,
pg_operator_desc, pg_operator_desc,
values, values,
...@@ -872,79 +885,5 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) ...@@ -872,79 +885,5 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
} }
} }
heap_endscan(pg_operator_scan);
heap_close(pg_operator_desc, RowExclusiveLock); heap_close(pg_operator_desc, RowExclusiveLock);
} }
/* ----------------------------------------------------------------
* OperatorCreate
*
* This is now just an interface procedure for OperatorDef ...
*
* "X" indicates an optional argument (i.e. one that can be NULL or 0)
* operatorName; -- operator name
* leftTypeId; -- X left type ID
* rightTypeId; -- X right type ID
* procedureName; -- procedure for operator
* precedence; -- operator precedence
* isLeftAssociative; -- operator is left associative
* commutatorName; -- X commutator operator name
* negatorName; -- X negator operator name
* restrictionName; -- X restriction sel. procedure
* joinName; -- X join sel. procedure
* canHash; -- hash join can be used with this operator
* leftSortName; -- X left sort operator (for merge join)
* rightSortName; -- X right sort operator (for merge join)
*/
void
OperatorCreate(const char *operatorName,
Oid leftTypeId,
Oid rightTypeId,
const char *procedureName,
uint16 precedence,
bool isLeftAssociative,
const char *commutatorName,
const char *negatorName,
const char *restrictionName,
const char *joinName,
bool canHash,
const char *leftSortName,
const char *rightSortName)
{
if (!OidIsValid(leftTypeId) && !OidIsValid(rightTypeId))
elog(ERROR, "at least one of leftarg or rightarg must be specified");
if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
{
/* If it's not a binary op, these things mustn't be set: */
if (commutatorName)
elog(ERROR, "only binary operators can have commutators");
if (joinName)
elog(ERROR, "only binary operators can have join selectivity");
if (canHash)
elog(ERROR, "only binary operators can hash");
if (leftSortName || rightSortName)
elog(ERROR, "only binary operators can have sort links");
}
/*
* Use OperatorDef() to define the specified operator and also create
* shells for the operator's associated operators if they don't
* already exist.
*/
OperatorDef(operatorName,
leftTypeId,
rightTypeId,
makeList1(makeString((char*) procedureName)), /* XXX */
precedence,
isLeftAssociative,
commutatorName,
negatorName,
restrictionName ? makeList1(makeString((char*) restrictionName)) : NIL, /* XXX */
joinName ? makeList1(makeString((char*) joinName)) : NIL, /* XXX */
canHash,
leftSortName,
rightSortName);
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -398,7 +398,7 @@ examine_attribute(Relation onerel, int attnum)
return NULL; return NULL;
/* If column has no "=" operator, we can't do much of anything */ /* 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,
attr->atttypid, attr->atttypid,
true); true);
...@@ -436,7 +436,7 @@ examine_attribute(Relation onerel, int attnum) ...@@ -436,7 +436,7 @@ examine_attribute(Relation onerel, int attnum)
stats->eqfunc = eqfunc; stats->eqfunc = eqfunc;
/* Is there a "<" operator with suitable semantics? */ /* Is there a "<" operator with suitable semantics? */
func_operator = compatible_oper("<", func_operator = compatible_oper(makeList1(makeString("<")),
attr->atttypid, attr->atttypid,
attr->atttypid, attr->atttypid,
true); true);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Copyright (c) 1999-2001, PostgreSQL Global Development Group * Copyright (c) 1999-2001, PostgreSQL Global Development Group
* *
* IDENTIFICATION * 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 @@ ...@@ -28,6 +28,7 @@
#include "commands/comment.h" #include "commands/comment.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/parse_func.h" #include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "parser/parse.h" #include "parser/parse.h"
#include "utils/acl.h" #include "utils/acl.h"
...@@ -53,7 +54,7 @@ static void CommentRule(List *qualname, char *comment); ...@@ -53,7 +54,7 @@ static void CommentRule(List *qualname, char *comment);
static void CommentType(List *typename, char *comment); static void CommentType(List *typename, char *comment);
static void CommentAggregate(List *aggregate, List *arguments, char *comment); static void CommentAggregate(List *aggregate, List *arguments, char *comment);
static void CommentProc(List *function, 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); static void CommentTrigger(List *qualname, char *comment);
...@@ -643,63 +644,29 @@ CommentProc(List *function, List *arguments, char *comment) ...@@ -643,63 +644,29 @@ CommentProc(List *function, List *arguments, char *comment)
* to be visible for both operator and function. * to be visible for both operator and function.
*/ */
static void 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 *typenode1 = (TypeName *) lfirst(arguments);
TypeName *typenode2 = (TypeName *) lsecond(arguments); TypeName *typenode2 = (TypeName *) lsecond(arguments);
char oprtype = 0; Oid oid;
Form_pg_operator data;
HeapTuple optuple;
Oid oid,
leftoid = InvalidOid,
rightoid = InvalidOid;
/* Attempt to fetch the left type oid, if specified */
if (typenode1 != NULL)
leftoid = typenameTypeId(typenode1);
/* Attempt to fetch the right type oid, if specified */
if (typenode2 != NULL)
rightoid = typenameTypeId(typenode2);
/* Determine operator type */
if (OidIsValid(leftoid) && (OidIsValid(rightoid)))
oprtype = 'b';
else if (OidIsValid(leftoid))
oprtype = 'r';
else if (OidIsValid(rightoid))
oprtype = 'l';
else
elog(ERROR, "operator '%s' is of an illegal type'", opername);
/* Attempt to fetch the operator oid */
optuple = SearchSysCache(OPERNAME, /* Look up the operator */
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 */ /* Valid user's ability to comment on this operator */
if (!pg_oper_ownercheck(oid, GetUserId())) if (!pg_oper_ownercheck(oid, GetUserId()))
elog(ERROR, "you are not permitted to comment on operator '%s'", elog(ERROR, "you are not permitted to comment on operator '%s'",
opername); NameListToString(opername));
/* Get the procedure associated with the operator */ /* Get the procedure associated with the operator */
data = (Form_pg_operator) GETSTRUCT(optuple); oid = get_opcode(oid);
oid = data->oprcode;
if (oid == InvalidOid) if (oid == InvalidOid)
elog(ERROR, "operator '%s' does not have an underlying function", opername); elog(ERROR, "operator '%s' does not have an underlying function",
NameListToString(opername));
ReleaseSysCache(optuple);
/* Call CreateComments() to create/drop the comments */ /* Call CreateComments() to create/drop the comments */
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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 * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "commands/comment.h" #include "commands/comment.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -61,21 +62,24 @@ DefineOperator(List *names, List *parameters) ...@@ -61,21 +62,24 @@ DefineOperator(List *names, List *parameters)
Oid oprNamespace; Oid oprNamespace;
uint16 precedence = 0; /* operator precedence */ uint16 precedence = 0; /* operator precedence */
bool canHash = false; /* operator hashes */ bool canHash = false; /* operator hashes */
bool canMerge = false; /* operator merges */
bool isLeftAssociative = true; /* operator is left bool isLeftAssociative = true; /* operator is left
* associative */ * associative */
char *functionName = NULL; /* function for operator */ List *functionName = NIL; /* function for operator */
TypeName *typeName1 = NULL; /* first type name */ TypeName *typeName1 = NULL; /* first type name */
TypeName *typeName2 = NULL; /* second type name */ TypeName *typeName2 = NULL; /* second type name */
Oid typeId1 = InvalidOid; /* types converted to OID */ Oid typeId1 = InvalidOid; /* types converted to OID */
Oid typeId2 = InvalidOid; Oid typeId2 = InvalidOid;
char *commutatorName = NULL; /* optional commutator operator List *commutatorName = NIL; /* optional commutator operator
* name */ * name */
char *negatorName = NULL; /* optional negator operator name */ List *negatorName = NIL; /* optional negator operator name */
char *restrictionName = NULL; /* optional restrict. sel. List *restrictionName = NIL; /* optional restrict. sel.
* procedure */ * procedure */
char *joinName = NULL; /* optional join sel. procedure name */ List *joinName = NIL; /* optional join sel. procedure */
char *sortName1 = NULL; /* optional first sort operator */ List *leftSortName = NIL; /* optional left sort operator */
char *sortName2 = NULL; /* optional second sort operator */ List *rightSortName = NIL; /* optional right sort operator */
List *ltCompareName = NIL; /* optional < compare operator */
List *gtCompareName = NIL; /* optional > compare operator */
List *pl; List *pl;
/* Convert list of names to a name and namespace */ /* Convert list of names to a name and namespace */
...@@ -101,7 +105,7 @@ DefineOperator(List *names, List *parameters) ...@@ -101,7 +105,7 @@ DefineOperator(List *names, List *parameters)
elog(ERROR, "setof type not implemented for rightarg"); elog(ERROR, "setof type not implemented for rightarg");
} }
else if (strcasecmp(defel->defname, "procedure") == 0) else if (strcasecmp(defel->defname, "procedure") == 0)
functionName = defGetString(defel); functionName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "precedence") == 0) else if (strcasecmp(defel->defname, "precedence") == 0)
{ {
/* NOT IMPLEMENTED (never worked in v4.2) */ /* NOT IMPLEMENTED (never worked in v4.2) */
...@@ -113,19 +117,25 @@ DefineOperator(List *names, List *parameters) ...@@ -113,19 +117,25 @@ DefineOperator(List *names, List *parameters)
elog(NOTICE, "CREATE OPERATOR: associativity not implemented"); elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
} }
else if (strcasecmp(defel->defname, "commutator") == 0) else if (strcasecmp(defel->defname, "commutator") == 0)
commutatorName = defGetString(defel); commutatorName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "negator") == 0) else if (strcasecmp(defel->defname, "negator") == 0)
negatorName = defGetString(defel); negatorName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "restrict") == 0) else if (strcasecmp(defel->defname, "restrict") == 0)
restrictionName = defGetString(defel); restrictionName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "join") == 0) else if (strcasecmp(defel->defname, "join") == 0)
joinName = defGetString(defel); joinName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "hashes") == 0) else if (strcasecmp(defel->defname, "hashes") == 0)
canHash = TRUE; canHash = TRUE;
else if (strcasecmp(defel->defname, "merges") == 0)
canMerge = TRUE;
else if (strcasecmp(defel->defname, "sort1") == 0) else if (strcasecmp(defel->defname, "sort1") == 0)
sortName1 = defGetString(defel); leftSortName = defGetQualifiedName(defel);
else if (strcasecmp(defel->defname, "sort2") == 0) 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 else
{ {
elog(WARNING, "DefineOperator: attribute \"%s\" not recognized", elog(WARNING, "DefineOperator: attribute \"%s\" not recognized",
...@@ -136,7 +146,7 @@ DefineOperator(List *names, List *parameters) ...@@ -136,7 +146,7 @@ DefineOperator(List *names, List *parameters)
/* /*
* make sure we have our required definitions * make sure we have our required definitions
*/ */
if (functionName == NULL) if (functionName == NIL)
elog(ERROR, "Define: \"procedure\" unspecified"); elog(ERROR, "Define: \"procedure\" unspecified");
/* Transform type names to type OIDs */ /* Transform type names to type OIDs */
...@@ -145,10 +155,31 @@ DefineOperator(List *names, List *parameters) ...@@ -145,10 +155,31 @@ DefineOperator(List *names, List *parameters)
if (typeName2) if (typeName2)
typeId2 = typenameTypeId(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.. * now have OperatorCreate do all the work..
*/ */
OperatorCreate(oprName, /* operator name */ OperatorCreate(oprName, /* operator name */
oprNamespace, /* namespace */
typeId1, /* left type id */ typeId1, /* left type id */
typeId2, /* right type id */ typeId2, /* right type id */
functionName, /* function for operator */ functionName, /* function for operator */
...@@ -161,9 +192,10 @@ DefineOperator(List *names, List *parameters) ...@@ -161,9 +192,10 @@ DefineOperator(List *names, List *parameters)
* procedure */ * procedure */
joinName, /* optional join sel. procedure name */ joinName, /* optional join sel. procedure name */
canHash, /* operator hashes */ canHash, /* operator hashes */
sortName1, /* optional first sort operator */ leftSortName, /* optional left sort operator */
sortName2); /* optional second sort operator */ rightSortName, /* optional right sort operator */
ltCompareName, /* optional < comparison op */
gtCompareName); /* optional < comparison op */
} }
...@@ -178,70 +210,36 @@ DefineOperator(List *names, List *parameters) ...@@ -178,70 +210,36 @@ DefineOperator(List *names, List *parameters)
* ... * ...
*/ */
void void
RemoveOperator(char *operatorName, /* operator name */ RemoveOperator(List *operatorName, /* operator name */
TypeName *typeName1, /* left argument type name */ TypeName *typeName1, /* left argument type name */
TypeName *typeName2) /* right argument type name */ TypeName *typeName2) /* right argument type name */
{ {
Oid operOid;
Relation relation; Relation relation;
HeapTuple tup; HeapTuple tup;
Oid typeId1 = InvalidOid;
Oid typeId2 = InvalidOid;
char oprtype;
if (typeName1) operOid = LookupOperNameTypeNames(operatorName, typeName1, typeName2,
typeId1 = typenameTypeId(typeName1); "RemoveOperator");
if (typeName2)
typeId2 = typenameTypeId(typeName2);
if (OidIsValid(typeId1) && OidIsValid(typeId2))
oprtype = 'b';
else if (OidIsValid(typeId1))
oprtype = 'r';
else
oprtype = 'l';
relation = heap_openr(OperatorRelationName, RowExclusiveLock); relation = heap_openr(OperatorRelationName, RowExclusiveLock);
tup = SearchSysCacheCopy(OPERNAME, tup = SearchSysCacheCopy(OPEROID,
PointerGetDatum(operatorName), ObjectIdGetDatum(operOid),
ObjectIdGetDatum(typeId1), 0, 0, 0);
ObjectIdGetDatum(typeId2),
CharGetDatum(oprtype));
if (HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup)) /* should not happen */
{ elog(ERROR, "RemoveOperator: failed to find tuple for operator '%s'",
if (!pg_oper_ownercheck(tup->t_data->t_oid, GetUserId())) NameListToString(operatorName));
if (!pg_oper_ownercheck(operOid, GetUserId()))
elog(ERROR, "RemoveOperator: operator '%s': permission denied", elog(ERROR, "RemoveOperator: operator '%s': permission denied",
operatorName); NameListToString(operatorName));
/* Delete any comments associated with this operator */ /* Delete any comments associated with this operator */
DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation)); DeleteComments(operOid, RelationGetRelid(relation));
simple_heap_delete(relation, &tup->t_self); 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_freetuple(tup);
heap_close(relation, RowExclusiveLock); heap_close(relation, RowExclusiveLock);
} }
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -925,7 +925,8 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
&peraggstate->inputtypeLen, &peraggstate->inputtypeLen,
&peraggstate->inputtypeByVal); &peraggstate->inputtypeByVal);
eq_function = compatible_oper_funcid("=", inputType, inputType, eq_function = compatible_oper_funcid(makeList1(makeString("=")),
inputType, inputType,
true); true);
if (!OidIsValid(eq_function)) if (!OidIsValid(eq_function))
elog(ERROR, "Unable to identify an equality operator for type '%s'", elog(ERROR, "Unable to identify an equality operator for type '%s'",
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* locate group boundaries. * locate group boundaries.
* *
* IDENTIFICATION * 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, ...@@ -490,7 +490,8 @@ execTuplesMatchPrepare(TupleDesc tupdesc,
Oid typid = tupdesc->attrs[att - 1]->atttypid; Oid typid = tupdesc->attrs[att - 1]->atttypid;
Oid eq_function; 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)) if (!OidIsValid(eq_function))
elog(ERROR, "Unable to identify an equality operator for type '%s'", elog(ERROR, "Unable to identify an equality operator for type '%s'",
typeidTypeName(typid)); typeidTypeName(typid));
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -1526,8 +1526,7 @@ _copyAExpr(A_Expr *from)
A_Expr *newnode = makeNode(A_Expr); A_Expr *newnode = makeNode(A_Expr);
newnode->oper = from->oper; newnode->oper = from->oper;
if (from->opname) Node_Copy(from, newnode, name);
newnode->opname = pstrdup(from->opname);
Node_Copy(from, newnode, lexpr); Node_Copy(from, newnode, lexpr);
Node_Copy(from, newnode, rexpr); Node_Copy(from, newnode, rexpr);
...@@ -1648,8 +1647,7 @@ _copySortGroupBy(SortGroupBy *from) ...@@ -1648,8 +1647,7 @@ _copySortGroupBy(SortGroupBy *from)
{ {
SortGroupBy *newnode = makeNode(SortGroupBy); SortGroupBy *newnode = makeNode(SortGroupBy);
if (from->useOp) Node_Copy(from, newnode, useOp);
newnode->useOp = pstrdup(from->useOp);
Node_Copy(from, newnode, node); Node_Copy(from, newnode, node);
return newnode; return newnode;
...@@ -2128,7 +2126,7 @@ _copyRemoveOperStmt(RemoveOperStmt *from) ...@@ -2128,7 +2126,7 @@ _copyRemoveOperStmt(RemoveOperStmt *from)
{ {
RemoveOperStmt *newnode = makeNode(RemoveOperStmt); RemoveOperStmt *newnode = makeNode(RemoveOperStmt);
newnode->opname = pstrdup(from->opname); Node_Copy(from, newnode, opname);
Node_Copy(from, newnode, args); Node_Copy(from, newnode, args);
return newnode; return newnode;
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -969,7 +969,7 @@ _equalRemoveFuncStmt(RemoveFuncStmt *a, RemoveFuncStmt *b)
static bool static bool
_equalRemoveOperStmt(RemoveOperStmt *a, RemoveOperStmt *b) _equalRemoveOperStmt(RemoveOperStmt *a, RemoveOperStmt *b)
{ {
if (!equalstr(a->opname, b->opname)) if (!equal(a->opname, b->opname))
return false; return false;
if (!equal(a->args, b->args)) if (!equal(a->args, b->args))
return false; return false;
...@@ -1400,7 +1400,7 @@ _equalAExpr(A_Expr *a, A_Expr *b) ...@@ -1400,7 +1400,7 @@ _equalAExpr(A_Expr *a, A_Expr *b)
{ {
if (a->oper != b->oper) if (a->oper != b->oper)
return false; return false;
if (!equalstr(a->opname, b->opname)) if (!equal(a->name, b->name))
return false; return false;
if (!equal(a->lexpr, b->lexpr)) if (!equal(a->lexpr, b->lexpr))
return false; return false;
...@@ -1520,7 +1520,7 @@ _equalTypeCast(TypeCast *a, TypeCast *b) ...@@ -1520,7 +1520,7 @@ _equalTypeCast(TypeCast *a, TypeCast *b)
static bool static bool
_equalSortGroupBy(SortGroupBy *a, SortGroupBy *b) _equalSortGroupBy(SortGroupBy *a, SortGroupBy *b)
{ {
if (!equalstr(a->useOp, b->useOp)) if (!equal(a->useOp, b->useOp))
return false; return false;
if (!equal(a->node, b->node)) if (!equal(a->node, b->node))
return false; return false;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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" #include "postgres.h"
...@@ -16,6 +16,39 @@ ...@@ -16,6 +16,39 @@
#include "utils/lsyscache.h" #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 - * makeOper -
* creates an Oper node * creates an Oper node
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which * Every (plan) node in POSTGRES has an associated "out" routine which
...@@ -1285,7 +1285,7 @@ _outAExpr(StringInfo str, A_Expr *node) ...@@ -1285,7 +1285,7 @@ _outAExpr(StringInfo str, A_Expr *node)
appendStringInfo(str, "NOT "); appendStringInfo(str, "NOT ");
break; break;
case OP: case OP:
_outToken(str, node->opname); _outNode(str, node->name);
appendStringInfo(str, " "); appendStringInfo(str, " ");
break; break;
default: default:
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -21,6 +21,7 @@
#include "access/nbtree.h" #include "access/nbtree.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/pg_amop.h" #include "catalog/pg_amop.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
...@@ -911,7 +912,8 @@ indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left) ...@@ -911,7 +912,8 @@ indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
* operator, but in practice that seems pretty unlikely for * operator, but in practice that seems pretty unlikely for
* binary-compatible types.) * 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)) if (OidIsValid(new_op))
{ {
...@@ -2143,14 +2145,15 @@ network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop) ...@@ -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 */ /* 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 static Oid
find_operator(const char *opname, Oid datatype) find_operator(const char *opname, Oid datatype)
{ {
return GetSysCacheOid(OPERNAME, return GetSysCacheOid(OPERNAMENSP,
PointerGetDatum(opname), PointerGetDatum(opname),
ObjectIdGetDatum(datatype), ObjectIdGetDatum(datatype),
ObjectIdGetDatum(datatype), ObjectIdGetDatum(datatype),
CharGetDatum('b')); ObjectIdGetDatum(PG_CATALOG_NAMESPACE));
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -740,7 +740,8 @@ process_implied_equality(Query *root, Node *item1, Node *item2,
*/ */
ltype = exprType(item1); ltype = exprType(item1);
rtype = exprType(item2); rtype = exprType(item2);
eq_operator = compatible_oper("=", ltype, rtype, true); eq_operator = compatible_oper(makeList1(makeString("=")),
ltype, rtype, true);
if (!HeapTupleIsValid(eq_operator)) if (!HeapTupleIsValid(eq_operator))
{ {
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -284,9 +284,9 @@ make_subplan(SubLink *slink)
* Note: we use make_operand in case runtime type conversion * Note: we use make_operand in case runtime type conversion
* function calls must be inserted for this operator! * function calls must be inserted for this operator!
*/ */
left = make_operand("", lefthand, left = make_operand(lefthand,
exprType(lefthand), opform->oprleft); exprType(lefthand), opform->oprleft);
right = make_operand("", (Node *) prm, right = make_operand((Node *) prm,
prm->paramtype, opform->oprright); prm->paramtype, opform->oprright);
ReleaseSysCache(tup); ReleaseSysCache(tup);
...@@ -433,9 +433,9 @@ make_subplan(SubLink *slink) ...@@ -433,9 +433,9 @@ make_subplan(SubLink *slink)
* Note: we use make_operand in case runtime type conversion * Note: we use make_operand in case runtime type conversion
* function calls must be inserted for this operator! * function calls must be inserted for this operator!
*/ */
left = make_operand("", lefthand, left = make_operand(lefthand,
exprType(lefthand), opform->oprleft); exprType(lefthand), opform->oprleft);
right = make_operand("", (Node *) con, right = make_operand((Node *) con,
con->consttype, opform->oprright); con->consttype, opform->oprright);
ReleaseSysCache(tup); ReleaseSysCache(tup);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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) ...@@ -1460,11 +1460,13 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
{ {
/* /*
* fktypoid[i] is the foreign key table's i'th element's type * 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 * pktypoid[i] is the primary key table's i'th element's type
* type oid We let oper() do our work for us, including *
* elog(ERROR) if the types don't compare with = * 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); ReleaseSysCache(o);
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -82,11 +82,10 @@ static int pfunc_num_args; ...@@ -82,11 +82,10 @@ static int pfunc_num_args;
*/ */
/*#define __YYSCLASS*/ /*#define __YYSCLASS*/
static Node *makeA_Expr(int oper, char *opname, Node *lexpr, Node *rexpr);
static Node *makeTypeCast(Node *arg, TypeName *typename); static Node *makeTypeCast(Node *arg, TypeName *typename);
static Node *makeStringConst(char *str, TypeName *typename); static Node *makeStringConst(char *str, TypeName *typename);
static Node *makeFloatConst(char *str); 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 SelectStmt *findLeftmostSelect(SelectStmt *node);
static void insertSelectOptions(SelectStmt *stmt, static void insertSelectOptions(SelectStmt *stmt,
List *sortClause, List *forUpdate, List *sortClause, List *forUpdate,
...@@ -177,13 +176,13 @@ static bool set_name_needs_quotes(const char *name); ...@@ -177,13 +176,13 @@ static bool set_name_needs_quotes(const char *name);
database_name, access_method_clause, access_method, attr_name, database_name, access_method_clause, access_method, attr_name,
class, index_name, name, function_name, file_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 <range> qualified_name, OptConstrFromTable
%type <str> opt_id, %type <str> opt_id,
all_Op, MathOp, opt_name, all_Op, MathOp, opt_name,
OptUseOp, opt_class, SpecialRuleRelation opt_class, SpecialRuleRelation
%type <str> opt_level, opt_encoding %type <str> opt_level, opt_encoding
%type <node> grantee %type <node> grantee
...@@ -202,7 +201,7 @@ static bool set_name_needs_quotes(const char *name); ...@@ -202,7 +201,7 @@ static bool set_name_needs_quotes(const char *name);
opt_column_list, columnList, opt_name_list, opt_column_list, columnList, opt_name_list,
sort_clause, sortby_list, index_params, index_list, name_list, sort_clause, sortby_list, index_params, index_list, name_list,
from_clause, from_list, opt_array_bounds, qualified_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, target_list, update_target_list, insert_column_list,
insert_target_list, insert_target_list,
def_list, opt_indirection, group_clause, TriggerFuncArgs, def_list, opt_indirection, group_clause, TriggerFuncArgs,
...@@ -404,7 +403,7 @@ static bool set_name_needs_quotes(const char *name); ...@@ -404,7 +403,7 @@ static bool set_name_needs_quotes(const char *name);
%nonassoc BETWEEN %nonassoc BETWEEN
%nonassoc IN %nonassoc IN
%left POSTFIXOP /* dummy for postfix Op rules */ %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 NOTNULL
%nonassoc ISNULL %nonassoc ISNULL
%nonassoc IS NULL_P TRUE_P FALSE_P UNKNOWN /* sets precedence for IS NULL, etc */ %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 ...@@ -2086,11 +2085,11 @@ DefineStmt: CREATE AGGREGATE func_name definition
n->definition = $4; n->definition = $4;
$$ = (Node *)n; $$ = (Node *)n;
} }
| CREATE OPERATOR all_Op definition | CREATE OPERATOR any_operator definition
{ {
DefineStmt *n = makeNode(DefineStmt); DefineStmt *n = makeNode(DefineStmt);
n->defType = OPERATOR; n->defType = OPERATOR;
n->defnames = makeList1(makeString($3)); /* XXX */ n->defnames = $3;
n->definition = $4; n->definition = $4;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -2227,11 +2226,11 @@ CommentStmt: COMMENT ON comment_type any_name IS comment_text ...@@ -2227,11 +2226,11 @@ CommentStmt: COMMENT ON comment_type any_name IS comment_text
n->comment = $7; n->comment = $7;
$$ = (Node *) n; $$ = (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); CommentStmt *n = makeNode(CommentStmt);
n->objtype = OPERATOR; n->objtype = OPERATOR;
n->objname = makeList1(makeString($4)); /* XXX */ n->objname = $4;
n->objargs = $6; n->objargs = $6;
n->comment = $9; n->comment = $9;
$$ = (Node *) n; $$ = (Node *) n;
...@@ -2812,7 +2811,7 @@ aggr_argtype: Typename { $$ = $1; } ...@@ -2812,7 +2811,7 @@ aggr_argtype: Typename { $$ = $1; }
| '*' { $$ = NULL; } | '*' { $$ = NULL; }
; ;
RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')' RemoveOperStmt: DROP OPERATOR any_operator '(' oper_argtypes ')'
{ {
RemoveOperStmt *n = makeNode(RemoveOperStmt); RemoveOperStmt *n = makeNode(RemoveOperStmt);
n->opname = $3; n->opname = $3;
...@@ -2833,6 +2832,12 @@ oper_argtypes: Typename ...@@ -2833,6 +2832,12 @@ oper_argtypes: Typename
{ $$ = makeList2($1, NULL); } { $$ = 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 ...@@ -3831,10 +3836,14 @@ sortby: a_expr OptUseOp
} }
; ;
OptUseOp: USING all_Op { $$ = $2; } OptUseOp: USING qual_all_Op
| ASC { $$ = "<"; } { $$ = $2; }
| DESC { $$ = ">"; } | ASC
| /*EMPTY*/ { $$ = "<"; /*default*/ } { $$ = makeList1(makeString("<")); }
| DESC
{ $$ = makeList1(makeString(">")); }
| /*EMPTY*/
{ $$ = makeList1(makeString("<")); /*default*/ }
; ;
...@@ -4593,7 +4602,7 @@ row_expr: '(' row_descriptor ')' IN select_with_parens ...@@ -4593,7 +4602,7 @@ row_expr: '(' row_descriptor ')' IN select_with_parens
{ {
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = $2; n->lefthand = $2;
n->oper = (List *) makeA_Expr(OP, "=", NULL, NULL); n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
n->useor = FALSE; n->useor = FALSE;
n->subLinkType = ANY_SUBLINK; n->subLinkType = ANY_SUBLINK;
n->subselect = $5; n->subselect = $5;
...@@ -4603,18 +4612,18 @@ row_expr: '(' row_descriptor ')' IN select_with_parens ...@@ -4603,18 +4612,18 @@ row_expr: '(' row_descriptor ')' IN select_with_parens
{ {
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = $2; n->lefthand = $2;
n->oper = (List *) makeA_Expr(OP, "<>", NULL, NULL); n->oper = (List *) makeSimpleA_Expr(OP, "<>", NULL, NULL);
n->useor = TRUE; n->useor = TRUE;
n->subLinkType = ALL_SUBLINK; n->subLinkType = ALL_SUBLINK;
n->subselect = $6; n->subselect = $6;
$$ = (Node *)n; $$ = (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); SubLink *n = makeNode(SubLink);
n->lefthand = $2; n->lefthand = $2;
n->oper = (List *) makeA_Expr(OP, $4, NULL, NULL); n->oper = (List *) makeA_Expr(OP, $4, NULL, NULL);
if (strcmp($4, "<>") == 0) if (strcmp(strVal(llast($4)), "<>") == 0)
n->useor = TRUE; n->useor = TRUE;
else else
n->useor = FALSE; n->useor = FALSE;
...@@ -4622,12 +4631,12 @@ row_expr: '(' row_descriptor ')' IN select_with_parens ...@@ -4622,12 +4631,12 @@ row_expr: '(' row_descriptor ')' IN select_with_parens
n->subselect = $6; n->subselect = $6;
$$ = (Node *)n; $$ = (Node *)n;
} }
| '(' row_descriptor ')' all_Op select_with_parens | '(' row_descriptor ')' qual_all_Op select_with_parens %prec Op
{ {
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = $2; n->lefthand = $2;
n->oper = (List *) makeA_Expr(OP, $4, NULL, NULL); n->oper = (List *) makeA_Expr(OP, $4, NULL, NULL);
if (strcmp($4, "<>") == 0) if (strcmp(strVal(llast($4)), "<>") == 0)
n->useor = TRUE; n->useor = TRUE;
else else
n->useor = FALSE; n->useor = FALSE;
...@@ -4635,7 +4644,7 @@ row_expr: '(' row_descriptor ')' IN select_with_parens ...@@ -4635,7 +4644,7 @@ row_expr: '(' row_descriptor ')' IN select_with_parens
n->subselect = $5; n->subselect = $5;
$$ = (Node *)n; $$ = (Node *)n;
} }
| '(' row_descriptor ')' all_Op '(' row_descriptor ')' | '(' row_descriptor ')' qual_all_Op '(' row_descriptor ')' %prec Op
{ {
$$ = makeRowExpr($4, $2, $6); $$ = makeRowExpr($4, $2, $6);
} }
...@@ -4696,6 +4705,18 @@ MathOp: '+' { $$ = "+"; } ...@@ -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 * General expressions
* This is the heart of the expression syntax. * This is the heart of the expression syntax.
...@@ -4735,52 +4756,52 @@ a_expr: c_expr ...@@ -4735,52 +4756,52 @@ a_expr: c_expr
* also to b_expr and to the MathOp list above. * also to b_expr and to the MathOp list above.
*/ */
| '+' a_expr %prec UMINUS | '+' a_expr %prec UMINUS
{ $$ = makeA_Expr(OP, "+", NULL, $2); } { $$ = (Node *) makeSimpleA_Expr(OP, "+", NULL, $2); }
| '-' a_expr %prec UMINUS | '-' a_expr %prec UMINUS
{ $$ = doNegate($2); } { $$ = doNegate($2); }
| '%' a_expr | '%' a_expr
{ $$ = makeA_Expr(OP, "%", NULL, $2); } { $$ = (Node *) makeSimpleA_Expr(OP, "%", NULL, $2); }
| '^' a_expr | '^' a_expr
{ $$ = makeA_Expr(OP, "^", NULL, $2); } { $$ = (Node *) makeSimpleA_Expr(OP, "^", NULL, $2); }
| a_expr '%' | a_expr '%'
{ $$ = makeA_Expr(OP, "%", $1, NULL); } { $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, NULL); }
| a_expr '^' | a_expr '^'
{ $$ = makeA_Expr(OP, "^", $1, NULL); } { $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, NULL); }
| a_expr '+' a_expr | a_expr '+' a_expr
{ $$ = makeA_Expr(OP, "+", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "+", $1, $3); }
| a_expr '-' a_expr | a_expr '-' a_expr
{ $$ = makeA_Expr(OP, "-", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "-", $1, $3); }
| a_expr '*' a_expr | a_expr '*' a_expr
{ $$ = makeA_Expr(OP, "*", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "*", $1, $3); }
| a_expr '/' a_expr | a_expr '/' a_expr
{ $$ = makeA_Expr(OP, "/", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "/", $1, $3); }
| a_expr '%' a_expr | a_expr '%' a_expr
{ $$ = makeA_Expr(OP, "%", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, $3); }
| a_expr '^' a_expr | a_expr '^' a_expr
{ $$ = makeA_Expr(OP, "^", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, $3); }
| a_expr '<' a_expr | a_expr '<' a_expr
{ $$ = makeA_Expr(OP, "<", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "<", $1, $3); }
| a_expr '>' a_expr | a_expr '>' a_expr
{ $$ = makeA_Expr(OP, ">", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, ">", $1, $3); }
| a_expr '=' a_expr | a_expr '=' a_expr
{ $$ = makeA_Expr(OP, "=", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "=", $1, $3); }
| a_expr Op a_expr | a_expr qual_Op a_expr %prec Op
{ $$ = makeA_Expr(OP, $2, $1, $3); } { $$ = (Node *) makeA_Expr(OP, $2, $1, $3); }
| Op a_expr | qual_Op a_expr %prec Op
{ $$ = makeA_Expr(OP, $1, NULL, $2); } { $$ = (Node *) makeA_Expr(OP, $1, NULL, $2); }
| a_expr Op %prec POSTFIXOP | a_expr qual_Op %prec POSTFIXOP
{ $$ = makeA_Expr(OP, $2, $1, NULL); } { $$ = (Node *) makeA_Expr(OP, $2, $1, NULL); }
| a_expr AND a_expr | a_expr AND a_expr
{ $$ = makeA_Expr(AND, NULL, $1, $3); } { $$ = (Node *) makeA_Expr(AND, NIL, $1, $3); }
| a_expr OR a_expr | a_expr OR a_expr
{ $$ = makeA_Expr(OR, NULL, $1, $3); } { $$ = (Node *) makeA_Expr(OR, NIL, $1, $3); }
| NOT a_expr | NOT a_expr
{ $$ = makeA_Expr(NOT, NULL, NULL, $2); } { $$ = (Node *) makeA_Expr(NOT, NIL, NULL, $2); }
| a_expr LIKE a_expr | a_expr LIKE a_expr
{ $$ = makeA_Expr(OP, "~~", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "~~", $1, $3); }
| a_expr LIKE a_expr ESCAPE a_expr | a_expr LIKE a_expr ESCAPE a_expr
{ {
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
...@@ -4788,10 +4809,10 @@ a_expr: c_expr ...@@ -4788,10 +4809,10 @@ a_expr: c_expr
n->args = makeList2($3, $5); n->args = makeList2($3, $5);
n->agg_star = FALSE; n->agg_star = FALSE;
n->agg_distinct = FALSE; n->agg_distinct = FALSE;
$$ = makeA_Expr(OP, "~~", $1, (Node *) n); $$ = (Node *) makeSimpleA_Expr(OP, "~~", $1, (Node *) n);
} }
| a_expr NOT LIKE a_expr | 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 | a_expr NOT LIKE a_expr ESCAPE a_expr
{ {
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
...@@ -4799,10 +4820,10 @@ a_expr: c_expr ...@@ -4799,10 +4820,10 @@ a_expr: c_expr
n->args = makeList2($4, $6); n->args = makeList2($4, $6);
n->agg_star = FALSE; n->agg_star = FALSE;
n->agg_distinct = FALSE; n->agg_distinct = FALSE;
$$ = makeA_Expr(OP, "!~~", $1, (Node *) n); $$ = (Node *) makeSimpleA_Expr(OP, "!~~", $1, (Node *) n);
} }
| a_expr ILIKE a_expr | a_expr ILIKE a_expr
{ $$ = makeA_Expr(OP, "~~*", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "~~*", $1, $3); }
| a_expr ILIKE a_expr ESCAPE a_expr | a_expr ILIKE a_expr ESCAPE a_expr
{ {
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
...@@ -4810,10 +4831,10 @@ a_expr: c_expr ...@@ -4810,10 +4831,10 @@ a_expr: c_expr
n->args = makeList2($3, $5); n->args = makeList2($3, $5);
n->agg_star = FALSE; n->agg_star = FALSE;
n->agg_distinct = FALSE; n->agg_distinct = FALSE;
$$ = makeA_Expr(OP, "~~*", $1, (Node *) n); $$ = (Node *) makeSimpleA_Expr(OP, "~~*", $1, (Node *) n);
} }
| a_expr NOT ILIKE a_expr | 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 | a_expr NOT ILIKE a_expr ESCAPE a_expr
{ {
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
...@@ -4821,7 +4842,7 @@ a_expr: c_expr ...@@ -4821,7 +4842,7 @@ a_expr: c_expr
n->args = makeList2($4, $6); n->args = makeList2($4, $6);
n->agg_star = FALSE; n->agg_star = FALSE;
n->agg_distinct = FALSE; n->agg_distinct = FALSE;
$$ = makeA_Expr(OP, "!~~*", $1, (Node *) n); $$ = (Node *) makeSimpleA_Expr(OP, "!~~*", $1, (Node *) n);
} }
/* NullTest clause /* NullTest clause
* Define SQL92-style Null test clause. * Define SQL92-style Null test clause.
...@@ -4915,15 +4936,15 @@ a_expr: c_expr ...@@ -4915,15 +4936,15 @@ a_expr: c_expr
} }
| a_expr BETWEEN b_expr AND b_expr %prec BETWEEN | a_expr BETWEEN b_expr AND b_expr %prec BETWEEN
{ {
$$ = makeA_Expr(AND, NULL, $$ = (Node *) makeA_Expr(AND, NIL,
makeA_Expr(OP, ">=", $1, $3), (Node *) makeSimpleA_Expr(OP, ">=", $1, $3),
makeA_Expr(OP, "<=", $1, $5)); (Node *) makeSimpleA_Expr(OP, "<=", $1, $5));
} }
| a_expr NOT BETWEEN b_expr AND b_expr %prec BETWEEN | a_expr NOT BETWEEN b_expr AND b_expr %prec BETWEEN
{ {
$$ = makeA_Expr(OR, NULL, $$ = (Node *) makeA_Expr(OR, NIL,
makeA_Expr(OP, "<", $1, $4), (Node *) makeSimpleA_Expr(OP, "<", $1, $4),
makeA_Expr(OP, ">", $1, $6)); (Node *) makeSimpleA_Expr(OP, ">", $1, $6));
} }
| a_expr IN in_expr | a_expr IN in_expr
{ {
...@@ -4932,7 +4953,8 @@ a_expr: c_expr ...@@ -4932,7 +4953,8 @@ a_expr: c_expr
{ {
SubLink *n = (SubLink *)$3; SubLink *n = (SubLink *)$3;
n->lefthand = makeList1($1); n->lefthand = makeList1($1);
n->oper = (List *) makeA_Expr(OP, "=", NULL, NULL); n->oper = (List *) makeSimpleA_Expr(OP, "=",
NULL, NULL);
n->useor = FALSE; n->useor = FALSE;
n->subLinkType = ANY_SUBLINK; n->subLinkType = ANY_SUBLINK;
$$ = (Node *)n; $$ = (Node *)n;
...@@ -4943,11 +4965,13 @@ a_expr: c_expr ...@@ -4943,11 +4965,13 @@ a_expr: c_expr
List *l; List *l;
foreach(l, (List *) $3) 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) if (n == NULL)
n = cmp; n = cmp;
else else
n = makeA_Expr(OR, NULL, n, cmp); n = (Node *) makeA_Expr(OR, NIL, n, cmp);
} }
$$ = n; $$ = n;
} }
...@@ -4959,7 +4983,8 @@ a_expr: c_expr ...@@ -4959,7 +4983,8 @@ a_expr: c_expr
{ {
SubLink *n = (SubLink *)$4; SubLink *n = (SubLink *)$4;
n->lefthand = makeList1($1); n->lefthand = makeList1($1);
n->oper = (List *) makeA_Expr(OP, "<>", NULL, NULL); n->oper = (List *) makeSimpleA_Expr(OP, "<>",
NULL, NULL);
n->useor = FALSE; n->useor = FALSE;
n->subLinkType = ALL_SUBLINK; n->subLinkType = ALL_SUBLINK;
$$ = (Node *)n; $$ = (Node *)n;
...@@ -4970,16 +4995,18 @@ a_expr: c_expr ...@@ -4970,16 +4995,18 @@ a_expr: c_expr
List *l; List *l;
foreach(l, (List *) $4) 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) if (n == NULL)
n = cmp; n = cmp;
else else
n = makeA_Expr(AND, NULL, n, cmp); n = (Node *) makeA_Expr(AND, NIL, n, cmp);
} }
$$ = n; $$ = 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); SubLink *n = makeNode(SubLink);
n->lefthand = makeList1($1); n->lefthand = makeList1($1);
...@@ -5007,42 +5034,42 @@ b_expr: c_expr ...@@ -5007,42 +5034,42 @@ b_expr: c_expr
| b_expr TYPECAST Typename | b_expr TYPECAST Typename
{ $$ = makeTypeCast($1, $3); } { $$ = makeTypeCast($1, $3); }
| '+' b_expr %prec UMINUS | '+' b_expr %prec UMINUS
{ $$ = makeA_Expr(OP, "+", NULL, $2); } { $$ = (Node *) makeSimpleA_Expr(OP, "+", NULL, $2); }
| '-' b_expr %prec UMINUS | '-' b_expr %prec UMINUS
{ $$ = doNegate($2); } { $$ = doNegate($2); }
| '%' b_expr | '%' b_expr
{ $$ = makeA_Expr(OP, "%", NULL, $2); } { $$ = (Node *) makeSimpleA_Expr(OP, "%", NULL, $2); }
| '^' b_expr | '^' b_expr
{ $$ = makeA_Expr(OP, "^", NULL, $2); } { $$ = (Node *) makeSimpleA_Expr(OP, "^", NULL, $2); }
| b_expr '%' | b_expr '%'
{ $$ = makeA_Expr(OP, "%", $1, NULL); } { $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, NULL); }
| b_expr '^' | b_expr '^'
{ $$ = makeA_Expr(OP, "^", $1, NULL); } { $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, NULL); }
| b_expr '+' b_expr | b_expr '+' b_expr
{ $$ = makeA_Expr(OP, "+", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "+", $1, $3); }
| b_expr '-' b_expr | b_expr '-' b_expr
{ $$ = makeA_Expr(OP, "-", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "-", $1, $3); }
| b_expr '*' b_expr | b_expr '*' b_expr
{ $$ = makeA_Expr(OP, "*", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "*", $1, $3); }
| b_expr '/' b_expr | b_expr '/' b_expr
{ $$ = makeA_Expr(OP, "/", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "/", $1, $3); }
| b_expr '%' b_expr | b_expr '%' b_expr
{ $$ = makeA_Expr(OP, "%", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "%", $1, $3); }
| b_expr '^' b_expr | b_expr '^' b_expr
{ $$ = makeA_Expr(OP, "^", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "^", $1, $3); }
| b_expr '<' b_expr | b_expr '<' b_expr
{ $$ = makeA_Expr(OP, "<", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "<", $1, $3); }
| b_expr '>' b_expr | b_expr '>' b_expr
{ $$ = makeA_Expr(OP, ">", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, ">", $1, $3); }
| b_expr '=' b_expr | b_expr '=' b_expr
{ $$ = makeA_Expr(OP, "=", $1, $3); } { $$ = (Node *) makeSimpleA_Expr(OP, "=", $1, $3); }
| b_expr Op b_expr | b_expr qual_Op b_expr %prec Op
{ $$ = makeA_Expr(OP, $2, $1, $3); } { $$ = (Node *) makeA_Expr(OP, $2, $1, $3); }
| Op b_expr | qual_Op b_expr %prec Op
{ $$ = makeA_Expr(OP, $1, NULL, $2); } { $$ = (Node *) makeA_Expr(OP, $1, NULL, $2); }
| b_expr Op %prec POSTFIXOP | b_expr qual_Op %prec POSTFIXOP
{ $$ = makeA_Expr(OP, $2, $1, NULL); } { $$ = (Node *) makeA_Expr(OP, $2, $1, NULL); }
; ;
/* /*
...@@ -5539,12 +5566,9 @@ case_expr: CASE case_arg when_clause_list case_default END_TRANS ...@@ -5539,12 +5566,9 @@ case_expr: CASE case_arg when_clause_list case_default END_TRANS
{ {
CaseExpr *c = makeNode(CaseExpr); CaseExpr *c = makeNode(CaseExpr);
CaseWhen *w = makeNode(CaseWhen); CaseWhen *w = makeNode(CaseWhen);
/*
A_Const *n = makeNode(A_Const); w->expr = (Node *) makeSimpleA_Expr(OP, "=", $3, $5);
n->val.type = T_Null; /* w->result is left NULL */
w->result = (Node *)n;
*/
w->expr = makeA_Expr(OP, "=", $3, $5);
c->args = makeList1(w); c->args = makeList1(w);
c->defresult = $3; c->defresult = $3;
$$ = (Node *)c; $$ = (Node *)c;
...@@ -6243,17 +6267,6 @@ SpecialRuleRelation: OLD ...@@ -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 * static Node *
makeTypeCast(Node *arg, TypeName *typename) makeTypeCast(Node *arg, TypeName *typename)
{ {
...@@ -6308,41 +6321,49 @@ makeFloatConst(char *str) ...@@ -6308,41 +6321,49 @@ makeFloatConst(char *str)
* - thomas 1997-12-22 * - thomas 1997-12-22
*/ */
static Node * static Node *
makeRowExpr(char *opr, List *largs, List *rargs) makeRowExpr(List *opr, List *largs, List *rargs)
{ {
Node *expr = NULL; Node *expr = NULL;
Node *larg, *rarg; Node *larg, *rarg;
char *oprname;
if (length(largs) != length(rargs)) 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) if (lnext(largs) != NIL)
expr = makeRowExpr(opr,lnext(largs),lnext(rargs)); expr = makeRowExpr(opr, lnext(largs), lnext(rargs));
larg = lfirst(largs); larg = lfirst(largs);
rarg = lfirst(rargs); rarg = lfirst(rargs);
if ((strcmp(opr, "=") == 0) oprname = strVal(llast(opr));
|| (strcmp(opr, "<") == 0)
|| (strcmp(opr, "<=") == 0) if ((strcmp(oprname, "=") == 0) ||
|| (strcmp(opr, ">") == 0) (strcmp(oprname, "<") == 0) ||
|| (strcmp(opr, ">=") == 0)) (strcmp(oprname, "<=") == 0) ||
(strcmp(oprname, ">") == 0) ||
(strcmp(oprname, ">=") == 0))
{ {
if (expr == NULL) if (expr == NULL)
expr = makeA_Expr(OP, opr, larg, rarg); expr = (Node *) makeA_Expr(OP, opr, larg, rarg);
else 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) if (expr == NULL)
expr = makeA_Expr(OP, opr, larg, rarg); expr = (Node *) makeA_Expr(OP, opr, larg, rarg);
else 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 else
{ {
elog(ERROR,"Operator '%s' not implemented for row expressions",opr); elog(ERROR, "Operator '%s' not implemented for row expressions",
oprname);
} }
return expr; return expr;
...@@ -6557,7 +6578,7 @@ doNegate(Node *n) ...@@ -6557,7 +6578,7 @@ doNegate(Node *n)
} }
} }
return makeA_Expr(OP, "-", NULL, n); return (Node *) makeSimpleA_Expr(OP, "-", NULL, n);
} }
static void static void
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -54,7 +54,7 @@ static Node *transformFromClauseItem(ParseState *pstate, Node *n,
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
List *tlist, int clause); List *tlist, int clause);
static List *addTargetToSortList(TargetEntry *tle, List *sortlist, static List *addTargetToSortList(TargetEntry *tle, List *sortlist,
List *targetlist, char *opname); List *targetlist, List *opname);
static bool exprIsInSortList(Node *expr, List *sortList, List *targetList); static bool exprIsInSortList(Node *expr, List *sortList, List *targetList);
...@@ -257,22 +257,15 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars) ...@@ -257,22 +257,15 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
Node *rvar = (Node *) lfirst(rvars); Node *rvar = (Node *) lfirst(rvars);
A_Expr *e; A_Expr *e;
e = makeNode(A_Expr); e = makeSimpleA_Expr(OP, "=", copyObject(lvar), copyObject(rvar));
e->oper = OP;
e->opname = "=";
e->lexpr = copyObject(lvar);
e->rexpr = copyObject(rvar);
if (result == NULL) if (result == NULL)
result = (Node *) e; result = (Node *) e;
else else
{ {
A_Expr *a = makeNode(A_Expr); A_Expr *a;
a->oper = AND; a = makeA_Expr(AND, NIL, result, (Node *) e);
a->opname = NULL;
a->lexpr = result;
a->rexpr = (Node *) e;
result = (Node *) a; result = (Node *) a;
} }
...@@ -1117,7 +1110,7 @@ transformDistinctClause(ParseState *pstate, List *distinctlist, ...@@ -1117,7 +1110,7 @@ transformDistinctClause(ParseState *pstate, List *distinctlist,
else else
{ {
*sortClause = addTargetToSortList(tle, *sortClause, *sortClause = addTargetToSortList(tle, *sortClause,
targetlist, NULL); targetlist, NIL);
/* /*
* Probably, the tle should always have been added at the * Probably, the tle should always have been added at the
...@@ -1160,7 +1153,7 @@ addAllTargetsToSortList(List *sortlist, List *targetlist) ...@@ -1160,7 +1153,7 @@ addAllTargetsToSortList(List *sortlist, List *targetlist)
TargetEntry *tle = (TargetEntry *) lfirst(i); TargetEntry *tle = (TargetEntry *) lfirst(i);
if (!tle->resdom->resjunk) if (!tle->resdom->resjunk)
sortlist = addTargetToSortList(tle, sortlist, targetlist, NULL); sortlist = addTargetToSortList(tle, sortlist, targetlist, NIL);
} }
return sortlist; return sortlist;
} }
...@@ -1169,13 +1162,13 @@ addAllTargetsToSortList(List *sortlist, List *targetlist) ...@@ -1169,13 +1162,13 @@ addAllTargetsToSortList(List *sortlist, List *targetlist)
* addTargetToSortList * addTargetToSortList
* If the given targetlist entry isn't already in the ORDER BY list, * 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 * 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. * Returns the updated ORDER BY list.
*/ */
static List * static List *
addTargetToSortList(TargetEntry *tle, List *sortlist, List *targetlist, addTargetToSortList(TargetEntry *tle, List *sortlist, List *targetlist,
char *opname) List *opname)
{ {
/* avoid making duplicate sortlist entries */ /* avoid making duplicate sortlist entries */
if (!exprIsInSortList(tle->expr, sortlist, targetlist)) if (!exprIsInSortList(tle->expr, sortlist, targetlist))
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -192,7 +192,8 @@ transformExpr(ParseState *pstate, Node *expr)
* into IS NULL exprs. * into IS NULL exprs.
*/ */
if (Transform_null_equals && if (Transform_null_equals &&
strcmp(a->opname, "=") == 0 && length(a->name) == 1 &&
strcmp(strVal(lfirst(a->name)), "=") == 0 &&
(exprIsNullConstant(a->lexpr) || (exprIsNullConstant(a->lexpr) ||
exprIsNullConstant(a->rexpr))) exprIsNullConstant(a->rexpr)))
{ {
...@@ -215,7 +216,7 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -215,7 +216,7 @@ transformExpr(ParseState *pstate, Node *expr)
Node *rexpr = transformExpr(pstate, Node *rexpr = transformExpr(pstate,
a->rexpr); a->rexpr);
result = (Node *) make_op(a->opname, result = (Node *) make_op(a->name,
lexpr, lexpr,
rexpr); rexpr);
} }
...@@ -366,21 +367,23 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -366,21 +367,23 @@ transformExpr(ParseState *pstate, Node *expr)
/* ALL, ANY, or MULTIEXPR: generate operator list */ /* ALL, ANY, or MULTIEXPR: generate operator list */
List *left_list = sublink->lefthand; List *left_list = sublink->lefthand;
List *right_list = qtree->targetList; List *right_list = qtree->targetList;
char *op; List *op;
char *opname;
List *elist; List *elist;
foreach(elist, left_list) foreach(elist, left_list)
lfirst(elist) = transformExpr(pstate, lfirst(elist)); lfirst(elist) = transformExpr(pstate, lfirst(elist));
Assert(IsA(sublink->oper, A_Expr)); 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; sublink->oper = NIL;
/* Combining operators other than =/<> is dubious... */ /* Combining operators other than =/<> is dubious... */
if (length(left_list) != 1 && if (length(left_list) != 1 &&
strcmp(op, "=") != 0 && strcmp(op, "<>") != 0) strcmp(opname, "=") != 0 && strcmp(opname, "<>") != 0)
elog(ERROR, "Row comparison cannot use '%s'", elog(ERROR, "Row comparison cannot use '%s'",
op); opname);
/* /*
* Scan subquery's targetlist to find values that will * Scan subquery's targetlist to find values that will
...@@ -420,7 +423,7 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -420,7 +423,7 @@ transformExpr(ParseState *pstate, Node *expr)
if (opform->oprresult != BOOLOID) if (opform->oprresult != BOOLOID)
elog(ERROR, "'%s' result type of '%s' must return '%s'" elog(ERROR, "'%s' result type of '%s' must return '%s'"
" to be used with quantified predicate subquery", " to be used with quantified predicate subquery",
op, typeidTypeName(opform->oprresult), opname, typeidTypeName(opform->oprresult),
typeidTypeName(BOOLOID)); typeidTypeName(BOOLOID));
newop = makeOper(oprid(optup), /* opno */ newop = makeOper(oprid(optup), /* opno */
...@@ -459,13 +462,8 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -459,13 +462,8 @@ transformExpr(ParseState *pstate, Node *expr)
if (c->arg != NULL) if (c->arg != NULL)
{ {
/* shorthand form was specified, so expand... */ /* shorthand form was specified, so expand... */
A_Expr *a = makeNode(A_Expr); warg = (Node *) makeSimpleA_Expr(OP, "=",
c->arg, warg);
a->oper = OP;
a->opname = "=";
a->lexpr = c->arg;
a->rexpr = warg;
warg = (Node *) a;
} }
neww->expr = transformExpr(pstate, warg); neww->expr = transformExpr(pstate, warg);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -62,10 +62,7 @@ make_parsestate(ParseState *parentParseState)
* Ensure argument type match by forcing conversion of constants. * Ensure argument type match by forcing conversion of constants.
*/ */
Node * Node *
make_operand(char *opname, make_operand(Node *tree, Oid orig_typeId, Oid target_typeId)
Node *tree,
Oid orig_typeId,
Oid target_typeId)
{ {
Node *result; Node *result;
...@@ -95,7 +92,7 @@ make_operand(char *opname, ...@@ -95,7 +92,7 @@ make_operand(char *opname,
* This is where some type conversion happens. * This is where some type conversion happens.
*/ */
Expr * Expr *
make_op(char *opname, Node *ltree, Node *rtree) make_op(List *opname, Node *ltree, Node *rtree)
{ {
Oid ltypeId, Oid ltypeId,
rtypeId; rtypeId;
...@@ -114,7 +111,7 @@ make_op(char *opname, Node *ltree, Node *rtree) ...@@ -114,7 +111,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
{ {
tup = right_oper(opname, ltypeId); tup = right_oper(opname, ltypeId);
opform = (Form_pg_operator) GETSTRUCT(tup); opform = (Form_pg_operator) GETSTRUCT(tup);
left = make_operand(opname, ltree, ltypeId, opform->oprleft); left = make_operand(ltree, ltypeId, opform->oprleft);
right = NULL; right = NULL;
} }
...@@ -123,7 +120,7 @@ make_op(char *opname, Node *ltree, Node *rtree) ...@@ -123,7 +120,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
{ {
tup = left_oper(opname, rtypeId); tup = left_oper(opname, rtypeId);
opform = (Form_pg_operator) GETSTRUCT(tup); opform = (Form_pg_operator) GETSTRUCT(tup);
right = make_operand(opname, rtree, rtypeId, opform->oprright); right = make_operand(rtree, rtypeId, opform->oprright);
left = NULL; left = NULL;
} }
...@@ -132,8 +129,8 @@ make_op(char *opname, Node *ltree, Node *rtree) ...@@ -132,8 +129,8 @@ make_op(char *opname, Node *ltree, Node *rtree)
{ {
tup = oper(opname, ltypeId, rtypeId, false); tup = oper(opname, ltypeId, rtypeId, false);
opform = (Form_pg_operator) GETSTRUCT(tup); opform = (Form_pg_operator) GETSTRUCT(tup);
left = make_operand(opname, ltree, ltypeId, opform->oprleft); left = make_operand(ltree, ltypeId, opform->oprleft);
right = make_operand(opname, rtree, rtypeId, opform->oprright); right = make_operand(rtree, rtypeId, opform->oprright);
} }
newop = makeOper(oprid(tup), /* opno */ newop = makeOper(oprid(tup), /* opno */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -19,6 +19,7 @@
#include "access/heapam.h" #include "access/heapam.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "parser/parse_coerce.h" #include "parser/parse_coerce.h"
#include "parser/parse_func.h" #include "parser/parse_func.h"
...@@ -28,17 +29,106 @@ ...@@ -28,17 +29,106 @@
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/syscache.h" #include "utils/syscache.h"
static Oid *oper_select_candidate(int nargs, Oid *input_typeids, static Oid binary_oper_exact(Oid arg1, Oid arg2,
CandidateList candidates); FuncCandidateList candidates);
static Operator oper_exact(char *op, Oid arg1, Oid arg2); static Oid oper_select_candidate(int nargs, Oid *input_typeids,
static Operator oper_inexact(char *op, Oid arg1, Oid arg2); FuncCandidateList candidates);
static int binary_oper_get_candidates(char *opname, static void op_error(List *op, Oid arg1, Oid arg2);
CandidateList *candidates); static void unary_op_error(List *op, Oid arg, bool is_left_op);
static int unary_oper_get_candidates(char *opname,
CandidateList *candidates,
char rightleft); /*
static void op_error(char *op, Oid arg1, Oid arg2); * LookupOperName
static void unary_op_error(char *op, Oid arg, bool is_left_op); * 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 */ /* Select an ordering operator for the given datatype */
...@@ -47,7 +137,8 @@ any_ordering_op(Oid argtype) ...@@ -47,7 +137,8 @@ any_ordering_op(Oid argtype)
{ {
Oid order_opid; 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)) if (!OidIsValid(order_opid))
elog(ERROR, "Unable to identify an ordering operator '%s' for type '%s'" elog(ERROR, "Unable to identify an ordering operator '%s' for type '%s'"
"\n\tUse an explicit ordering operator or modify the query", "\n\tUse an explicit ordering operator or modify the query",
...@@ -72,116 +163,32 @@ oprfuncid(Operator op) ...@@ -72,116 +163,32 @@ oprfuncid(Operator op)
} }
/* binary_oper_get_candidates() /* binary_oper_exact()
* given opname, find all possible input type pairs for which an operator * Check for an "exact" match to the specified operand types.
* named opname exists. *
* Build a list of the candidate input types. * If one operand is an unknown literal, assume it should be taken to be
* Returns number of candidates found. * the same type as the other operand for this purpose.
*/
static int
binary_oper_get_candidates(char *opname,
CandidateList *candidates)
{
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 == '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++;
}
}
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 static Oid
unary_oper_get_candidates(char *opname, binary_oper_exact(Oid arg1, Oid arg2,
CandidateList *candidates, FuncCandidateList candidates)
char rightleft)
{ {
Relation pg_operator_desc; /* Unspecified type for one of the arguments? then use the other */
SysScanDesc pg_operator_scan; if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid))
HeapTuple tup; arg1 = arg2;
int ncandidates = 0; else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))
ScanKeyData opKey[1]; 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)))
{
Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tup);
if (oper->oprkind == rightleft) while (candidates != NULL)
{ {
CandidateList current_candidate; if (arg1 == candidates->args[0] &&
arg2 == candidates->args[1])
current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList)); return candidates->oid;
current_candidate->args = (Oid *) palloc(sizeof(Oid)); candidates = candidates->next;
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); return InvalidOid;
heap_close(pg_operator_desc, AccessShareLock); }
return ncandidates;
} /* unary_oper_get_candidates() */
/* oper_select_candidate() /* oper_select_candidate()
...@@ -234,13 +241,13 @@ unary_oper_get_candidates(char *opname, ...@@ -234,13 +241,13 @@ unary_oper_get_candidates(char *opname,
* some sense. (see equivalentOpersAfterPromotion for details.) * some sense. (see equivalentOpersAfterPromotion for details.)
* - ay 6/95 * - ay 6/95
*/ */
static Oid * static Oid
oper_select_candidate(int nargs, oper_select_candidate(int nargs,
Oid *input_typeids, Oid *input_typeids,
CandidateList candidates) FuncCandidateList candidates)
{ {
CandidateList current_candidate; FuncCandidateList current_candidate;
CandidateList last_candidate; FuncCandidateList last_candidate;
Oid *current_typeids; Oid *current_typeids;
Oid current_type; Oid current_type;
int unknownOids; int unknownOids;
...@@ -289,9 +296,9 @@ oper_select_candidate(int nargs, ...@@ -289,9 +296,9 @@ oper_select_candidate(int nargs,
/* Done if no candidate or only one candidate survives */ /* Done if no candidate or only one candidate survives */
if (ncandidates == 0) if (ncandidates == 0)
return NULL; return InvalidOid;
if (ncandidates == 1) if (ncandidates == 1)
return candidates->args; return candidates->oid;
/* /*
* Run through all candidates and keep those with the most matches on * Run through all candidates and keep those with the most matches on
...@@ -335,7 +342,7 @@ oper_select_candidate(int nargs, ...@@ -335,7 +342,7 @@ oper_select_candidate(int nargs,
last_candidate->next = NULL; last_candidate->next = NULL;
if (ncandidates == 1) if (ncandidates == 1)
return candidates->args; return candidates->oid;
/* /*
* Still too many candidates? Run through all candidates and keep * Still too many candidates? Run through all candidates and keep
...@@ -382,7 +389,7 @@ oper_select_candidate(int nargs, ...@@ -382,7 +389,7 @@ oper_select_candidate(int nargs,
last_candidate->next = NULL; last_candidate->next = NULL;
if (ncandidates == 1) if (ncandidates == 1)
return candidates->args; return candidates->oid;
/* /*
* Still too many candidates? Now look for candidates which are * Still too many candidates? Now look for candidates which are
...@@ -428,7 +435,7 @@ oper_select_candidate(int nargs, ...@@ -428,7 +435,7 @@ oper_select_candidate(int nargs,
last_candidate->next = NULL; last_candidate->next = NULL;
if (ncandidates == 1) if (ncandidates == 1)
return candidates->args; return candidates->oid;
/* /*
* Still too many candidates? Try assigning types for the unknown * Still too many candidates? Try assigning types for the unknown
...@@ -467,7 +474,7 @@ oper_select_candidate(int nargs, ...@@ -467,7 +474,7 @@ oper_select_candidate(int nargs,
nmatch++; nmatch++;
} }
if (nmatch == nargs) if (nmatch == nargs)
return current_typeids; return current_candidate->oid;
} }
} }
...@@ -602,87 +609,12 @@ oper_select_candidate(int nargs, ...@@ -602,87 +609,12 @@ oper_select_candidate(int nargs,
} }
if (ncandidates == 1) 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_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 /* oper() -- search for a binary operator
* Given operator name, types of arg1 and arg2, return oper struct. * Given operator name, types of arg1 and arg2, return oper struct.
* *
...@@ -697,22 +629,48 @@ oper_inexact(char *op, Oid arg1, Oid arg2) ...@@ -697,22 +629,48 @@ oper_inexact(char *op, Oid arg1, Oid arg2)
* must ReleaseSysCache() the entry when done with it. * must ReleaseSysCache() the entry when done with it.
*/ */
Operator 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... */ /* Get binary operators of given name */
if (HeapTupleIsValid(tup = oper_exact(opname, ltypeId, rtypeId))) clist = OpernameGetCandidates(opname, 'b');
return (Operator) tup;
/* try to find a match on likely candidates... */ /* No operators found? Then fail... */
if (HeapTupleIsValid(tup = oper_inexact(opname, ltypeId, rtypeId))) if (clist != NULL)
return (Operator) tup; {
/*
* 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); op_error(opname, ltypeId, rtypeId);
return (Operator) NULL; return (Operator) tup;
} }
/* compatible_oper() /* compatible_oper()
...@@ -723,7 +681,7 @@ oper(char *opname, Oid ltypeId, Oid rtypeId, bool noError) ...@@ -723,7 +681,7 @@ oper(char *opname, Oid ltypeId, Oid rtypeId, bool noError)
* are accepted). Otherwise, the semantics are the same. * are accepted). Otherwise, the semantics are the same.
*/ */
Operator Operator
compatible_oper(char *op, Oid arg1, Oid arg2, bool noError) compatible_oper(List *op, Oid arg1, Oid arg2, bool noError)
{ {
Operator optup; Operator optup;
Form_pg_operator opform; Form_pg_operator opform;
...@@ -755,7 +713,7 @@ compatible_oper(char *op, Oid arg1, Oid arg2, bool noError) ...@@ -755,7 +713,7 @@ compatible_oper(char *op, Oid arg1, Oid arg2, bool noError)
* lookup fails and noError is true. * lookup fails and noError is true.
*/ */
Oid 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; Operator optup;
Oid result; Oid result;
...@@ -777,7 +735,7 @@ compatible_oper_opid(char *op, Oid arg1, Oid arg2, bool noError) ...@@ -777,7 +735,7 @@ compatible_oper_opid(char *op, Oid arg1, Oid arg2, bool noError)
* lookup fails and noError is true. * lookup fails and noError is true.
*/ */
Oid 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; Operator optup;
Oid result; Oid result;
...@@ -805,45 +763,49 @@ compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError) ...@@ -805,45 +763,49 @@ compatible_oper_funcid(char *op, Oid arg1, Oid arg2, bool noError)
* must ReleaseSysCache() the entry when done with it. * must ReleaseSysCache() the entry when done with it.
*/ */
Operator Operator
right_oper(char *op, Oid arg) right_oper(List *op, Oid arg)
{ {
HeapTuple tup; FuncCandidateList clist;
CandidateList candidates; Oid operOid = InvalidOid;
int ncandidates; HeapTuple tup = NULL;
Oid *targetOid;
/* Try for exact match */ /* Find candidates */
tup = SearchSysCache(OPERNAME, clist = OpernameGetCandidates(op, 'r');
PointerGetDatum(op),
ObjectIdGetDatum(arg),
ObjectIdGetDatum(InvalidOid),
CharGetDatum('r'));
if (!HeapTupleIsValid(tup)) if (clist != NULL)
{ {
/* Try for inexact matches */ /*
ncandidates = unary_oper_get_candidates(op, &candidates, 'r'); * First, quickly check to see if there is an exactly matching
if (ncandidates == 0) * operator (there can be only one such entry in the list).
unary_op_error(op, arg, FALSE); */
else 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 * We must run oper_select_candidate even if only one
* candidate, otherwise we may falsely return a * candidate, otherwise we may falsely return a
* non-type-compatible operator. * non-type-compatible operator.
*/ */
targetOid = oper_select_candidate(1, &arg, candidates); operOid = oper_select_candidate(1, &arg, clist);
if (targetOid != NULL) }
tup = SearchSysCache(OPERNAME, if (OidIsValid(operOid))
PointerGetDatum(op), tup = SearchSysCache(OPEROID,
ObjectIdGetDatum(targetOid[0]), ObjectIdGetDatum(operOid),
ObjectIdGetDatum(InvalidOid), 0, 0, 0);
CharGetDatum('r'));
} }
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
unary_op_error(op, arg, FALSE); unary_op_error(op, arg, FALSE);
}
return (Operator) tup; return (Operator) tup;
} /* right_oper() */ } /* right_oper() */
...@@ -861,45 +823,54 @@ right_oper(char *op, Oid arg) ...@@ -861,45 +823,54 @@ right_oper(char *op, Oid arg)
* must ReleaseSysCache() the entry when done with it. * must ReleaseSysCache() the entry when done with it.
*/ */
Operator Operator
left_oper(char *op, Oid arg) left_oper(List *op, Oid arg)
{ {
HeapTuple tup; FuncCandidateList clist;
CandidateList candidates; Oid operOid = InvalidOid;
int ncandidates; HeapTuple tup = NULL;
Oid *targetOid;
/* Try for exact match */ /* Find candidates */
tup = SearchSysCache(OPERNAME, clist = OpernameGetCandidates(op, 'l');
PointerGetDatum(op),
ObjectIdGetDatum(InvalidOid),
ObjectIdGetDatum(arg),
CharGetDatum('l'));
if (!HeapTupleIsValid(tup)) if (clist != NULL)
{ {
/* Try for inexact matches */ /*
ncandidates = unary_oper_get_candidates(op, &candidates, 'l'); * First, quickly check to see if there is an exactly matching
if (ncandidates == 0) * operator (there can be only one such entry in the list).
unary_op_error(op, arg, TRUE); *
else * 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 * We must run oper_select_candidate even if only one
* candidate, otherwise we may falsely return a * candidate, otherwise we may falsely return a
* non-type-compatible operator. * non-type-compatible operator.
*/ */
targetOid = oper_select_candidate(1, &arg, candidates); operOid = oper_select_candidate(1, &arg, clist);
if (targetOid != NULL) }
tup = SearchSysCache(OPERNAME, if (OidIsValid(operOid))
PointerGetDatum(op), tup = SearchSysCache(OPEROID,
ObjectIdGetDatum(InvalidOid), ObjectIdGetDatum(operOid),
ObjectIdGetDatum(targetOid[0]), 0, 0, 0);
CharGetDatum('l'));
} }
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
unary_op_error(op, arg, TRUE); unary_op_error(op, arg, TRUE);
}
return (Operator) tup; return (Operator) tup;
} /* left_oper() */ } /* left_oper() */
...@@ -910,19 +881,22 @@ left_oper(char *op, Oid arg) ...@@ -910,19 +881,22 @@ left_oper(char *op, Oid arg)
* is not found. * is not found.
*/ */
static void static void
op_error(char *op, Oid arg1, Oid arg2) op_error(List *op, Oid arg1, Oid arg2)
{ {
if (!typeidIsValid(arg1)) if (!typeidIsValid(arg1))
elog(ERROR, "Left hand side of operator '%s' has an unknown type" 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)) if (!typeidIsValid(arg2))
elog(ERROR, "Right hand side of operator %s has an unknown type" 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'" 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", "\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() /* unary_op_error()
...@@ -930,28 +904,28 @@ op_error(char *op, Oid arg1, Oid arg2) ...@@ -930,28 +904,28 @@ op_error(char *op, Oid arg1, Oid arg2)
* is not found. * is not found.
*/ */
static void 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 (!typeidIsValid(arg))
{ {
if (is_left_op) if (is_left_op)
elog(ERROR, "operand of prefix operator '%s' has an unknown type" elog(ERROR, "operand of prefix operator '%s' has an unknown type"
"\n\t(probably an invalid column reference)", "\n\t(probably an invalid column reference)",
op); NameListToString(op));
else else
elog(ERROR, "operand of postfix operator '%s' has an unknown type" elog(ERROR, "operand of postfix operator '%s' has an unknown type"
"\n\t(probably an invalid column reference)", "\n\t(probably an invalid column reference)",
op); NameListToString(op));
} }
else else
{ {
if (is_left_op) if (is_left_op)
elog(ERROR, "Unable to identify a prefix operator '%s' for type '%s'" elog(ERROR, "Unable to identify a prefix operator '%s' for type '%s'"
"\n\tYou may need to add parentheses or an explicit cast", "\n\tYou may need to add parentheses or an explicit cast",
op, format_type_be(arg)); NameListToString(op), format_type_be(arg));
else else
elog(ERROR, "Unable to identify a postfix operator '%s' for type '%s'" elog(ERROR, "Unable to identify a postfix operator '%s' for type '%s'"
"\n\tYou may need to add parentheses or an explicit cast", "\n\tYou may need to add parentheses or an explicit cast",
op, format_type_be(arg)); NameListToString(op), format_type_be(arg));
} }
} }
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 2000-2001, PostgreSQL Global Development Group * Portions Copyright (c) 2000-2001, PostgreSQL Global Development Group
* Copyright 1999 Jan Wieck * 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 @@ ...@@ -36,6 +36,7 @@
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "executor/spi_priv.h" #include "executor/spi_priv.h"
#include "parser/parse_oper.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "miscadmin.h" #include "miscadmin.h"
...@@ -3338,27 +3339,20 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue) ...@@ -3338,27 +3339,20 @@ ri_AttributesEqual(Oid typeid, Datum oldvalue, Datum newvalue)
HASH_FIND, NULL); HASH_FIND, NULL);
/* /*
* If not found, lookup the OPERNAME system cache for it to get the * If not found, lookup the operator, then do the function manager
* func OID, then do the function manager lookup, and remember that * lookup, and remember that info.
* info.
*/ */
if (!entry) if (!entry)
{ {
HeapTuple opr_tup;
Oid opr_proc; Oid opr_proc;
FmgrInfo finfo; FmgrInfo finfo;
opr_tup = SearchSysCache(OPERNAME, opr_proc = compatible_oper_funcid(makeList1(makeString("=")),
PointerGetDatum("="), typeid, typeid, true);
ObjectIdGetDatum(typeid), if (!OidIsValid(opr_proc))
ObjectIdGetDatum(typeid),
CharGetDatum('b'));
if (!HeapTupleIsValid(opr_tup))
elog(ERROR, elog(ERROR,
"ri_AttributesEqual(): cannot find '=' operator for type %u", "ri_AttributesEqual(): cannot find '=' operator for type %u",
typeid); typeid);
opr_proc = ((Form_pg_operator) GETSTRUCT(opr_tup))->oprcode;
ReleaseSysCache(opr_tup);
/* /*
* Since fmgr_info could fail, call it *before* creating the * Since fmgr_info could fail, call it *before* creating the
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -74,6 +74,7 @@
#include "access/heapam.h" #include "access/heapam.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_statistic.h" #include "catalog/pg_statistic.h"
...@@ -3285,14 +3286,15 @@ string_lessthan(const char *str1, const char *str2, Oid datatype) ...@@ -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 */ /* 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 static Oid
find_operator(const char *opname, Oid datatype) find_operator(const char *opname, Oid datatype)
{ {
return GetSysCacheOid(OPERNAME, return GetSysCacheOid(OPERNAMENSP,
PointerGetDatum(opname), PointerGetDatum(opname),
ObjectIdGetDatum(datatype), ObjectIdGetDatum(datatype),
ObjectIdGetDatum(datatype), ObjectIdGetDatum(datatype),
CharGetDatum('b')); ObjectIdGetDatum(PG_CATALOG_NAMESPACE));
} }
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 * NOTES
* Eventually, the index information should go through here, too. * 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) ...@@ -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 * ltype ">" rtype) for an operator previously determined to be
* mergejoinable. Optionally, fetches the regproc ids of these * mergejoinable. Optionally, fetches the regproc ids of these
* operators, as well as their operator OIDs. * 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 void
op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop, op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
...@@ -389,11 +385,9 @@ op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop, ...@@ -389,11 +385,9 @@ op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
{ {
HeapTuple tp; HeapTuple tp;
Form_pg_operator optup; 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, tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno), ObjectIdGetDatum(opno),
...@@ -401,44 +395,23 @@ op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop, ...@@ -401,44 +395,23 @@ op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
if (!HeapTupleIsValid(tp)) /* shouldn't happen */ if (!HeapTupleIsValid(tp)) /* shouldn't happen */
elog(ERROR, "op_mergejoin_crossops: operator %u not found", opno); elog(ERROR, "op_mergejoin_crossops: operator %u not found", opno);
optup = (Form_pg_operator) GETSTRUCT(tp); optup = (Form_pg_operator) GETSTRUCT(tp);
oprleft = optup->oprleft; *ltop = optup->oprltcmpop;
oprright = optup->oprright; *gtop = optup->oprgtcmpop;
ReleaseSysCache(tp); ReleaseSysCache(tp);
/* /* Check < op provided */
* Look up the "<" operator with the same input types. If there isn't if (!OidIsValid(*ltop))
* one, whoever marked the "=" operator mergejoinable was a loser.
*/
tp = SearchSysCache(OPERNAME,
PointerGetDatum("<"),
ObjectIdGetDatum(oprleft),
ObjectIdGetDatum(oprright),
CharGetDatum('b'));
if (!HeapTupleIsValid(tp))
elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching < operator", elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching < operator",
opno); opno);
optup = (Form_pg_operator) GETSTRUCT(tp);
*ltop = tp->t_data->t_oid;
if (ltproc) if (ltproc)
*ltproc = optup->oprcode; *ltproc = get_opcode(*ltop);
ReleaseSysCache(tp);
/* /* Check > op provided */
* And the same for the ">" operator. if (!OidIsValid(*gtop))
*/
tp = SearchSysCache(OPERNAME,
PointerGetDatum(">"),
ObjectIdGetDatum(oprleft),
ObjectIdGetDatum(oprright),
CharGetDatum('b'));
if (!HeapTupleIsValid(tp))
elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching > operator", elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching > operator",
opno); opno);
optup = (Form_pg_operator) GETSTRUCT(tp);
*gtop = tp->t_data->t_oid;
if (gtproc) if (gtproc)
*gtproc = optup->oprcode; *gtproc = get_opcode(*gtop);
ReleaseSysCache(tp);
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* These routines allow the parser/planner/executor to perform * These routines allow the parser/planner/executor to perform
...@@ -273,15 +273,15 @@ static const struct cachedesc cacheinfo[] = { ...@@ -273,15 +273,15 @@ static const struct cachedesc cacheinfo[] = {
0, 0,
0 0
}}, }},
{OperatorRelationName, /* OPERNAME */ {OperatorRelationName, /* OPERNAMENSP */
OperatorNameIndex, OperatorNameNspIndex,
0, 0,
4, 4,
{ {
Anum_pg_operator_oprname, Anum_pg_operator_oprname,
Anum_pg_operator_oprleft, Anum_pg_operator_oprleft,
Anum_pg_operator_oprright, Anum_pg_operator_oprright,
Anum_pg_operator_oprkind Anum_pg_operator_oprnamespace
}}, }},
{OperatorRelationName, /* OPEROID */ {OperatorRelationName, /* OPEROID */
OperatorOidIndex, OperatorOidIndex,
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200204151 #define CATALOG_VERSION_NO 200204161
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -74,7 +74,7 @@
#define NamespaceOidIndex "pg_namespace_oid_index" #define NamespaceOidIndex "pg_namespace_oid_index"
#define OpclassAmNameIndex "pg_opclass_am_name_index" #define OpclassAmNameIndex "pg_opclass_am_name_index"
#define OpclassOidIndex "pg_opclass_oid_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 OperatorOidIndex "pg_operator_oid_index"
#define ProcedureNameNspIndex "pg_proc_proname_args_nsp_index" #define ProcedureNameNspIndex "pg_proc_proname_args_nsp_index"
#define ProcedureOidIndex "pg_proc_oid_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_ ...@@ -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_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_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_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_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)); 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 */ /* This following index is not used for a cache and is not unique */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -43,6 +43,8 @@ extern Oid TypenameGetTypid(const char *typname);
extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs); extern FuncCandidateList FuncnameGetCandidates(List *names, int nargs);
extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind);
extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p); extern Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p);
extern RangeVar *makeRangeVarFromNameList(List *names); extern RangeVar *makeRangeVarFromNameList(List *names);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -42,7 +42,7 @@ extern void CreateFunction(ProcedureStmt *stmt);
extern void RemoveFunction(List *functionName, List *argTypes); extern void RemoveFunction(List *functionName, List *argTypes);
extern void DefineOperator(List *names, List *parameters); extern void DefineOperator(List *names, List *parameters);
extern void RemoveOperator(char *operatorName, extern void RemoveOperator(List *operatorName,
TypeName *typeName1, TypeName *typeName2); TypeName *typeName1, TypeName *typeName2);
extern void DefineAggregate(List *names, List *parameters); extern void DefineAggregate(List *names, List *parameters);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -16,6 +16,11 @@
#include "nodes/parsenodes.h" #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, extern Oper *makeOper(Oid opno,
Oid opid, Oid opid,
Oid opresulttype); Oid opresulttype);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -158,7 +158,7 @@ typedef struct A_Expr
{ {
NodeTag type; NodeTag type;
int oper; /* type of operation (OP,OR,AND,NOT) */ 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 *lexpr; /* left argument */
Node *rexpr; /* right argument */ Node *rexpr; /* right argument */
} A_Expr; } A_Expr;
...@@ -373,7 +373,7 @@ typedef struct InsertDefault ...@@ -373,7 +373,7 @@ typedef struct InsertDefault
typedef struct SortGroupBy typedef struct SortGroupBy
{ {
NodeTag type; NodeTag type;
char *useOp; /* operator to use */ List *useOp; /* operator to use */
Node *node; /* Expression */ Node *node; /* Expression */
} SortGroupBy; } SortGroupBy;
...@@ -1189,7 +1189,7 @@ typedef struct RemoveFuncStmt ...@@ -1189,7 +1189,7 @@ typedef struct RemoveFuncStmt
typedef struct RemoveOperStmt typedef struct RemoveOperStmt
{ {
NodeTag type; NodeTag type;
char *opname; /* operator to drop */ List *opname; /* operator to drop */
List *args; /* types of the arguments */ List *args; /* types of the arguments */
} RemoveOperStmt; } RemoveOperStmt;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -28,16 +28,6 @@ typedef struct _InhPaths
Oid *supervec; /* vector of superclasses */ Oid *supervec; /* vector of superclasses */
} InhPaths; } 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 */ /* Result codes for func_get_detail */
typedef enum typedef enum
{ {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 ...@@ -51,9 +51,8 @@ typedef struct ParseState
} ParseState; } ParseState;
extern ParseState *make_parsestate(ParseState *parentParseState); extern ParseState *make_parsestate(ParseState *parentParseState);
extern Expr *make_op(char *opname, Node *ltree, Node *rtree); extern Expr *make_op(List *opname, Node *ltree, Node *rtree);
extern Node *make_operand(char *opname, Node *tree, extern Node *make_operand(Node *tree, Oid orig_typeId, Oid target_typeId);
Oid orig_typeId, Oid target_typeId);
extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno); extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno);
extern ArrayRef *transformArraySubscripts(ParseState *pstate, extern ArrayRef *transformArraySubscripts(ParseState *pstate,
Node *arrayBase, Node *arrayBase,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -15,25 +15,31 @@
#define PARSE_OPER_H #define PARSE_OPER_H
#include "access/htup.h" #include "access/htup.h"
#include "nodes/parsenodes.h"
typedef HeapTuple Operator; 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 */ /* Routines to find operators matching a name and given input types */
/* NB: the selected operator may require coercion of the 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 oper(List *op, Oid arg1, Oid arg2, bool noError);
extern Operator right_oper(char *op, Oid arg); extern Operator right_oper(List *op, Oid arg);
extern Operator left_oper(char *op, Oid arg); extern Operator left_oper(List *op, Oid arg);
/* Routines to find operators that DO NOT require coercion --- ie, their */ /* Routines to find operators that DO NOT require coercion --- ie, their */
/* input types are either exactly as given, or binary-compatible */ /* 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 */ /* currently no need for compatible_left_oper/compatible_right_oper */
/* Convenience routines that call compatible_oper() and return either */ /* Convenience routines that call compatible_oper() and return either */
/* the operator OID or the underlying function OID, or InvalidOid if fail */ /* 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_opid(List *op, Oid arg1, Oid arg2, bool noError);
extern Oid compatible_oper_funcid(char *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 */ /* Convenience routine that packages a specific call on compatible_oper */
extern Oid any_ordering_op(Oid argtype); extern Oid any_ordering_op(Oid argtype);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 @@ ...@@ -46,7 +46,7 @@
#define LANGOID 15 #define LANGOID 15
#define NAMESPACENAME 16 #define NAMESPACENAME 16
#define NAMESPACEOID 17 #define NAMESPACEOID 17
#define OPERNAME 18 #define OPERNAMENSP 18
#define OPEROID 19 #define OPEROID 19
#define PROCNAMENSP 20 #define PROCNAMENSP 20
#define PROCOID 21 #define PROCOID 21
......
...@@ -173,13 +173,13 @@ drop operator; ...@@ -173,13 +173,13 @@ drop operator;
ERROR: parser: parse error at or near ";" ERROR: parser: parse error at or near ";"
-- bad operator name -- bad operator name
drop operator equals; drop operator equals;
ERROR: parser: parse error at or near "equals" ERROR: parser: parse error at or near ";"
-- missing type list -- missing type list
drop operator ===; drop operator ===;
ERROR: parser: parse error at or near ";" ERROR: parser: parse error at or near ";"
-- missing parentheses -- missing parentheses
drop operator int4, int4; drop operator int4, int4;
ERROR: parser: parse error at or near "int4" ERROR: parser: parse error at or near ","
-- missing operator name -- missing operator name
drop operator (int4, int4); drop operator (int4, int4);
ERROR: parser: parse error at or near "(" ERROR: parser: parse error at or near "("
...@@ -191,7 +191,7 @@ drop operator === (int4); ...@@ -191,7 +191,7 @@ drop operator === (int4);
ERROR: parser: argument type missing (use NONE for unary operators) ERROR: parser: argument type missing (use NONE for unary operators)
-- no such operator by that name -- no such operator by that name
drop operator === (int4, int4); 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 -- no such type1
drop operator = (nonesuch); drop operator = (nonesuch);
ERROR: parser: argument type missing (use NONE for unary operators) ERROR: parser: argument type missing (use NONE for unary operators)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment