postgresql/doc/src/sgml/ref/create_operator.sgml

432 lines
12 KiB
Plaintext
Raw Normal View History

<REFENTRY ID="SQL-CREATEOPERATOR">
<REFMETA>
<REFENTRYTITLE>
CREATE OPERATOR
</REFENTRYTITLE>
<REFMISCINFO>SQL - Language Statements</REFMISCINFO>
</REFMETA>
<REFNAMEDIV>
<REFNAME>
CREATE OPERATOR
</REFNAME>
<REFPURPOSE>
Defines a new user operator
</REFPURPOSE>
</refnamediv>
<REFSYNOPSISDIV>
<REFSYNOPSISDIVINFO>
1998-09-16 16:43:12 +02:00
<DATE>1998-09-09</DATE>
</REFSYNOPSISDIVINFO>
<SYNOPSIS>
CREATE OPERATOR <replaceable>name</replaceable> (
PROCEDURE = <replaceable class="parameter">func_name</replaceable>
1998-09-16 16:43:12 +02:00
[, LEFTARG = <replaceable class="parameter">type1</replaceable> ]
[, RIGHTARG = <replaceable class="parameter">type2</replaceable> ]
[, COMMUTATOR = <replaceable class="parameter">com_op</replaceable> ]
[, NEGATOR = <replaceable class="parameter">neg_op</replaceable> ]
[, RESTRICT = <replaceable class="parameter">res_proc</replaceable> ]
[, HASHES ]
[, JOIN = <replaceable class="parameter">join_proc</replaceable> ]
[, SORT = <replaceable class="parameter">sort_op</replaceable> [, ...] ]
)
</SYNOPSIS>
<REFSECT2 ID="R2-SQL-CREATEOPERATOR-1">
<REFSECT2INFO>
1998-09-16 16:43:12 +02:00
<DATE>1998-09-09</DATE>
</REFSECT2INFO>
<TITLE>
Inputs
</TITLE>
<PARA>
</PARA>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<replaceable class="parameter">name</replaceable>
</TERM>
<LISTITEM>
<PARA>
1998-09-16 16:43:12 +02:00
The operator to be defined. See below for allowable characters.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
1998-09-16 16:43:12 +02:00
<replaceable class="parameter">func_name</replaceable>
</TERM>
<LISTITEM>
<PARA>
1998-09-16 16:43:12 +02:00
The function used to implement this operator.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
1998-09-16 16:43:12 +02:00
<replaceable class="parameter">type1</replaceable>
</TERM>
<LISTITEM>
<PARA>
1998-09-16 16:43:12 +02:00
The type for the left-hand side of the operator, if any. This option would be
omitted for a right-unary operator.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
1998-09-16 16:43:12 +02:00
<replaceable class="parameter">type2</replaceable>
</TERM>
<LISTITEM>
<PARA>
1998-09-16 16:43:12 +02:00
The type for the right-hand side of the operator, if any. This option would be
omitted for a left-unary operator.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<replaceable class="parameter">com_op</replaceable>
</TERM>
<LISTITEM>
<PARA>
1998-09-16 16:43:12 +02:00
The corresponding commutative operator.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<replaceable class="parameter">neg_op</replaceable>
</TERM>
<LISTITEM>
<PARA>
1998-09-16 16:43:12 +02:00
The corresponding negation operator.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<replaceable class="parameter">res_proc</replaceable>
</TERM>
<LISTITEM>
<PARA>
1998-09-16 16:43:12 +02:00
The corresponding restriction operator.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
HASHES
</TERM>
<LISTITEM>
<PARA>
This operator can support a hash-join algorithm.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<replaceable class="parameter">join_proc</replaceable>
</TERM>
<LISTITEM>
<PARA>
1998-09-16 16:43:12 +02:00
Procedure supporting table joins.
</PARA>
</LISTITEM>
</VARLISTENTRY>
<VARLISTENTRY>
<TERM>
<replaceable class="parameter">sort_op</replaceable>
</TERM>
<LISTITEM>
<PARA>
1998-09-16 16:43:12 +02:00
Operator to use for sorting.
</PARA>
</LISTITEM>
</VARLISTENTRY>
</variablelist>
1998-09-16 16:43:12 +02:00
</REFSECT2>
<REFSECT2 ID="R2-SQL-CREATEOPERATOR-2">
<REFSECT2INFO>
1998-09-16 16:43:12 +02:00
<DATE>1998-09-09</DATE>
</REFSECT2INFO>
<TITLE>
Outputs
</TITLE>
<PARA>
<VARIABLELIST>
<VARLISTENTRY>
<TERM>
<ReturnValue>CREATE</ReturnValue>
</TERM>
<LISTITEM>
<PARA>
Message returned if the operator is successfully created.
</para>
</listitem>
</varlistentry>
</VARIABLELIST>
</para>
</REFSECT2>
</REFSYNOPSISDIV>
<REFSECT1 ID="R1-SQL-CREATEOPERATOR-1">
<REFSECT1INFO>
1998-09-16 16:43:12 +02:00
<DATE>1998-09-09</DATE>
</REFSECT1INFO>
<TITLE>
Description
</TITLE>
<PARA>
<command>CREATE OPERATOR</command> defines a new operator,
<replaceable class="parameter">name</replaceable>.
The user who defines an operator becomes its owner.
</para>
<para>
The operator <replaceable class="parameter">name</replaceable>
is a sequence of up to thirty two (32) characters in any combination
from the following:
<literallayout>
+ - * / &lt; &gt; = ~ ! @ # % ^ & | ` ? $ :
</literallayout>
<note>
<para>
No alphabetic characters are allowed in an operator name.
This enables <productname>Postgres</productname> to parse SQL input
into tokens without requiring spaces between each token.
</para>
</note>
</para>
<para>
1998-09-16 16:43:12 +02:00
The operator "!=" is mapped to "&lt;&gt;" on input, so they are
therefore equivalent.
</para>
<para>
1998-09-16 16:43:12 +02:00
At least one of LEFTARG and RIGHTARG must be defined. For
binary operators, both should be defined. For right unary
1998-09-16 16:43:12 +02:00
operators, only LEFTARG should be defined, while for left
unary operators only RIGHTARG should be defined.
</para>
<para>
Also, the
<replaceable class="parameter">func_name</replaceable> procedure must have
1998-09-16 16:43:12 +02:00
been previously defined using <command>CREATE FUNCTION</command> and must
be defined to accept the correct number of arguments
(either one or two).
</para>
<para>
1998-09-16 16:43:12 +02:00
The commutator operator is present so that
<productname>Postgres</productname> can
1998-09-16 16:43:12 +02:00
reverse the order of the operands if it wishes.
For example, the operator area-less-than, &lt;&lt;&lt;,
would have a commutator
operator, area-greater-than, &gt;&gt;&gt;.
Hence, the query optimizer could freely convert:
<programlisting>
"0,0,1,1"::box &gt;&gt;&gt; MYBOXES.description
</programlisting>
to
<programlisting>
MYBOXES.description &lt;&lt;&lt; "0,0,1,1"::box</programlisting>
</para>
<para>
This allows the execution code to always use the latter
representation and simplifies the query optimizer some
what.
</para>
<para>
Suppose that an
1998-09-16 16:43:12 +02:00
operator, area-equal, ===, exists, as well as an area not
equal, !==.
The negator operator allows the query optimizer to convert
<programlisting>
NOT MYBOXES.description === "0,0,1,1"::box
</programlisting>
to
<programlisting>
MYBOXES.description !== "0,0,1,1"::box
</programlisting>
</para>
<para>
1998-09-16 16:43:12 +02:00
If a commutator operator name is supplied,
<productname>Postgres</productname>
searches for it in the catalog. If it is found and it
does not yet have a commutator itself, then the commutator's
entry is updated to have the current (new) operator
as its commutator. This applies to the negator, as well.
</para>
<para>
This is to allow the definition of two operators that are
the commutators or the negators of each other. The first
operator should be defined without a commutator or negator
(as appropriate). When the second operator is defined,
name the first as the commutator or negator. The first
will be updated as a side effect.
</para>
<para>
The next two specifications are present to support the
1998-09-16 16:43:12 +02:00
query optimizer in performing joins.
<productname>Postgres</productname> can always
evaluate a join (i.e., processing a clause with two tuple
variables separated by an operator that returns a boolean)
1998-09-16 16:43:12 +02:00
by iterative substitution [WONG76].
In addition, <productname>Postgres</productname>
is planning on implementing a hash-join algorithm along
the lines of [SHAP86]; however, it must know whether this
1998-09-16 16:43:12 +02:00
strategy is applicable.
For example, a hash-join
algorithm is usable for a clause of the form:
<programlisting>
MYBOXES.description === MYBOXES2.description
</programlisting>
but not for a clause of the form:
<programlisting>
MYBOXES.description &lt;&lt;&lt; MYBOXES2.description.
</programlisting>
1998-09-16 16:43:12 +02:00
The HASHES flag gives the needed information to the query
optimizer concerning whether a hash join strategy is
usable for the operator in question.</para>
<para>
Similarly, the two sort operators indicate to the query
optimizer whether merge-sort is a usable join strategy and
what operators should be used to sort the two operand
classes. For the === clause above, the optimizer must
1998-09-16 16:43:12 +02:00
sort both relations using the operator, &lt;&lt;&lt;. On the other
hand, merge-sort is not usable with the clause:
<programlisting>
MYBOXES.description &lt;&lt;&lt; MYBOXES2.description
</programlisting>
</para>
<para>
1998-09-16 16:43:12 +02:00
If other join strategies are found to be practical,
<productname>Postgres</productname>
will change the optimizer and run-time system to use
them and will require additional specification when an
operator is defined. Fortunately, the research community
invents new join strategies infrequently, and the added
generality of user-defined join strategies was not felt to
be worth the complexity involved.
</para>
<para>
The last two pieces of the specification are present so
the query optimizer can estimate result sizes. If a
clause of the form:
<programlisting>
MYBOXES.description &lt;&lt;&lt; "0,0,1,1"::box
</programlisting>
1998-09-16 16:43:12 +02:00
is present in the qualification,
then <productname>Postgres</productname> may have to
estimate the fraction of the instances in MYBOXES that
1998-09-16 16:43:12 +02:00
satisfy the clause. The function
<replaceable class="parameter">res_proc</replaceable>
must be a registered function (meaning it is already defined using
define function(l)) which accepts one argument of the correct
data type and returns a floating point number. The
query optimizer simply calls this function, passing the
parameter "0,0,1,1" and multiplies the result by the relation
size to get the desired expected number of instances.
</para>
<para>
Similarly, when the operands of the operator both contain
instance variables, the query optimizer must estimate the
size of the resulting join. The function join_proc will
return another floating point number which will be multiplied
by the cardinalities of the two classes involved to
compute the desired expected result size.
</para>
<para>
The difference between the function
<programlisting>
my_procedure_1 (MYBOXES.description, "0,0,1,1"::box)
</programlisting>
and the operator
<programlisting>
MYBOXES.description === "0,0,1,1"::box
</programlisting>
1998-09-16 16:43:12 +02:00
is that <productname>Postgres</productname>
attempts to optimize operators and can
decide to use an index to restrict the search space when
operators are involved. However, there is no attempt to
optimize functions, and they are performed by brute force.
Moreover, functions can have any number of arguments while
operators are restricted to one or two.
</PARA>
<REFSECT2 ID="R2-SQL-CREATEOPERATOR-3">
<REFSECT2INFO>
1998-09-16 16:43:12 +02:00
<DATE>1998-09-09</DATE>
</REFSECT2INFO>
<TITLE>
Notes
</TITLE>
<PARA>
1998-09-16 16:43:12 +02:00
Refer to the chapter on operators in the
<citetitle>PostgreSQL User's Guide</citetitle>
for further information.
1998-09-16 16:43:12 +02:00
Refer to <command>DROP OPERATOR</command> to delete
user-defined operators from a database.
</para>
</REFSECT2>
</refsect1>
<REFSECT1 ID="R1-SQL-CREATEOPERATOR-2">
<TITLE>
Usage
</TITLE>
<PARA>The following command defines a new operator,
area-equality, for the BOX data type.
</PARA>
<ProgramListing>
CREATE OPERATOR === (
LEFTARG = box,
RIGHTARG = box,
PROCEDURE = area_equal_procedure,
COMMUTATOR = ===,
NEGATOR = !==,
RESTRICT = area_restriction_procedure,
HASHES,
JOIN = area-join-procedure,
SORT = <<<, <<<)
</ProgramListing>
</REFSECT1>
<REFSECT1 ID="R1-SQL-CREATEOPERATOR-3">
<TITLE>
Compatibility
</TITLE>
<PARA>
1998-09-16 16:43:12 +02:00
CREATE OPERATOR is a <productname>Postgres</productname> extension.
</PARA>
<REFSECT2 ID="R2-SQL-CREATEOPERATOR-4">
<REFSECT2INFO>
1998-09-16 16:43:12 +02:00
<DATE>1998-09-09</DATE>
</REFSECT2INFO>
<TITLE>
SQL92
</TITLE>
<PARA>
1998-09-16 16:43:12 +02:00
There is no CREATE OPERATOR statement in <acronym>SQL92</acronym>.
</PARA>
</refsect2>
</refsect1>
</REFENTRY>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->