Commit a33cf104 authored by Tom Lane's avatar Tom Lane

Add CREATE/ALTER/DROP OPERATOR FAMILY commands, also COMMENT ON OPERATOR

FAMILY; and add FAMILY option to CREATE OPERATOR CLASS to allow adding a
class to a pre-existing family.  Per previous discussion.  Man, what a
tedious lot of cutting and pasting ...
parent 8502b685
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.68 2006/09/18 19:54:01 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.69 2007/01/23 05:07:16 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
Complete list of usable sgml source files in this directory. Complete list of usable sgml source files in this directory.
--> -->
...@@ -16,6 +16,7 @@ Complete list of usable sgml source files in this directory. ...@@ -16,6 +16,7 @@ Complete list of usable sgml source files in this directory.
<!entity alterLanguage system "alter_language.sgml"> <!entity alterLanguage system "alter_language.sgml">
<!entity alterOperator system "alter_operator.sgml"> <!entity alterOperator system "alter_operator.sgml">
<!entity alterOperatorClass system "alter_opclass.sgml"> <!entity alterOperatorClass system "alter_opclass.sgml">
<!entity alterOperatorFamily system "alter_opfamily.sgml">
<!entity alterRole system "alter_role.sgml"> <!entity alterRole system "alter_role.sgml">
<!entity alterSchema system "alter_schema.sgml"> <!entity alterSchema system "alter_schema.sgml">
<!entity alterSequence system "alter_sequence.sgml"> <!entity alterSequence system "alter_sequence.sgml">
...@@ -45,6 +46,7 @@ Complete list of usable sgml source files in this directory. ...@@ -45,6 +46,7 @@ Complete list of usable sgml source files in this directory.
<!entity createLanguage system "create_language.sgml"> <!entity createLanguage system "create_language.sgml">
<!entity createOperator system "create_operator.sgml"> <!entity createOperator system "create_operator.sgml">
<!entity createOperatorClass system "create_opclass.sgml"> <!entity createOperatorClass system "create_opclass.sgml">
<!entity createOperatorFamily system "create_opfamily.sgml">
<!entity createRole system "create_role.sgml"> <!entity createRole system "create_role.sgml">
<!entity createRule system "create_rule.sgml"> <!entity createRule system "create_rule.sgml">
<!entity createSchema system "create_schema.sgml"> <!entity createSchema system "create_schema.sgml">
...@@ -70,6 +72,7 @@ Complete list of usable sgml source files in this directory. ...@@ -70,6 +72,7 @@ Complete list of usable sgml source files in this directory.
<!entity dropLanguage system "drop_language.sgml"> <!entity dropLanguage system "drop_language.sgml">
<!entity dropOperator system "drop_operator.sgml"> <!entity dropOperator system "drop_operator.sgml">
<!entity dropOperatorClass system "drop_opclass.sgml"> <!entity dropOperatorClass system "drop_opclass.sgml">
<!entity dropOperatorFamily system "drop_opfamily.sgml">
<!entity dropOwned system "drop_owned.sgml"> <!entity dropOwned system "drop_owned.sgml">
<!entity dropRole system "drop_role.sgml"> <!entity dropRole system "drop_role.sgml">
<!entity dropRule system "drop_rule.sgml"> <!entity dropRule system "drop_rule.sgml">
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_opclass.sgml,v 1.7 2006/09/16 00:30:16 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/alter_opclass.sgml,v 1.8 2007/01/23 05:07:17 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -102,6 +102,7 @@ ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="p ...@@ -102,6 +102,7 @@ ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="p
<simplelist type="inline"> <simplelist type="inline">
<member><xref linkend="sql-createopclass" endterm="sql-createopclass-title"></member> <member><xref linkend="sql-createopclass" endterm="sql-createopclass-title"></member>
<member><xref linkend="sql-dropopclass" endterm="sql-dropopclass-title"></member> <member><xref linkend="sql-dropopclass" endterm="sql-dropopclass-title"></member>
<member><xref linkend="sql-alteropfamily" endterm="sql-alteropfamily-title"></member>
</simplelist> </simplelist>
</refsect1> </refsect1>
</refentry> </refentry>
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_opfamily.sgml,v 1.1 2007/01/23 05:07:17 tgl Exp $
PostgreSQL documentation
-->
<refentry id="SQL-ALTEROPFAMILY">
<refmeta>
<refentrytitle id="SQL-ALTEROPFAMILY-TITLE">ALTER OPERATOR FAMILY</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>ALTER OPERATOR FAMILY</refname>
<refpurpose>change the definition of an operator family</refpurpose>
</refnamediv>
<indexterm zone="sql-alteropfamily">
<primary>ALTER OPERATOR FAMILY</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> ADD
{ OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_name</replaceable> ( <replaceable class="parameter">op_type</replaceable>, <replaceable class="parameter">op_type</replaceable> ) [ RECHECK ]
| FUNCTION <replaceable class="parameter">support_number</replaceable> [ ( <replaceable class="parameter">op_type</replaceable> [ , <replaceable class="parameter">op_type</replaceable> ] ) ] <replaceable class="parameter">funcname</replaceable> ( <replaceable class="parameter">argument_type</replaceable> [, ...] )
} [, ... ]
ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> DROP
{ OPERATOR <replaceable class="parameter">strategy_number</replaceable> ( <replaceable class="parameter">op_type</replaceable> [ , <replaceable class="parameter">op_type</replaceable> ] )
| FUNCTION <replaceable class="parameter">support_number</replaceable> ( <replaceable class="parameter">op_type</replaceable> [ , <replaceable class="parameter">op_type</replaceable> ] )
} [, ... ]
ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> RENAME TO <replaceable>newname</replaceable>
ALTER OPERATOR FAMILY <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> OWNER TO <replaceable>newowner</replaceable>
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>ALTER OPERATOR FAMILY</command> changes the definition of
an operator family. You can add operators and support functions
to the family, remove them from the family,
or change the family's name or owner.
</para>
<para>
When operators and support functions are added to a family with
<command>ALTER OPERATOR FAMILY</command>, they are not part of any
specific operator class within the family, but are just <quote>loose</>
within the family. This indicates that these operators and functions
are compatible with the family's semantics, but are not required for
correct functioning of any specific index. (Operators and functions
that are so required should be declared as part of an operator class,
instead; see <xref linkend="sql-createopclass"
endterm="sql-createopclass-title">.)
<productname>PostgreSQL</productname> will allow loose members of a
family to be dropped from the family at any time, but members of an
operator class cannot be dropped without dropping the whole class and
any indexes that depend on it.
Typically, single-data-type operators
and functions are part of operator classes because they are needed to
support an index on that specific data type, while cross-data-type
operators and functions are made loose members of the family.
</para>
<para>
You must be a superuser to use <command>ALTER OPERATOR FAMILY</>.
</para>
</refsect1>
<refsect1>
<title>Parameters</title>
<variablelist>
<varlistentry>
<term><replaceable class="parameter">name</replaceable></term>
<listitem>
<para>
The name (optionally schema-qualified) of an existing operator
family.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">index_method</replaceable></term>
<listitem>
<para>
The name of the index method this operator family is for.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">strategy_number</replaceable></term>
<listitem>
<para>
The index method's strategy number for an operator
associated with the operator family.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">operator_name</replaceable></term>
<listitem>
<para>
The name (optionally schema-qualified) of an operator associated
with the operator family.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">op_type</replaceable></term>
<listitem>
<para>
In an <literal>OPERATOR</> clause,
the operand data type(s) of the operator, or <literal>NONE</> to
signify a left-unary or right-unary operator. Unlike the comparable
syntax in <command>CREATE OPERATOR CLASS</>, the operand data types
must always be specified.
</para>
<para>
In an <literal>ADD FUNCTION</> clause, the operand data type(s) the
function is intended to support, if different from
the input data type(s) of the function. For B-tree and hash indexes
it is not necessary to specify <replaceable
class="parameter">op_type</replaceable> since the function's input
data type(s) are always the correct ones to use. For GIN and GiST
indexes it is necessary to specify the input data type the function
is to be used with.
</para>
<para>
In a <literal>DROP FUNCTION</> clause, the operand data type(s) the
function is intended to support must be specified.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>RECHECK</></term>
<listitem>
<para>
If present, the index is <quote>lossy</> for this operator, and
so the rows retrieved using the index must be rechecked to
verify that they actually satisfy the qualification clause
involving this operator.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">support_number</replaceable></term>
<listitem>
<para>
The index method's support procedure number for a
function associated with the operator family.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">funcname</replaceable></term>
<listitem>
<para>
The name (optionally schema-qualified) of a function that is an
index method support procedure for the operator family.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">argument_types</replaceable></term>
<listitem>
<para>
The parameter data type(s) of the function.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">newname</replaceable></term>
<listitem>
<para>
The new name of the operator family.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">newowner</replaceable></term>
<listitem>
<para>
The new owner of the operator family.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
The <literal>OPERATOR</> and <literal>FUNCTION</>
clauses may appear in any order.
</para>
</refsect1>
<refsect1>
<title>Notes</title>
<para>
Notice that the <literal>DROP</> syntax only specifies the <quote>slot</>
in the operator family, by strategy or support number and input data
type(s). The name of the operator or function occupying the slot is not
mentioned. Also, for <literal>DROP FUNCTION</> the type(s) to specify
are the input data type(s) the function is intended to support; for
GIN and GiST indexes this may have nothing to do with the actual input
argument types of the function.
</para>
<para>
Because the index machinery does not check access permissions on functions
before using them, including a function or operator in an operator family
is tantamount to granting public execute permission on it. This is usually
not an issue for the sorts of functions that are useful in an operator
family.
</para>
<para>
The operators should not be defined by SQL functions. A SQL function
is likely to be inlined into the calling query, which will prevent
the optimizer from recognizing that the query matches an index.
</para>
</refsect1>
<refsect1>
<title>Examples</title>
<para>
The following example command adds cross-data-type operators and
support functions to an operator family that already contains B-tree
operator classes for data types <type>int4</> and <type>int2</>.
</para>
<programlisting>
ALTER OPERATOR FAMILY integer_ops USING btree ADD
-- int4 vs int2
OPERATOR 1 &lt; (int4, int2) ,
OPERATOR 2 &lt;= (int4, int2) ,
OPERATOR 3 = (int4, int2) ,
OPERATOR 4 &gt;= (int4, int2) ,
OPERATOR 5 &gt; (int4, int2) ,
FUNCTION 1 btint42cmp(int4, int2) ,
-- int2 vs int4
OPERATOR 1 &lt; (int2, int4) ,
OPERATOR 2 &lt;= (int2, int4) ,
OPERATOR 3 = (int2, int4) ,
OPERATOR 4 &gt;= (int2, int4) ,
OPERATOR 5 &gt; (int2, int4) ,
FUNCTION 1 btint24cmp(int2, int4) ;
</programlisting>
<para>
To remove these entries again:
</para>
<programlisting>
ALTER OPERATOR FAMILY integer_ops USING btree DROP
-- int4 vs int2
OPERATOR 1 (int4, int2) ,
OPERATOR 2 (int4, int2) ,
OPERATOR 3 (int4, int2) ,
OPERATOR 4 (int4, int2) ,
OPERATOR 5 (int4, int2) ,
FUNCTION 1 (int4, int2) ,
-- int2 vs int4
OPERATOR 1 (int2, int4) ,
OPERATOR 2 (int2, int4) ,
OPERATOR 3 (int2, int4) ,
OPERATOR 4 (int2, int4) ,
OPERATOR 5 (int2, int4) ,
FUNCTION 1 (int2, int4) ;
</programlisting>
</refsect1>
<refsect1>
<title>Compatibility</title>
<para>
There is no <command>ALTER OPERATOR FAMILY</command> statement in
the SQL standard.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-createopfamily" endterm="sql-createopfamily-title"></member>
<member><xref linkend="sql-dropopfamily" endterm="sql-dropopfamily-title"></member>
<member><xref linkend="sql-createopclass" endterm="sql-createopclass-title"></member>
<member><xref linkend="sql-alteropclass" endterm="sql-alteropclass-title"></member>
<member><xref linkend="sql-dropopclass" endterm="sql-dropopclass-title"></member>
</simplelist>
</refsect1>
</refentry>
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/comment.sgml,v 1.33 2006/10/23 18:10:32 petere Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/comment.sgml,v 1.34 2007/01/23 05:07:17 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -35,6 +35,7 @@ COMMENT ON ...@@ -35,6 +35,7 @@ COMMENT ON
LARGE OBJECT <replaceable class="PARAMETER">large_object_oid</replaceable> | LARGE OBJECT <replaceable class="PARAMETER">large_object_oid</replaceable> |
OPERATOR <replaceable class="PARAMETER">op</replaceable> (<replaceable class="PARAMETER">leftoperand_type</replaceable>, <replaceable class="PARAMETER">rightoperand_type</replaceable>) | OPERATOR <replaceable class="PARAMETER">op</replaceable> (<replaceable class="PARAMETER">leftoperand_type</replaceable>, <replaceable class="PARAMETER">rightoperand_type</replaceable>) |
OPERATOR CLASS <replaceable class="PARAMETER">object_name</replaceable> USING <replaceable class="parameter">index_method</replaceable> | OPERATOR CLASS <replaceable class="PARAMETER">object_name</replaceable> USING <replaceable class="parameter">index_method</replaceable> |
OPERATOR FAMILY <replaceable class="PARAMETER">object_name</replaceable> USING <replaceable class="parameter">index_method</replaceable> |
[ PROCEDURAL ] LANGUAGE <replaceable class="PARAMETER">object_name</replaceable> | [ PROCEDURAL ] LANGUAGE <replaceable class="PARAMETER">object_name</replaceable> |
ROLE <replaceable class="PARAMETER">object_name</replaceable> | ROLE <replaceable class="PARAMETER">object_name</replaceable> |
RULE <replaceable class="PARAMETER">rule_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> | RULE <replaceable class="PARAMETER">rule_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
...@@ -92,7 +93,7 @@ COMMENT ON ...@@ -92,7 +93,7 @@ COMMENT ON
<para> <para>
The name of the object to be commented. Names of tables, The name of the object to be commented. Names of tables,
aggregates, domains, functions, indexes, operators, operator classes, aggregates, domains, functions, indexes, operators, operator classes,
sequences, types, and views may be schema-qualified. operator families, sequences, types, and views may be schema-qualified.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -247,6 +248,7 @@ COMMENT ON LARGE OBJECT 346344 IS 'Planning document'; ...@@ -247,6 +248,7 @@ COMMENT ON LARGE OBJECT 346344 IS 'Planning document';
COMMENT ON OPERATOR ^ (text, text) IS 'Performs intersection of two texts'; COMMENT ON OPERATOR ^ (text, text) IS 'Performs intersection of two texts';
COMMENT ON OPERATOR - (NONE, text) IS 'This is a prefix operator on text'; COMMENT ON OPERATOR - (NONE, text) IS 'This is a prefix operator on text';
COMMENT ON OPERATOR CLASS int4ops USING btree IS '4 byte integer operators for btrees'; COMMENT ON OPERATOR CLASS int4ops USING btree IS '4 byte integer operators for btrees';
COMMENT ON OPERATOR FAMILY integer_ops USING btree IS 'all integer operators for btrees';
COMMENT ON ROLE my_role IS 'Administration group for finance tables'; COMMENT ON ROLE my_role IS 'Administration group for finance tables';
COMMENT ON RULE my_rule ON my_table IS 'Logs updates of employee records'; COMMENT ON RULE my_rule ON my_table IS 'Logs updates of employee records';
COMMENT ON SCHEMA my_schema IS 'Departmental data'; COMMENT ON SCHEMA my_schema IS 'Departmental data';
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_opclass.sgml,v 1.18 2006/10/16 17:28:03 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/create_opclass.sgml,v 1.19 2007/01/23 05:07:17 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -20,9 +20,10 @@ PostgreSQL documentation ...@@ -20,9 +20,10 @@ PostgreSQL documentation
<refsynopsisdiv> <refsynopsisdiv>
<synopsis> <synopsis>
CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAULT ] FOR TYPE <replaceable class="parameter">data_type</replaceable> USING <replaceable class="parameter">index_method</replaceable> AS CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAULT ] FOR TYPE <replaceable class="parameter">data_type</replaceable>
USING <replaceable class="parameter">index_method</replaceable> [ FAMILY <replaceable class="parameter">family_name</replaceable> ] AS
{ OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_name</replaceable> [ ( <replaceable class="parameter">op_type</replaceable>, <replaceable class="parameter">op_type</replaceable> ) ] [ RECHECK ] { OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_name</replaceable> [ ( <replaceable class="parameter">op_type</replaceable>, <replaceable class="parameter">op_type</replaceable> ) ] [ RECHECK ]
| FUNCTION <replaceable class="parameter">support_number</replaceable> <replaceable class="parameter">funcname</replaceable> ( <replaceable class="parameter">argument_type</replaceable> [, ...] ) | FUNCTION <replaceable class="parameter">support_number</replaceable> [ ( <replaceable class="parameter">op_type</replaceable> [ , <replaceable class="parameter">op_type</replaceable> ] ) ] <replaceable class="parameter">funcname</replaceable> ( <replaceable class="parameter">argument_type</replaceable> [, ...] )
| STORAGE <replaceable class="parameter">storage_type</replaceable> | STORAGE <replaceable class="parameter">storage_type</replaceable>
} [, ... ] } [, ... ]
</synopsis> </synopsis>
...@@ -40,7 +41,7 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL ...@@ -40,7 +41,7 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
be used by be used by
the index method when the operator class is selected for an the index method when the operator class is selected for an
index column. All the operators and functions used by an operator index column. All the operators and functions used by an operator
class must be defined before the operator class is created. class must be defined before the operator class can be created.
</para> </para>
<para> <para>
...@@ -65,6 +66,15 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL ...@@ -65,6 +66,15 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
responsibility to define a valid operator class. responsibility to define a valid operator class.
</para> </para>
<para>
Related operator classes can be grouped into <firstterm>operator
families</>. To add a new operator class to an existing family,
specify the <literal>FAMILY</> option in <command>CREATE OPERATOR
CLASS</command>. Without this option, the new class is placed into
a family named the same as the new class (creating that family if
it doesn't already exist).
</para>
<para> <para>
Refer to <xref linkend="xindex"> for further information. Refer to <xref linkend="xindex"> for further information.
</para> </para>
...@@ -113,6 +123,17 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL ...@@ -113,6 +123,17 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><replaceable class="parameter">family_name</replaceable></term>
<listitem>
<para>
The name of the existing operator family to add this operator class to.
If not specified, a family named the same as the operator class is
used (creating it, if it doesn't already exist).
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="parameter">strategy_number</replaceable></term> <term><replaceable class="parameter">strategy_number</replaceable></term>
<listitem> <listitem>
...@@ -137,11 +158,24 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL ...@@ -137,11 +158,24 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
<term><replaceable class="parameter">op_type</replaceable></term> <term><replaceable class="parameter">op_type</replaceable></term>
<listitem> <listitem>
<para> <para>
The operand data type(s) of an operator, or <literal>NONE</> to In an <literal>OPERATOR</> clause,
the operand data type(s) of the operator, or <literal>NONE</> to
signify a left-unary or right-unary operator. The operand data signify a left-unary or right-unary operator. The operand data
types may be omitted in the normal case where they are the same types may be omitted in the normal case where they are the same
as the operator class's data type. as the operator class's data type.
</para> </para>
<para>
In a <literal>FUNCTION</> clause, the operand data type(s) the
function is intended to support, if different from
the input data type(s) of the function (for B-tree and hash indexes)
or the class's data type (for GIN and GiST indexes). These defaults
are always correct, so there is no point in specifying <replaceable
class="parameter">op_type</replaceable> in a <literal>FUNCTION</> clause
in <command>CREATE OPERATOR CLASS</>, but the option is provided
for consistency with the comparable syntax in
<command>ALTER OPERATOR FAMILY</>.
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -192,7 +226,7 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL ...@@ -192,7 +226,7 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
<para> <para>
The data type actually stored in the index. Normally this is The data type actually stored in the index. Normally this is
the same as the column data type, but some index methods the same as the column data type, but some index methods
(GIN and GiST for now) allow it to be different. The (currently GIN and GiST) allow it to be different. The
<literal>STORAGE</> clause must be omitted unless the index <literal>STORAGE</> clause must be omitted unless the index
method allows a different type to be used. method allows a different type to be used.
</para> </para>
...@@ -268,6 +302,8 @@ CREATE OPERATOR CLASS gist__int_ops ...@@ -268,6 +302,8 @@ CREATE OPERATOR CLASS gist__int_ops
<simplelist type="inline"> <simplelist type="inline">
<member><xref linkend="sql-alteropclass" endterm="sql-alteropclass-title"></member> <member><xref linkend="sql-alteropclass" endterm="sql-alteropclass-title"></member>
<member><xref linkend="sql-dropopclass" endterm="sql-dropopclass-title"></member> <member><xref linkend="sql-dropopclass" endterm="sql-dropopclass-title"></member>
<member><xref linkend="sql-createopfamily" endterm="sql-createopfamily-title"></member>
<member><xref linkend="sql-alteropfamily" endterm="sql-alteropfamily-title"></member>
</simplelist> </simplelist>
</refsect1> </refsect1>
</refentry> </refentry>
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_opfamily.sgml,v 1.1 2007/01/23 05:07:17 tgl Exp $
PostgreSQL documentation
-->
<refentry id="SQL-CREATEOPFAMILY">
<refmeta>
<refentrytitle id="sql-createopfamily-title">CREATE OPERATOR FAMILY</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>CREATE OPERATOR FAMILY</refname>
<refpurpose>define a new operator family</refpurpose>
</refnamediv>
<indexterm zone="sql-createopfamily">
<primary>CREATE OPERATOR FAMILY</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
CREATE OPERATOR FAMILY <replaceable class="parameter">name</replaceable> USING <replaceable class="parameter">index_method</replaceable>
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>CREATE OPERATOR FAMILY</command> creates a new operator family.
An operator family defines a collection of related operator classes,
and perhaps some additional operators and support functions that are
compatible with these operator classes but not essential for the
functioning of any individual index. (Operators and functions that
are essential to indexes should be grouped within the relevant operator
class, rather than being <quote>loose</> in the operator family.
Typically, single-data-type operators are bound to operator classes,
while cross-data-type operators can be loose in an operator family
containing operator classes for both data types.)
</para>
<para>
The new operator family is initially empty. It should be populated
by issuing subsequent <command>CREATE OPERATOR CLASS</command> commands
to add contained operator classes, and optionally
<command>ALTER OPERATOR FAMILY</command> commands to add <quote>loose</>
operators and their corresponding support functions.
</para>
<para>
If a schema name is given then the operator family is created in the
specified schema. Otherwise it is created in the current schema.
Two operator families in the same schema can have the same name only if they
are for different index methods.
</para>
<para>
The user who defines an operator family becomes its owner. Presently,
the creating user must be a superuser. (This restriction is made because
an erroneous operator family definition could confuse or even crash the
server.)
</para>
<para>
<command>CREATE OPERATOR FAMILY</command> does not presently check
whether the operator family definition includes all the operators and
functions required by the index method, nor whether the operators and
functions form a self-consistent set. It is the user's
responsibility to define a valid operator family.
</para>
<para>
Refer to <xref linkend="xindex"> for further information.
</para>
</refsect1>
<refsect1>
<title>Parameters</title>
<variablelist>
<varlistentry>
<term><replaceable class="parameter">name</replaceable></term>
<listitem>
<para>
The name of the operator family to be created. The name may be
schema-qualified.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">index_method</replaceable></term>
<listitem>
<para>
The name of the index method this operator family is for.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Compatibility</title>
<para>
<command>CREATE OPERATOR FAMILY</command> is a
<productname>PostgreSQL</productname> extension. There is no
<command>CREATE OPERATOR FAMILY</command> statement in the SQL
standard.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-alteropfamily" endterm="sql-alteropfamily-title"></member>
<member><xref linkend="sql-dropopfamily" endterm="sql-dropopfamily-title"></member>
<member><xref linkend="sql-createopclass" endterm="sql-createopclass-title"></member>
<member><xref linkend="sql-alteropclass" endterm="sql-alteropclass-title"></member>
<member><xref linkend="sql-dropopclass" endterm="sql-dropopclass-title"></member>
</simplelist>
</refsect1>
</refentry>
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/drop_opclass.sgml,v 1.10 2006/09/16 00:30:18 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/drop_opclass.sgml,v 1.11 2007/01/23 05:07:17 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -31,6 +31,13 @@ DROP OPERATOR CLASS [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceab ...@@ -31,6 +31,13 @@ DROP OPERATOR CLASS [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceab
<command>DROP OPERATOR CLASS</command> drops an existing operator class. <command>DROP OPERATOR CLASS</command> drops an existing operator class.
To execute this command you must be the owner of the operator class. To execute this command you must be the owner of the operator class.
</para> </para>
<para>
<command>DROP OPERATOR CLASS</command> does not drop any of the operators
or functions referenced by the class. If there are any indexes depending
on the operator class, you will need to specify
<literal>CASCADE</> for the drop to complete.
</para>
</refsect1> </refsect1>
<refsect1> <refsect1>
...@@ -86,6 +93,20 @@ DROP OPERATOR CLASS [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceab ...@@ -86,6 +93,20 @@ DROP OPERATOR CLASS [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceab
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1>
<title>Notes</title>
<para>
<command>DROP OPERATOR CLASS</> will not drop the operator family
containing the class, even if there is nothing else left in the
family (in particular, in the case where the family was implicitly
created by <command>CREATE OPERATOR CLASS</>). An empty operator
family is harmless, but for the sake of tidiness you may wish to
remove the family with <command>DROP OPERATOR FAMILY</>; or perhaps
better, use <command>DROP OPERATOR FAMILY</> in the first place.
</para>
</refsect1>
<refsect1> <refsect1>
<title>Examples</title> <title>Examples</title>
...@@ -118,6 +139,7 @@ DROP OPERATOR CLASS widget_ops USING btree; ...@@ -118,6 +139,7 @@ DROP OPERATOR CLASS widget_ops USING btree;
<simplelist type="inline"> <simplelist type="inline">
<member><xref linkend="sql-alteropclass" endterm="sql-alteropclass-title"></member> <member><xref linkend="sql-alteropclass" endterm="sql-alteropclass-title"></member>
<member><xref linkend="sql-createopclass" endterm="sql-createopclass-title"></member> <member><xref linkend="sql-createopclass" endterm="sql-createopclass-title"></member>
<member><xref linkend="sql-dropopfamily" endterm="sql-dropopfamily-title"></member>
</simplelist> </simplelist>
</refsect1> </refsect1>
......
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/drop_opfamily.sgml,v 1.1 2007/01/23 05:07:17 tgl Exp $
PostgreSQL documentation
-->
<refentry id="SQL-DROPOPFAMILY">
<refmeta>
<refentrytitle id="SQL-DROPOPFAMILY-TITLE">DROP OPERATOR FAMILY</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>DROP OPERATOR FAMILY</refname>
<refpurpose>remove an operator family</refpurpose>
</refnamediv>
<indexterm zone="sql-dropopfamily">
<primary>DROP OPERATOR FAMILY</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
DROP OPERATOR FAMILY [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> USING <replaceable class="PARAMETER">index_method</replaceable> [ CASCADE | RESTRICT ]
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>DROP OPERATOR FAMILY</command> drops an existing operator family.
To execute this command you must be the owner of the operator family.
</para>
<para>
<command>DROP OPERATOR FAMILY</command> includes dropping any operator
classes contained in the family, but it does not drop any of the operators
or functions referenced by the family. If there are any indexes depending
on operator classes within the family, you will need to specify
<literal>CASCADE</> for the drop to complete.
</para>
</refsect1>
<refsect1>
<title>Parameters</title>
<variablelist>
<varlistentry>
<term><literal>IF EXISTS</literal></term>
<listitem>
<para>
Do not throw an error if the operator family does not exist.
A notice is issued in this case.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">name</replaceable></term>
<listitem>
<para>
The name (optionally schema-qualified) of an existing operator family.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">index_method</replaceable></term>
<listitem>
<para>
The name of the index access method the operator family is for.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>CASCADE</literal></term>
<listitem>
<para>
Automatically drop objects that depend on the operator family.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>RESTRICT</literal></term>
<listitem>
<para>
Refuse to drop the operator family if any objects depend on it.
This is the default.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Examples</title>
<para>
Remove the B-tree operator family <literal>float_ops</literal>:
<programlisting>
DROP OPERATOR FAMILY float_ops USING btree;
</programlisting>
This command will not succeed if there are any existing indexes
that use operator classes within the family. Add <literal>CASCADE</> to
drop such indexes along with the operator family.
</para>
</refsect1>
<refsect1>
<title>Compatibility</title>
<para>
There is no <command>DROP OPERATOR FAMILY</command> statement in the
SQL standard.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-alteropfamily" endterm="sql-alteropfamily-title"></member>
<member><xref linkend="sql-createopfamily" endterm="sql-createopfamily-title"></member>
<member><xref linkend="sql-alteropclass" endterm="sql-alteropclass-title"></member>
<member><xref linkend="sql-createopclass" endterm="sql-createopclass-title"></member>
<member><xref linkend="sql-dropopclass" endterm="sql-dropopclass-title"></member>
</simplelist>
</refsect1>
</refentry>
<!-- $PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.60 2006/09/18 19:54:01 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.61 2007/01/23 05:07:17 tgl Exp $ -->
<part id="reference"> <part id="reference">
<title>Reference</title> <title>Reference</title>
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
&alterLanguage; &alterLanguage;
&alterOperator; &alterOperator;
&alterOperatorClass; &alterOperatorClass;
&alterOperatorFamily;
&alterRole; &alterRole;
&alterSchema; &alterSchema;
&alterSequence; &alterSequence;
...@@ -73,6 +74,7 @@ ...@@ -73,6 +74,7 @@
&createLanguage; &createLanguage;
&createOperator; &createOperator;
&createOperatorClass; &createOperatorClass;
&createOperatorFamily;
&createRole; &createRole;
&createRule; &createRule;
&createSchema; &createSchema;
...@@ -98,6 +100,7 @@ ...@@ -98,6 +100,7 @@
&dropLanguage; &dropLanguage;
&dropOperator; &dropOperator;
&dropOperatorClass; &dropOperatorClass;
&dropOperatorFamily;
&dropOwned; &dropOwned;
&dropRole; &dropRole;
&dropRule; &dropRule;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.134 2007/01/05 22:19:24 momjian Exp $ * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.135 2007/01/23 05:07:17 tgl Exp $
* *
* NOTES * NOTES
* See acl.h. * See acl.h.
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "catalog/pg_namespace.h" #include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h" #include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_tablespace.h" #include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
...@@ -1413,6 +1414,8 @@ static const char *const no_priv_msg[MAX_ACL_KIND] = ...@@ -1413,6 +1414,8 @@ static const char *const no_priv_msg[MAX_ACL_KIND] =
gettext_noop("permission denied for schema %s"), gettext_noop("permission denied for schema %s"),
/* ACL_KIND_OPCLASS */ /* ACL_KIND_OPCLASS */
gettext_noop("permission denied for operator class %s"), gettext_noop("permission denied for operator class %s"),
/* ACL_KIND_OPFAMILY */
gettext_noop("permission denied for operator family %s"),
/* ACL_KIND_CONVERSION */ /* ACL_KIND_CONVERSION */
gettext_noop("permission denied for conversion %s"), gettext_noop("permission denied for conversion %s"),
/* ACL_KIND_TABLESPACE */ /* ACL_KIND_TABLESPACE */
...@@ -1439,6 +1442,8 @@ static const char *const not_owner_msg[MAX_ACL_KIND] = ...@@ -1439,6 +1442,8 @@ static const char *const not_owner_msg[MAX_ACL_KIND] =
gettext_noop("must be owner of schema %s"), gettext_noop("must be owner of schema %s"),
/* ACL_KIND_OPCLASS */ /* ACL_KIND_OPCLASS */
gettext_noop("must be owner of operator class %s"), gettext_noop("must be owner of operator class %s"),
/* ACL_KIND_OPFAMILY */
gettext_noop("must be owner of operator family %s"),
/* ACL_KIND_CONVERSION */ /* ACL_KIND_CONVERSION */
gettext_noop("must be owner of conversion %s"), gettext_noop("must be owner of conversion %s"),
/* ACL_KIND_TABLESPACE */ /* ACL_KIND_TABLESPACE */
...@@ -2239,6 +2244,35 @@ pg_opclass_ownercheck(Oid opc_oid, Oid roleid) ...@@ -2239,6 +2244,35 @@ pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
return has_privs_of_role(roleid, ownerId); return has_privs_of_role(roleid, ownerId);
} }
/*
* Ownership check for an operator family (specified by OID).
*/
bool
pg_opfamily_ownercheck(Oid opf_oid, Oid roleid)
{
HeapTuple tuple;
Oid ownerId;
/* Superusers bypass all permission checking. */
if (superuser_arg(roleid))
return true;
tuple = SearchSysCache(OPFAMILYOID,
ObjectIdGetDatum(opf_oid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family with OID %u does not exist",
opf_oid)));
ownerId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfowner;
ReleaseSysCache(tuple);
return has_privs_of_role(roleid, ownerId);
}
/* /*
* Ownership check for a database (specified by OID). * Ownership check for a database (specified by OID).
*/ */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.21 2007/01/05 22:19:25 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.22 2007/01/23 05:07:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -66,6 +66,10 @@ ExecRenameStmt(RenameStmt *stmt) ...@@ -66,6 +66,10 @@ ExecRenameStmt(RenameStmt *stmt)
RenameOpClass(stmt->object, stmt->subname, stmt->newname); RenameOpClass(stmt->object, stmt->subname, stmt->newname);
break; break;
case OBJECT_OPFAMILY:
RenameOpFamily(stmt->object, stmt->subname, stmt->newname);
break;
case OBJECT_ROLE: case OBJECT_ROLE:
RenameRole(stmt->subname, stmt->newname); RenameRole(stmt->subname, stmt->newname);
break; break;
...@@ -211,6 +215,10 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt) ...@@ -211,6 +215,10 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
AlterOpClassOwner(stmt->object, stmt->addname, newowner); AlterOpClassOwner(stmt->object, stmt->addname, newowner);
break; break;
case OBJECT_OPFAMILY:
AlterOpFamilyOwner(stmt->object, stmt->addname, newowner);
break;
case OBJECT_SCHEMA: case OBJECT_SCHEMA:
AlterSchemaOwner((char *) linitial(stmt->object), newowner); AlterSchemaOwner((char *) linitial(stmt->object), newowner);
break; break;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Copyright (c) 1996-2007, PostgreSQL Global Development Group * Copyright (c) 1996-2007, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.94 2007/01/05 22:19:25 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.95 2007/01/23 05:07:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "catalog/pg_namespace.h" #include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h" #include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h" #include "catalog/pg_rewrite.h"
#include "catalog/pg_shdescription.h" #include "catalog/pg_shdescription.h"
...@@ -72,6 +73,7 @@ static void CommentConstraint(List *qualname, char *comment); ...@@ -72,6 +73,7 @@ static void CommentConstraint(List *qualname, char *comment);
static void CommentConversion(List *qualname, char *comment); static void CommentConversion(List *qualname, char *comment);
static void CommentLanguage(List *qualname, char *comment); static void CommentLanguage(List *qualname, char *comment);
static void CommentOpClass(List *qualname, List *arguments, char *comment); static void CommentOpClass(List *qualname, List *arguments, char *comment);
static void CommentOpFamily(List *qualname, List *arguments, char *comment);
static void CommentLargeObject(List *qualname, char *comment); static void CommentLargeObject(List *qualname, char *comment);
static void CommentCast(List *qualname, List *arguments, char *comment); static void CommentCast(List *qualname, List *arguments, char *comment);
static void CommentTablespace(List *qualname, char *comment); static void CommentTablespace(List *qualname, char *comment);
...@@ -134,6 +136,9 @@ CommentObject(CommentStmt *stmt) ...@@ -134,6 +136,9 @@ CommentObject(CommentStmt *stmt)
case OBJECT_OPCLASS: case OBJECT_OPCLASS:
CommentOpClass(stmt->objname, stmt->objargs, stmt->comment); CommentOpClass(stmt->objname, stmt->objargs, stmt->comment);
break; break;
case OBJECT_OPFAMILY:
CommentOpFamily(stmt->objname, stmt->objargs, stmt->comment);
break;
case OBJECT_LARGEOBJECT: case OBJECT_LARGEOBJECT:
CommentLargeObject(stmt->objname, stmt->comment); CommentLargeObject(stmt->objname, stmt->comment);
break; break;
...@@ -1263,6 +1268,92 @@ CommentOpClass(List *qualname, List *arguments, char *comment) ...@@ -1263,6 +1268,92 @@ CommentOpClass(List *qualname, List *arguments, char *comment)
CreateComments(opcID, OperatorClassRelationId, 0, comment); CreateComments(opcID, OperatorClassRelationId, 0, comment);
} }
/*
* CommentOpFamily --
*
* This routine is used to allow a user to provide comments on an
* operator family. The operator family for commenting is determined by both
* its name and its argument list which defines the index method
* the operator family is used for. The argument list is expected to contain
* a single name (represented as a string Value node).
*/
static void
CommentOpFamily(List *qualname, List *arguments, char *comment)
{
char *amname;
char *schemaname;
char *opfname;
Oid amID;
Oid opfID;
HeapTuple tuple;
Assert(list_length(arguments) == 1);
amname = strVal(linitial(arguments));
/*
* Get the access method's OID.
*/
amID = GetSysCacheOid(AMNAME,
CStringGetDatum(amname),
0, 0, 0);
if (!OidIsValid(amID))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
amname)));
/*
* Look up the opfamily.
*/
/* deconstruct the name list */
DeconstructQualifiedName(qualname, &schemaname, &opfname);
if (schemaname)
{
/* Look in specific schema only */
Oid namespaceId;
namespaceId = LookupExplicitNamespace(schemaname);
tuple = SearchSysCache(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amID),
PointerGetDatum(opfname),
ObjectIdGetDatum(namespaceId),
0);
}
else
{
/* Unqualified opfamily name, so search the search path */
opfID = OpfamilynameGetOpfid(amID, opfname);
if (!OidIsValid(opfID))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
opfname, amname)));
tuple = SearchSysCache(OPFAMILYOID,
ObjectIdGetDatum(opfID),
0, 0, 0);
}
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
NameListToString(qualname), amname)));
opfID = HeapTupleGetOid(tuple);
/* Permission check: must own opfamily */
if (!pg_opfamily_ownercheck(opfID, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
NameListToString(qualname));
ReleaseSysCache(tuple);
/* Call CreateComments() to create/drop the comments */
CreateComments(opfID, OperatorFamilyRelationId, 0, comment);
}
/* /*
* CommentLargeObject -- * CommentLargeObject --
* *
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.52 2007/01/05 22:19:26 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.53 2007/01/23 05:07:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -55,15 +55,30 @@ typedef struct ...@@ -55,15 +55,30 @@ typedef struct
} OpFamilyMember; } OpFamilyMember;
static void AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
int maxOpNumber, int maxProcNumber,
List *items);
static void AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
int maxOpNumber, int maxProcNumber,
List *items);
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype);
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid); static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid); static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc); static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc);
static void storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, static void storeOperators(List *opfamilyname, Oid amoid,
List *operators); Oid opfamilyoid, Oid opclassoid,
static void storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators, bool isAdd);
List *procedures); static void storeProcedures(List *opfamilyname, Oid amoid,
Oid opfamilyoid, Oid opclassoid,
List *procedures, bool isAdd);
static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *operators);
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *procedures);
static void AlterOpClassOwner_internal(Relation rel, HeapTuple tuple, static void AlterOpClassOwner_internal(Relation rel, HeapTuple tuple,
Oid newOwnerId); Oid newOwnerId);
static void AlterOpFamilyOwner_internal(Relation rel, HeapTuple tuple,
Oid newOwnerId);
/* /*
...@@ -452,6 +467,12 @@ DefineOpClass(CreateOpClassStmt *stmt) ...@@ -452,6 +467,12 @@ DefineOpClass(CreateOpClassStmt *stmt)
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember)); member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = funcOid; member->object = funcOid;
member->number = item->number; member->number = item->number;
/* allow overriding of the function's actual arg types */
if (item->class_args)
processTypesSpec(item->class_args,
&member->lefttype, &member->righttype);
assignProcTypes(member, amoid, typeoid); assignProcTypes(member, amoid, typeoid);
addFamilyMember(&procedures, member, true); addFamilyMember(&procedures, member, true);
break; break;
...@@ -570,8 +591,10 @@ DefineOpClass(CreateOpClassStmt *stmt) ...@@ -570,8 +591,10 @@ DefineOpClass(CreateOpClassStmt *stmt)
* Now add tuples to pg_amop and pg_amproc tying in the operators and * Now add tuples to pg_amop and pg_amproc tying in the operators and
* functions. Dependencies on them are inserted, too. * functions. Dependencies on them are inserted, too.
*/ */
storeOperators(amoid, opfamilyoid, opclassoid, operators); storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
storeProcedures(amoid, opfamilyoid, opclassoid, procedures); opclassoid, operators, false);
storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
opclassoid, procedures, false);
/* /*
* Create dependencies for the opclass proper. Note: we do not create a * Create dependencies for the opclass proper. Note: we do not create a
...@@ -615,151 +638,565 @@ DefineOpClass(CreateOpClassStmt *stmt) ...@@ -615,151 +638,565 @@ DefineOpClass(CreateOpClassStmt *stmt)
heap_close(rel, RowExclusiveLock); heap_close(rel, RowExclusiveLock);
} }
/* /*
* Determine the lefttype/righttype to assign to an operator, * DefineOpFamily
* and do any validity checking we can manage. * Define a new index operator family.
*/ */
static void void
assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid) DefineOpFamily(CreateOpFamilyStmt *stmt)
{ {
Operator optup; char *opfname; /* name of opfamily we're creating */
Form_pg_operator opform; Oid amoid, /* our AM's oid */
namespaceoid, /* namespace to create opfamily in */
opfamilyoid; /* oid of opfamily we create */
Relation rel;
HeapTuple tup;
Datum values[Natts_pg_opfamily];
char nulls[Natts_pg_opfamily];
AclResult aclresult;
NameData opfName;
ObjectAddress myself,
referenced;
/* Fetch the operator definition */ /* Convert list of names to a name and namespace */
optup = SearchSysCache(OPEROID, namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
ObjectIdGetDatum(member->object), &opfname);
0, 0, 0);
if (optup == NULL) /* Check we have creation rights in target namespace */
elog(ERROR, "cache lookup failed for operator %u", member->object); aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
opform = (Form_pg_operator) GETSTRUCT(optup); if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceoid));
/* Get necessary info about access method */
tup = SearchSysCache(AMNAME,
CStringGetDatum(stmt->amname),
0, 0, 0);
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
stmt->amname)));
amoid = HeapTupleGetOid(tup);
/* XXX Should we make any privilege check against the AM? */
ReleaseSysCache(tup);
/* /*
* Opfamily operators must be binary ops returning boolean. * Currently, we require superuser privileges to create an opfamily.
* See comments in DefineOpClass.
*
* XXX re-enable NOT_USED code sections below if you remove this test.
*/ */
if (opform->oprkind != 'b') if (!superuser())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("index operators must be binary"))); errmsg("must be superuser to create an operator family")));
if (opform->oprresult != BOOLOID)
rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
/*
* Make sure there is no existing opfamily of this name (this is just to
* give a more friendly error message than "duplicate key").
*/
if (SearchSysCacheExists(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amoid),
CStringGetDatum(opfname),
ObjectIdGetDatum(namespaceoid),
0))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("index operators must return boolean"))); errmsg("operator family \"%s\" for access method \"%s\" already exists",
opfname, stmt->amname)));
/* /*
* If lefttype/righttype isn't specified, use the operator's input types * Okay, let's create the pg_opfamily entry.
*/ */
if (!OidIsValid(member->lefttype)) memset(values, 0, sizeof(values));
member->lefttype = opform->oprleft; memset(nulls, ' ', sizeof(nulls));
if (!OidIsValid(member->righttype))
member->righttype = opform->oprright;
ReleaseSysCache(optup); values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
namestrcpy(&opfName, opfname);
values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
tup = heap_formtuple(rel->rd_att, values, nulls);
opfamilyoid = simple_heap_insert(rel, tup);
CatalogUpdateIndexes(rel, tup);
heap_freetuple(tup);
/*
* Create dependencies for the opfamily proper. Note: we do not create a
* dependency link to the AM, because we don't currently support DROP
* ACCESS METHOD.
*/
myself.classId = OperatorFamilyRelationId;
myself.objectId = opfamilyoid;
myself.objectSubId = 0;
/* dependency on namespace */
referenced.classId = NamespaceRelationId;
referenced.objectId = namespaceoid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on owner */
recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
heap_close(rel, RowExclusiveLock);
} }
/* /*
* Determine the lefttype/righttype to assign to a support procedure, * AlterOpFamily
* and do any validity checking we can manage. * Add or remove operators/procedures within an existing operator family.
*
* Note: this implements only ALTER OPERATOR FAMILY ... ADD/DROP. Some
* other commands called ALTER OPERATOR FAMILY exist, but go through
* different code paths.
*/ */
static void void
assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid) AlterOpFamily(AlterOpFamilyStmt *stmt)
{ {
HeapTuple proctup; Oid amoid, /* our AM's oid */
Form_pg_proc procform; opfamilyoid; /* oid of opfamily */
int maxOpNumber, /* amstrategies value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
Form_pg_am pg_am;
/* Fetch the procedure definition */ /* Get necessary info about access method */
proctup = SearchSysCache(PROCOID, tup = SearchSysCache(AMNAME,
ObjectIdGetDatum(member->object), CStringGetDatum(stmt->amname),
0, 0, 0); 0, 0, 0);
if (proctup == NULL) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for function %u", member->object); ereport(ERROR,
procform = (Form_pg_proc) GETSTRUCT(proctup); (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
stmt->amname)));
amoid = HeapTupleGetOid(tup);
pg_am = (Form_pg_am) GETSTRUCT(tup);
maxOpNumber = pg_am->amstrategies;
/* if amstrategies is zero, just enforce that op numbers fit in int16 */
if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
maxProcNumber = pg_am->amsupport;
/* XXX Should we make any privilege check against the AM? */
ReleaseSysCache(tup);
/* Look up the opfamily */
tup = OpFamilyCacheLookup(amoid, stmt->opfamilyname);
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
NameListToString(stmt->opfamilyname), stmt->amname)));
opfamilyoid = HeapTupleGetOid(tup);
ReleaseSysCache(tup);
/* /*
* btree support procs must be 2-arg procs returning int4; hash support * Currently, we require superuser privileges to alter an opfamily.
* procs must be 1-arg procs returning int4; otherwise we don't know. *
* XXX re-enable NOT_USED code sections below if you remove this test.
*/ */
if (amoid == BTREE_AM_OID) if (!superuser())
{ ereport(ERROR,
if (procform->pronargs != 2) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
ereport(ERROR, errmsg("must be superuser to alter an operator family")));
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("btree procedures must have two arguments")));
if (procform->prorettype != INT4OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("btree procedures must return integer")));
/*
* If lefttype/righttype isn't specified, use the proc's input types
*/
if (!OidIsValid(member->lefttype))
member->lefttype = procform->proargtypes.values[0];
if (!OidIsValid(member->righttype))
member->righttype = procform->proargtypes.values[1];
}
else if (amoid == HASH_AM_OID)
{
if (procform->pronargs != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("hash procedures must have one argument")));
if (procform->prorettype != INT4OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("hash procedures must return integer")));
/* /*
* If lefttype/righttype isn't specified, use the proc's input type * ADD and DROP cases need separate code from here on down.
*/ */
if (!OidIsValid(member->lefttype)) if (stmt->isDrop)
member->lefttype = procform->proargtypes.values[0]; AlterOpFamilyDrop(stmt->opfamilyname, amoid, opfamilyoid,
if (!OidIsValid(member->righttype)) maxOpNumber, maxProcNumber,
member->righttype = procform->proargtypes.values[0]; stmt->items);
}
else else
{ AlterOpFamilyAdd(stmt->opfamilyname, amoid, opfamilyoid,
/* maxOpNumber, maxProcNumber,
* The default for GiST and GIN in CREATE OPERATOR CLASS is to use stmt->items);
* the class' opcintype as lefttype and righttype. In CREATE or
* ALTER OPERATOR FAMILY, opcintype isn't available, so make the
* user specify the types.
*/
if (!OidIsValid(member->lefttype))
member->lefttype = typeoid;
if (!OidIsValid(member->righttype))
member->righttype = typeoid;
if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("associated data types must be specified for index support procedure")));
}
ReleaseSysCache(proctup);
} }
/* /*
* Add a new family member to the appropriate list, after checking for * ADD part of ALTER OP FAMILY
* duplicated strategy or proc number.
*/ */
static void static void
addFamilyMember(List **list, OpFamilyMember *member, bool isProc) AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
int maxOpNumber, int maxProcNumber,
List *items)
{ {
List *operators; /* OpFamilyMember list for operators */
List *procedures; /* OpFamilyMember list for support procs */
ListCell *l; ListCell *l;
foreach(l, *list) operators = NIL;
procedures = NIL;
/*
* Scan the "items" list to obtain additional info.
*/
foreach(l, items)
{ {
OpFamilyMember *old = (OpFamilyMember *) lfirst(l); CreateOpClassItem *item = lfirst(l);
Oid operOid;
Oid funcOid;
OpFamilyMember *member;
if (old->number == member->number && Assert(IsA(item, CreateOpClassItem));
old->lefttype == member->lefttype && switch (item->itemtype)
old->righttype == member->righttype)
{ {
if (isProc) case OPCLASS_ITEM_OPERATOR:
ereport(ERROR, if (item->number <= 0 || item->number > maxOpNumber)
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), ereport(ERROR,
errmsg("procedure number %d for (%s,%s) appears more than once", (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
member->number, errmsg("invalid operator number %d,"
format_type_be(member->lefttype), " must be between 1 and %d",
item->number, maxOpNumber)));
if (item->args != NIL)
{
TypeName *typeName1 = (TypeName *) linitial(item->args);
TypeName *typeName2 = (TypeName *) lsecond(item->args);
operOid = LookupOperNameTypeNames(NULL, item->name,
typeName1, typeName2,
false, -1);
}
else
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
operOid = InvalidOid; /* keep compiler quiet */
}
#ifdef NOT_USED
/* XXX this is unnecessary given the superuser check above */
/* Caller must own operator and its underlying function */
if (!pg_oper_ownercheck(operOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
get_opname(operOid));
funcOid = get_opcode(operOid);
if (!pg_proc_ownercheck(funcOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
get_func_name(funcOid));
#endif
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = operOid;
member->number = item->number;
member->recheck = item->recheck;
assignOperTypes(member, amoid, InvalidOid);
addFamilyMember(&operators, member, false);
break;
case OPCLASS_ITEM_FUNCTION:
if (item->number <= 0 || item->number > maxProcNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid procedure number %d,"
" must be between 1 and %d",
item->number, maxProcNumber)));
funcOid = LookupFuncNameTypeNames(item->name, item->args,
false);
#ifdef NOT_USED
/* XXX this is unnecessary given the superuser check above */
/* Caller must own function */
if (!pg_proc_ownercheck(funcOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
get_func_name(funcOid));
#endif
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = funcOid;
member->number = item->number;
/* allow overriding of the function's actual arg types */
if (item->class_args)
processTypesSpec(item->class_args,
&member->lefttype, &member->righttype);
assignProcTypes(member, amoid, InvalidOid);
addFamilyMember(&procedures, member, true);
break;
case OPCLASS_ITEM_STORAGETYPE:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("STORAGE may not be specified in ALTER OPERATOR FAMILY")));
break;
default:
elog(ERROR, "unrecognized item type: %d", item->itemtype);
break;
}
}
/*
* Add tuples to pg_amop and pg_amproc tying in the operators and
* functions. Dependencies on them are inserted, too.
*/
storeOperators(opfamilyname, amoid, opfamilyoid,
InvalidOid, operators, true);
storeProcedures(opfamilyname, amoid, opfamilyoid,
InvalidOid, procedures, true);
}
/*
* DROP part of ALTER OP FAMILY
*/
static void
AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
int maxOpNumber, int maxProcNumber,
List *items)
{
List *operators; /* OpFamilyMember list for operators */
List *procedures; /* OpFamilyMember list for support procs */
ListCell *l;
operators = NIL;
procedures = NIL;
/*
* Scan the "items" list to obtain additional info.
*/
foreach(l, items)
{
CreateOpClassItem *item = lfirst(l);
Oid lefttype,
righttype;
OpFamilyMember *member;
Assert(IsA(item, CreateOpClassItem));
switch (item->itemtype)
{
case OPCLASS_ITEM_OPERATOR:
if (item->number <= 0 || item->number > maxOpNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid operator number %d,"
" must be between 1 and %d",
item->number, maxOpNumber)));
processTypesSpec(item->args, &lefttype, &righttype);
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->number = item->number;
member->lefttype = lefttype;
member->righttype = righttype;
addFamilyMember(&operators, member, false);
break;
case OPCLASS_ITEM_FUNCTION:
if (item->number <= 0 || item->number > maxProcNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid procedure number %d,"
" must be between 1 and %d",
item->number, maxProcNumber)));
processTypesSpec(item->args, &lefttype, &righttype);
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->number = item->number;
member->lefttype = lefttype;
member->righttype = righttype;
addFamilyMember(&procedures, member, true);
break;
case OPCLASS_ITEM_STORAGETYPE:
/* grammar prevents this from appearing */
default:
elog(ERROR, "unrecognized item type: %d", item->itemtype);
break;
}
}
/*
* Remove tuples from pg_amop and pg_amproc.
*/
dropOperators(opfamilyname, amoid, opfamilyoid, operators);
dropProcedures(opfamilyname, amoid, opfamilyoid, procedures);
}
/*
* Deal with explicit arg types used in ALTER ADD/DROP
*/
static void
processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
{
TypeName *typeName;
Assert(args != NIL);
typeName = (TypeName *) linitial(args);
*lefttype = typenameTypeId(NULL, typeName);
if (list_length(args) > 1)
{
typeName = (TypeName *) lsecond(args);
*righttype = typenameTypeId(NULL, typeName);
}
else
*righttype = *lefttype;
if (list_length(args) > 2)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("one or two argument types must be specified")));
}
/*
* Determine the lefttype/righttype to assign to an operator,
* and do any validity checking we can manage.
*/
static void
assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
{
Operator optup;
Form_pg_operator opform;
/* Fetch the operator definition */
optup = SearchSysCache(OPEROID,
ObjectIdGetDatum(member->object),
0, 0, 0);
if (optup == NULL)
elog(ERROR, "cache lookup failed for operator %u", member->object);
opform = (Form_pg_operator) GETSTRUCT(optup);
/*
* Opfamily operators must be binary ops returning boolean.
*/
if (opform->oprkind != 'b')
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("index operators must be binary")));
if (opform->oprresult != BOOLOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("index operators must return boolean")));
/*
* If lefttype/righttype isn't specified, use the operator's input types
*/
if (!OidIsValid(member->lefttype))
member->lefttype = opform->oprleft;
if (!OidIsValid(member->righttype))
member->righttype = opform->oprright;
ReleaseSysCache(optup);
}
/*
* Determine the lefttype/righttype to assign to a support procedure,
* and do any validity checking we can manage.
*/
static void
assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
{
HeapTuple proctup;
Form_pg_proc procform;
/* Fetch the procedure definition */
proctup = SearchSysCache(PROCOID,
ObjectIdGetDatum(member->object),
0, 0, 0);
if (proctup == NULL)
elog(ERROR, "cache lookup failed for function %u", member->object);
procform = (Form_pg_proc) GETSTRUCT(proctup);
/*
* btree support procs must be 2-arg procs returning int4; hash support
* procs must be 1-arg procs returning int4; otherwise we don't know.
*/
if (amoid == BTREE_AM_OID)
{
if (procform->pronargs != 2)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("btree procedures must have two arguments")));
if (procform->prorettype != INT4OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("btree procedures must return integer")));
/*
* If lefttype/righttype isn't specified, use the proc's input types
*/
if (!OidIsValid(member->lefttype))
member->lefttype = procform->proargtypes.values[0];
if (!OidIsValid(member->righttype))
member->righttype = procform->proargtypes.values[1];
}
else if (amoid == HASH_AM_OID)
{
if (procform->pronargs != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("hash procedures must have one argument")));
if (procform->prorettype != INT4OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("hash procedures must return integer")));
/*
* If lefttype/righttype isn't specified, use the proc's input type
*/
if (!OidIsValid(member->lefttype))
member->lefttype = procform->proargtypes.values[0];
if (!OidIsValid(member->righttype))
member->righttype = procform->proargtypes.values[0];
}
else
{
/*
* The default for GiST and GIN in CREATE OPERATOR CLASS is to use
* the class' opcintype as lefttype and righttype. In CREATE or
* ALTER OPERATOR FAMILY, opcintype isn't available, so make the
* user specify the types.
*/
if (!OidIsValid(member->lefttype))
member->lefttype = typeoid;
if (!OidIsValid(member->righttype))
member->righttype = typeoid;
if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("associated data types must be specified for index support procedure")));
}
ReleaseSysCache(proctup);
}
/*
* Add a new family member to the appropriate list, after checking for
* duplicated strategy or proc number.
*/
static void
addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
{
ListCell *l;
foreach(l, *list)
{
OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
if (old->number == member->number &&
old->lefttype == member->lefttype &&
old->righttype == member->righttype)
{
if (isProc)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("procedure number %d for (%s,%s) appears more than once",
member->number,
format_type_be(member->lefttype),
format_type_be(member->righttype)))); format_type_be(member->righttype))));
else else
ereport(ERROR, ereport(ERROR,
...@@ -781,7 +1218,9 @@ addFamilyMember(List **list, OpFamilyMember *member, bool isProc) ...@@ -781,7 +1218,9 @@ addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
* else make an AUTO dependency on the opfamily. * else make an AUTO dependency on the opfamily.
*/ */
static void static void
storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators) storeOperators(List *opfamilyname, Oid amoid,
Oid opfamilyoid, Oid opclassoid,
List *operators, bool isAdd)
{ {
Relation rel; Relation rel;
Datum values[Natts_pg_amop]; Datum values[Natts_pg_amop];
...@@ -798,6 +1237,24 @@ storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators) ...@@ -798,6 +1237,24 @@ storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators)
{ {
OpFamilyMember *op = (OpFamilyMember *) lfirst(l); OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
/*
* If adding to an existing family, check for conflict with an
* existing pg_amop entry (just to give a nicer error message)
*/
if (isAdd &&
SearchSysCacheExists(AMOPSTRATEGY,
ObjectIdGetDatum(opfamilyoid),
ObjectIdGetDatum(op->lefttype),
ObjectIdGetDatum(op->righttype),
Int16GetDatum(op->number)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
op->number,
format_type_be(op->lefttype),
format_type_be(op->righttype),
NameListToString(opfamilyname))));
/* Create the pg_amop entry */ /* Create the pg_amop entry */
memset(values, 0, sizeof(values)); memset(values, 0, sizeof(values));
memset(nulls, ' ', sizeof(nulls)); memset(nulls, ' ', sizeof(nulls));
...@@ -862,7 +1319,9 @@ storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators) ...@@ -862,7 +1319,9 @@ storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators)
* else make an AUTO dependency on the opfamily. * else make an AUTO dependency on the opfamily.
*/ */
static void static void
storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures) storeProcedures(List *opfamilyname, Oid amoid,
Oid opfamilyoid, Oid opclassoid,
List *procedures, bool isAdd)
{ {
Relation rel; Relation rel;
Datum values[Natts_pg_amproc]; Datum values[Natts_pg_amproc];
...@@ -879,6 +1338,24 @@ storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures) ...@@ -879,6 +1338,24 @@ storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures)
{ {
OpFamilyMember *proc = (OpFamilyMember *) lfirst(l); OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
/*
* If adding to an existing family, check for conflict with an
* existing pg_amproc entry (just to give a nicer error message)
*/
if (isAdd &&
SearchSysCacheExists(AMPROCNUM,
ObjectIdGetDatum(opfamilyoid),
ObjectIdGetDatum(proc->lefttype),
ObjectIdGetDatum(proc->righttype),
Int16GetDatum(proc->number)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
proc->number,
format_type_be(proc->lefttype),
format_type_be(proc->righttype),
NameListToString(opfamilyname))));
/* Create the pg_amproc entry */ /* Create the pg_amproc entry */
memset(values, 0, sizeof(values)); memset(values, 0, sizeof(values));
memset(nulls, ' ', sizeof(nulls)); memset(nulls, ' ', sizeof(nulls));
...@@ -934,6 +1411,87 @@ storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures) ...@@ -934,6 +1411,87 @@ storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures)
} }
/*
* Remove operator entries from an opfamily.
*
* Note: this is only allowed for "loose" members of an opfamily, hence
* behavior is always RESTRICT.
*/
static void
dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *operators)
{
ListCell *l;
foreach(l, operators)
{
OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
Oid amopid;
ObjectAddress object;
amopid = GetSysCacheOid(AMOPSTRATEGY,
ObjectIdGetDatum(opfamilyoid),
ObjectIdGetDatum(op->lefttype),
ObjectIdGetDatum(op->righttype),
Int16GetDatum(op->number));
if (!OidIsValid(amopid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
op->number,
format_type_be(op->lefttype),
format_type_be(op->righttype),
NameListToString(opfamilyname))));
object.classId = AccessMethodOperatorRelationId;
object.objectId = amopid;
object.objectSubId = 0;
performDeletion(&object, DROP_RESTRICT);
}
}
/*
* Remove procedure entries from an opfamily.
*
* Note: this is only allowed for "loose" members of an opfamily, hence
* behavior is always RESTRICT.
*/
static void
dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *procedures)
{
ListCell *l;
foreach(l, procedures)
{
OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
Oid amprocid;
ObjectAddress object;
amprocid = GetSysCacheOid(AMPROCNUM,
ObjectIdGetDatum(opfamilyoid),
ObjectIdGetDatum(op->lefttype),
ObjectIdGetDatum(op->righttype),
Int16GetDatum(op->number));
if (!OidIsValid(amprocid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
op->number,
format_type_be(op->lefttype),
format_type_be(op->righttype),
NameListToString(opfamilyname))));
object.classId = AccessMethodProcedureRelationId;
object.objectId = amprocid;
object.objectSubId = 0;
performDeletion(&object, DROP_RESTRICT);
}
}
/* /*
* RemoveOpClass * RemoveOpClass
* Deletes an opclass. * Deletes an opclass.
...@@ -997,6 +1555,70 @@ RemoveOpClass(RemoveOpClassStmt *stmt) ...@@ -997,6 +1555,70 @@ RemoveOpClass(RemoveOpClassStmt *stmt)
performDeletion(&object, stmt->behavior); performDeletion(&object, stmt->behavior);
} }
/*
* RemoveOpFamily
* Deletes an opfamily.
*/
void
RemoveOpFamily(RemoveOpFamilyStmt *stmt)
{
Oid amID,
opfID;
HeapTuple tuple;
ObjectAddress object;
/*
* Get the access method's OID.
*/
amID = GetSysCacheOid(AMNAME,
CStringGetDatum(stmt->amname),
0, 0, 0);
if (!OidIsValid(amID))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
stmt->amname)));
/*
* Look up the opfamily.
*/
tuple = OpFamilyCacheLookup(amID, stmt->opfamilyname);
if (!HeapTupleIsValid(tuple))
{
if (!stmt->missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
NameListToString(stmt->opfamilyname), stmt->amname)));
else
ereport(NOTICE,
(errmsg("operator family \"%s\" does not exist for access method \"%s\"",
NameListToString(stmt->opfamilyname), stmt->amname)));
return;
}
opfID = HeapTupleGetOid(tuple);
/* Permission check: must own opfamily or its namespace */
if (!pg_opfamily_ownercheck(opfID, GetUserId()) &&
!pg_namespace_ownercheck(((Form_pg_opfamily) GETSTRUCT(tuple))->opfnamespace,
GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
NameListToString(stmt->opfamilyname));
ReleaseSysCache(tuple);
/*
* Do the deletion
*/
object.classId = OperatorFamilyRelationId;
object.objectId = opfID;
object.objectSubId = 0;
performDeletion(&object, stmt->behavior);
}
/* /*
* Deletion subroutines for use by dependency.c. * Deletion subroutines for use by dependency.c.
*/ */
...@@ -1202,29 +1824,104 @@ RenameOpClass(List *name, const char *access_method, const char *newname) ...@@ -1202,29 +1824,104 @@ RenameOpClass(List *name, const char *access_method, const char *newname)
} }
/* /*
* Change opclass owner by oid * Rename opfamily
*/ */
#ifdef NOT_USED
void void
AlterOpClassOwner_oid(Oid opcOid, Oid newOwnerId) RenameOpFamily(List *name, const char *access_method, const char *newname)
{ {
Relation rel; Oid opfOid;
Oid amOid;
Oid namespaceOid;
char *schemaname;
char *opfname;
HeapTuple tup; HeapTuple tup;
Relation rel;
AclResult aclresult;
rel = heap_open(OperatorClassRelationId, RowExclusiveLock); amOid = GetSysCacheOid(AMNAME,
CStringGetDatum(access_method),
0, 0, 0);
if (!OidIsValid(amOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
access_method)));
tup = SearchSysCacheCopy(CLAOID, rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
ObjectIdGetDatum(opcOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* shouldn't happen */
elog(ERROR, "cache lookup failed for opclass %u", opcOid);
AlterOpClassOwner_internal(rel, tup, newOwnerId); /*
* Look up the opfamily
*/
DeconstructQualifiedName(name, &schemaname, &opfname);
if (schemaname)
{
namespaceOid = LookupExplicitNamespace(schemaname);
tup = SearchSysCacheCopy(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amOid),
PointerGetDatum(opfname),
ObjectIdGetDatum(namespaceOid),
0);
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
opfname, access_method)));
opfOid = HeapTupleGetOid(tup);
}
else
{
opfOid = OpfamilynameGetOpfid(amOid, opfname);
if (!OidIsValid(opfOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
opfname, access_method)));
tup = SearchSysCacheCopy(OPFAMILYOID,
ObjectIdGetDatum(opfOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
namespaceOid = ((Form_pg_opfamily) GETSTRUCT(tup))->opfnamespace;
}
/* make sure the new name doesn't exist */
if (SearchSysCacheExists(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amOid),
CStringGetDatum(newname),
ObjectIdGetDatum(namespaceOid),
0))
{
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
newname, access_method,
get_namespace_name(namespaceOid))));
}
/* must be owner */
if (!pg_opfamily_ownercheck(opfOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
NameListToString(name));
/* must have CREATE privilege on namespace */
aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
/* rename */
namestrcpy(&(((Form_pg_opfamily) GETSTRUCT(tup))->opfname), newname);
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
heap_freetuple(tup);
heap_close(rel, NoLock); heap_close(rel, NoLock);
heap_freetuple(tup);
} }
#endif
/* /*
* Change opclass owner by name * Change opclass owner by name
...@@ -1352,3 +2049,130 @@ AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId) ...@@ -1352,3 +2049,130 @@ AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
newOwnerId); newOwnerId);
} }
} }
/*
* Change opfamily owner by name
*/
void
AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId)
{
Oid amOid;
Relation rel;
HeapTuple tup;
char *opfname;
char *schemaname;
amOid = GetSysCacheOid(AMNAME,
CStringGetDatum(access_method),
0, 0, 0);
if (!OidIsValid(amOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
access_method)));
rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
/*
* Look up the opfamily
*/
DeconstructQualifiedName(name, &schemaname, &opfname);
if (schemaname)
{
Oid namespaceOid;
namespaceOid = LookupExplicitNamespace(schemaname);
tup = SearchSysCacheCopy(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amOid),
PointerGetDatum(opfname),
ObjectIdGetDatum(namespaceOid),
0);
if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
opfname, access_method)));
}
else
{
Oid opfOid;
opfOid = OpfamilynameGetOpfid(amOid, opfname);
if (!OidIsValid(opfOid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"",
opfname, access_method)));
tup = SearchSysCacheCopy(OPFAMILYOID,
ObjectIdGetDatum(opfOid),
0, 0, 0);
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
}
AlterOpFamilyOwner_internal(rel, tup, newOwnerId);
heap_freetuple(tup);
heap_close(rel, NoLock);
}
/*
* The first parameter is pg_opfamily, opened and suitably locked. The second
* parameter is a copy of the tuple from pg_opfamily we want to modify.
*/
static void
AlterOpFamilyOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
{
Oid namespaceOid;
AclResult aclresult;
Form_pg_opfamily opfForm;
Assert(tup->t_tableOid == OperatorFamilyRelationId);
Assert(RelationGetRelid(rel) == OperatorFamilyRelationId);
opfForm = (Form_pg_opfamily) GETSTRUCT(tup);
namespaceOid = opfForm->opfnamespace;
/*
* If the new owner is the same as the existing owner, consider the
* command to have succeeded. This is for dump restoration purposes.
*/
if (opfForm->opfowner != newOwnerId)
{
/* Superusers can always do it */
if (!superuser())
{
/* Otherwise, must be owner of the existing object */
if (!pg_opfamily_ownercheck(HeapTupleGetOid(tup), GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
NameStr(opfForm->opfname));
/* Must be able to become new owner */
check_is_member_of_role(GetUserId(), newOwnerId);
/* New owner must have CREATE privilege on namespace */
aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceOid));
}
/*
* Modify the owner --- okay to scribble on tup because it's a copy
*/
opfForm->opfowner = newOwnerId;
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
/* Update owner dependency reference */
changeDependencyOnOwner(OperatorFamilyRelationId, HeapTupleGetOid(tup),
newOwnerId);
}
}
...@@ -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
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.363 2007/01/22 20:00:39 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.364 2007/01/23 05:07:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2158,6 +2158,19 @@ _copyRemoveOpClassStmt(RemoveOpClassStmt *from) ...@@ -2158,6 +2158,19 @@ _copyRemoveOpClassStmt(RemoveOpClassStmt *from)
return newnode; return newnode;
} }
static RemoveOpFamilyStmt *
_copyRemoveOpFamilyStmt(RemoveOpFamilyStmt *from)
{
RemoveOpFamilyStmt *newnode = makeNode(RemoveOpFamilyStmt);
COPY_NODE_FIELD(opfamilyname);
COPY_STRING_FIELD(amname);
COPY_SCALAR_FIELD(behavior);
COPY_SCALAR_FIELD(missing_ok);
return newnode;
}
static RenameStmt * static RenameStmt *
_copyRenameStmt(RenameStmt *from) _copyRenameStmt(RenameStmt *from)
{ {
...@@ -2332,11 +2345,36 @@ _copyCreateOpClassItem(CreateOpClassItem *from) ...@@ -2332,11 +2345,36 @@ _copyCreateOpClassItem(CreateOpClassItem *from)
COPY_NODE_FIELD(args); COPY_NODE_FIELD(args);
COPY_SCALAR_FIELD(number); COPY_SCALAR_FIELD(number);
COPY_SCALAR_FIELD(recheck); COPY_SCALAR_FIELD(recheck);
COPY_NODE_FIELD(class_args);
COPY_NODE_FIELD(storedtype); COPY_NODE_FIELD(storedtype);
return newnode; return newnode;
} }
static CreateOpFamilyStmt *
_copyCreateOpFamilyStmt(CreateOpFamilyStmt *from)
{
CreateOpFamilyStmt *newnode = makeNode(CreateOpFamilyStmt);
COPY_NODE_FIELD(opfamilyname);
COPY_STRING_FIELD(amname);
return newnode;
}
static AlterOpFamilyStmt *
_copyAlterOpFamilyStmt(AlterOpFamilyStmt *from)
{
AlterOpFamilyStmt *newnode = makeNode(AlterOpFamilyStmt);
COPY_NODE_FIELD(opfamilyname);
COPY_STRING_FIELD(amname);
COPY_SCALAR_FIELD(isDrop);
COPY_NODE_FIELD(items);
return newnode;
}
static CreatedbStmt * static CreatedbStmt *
_copyCreatedbStmt(CreatedbStmt *from) _copyCreatedbStmt(CreatedbStmt *from)
{ {
...@@ -3163,6 +3201,9 @@ copyObject(void *from) ...@@ -3163,6 +3201,9 @@ copyObject(void *from)
case T_RemoveOpClassStmt: case T_RemoveOpClassStmt:
retval = _copyRemoveOpClassStmt(from); retval = _copyRemoveOpClassStmt(from);
break; break;
case T_RemoveOpFamilyStmt:
retval = _copyRemoveOpFamilyStmt(from);
break;
case T_RenameStmt: case T_RenameStmt:
retval = _copyRenameStmt(from); retval = _copyRenameStmt(from);
break; break;
...@@ -3205,6 +3246,12 @@ copyObject(void *from) ...@@ -3205,6 +3246,12 @@ copyObject(void *from)
case T_CreateOpClassItem: case T_CreateOpClassItem:
retval = _copyCreateOpClassItem(from); retval = _copyCreateOpClassItem(from);
break; break;
case T_CreateOpFamilyStmt:
retval = _copyCreateOpFamilyStmt(from);
break;
case T_AlterOpFamilyStmt:
retval = _copyAlterOpFamilyStmt(from);
break;
case T_CreatedbStmt: case T_CreatedbStmt:
retval = _copyCreatedbStmt(from); retval = _copyCreatedbStmt(from);
break; break;
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.296 2007/01/20 20:45:38 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.297 2007/01/23 05:07:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1053,6 +1053,17 @@ _equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b) ...@@ -1053,6 +1053,17 @@ _equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b)
return true; return true;
} }
static bool
_equalRemoveOpFamilyStmt(RemoveOpFamilyStmt *a, RemoveOpFamilyStmt *b)
{
COMPARE_NODE_FIELD(opfamilyname);
COMPARE_STRING_FIELD(amname);
COMPARE_SCALAR_FIELD(behavior);
COMPARE_SCALAR_FIELD(missing_ok);
return true;
}
static bool static bool
_equalRenameStmt(RenameStmt *a, RenameStmt *b) _equalRenameStmt(RenameStmt *a, RenameStmt *b)
{ {
...@@ -1199,11 +1210,32 @@ _equalCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *b) ...@@ -1199,11 +1210,32 @@ _equalCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *b)
COMPARE_NODE_FIELD(args); COMPARE_NODE_FIELD(args);
COMPARE_SCALAR_FIELD(number); COMPARE_SCALAR_FIELD(number);
COMPARE_SCALAR_FIELD(recheck); COMPARE_SCALAR_FIELD(recheck);
COMPARE_NODE_FIELD(class_args);
COMPARE_NODE_FIELD(storedtype); COMPARE_NODE_FIELD(storedtype);
return true; return true;
} }
static bool
_equalCreateOpFamilyStmt(CreateOpFamilyStmt *a, CreateOpFamilyStmt *b)
{
COMPARE_NODE_FIELD(opfamilyname);
COMPARE_STRING_FIELD(amname);
return true;
}
static bool
_equalAlterOpFamilyStmt(AlterOpFamilyStmt *a, AlterOpFamilyStmt *b)
{
COMPARE_NODE_FIELD(opfamilyname);
COMPARE_STRING_FIELD(amname);
COMPARE_SCALAR_FIELD(isDrop);
COMPARE_NODE_FIELD(items);
return true;
}
static bool static bool
_equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b) _equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
{ {
...@@ -2148,6 +2180,9 @@ equal(void *a, void *b) ...@@ -2148,6 +2180,9 @@ equal(void *a, void *b)
case T_RemoveOpClassStmt: case T_RemoveOpClassStmt:
retval = _equalRemoveOpClassStmt(a, b); retval = _equalRemoveOpClassStmt(a, b);
break; break;
case T_RemoveOpFamilyStmt:
retval = _equalRemoveOpFamilyStmt(a, b);
break;
case T_RenameStmt: case T_RenameStmt:
retval = _equalRenameStmt(a, b); retval = _equalRenameStmt(a, b);
break; break;
...@@ -2190,6 +2225,12 @@ equal(void *a, void *b) ...@@ -2190,6 +2225,12 @@ equal(void *a, void *b)
case T_CreateOpClassItem: case T_CreateOpClassItem:
retval = _equalCreateOpClassItem(a, b); retval = _equalCreateOpClassItem(a, b);
break; break;
case T_CreateOpFamilyStmt:
retval = _equalCreateOpFamilyStmt(a, b);
break;
case T_AlterOpFamilyStmt:
retval = _equalAlterOpFamilyStmt(a, b);
break;
case T_CreatedbStmt: case T_CreatedbStmt:
retval = _equalCreatedbStmt(a, b); retval = _equalCreatedbStmt(a, b);
break; break;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.575 2007/01/22 01:35:21 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.576 2007/01/23 05:07:17 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -152,11 +152,12 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) ...@@ -152,11 +152,12 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
CreateDomainStmt CreateGroupStmt CreateOpClassStmt CreatePLangStmt CreateDomainStmt CreateGroupStmt CreateOpClassStmt
CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateAssertStmt CreateTrigStmt CreateUserStmt CreateRoleStmt CreateAssertStmt CreateTrigStmt CreateUserStmt CreateRoleStmt
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt
DropGroupStmt DropOpClassStmt DropPLangStmt DropStmt DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
DropUserStmt DropdbStmt DropTableSpaceStmt ExplainStmt FetchStmt DropUserStmt DropdbStmt DropTableSpaceStmt ExplainStmt FetchStmt
GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
...@@ -174,7 +175,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) ...@@ -174,7 +175,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
%type <node> select_no_parens select_with_parens select_clause %type <node> select_no_parens select_with_parens select_clause
simple_select values_clause simple_select values_clause
%type <node> alter_column_default opclass_item alter_using %type <node> alter_column_default opclass_item opclass_drop alter_using
%type <ival> add_drop opt_asc_desc opt_nulls_order %type <ival> add_drop opt_asc_desc opt_nulls_order
%type <node> alter_table_cmd alter_rel_cmd %type <node> alter_table_cmd alter_rel_cmd
...@@ -229,7 +230,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) ...@@ -229,7 +230,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
OptTableElementList TableElementList OptInherit definition OptTableElementList TableElementList OptInherit definition
OptWith opt_distinct opt_definition func_args func_args_list OptWith opt_distinct opt_definition func_args func_args_list
func_as createfunc_opt_list alterfunc_opt_list func_as createfunc_opt_list alterfunc_opt_list
aggr_args aggr_args_list old_aggr_definition old_aggr_list aggr_args old_aggr_definition old_aggr_list
oper_argtypes RuleActionList RuleActionMulti oper_argtypes RuleActionList RuleActionMulti
opt_column_list columnList opt_name_list opt_column_list columnList opt_name_list
sort_clause opt_sort_clause sortby_list index_params sort_clause opt_sort_clause sortby_list index_params
...@@ -240,10 +241,10 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) ...@@ -240,10 +241,10 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
set_clause_list set_clause multiple_set_clause set_clause_list set_clause multiple_set_clause
ctext_expr_list ctext_row def_list indirection opt_indirection ctext_expr_list ctext_row def_list indirection opt_indirection
group_clause TriggerFuncArgs select_limit group_clause TriggerFuncArgs select_limit
opt_select_limit opclass_item_list opt_select_limit opclass_item_list opclass_drop_list
transaction_mode_list_or_empty opt_opfamily transaction_mode_list_or_empty
TableFuncElementList opt_type_modifiers TableFuncElementList opt_type_modifiers
prep_type_clause prep_type_list prep_type_clause
execute_param_clause using_clause returning_clause execute_param_clause using_clause returning_clause
%type <range> into_clause OptTempTableName %type <range> into_clause OptTempTableName
...@@ -381,7 +382,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) ...@@ -381,7 +382,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
FALSE_P FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
FREEZE FROM FULL FUNCTION FREEZE FROM FULL FUNCTION
GLOBAL GRANT GRANTED GREATEST GROUP_P GLOBAL GRANT GRANTED GREATEST GROUP_P
...@@ -548,6 +549,8 @@ stmt : ...@@ -548,6 +549,8 @@ stmt :
| CreateFunctionStmt | CreateFunctionStmt
| CreateGroupStmt | CreateGroupStmt
| CreateOpClassStmt | CreateOpClassStmt
| CreateOpFamilyStmt
| AlterOpFamilyStmt
| CreatePLangStmt | CreatePLangStmt
| CreateSchemaStmt | CreateSchemaStmt
| CreateSeqStmt | CreateSeqStmt
...@@ -565,6 +568,7 @@ stmt : ...@@ -565,6 +568,7 @@ stmt :
| DropCastStmt | DropCastStmt
| DropGroupStmt | DropGroupStmt
| DropOpClassStmt | DropOpClassStmt
| DropOpFamilyStmt
| DropOwnedStmt | DropOwnedStmt
| DropPLangStmt | DropPLangStmt
| DropRuleStmt | DropRuleStmt
...@@ -929,7 +933,7 @@ AlterGroupStmt: ...@@ -929,7 +933,7 @@ AlterGroupStmt:
} }
; ;
add_drop: ADD_P { $$ = +1; } add_drop: ADD_P { $$ = +1; }
| DROP { $$ = -1; } | DROP { $$ = -1; }
; ;
...@@ -2879,15 +2883,10 @@ def_arg: func_type { $$ = (Node *)$1; } ...@@ -2879,15 +2883,10 @@ def_arg: func_type { $$ = (Node *)$1; }
| Sconst { $$ = (Node *)makeString($1); } | Sconst { $$ = (Node *)makeString($1); }
; ;
aggr_args: '(' aggr_args_list ')' { $$ = $2; } aggr_args: '(' type_list ')' { $$ = $2; }
| '(' '*' ')' { $$ = NIL; } | '(' '*' ')' { $$ = NIL; }
; ;
aggr_args_list:
Typename { $$ = list_make1($1); }
| aggr_args_list ',' Typename { $$ = lappend($1, $3); }
;
old_aggr_definition: '(' old_aggr_list ')' { $$ = $2; } old_aggr_definition: '(' old_aggr_list ')' { $$ = $2; }
; ;
...@@ -2906,20 +2905,24 @@ old_aggr_elem: IDENT '=' def_arg ...@@ -2906,20 +2905,24 @@ old_aggr_elem: IDENT '=' def_arg
* *
* QUERIES : * QUERIES :
* CREATE OPERATOR CLASS ... * CREATE OPERATOR CLASS ...
* CREATE OPERATOR FAMILY ...
* ALTER OPERATOR FAMILY ...
* DROP OPERATOR CLASS ... * DROP OPERATOR CLASS ...
* DROP OPERATOR FAMILY ...
* *
*****************************************************************************/ *****************************************************************************/
CreateOpClassStmt: CreateOpClassStmt:
CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename
USING access_method AS opclass_item_list USING access_method opt_opfamily AS opclass_item_list
{ {
CreateOpClassStmt *n = makeNode(CreateOpClassStmt); CreateOpClassStmt *n = makeNode(CreateOpClassStmt);
n->opclassname = $4; n->opclassname = $4;
n->isDefault = $5; n->isDefault = $5;
n->datatype = $8; n->datatype = $8;
n->amname = $10; n->amname = $10;
n->items = $12; n->opfamilyname = $11;
n->items = $13;
$$ = (Node *) n; $$ = (Node *) n;
} }
; ;
...@@ -2959,6 +2962,16 @@ opclass_item: ...@@ -2959,6 +2962,16 @@ opclass_item:
n->number = $2; n->number = $2;
$$ = (Node *) n; $$ = (Node *) n;
} }
| FUNCTION Iconst '(' type_list ')' func_name func_args
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_FUNCTION;
n->name = $6;
n->args = extractArgTypes($7);
n->number = $2;
n->class_args = $4;
$$ = (Node *) n;
}
| STORAGE Typename | STORAGE Typename
{ {
CreateOpClassItem *n = makeNode(CreateOpClassItem); CreateOpClassItem *n = makeNode(CreateOpClassItem);
...@@ -2968,12 +2981,72 @@ opclass_item: ...@@ -2968,12 +2981,72 @@ opclass_item:
} }
; ;
opt_default: DEFAULT { $$ = TRUE; } opt_default: DEFAULT { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; } | /*EMPTY*/ { $$ = FALSE; }
;
opt_opfamily: FAMILY any_name { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
opt_recheck: RECHECK { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
CreateOpFamilyStmt:
CREATE OPERATOR FAMILY any_name USING access_method
{
CreateOpFamilyStmt *n = makeNode(CreateOpFamilyStmt);
n->opfamilyname = $4;
n->amname = $6;
$$ = (Node *) n;
}
;
AlterOpFamilyStmt:
ALTER OPERATOR FAMILY any_name USING access_method ADD_P opclass_item_list
{
AlterOpFamilyStmt *n = makeNode(AlterOpFamilyStmt);
n->opfamilyname = $4;
n->amname = $6;
n->isDrop = false;
n->items = $8;
$$ = (Node *) n;
}
| ALTER OPERATOR FAMILY any_name USING access_method DROP opclass_drop_list
{
AlterOpFamilyStmt *n = makeNode(AlterOpFamilyStmt);
n->opfamilyname = $4;
n->amname = $6;
n->isDrop = true;
n->items = $8;
$$ = (Node *) n;
}
;
opclass_drop_list:
opclass_drop { $$ = list_make1($1); }
| opclass_drop_list ',' opclass_drop { $$ = lappend($1, $3); }
; ;
opt_recheck: RECHECK { $$ = TRUE; } opclass_drop:
| /*EMPTY*/ { $$ = FALSE; } OPERATOR Iconst '(' type_list ')'
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_OPERATOR;
n->number = $2;
n->args = $4;
$$ = (Node *) n;
}
| FUNCTION Iconst '(' type_list ')'
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
n->itemtype = OPCLASS_ITEM_FUNCTION;
n->number = $2;
n->args = $4;
$$ = (Node *) n;
}
; ;
...@@ -2998,6 +3071,28 @@ DropOpClassStmt: ...@@ -2998,6 +3071,28 @@ DropOpClassStmt:
} }
; ;
DropOpFamilyStmt:
DROP OPERATOR FAMILY any_name USING access_method opt_drop_behavior
{
RemoveOpFamilyStmt *n = makeNode(RemoveOpFamilyStmt);
n->opfamilyname = $4;
n->amname = $6;
n->behavior = $7;
n->missing_ok = false;
$$ = (Node *) n;
}
| DROP OPERATOR FAMILY IF_P EXISTS any_name USING access_method opt_drop_behavior
{
RemoveOpFamilyStmt *n = makeNode(RemoveOpFamilyStmt);
n->opfamilyname = $6;
n->amname = $8;
n->behavior = $9;
n->missing_ok = true;
$$ = (Node *) n;
}
;
/***************************************************************************** /*****************************************************************************
* *
* QUERY: * QUERY:
...@@ -3201,6 +3296,15 @@ CommentStmt: ...@@ -3201,6 +3296,15 @@ CommentStmt:
n->comment = $9; n->comment = $9;
$$ = (Node *) n; $$ = (Node *) n;
} }
| COMMENT ON OPERATOR FAMILY any_name USING access_method IS comment_text
{
CommentStmt *n = makeNode(CommentStmt);
n->objtype = OBJECT_OPFAMILY;
n->objname = $5;
n->objargs = list_make1(makeString($7));
n->comment = $9;
$$ = (Node *) n;
}
| COMMENT ON LARGE_P OBJECT_P NumericOnly IS comment_text | COMMENT ON LARGE_P OBJECT_P NumericOnly IS comment_text
{ {
CommentStmt *n = makeNode(CommentStmt); CommentStmt *n = makeNode(CommentStmt);
...@@ -4115,9 +4219,9 @@ oper_argtypes: ...@@ -4115,9 +4219,9 @@ oper_argtypes:
} }
| Typename ',' Typename | Typename ',' Typename
{ $$ = list_make2($1, $3); } { $$ = list_make2($1, $3); }
| NONE ',' Typename /* left unary */ | NONE ',' Typename /* left unary */
{ $$ = list_make2(NULL, $3); } { $$ = list_make2(NULL, $3); }
| Typename ',' NONE /* right unary */ | Typename ',' NONE /* right unary */
{ $$ = list_make2($1, NULL); } { $$ = list_make2($1, NULL); }
; ;
...@@ -4174,8 +4278,8 @@ DropCastStmt: DROP CAST opt_if_exists '(' Typename AS Typename ')' opt_drop_beha ...@@ -4174,8 +4278,8 @@ DropCastStmt: DROP CAST opt_if_exists '(' Typename AS Typename ')' opt_drop_beha
} }
; ;
opt_if_exists: IF_P EXISTS { $$ = true; } opt_if_exists: IF_P EXISTS { $$ = TRUE; }
| /*EMPTY*/ { $$ = false; } | /*EMPTY*/ { $$ = FALSE; }
; ;
...@@ -4294,6 +4398,15 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name ...@@ -4294,6 +4398,15 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
n->newname = $9; n->newname = $9;
$$ = (Node *)n; $$ = (Node *)n;
} }
| ALTER OPERATOR FAMILY any_name USING access_method RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_OPFAMILY;
n->object = $4;
n->subname = $6;
n->newname = $9;
$$ = (Node *)n;
}
| ALTER SCHEMA name RENAME TO name | ALTER SCHEMA name RENAME TO name
{ {
RenameStmt *n = makeNode(RenameStmt); RenameStmt *n = makeNode(RenameStmt);
...@@ -4493,6 +4606,15 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId ...@@ -4493,6 +4606,15 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9; n->newowner = $9;
$$ = (Node *)n; $$ = (Node *)n;
} }
| ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPFAMILY;
n->object = $4;
n->addname = $6;
n->newowner = $9;
$$ = (Node *)n;
}
| ALTER SCHEMA name OWNER TO RoleId | ALTER SCHEMA name OWNER TO RoleId
{ {
AlterOwnerStmt *n = makeNode(AlterOwnerStmt); AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
...@@ -5302,15 +5424,10 @@ PrepareStmt: PREPARE name prep_type_clause AS PreparableStmt ...@@ -5302,15 +5424,10 @@ PrepareStmt: PREPARE name prep_type_clause AS PreparableStmt
} }
; ;
prep_type_clause: '(' prep_type_list ')' { $$ = $2; } prep_type_clause: '(' type_list ')' { $$ = $2; }
| /* EMPTY */ { $$ = NIL; } | /* EMPTY */ { $$ = NIL; }
; ;
prep_type_list: Typename { $$ = list_make1($1); }
| prep_type_list ',' Typename
{ $$ = lappend($1, $3); }
;
PreparableStmt: PreparableStmt:
SelectStmt SelectStmt
| InsertStmt | InsertStmt
...@@ -7968,14 +8085,8 @@ extract_list: ...@@ -7968,14 +8085,8 @@ extract_list:
| /*EMPTY*/ { $$ = NIL; } | /*EMPTY*/ { $$ = NIL; }
; ;
type_list: type_list ',' Typename type_list: Typename { $$ = list_make1($1); }
{ | type_list ',' Typename { $$ = lappend($1, $3); }
$$ = lappend($1, $3);
}
| Typename
{
$$ = list_make1($1);
}
; ;
array_expr_list: array_expr array_expr_list: array_expr
...@@ -8604,6 +8715,7 @@ unreserved_keyword: ...@@ -8604,6 +8715,7 @@ unreserved_keyword:
| EXECUTE | EXECUTE
| EXPLAIN | EXPLAIN
| EXTERNAL | EXTERNAL
| FAMILY
| FETCH | FETCH
| FIRST_P | FIRST_P
| FORCE | FORCE
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.182 2007/01/22 01:35:21 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.183 2007/01/23 05:07:18 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -145,6 +145,7 @@ static const ScanKeyword ScanKeywords[] = { ...@@ -145,6 +145,7 @@ static const ScanKeyword ScanKeywords[] = {
{"external", EXTERNAL}, {"external", EXTERNAL},
{"extract", EXTRACT}, {"extract", EXTRACT},
{"false", FALSE_P}, {"false", FALSE_P},
{"family", FAMILY},
{"fetch", FETCH}, {"fetch", FETCH},
{"first", FIRST_P}, {"first", FIRST_P},
{"float", FLOAT_P}, {"float", FLOAT_P},
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.270 2007/01/05 22:19:39 momjian Exp $ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.271 2007/01/23 05:07:18 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -322,6 +322,8 @@ check_xact_readonly(Node *parsetree) ...@@ -322,6 +322,8 @@ check_xact_readonly(Node *parsetree)
case T_IndexStmt: case T_IndexStmt:
case T_CreatePLangStmt: case T_CreatePLangStmt:
case T_CreateOpClassStmt: case T_CreateOpClassStmt:
case T_CreateOpFamilyStmt:
case T_AlterOpFamilyStmt:
case T_RuleStmt: case T_RuleStmt:
case T_CreateSchemaStmt: case T_CreateSchemaStmt:
case T_CreateSeqStmt: case T_CreateSeqStmt:
...@@ -338,6 +340,7 @@ check_xact_readonly(Node *parsetree) ...@@ -338,6 +340,7 @@ check_xact_readonly(Node *parsetree)
case T_DropRoleStmt: case T_DropRoleStmt:
case T_DropPLangStmt: case T_DropPLangStmt:
case T_RemoveOpClassStmt: case T_RemoveOpClassStmt:
case T_RemoveOpFamilyStmt:
case T_DropPropertyStmt: case T_DropPropertyStmt:
case T_GrantStmt: case T_GrantStmt:
case T_GrantRoleStmt: case T_GrantRoleStmt:
...@@ -1099,10 +1102,22 @@ ProcessUtility(Node *parsetree, ...@@ -1099,10 +1102,22 @@ ProcessUtility(Node *parsetree,
DefineOpClass((CreateOpClassStmt *) parsetree); DefineOpClass((CreateOpClassStmt *) parsetree);
break; break;
case T_CreateOpFamilyStmt:
DefineOpFamily((CreateOpFamilyStmt *) parsetree);
break;
case T_AlterOpFamilyStmt:
AlterOpFamily((AlterOpFamilyStmt *) parsetree);
break;
case T_RemoveOpClassStmt: case T_RemoveOpClassStmt:
RemoveOpClass((RemoveOpClassStmt *) parsetree); RemoveOpClass((RemoveOpClassStmt *) parsetree);
break; break;
case T_RemoveOpFamilyStmt:
RemoveOpFamily((RemoveOpFamilyStmt *) parsetree);
break;
default: default:
elog(ERROR, "unrecognized node type: %d", elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(parsetree)); (int) nodeTag(parsetree));
...@@ -1445,6 +1460,9 @@ CreateCommandTag(Node *parsetree) ...@@ -1445,6 +1460,9 @@ CreateCommandTag(Node *parsetree)
case OBJECT_OPCLASS: case OBJECT_OPCLASS:
tag = "ALTER OPERATOR CLASS"; tag = "ALTER OPERATOR CLASS";
break; break;
case OBJECT_OPFAMILY:
tag = "ALTER OPERATOR FAMILY";
break;
case OBJECT_ROLE: case OBJECT_ROLE:
tag = "ALTER ROLE"; tag = "ALTER ROLE";
break; break;
...@@ -1518,6 +1536,9 @@ CreateCommandTag(Node *parsetree) ...@@ -1518,6 +1536,9 @@ CreateCommandTag(Node *parsetree)
case OBJECT_OPCLASS: case OBJECT_OPCLASS:
tag = "ALTER OPERATOR CLASS"; tag = "ALTER OPERATOR CLASS";
break; break;
case OBJECT_OPFAMILY:
tag = "ALTER OPERATOR FAMILY";
break;
case OBJECT_SCHEMA: case OBJECT_SCHEMA:
tag = "ALTER SCHEMA"; tag = "ALTER SCHEMA";
break; break;
...@@ -1777,10 +1798,22 @@ CreateCommandTag(Node *parsetree) ...@@ -1777,10 +1798,22 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE OPERATOR CLASS"; tag = "CREATE OPERATOR CLASS";
break; break;
case T_CreateOpFamilyStmt:
tag = "CREATE OPERATOR FAMILY";
break;
case T_AlterOpFamilyStmt:
tag = "ALTER OPERATOR FAMILY";
break;
case T_RemoveOpClassStmt: case T_RemoveOpClassStmt:
tag = "DROP OPERATOR CLASS"; tag = "DROP OPERATOR CLASS";
break; break;
case T_RemoveOpFamilyStmt:
tag = "DROP OPERATOR FAMILY";
break;
case T_PrepareStmt: case T_PrepareStmt:
tag = "PREPARE"; tag = "PREPARE";
break; break;
...@@ -2147,10 +2180,22 @@ GetCommandLogLevel(Node *parsetree) ...@@ -2147,10 +2180,22 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_DDL; lev = LOGSTMT_DDL;
break; break;
case T_CreateOpFamilyStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterOpFamilyStmt:
lev = LOGSTMT_DDL;
break;
case T_RemoveOpClassStmt: case T_RemoveOpClassStmt:
lev = LOGSTMT_DDL; lev = LOGSTMT_DDL;
break; break;
case T_RemoveOpFamilyStmt:
lev = LOGSTMT_DDL;
break;
case T_PrepareStmt: case T_PrepareStmt:
{ {
PrepareStmt *stmt = (PrepareStmt *) parsetree; PrepareStmt *stmt = (PrepareStmt *) parsetree;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.79 2007/01/05 22:19:53 momjian Exp $ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.80 2007/01/23 05:07:18 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -79,13 +79,18 @@ extern void AlterAggregateOwner(List *name, List *args, Oid newOwnerId); ...@@ -79,13 +79,18 @@ extern void AlterAggregateOwner(List *name, List *args, Oid newOwnerId);
/* commands/opclasscmds.c */ /* commands/opclasscmds.c */
extern void DefineOpClass(CreateOpClassStmt *stmt); extern void DefineOpClass(CreateOpClassStmt *stmt);
extern void DefineOpFamily(CreateOpFamilyStmt *stmt);
extern void AlterOpFamily(AlterOpFamilyStmt *stmt);
extern void RemoveOpClass(RemoveOpClassStmt *stmt); extern void RemoveOpClass(RemoveOpClassStmt *stmt);
extern void RemoveOpFamily(RemoveOpFamilyStmt *stmt);
extern void RemoveOpClassById(Oid opclassOid); extern void RemoveOpClassById(Oid opclassOid);
extern void RemoveOpFamilyById(Oid opfamilyOid); extern void RemoveOpFamilyById(Oid opfamilyOid);
extern void RemoveAmOpEntryById(Oid entryOid); extern void RemoveAmOpEntryById(Oid entryOid);
extern void RemoveAmProcEntryById(Oid entryOid); extern void RemoveAmProcEntryById(Oid entryOid);
extern void RenameOpClass(List *name, const char *access_method, const char *newname); extern void RenameOpClass(List *name, const char *access_method, const char *newname);
extern void RenameOpFamily(List *name, const char *access_method, const char *newname);
extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId); extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId);
extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
/* support routines in commands/define.c */ /* support routines in commands/define.c */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.192 2007/01/20 20:45:40 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.193 2007/01/23 05:07:18 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -286,7 +286,10 @@ typedef enum NodeTag ...@@ -286,7 +286,10 @@ typedef enum NodeTag
T_CreateCastStmt, T_CreateCastStmt,
T_DropCastStmt, T_DropCastStmt,
T_CreateOpClassStmt, T_CreateOpClassStmt,
T_CreateOpFamilyStmt,
T_AlterOpFamilyStmt,
T_RemoveOpClassStmt, T_RemoveOpClassStmt,
T_RemoveOpFamilyStmt,
T_PrepareStmt, T_PrepareStmt,
T_ExecuteStmt, T_ExecuteStmt,
T_DeallocateStmt, T_DeallocateStmt,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.338 2007/01/09 02:14:15 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.339 2007/01/23 05:07:18 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -852,6 +852,7 @@ typedef enum ObjectType ...@@ -852,6 +852,7 @@ typedef enum ObjectType
OBJECT_LARGEOBJECT, OBJECT_LARGEOBJECT,
OBJECT_OPCLASS, OBJECT_OPCLASS,
OBJECT_OPERATOR, OBJECT_OPERATOR,
OBJECT_OPFAMILY,
OBJECT_ROLE, OBJECT_ROLE,
OBJECT_RULE, OBJECT_RULE,
OBJECT_SCHEMA, OBJECT_SCHEMA,
...@@ -1194,7 +1195,7 @@ typedef struct DropTableSpaceStmt ...@@ -1194,7 +1195,7 @@ typedef struct DropTableSpaceStmt
{ {
NodeTag type; NodeTag type;
char *tablespacename; char *tablespacename;
bool missing_ok; /* skip error if a missing? */ bool missing_ok; /* skip error if missing? */
} DropTableSpaceStmt; } DropTableSpaceStmt;
/* ---------------------- /* ----------------------
...@@ -1362,10 +1363,35 @@ typedef struct CreateOpClassItem ...@@ -1362,10 +1363,35 @@ typedef struct CreateOpClassItem
List *args; /* argument types */ List *args; /* argument types */
int number; /* strategy num or support proc num */ int number; /* strategy num or support proc num */
bool recheck; /* only used for operators */ bool recheck; /* only used for operators */
List *class_args; /* only used for functions */
/* fields used for a storagetype item: */ /* fields used for a storagetype item: */
TypeName *storedtype; /* datatype stored in index */ TypeName *storedtype; /* datatype stored in index */
} CreateOpClassItem; } CreateOpClassItem;
/* ----------------------
* Create Operator Family Statement
* ----------------------
*/
typedef struct CreateOpFamilyStmt
{
NodeTag type;
List *opfamilyname; /* qualified name (list of Value strings) */
char *amname; /* name of index AM opfamily is for */
} CreateOpFamilyStmt;
/* ----------------------
* Alter Operator Family Statement
* ----------------------
*/
typedef struct AlterOpFamilyStmt
{
NodeTag type;
List *opfamilyname; /* qualified name (list of Value strings) */
char *amname; /* name of index AM opfamily is for */
bool isDrop; /* ADD or DROP the items? */
List *items; /* List of CreateOpClassItem nodes */
} AlterOpFamilyStmt;
/* ---------------------- /* ----------------------
* Drop Table|Sequence|View|Index|Type|Domain|Conversion|Schema Statement * Drop Table|Sequence|View|Index|Type|Domain|Conversion|Schema Statement
* ---------------------- * ----------------------
...@@ -1395,7 +1421,7 @@ typedef struct DropPropertyStmt ...@@ -1395,7 +1421,7 @@ typedef struct DropPropertyStmt
char *property; /* name of rule, trigger, etc */ char *property; /* name of rule, trigger, etc */
ObjectType removeType; /* OBJECT_RULE or OBJECT_TRIGGER */ ObjectType removeType; /* OBJECT_RULE or OBJECT_TRIGGER */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */ DropBehavior behavior; /* RESTRICT or CASCADE behavior */
bool missing_ok; /* skip error if a missing? */ bool missing_ok; /* skip error if missing? */
} DropPropertyStmt; } DropPropertyStmt;
/* ---------------------- /* ----------------------
...@@ -1546,7 +1572,7 @@ typedef struct RemoveFuncStmt ...@@ -1546,7 +1572,7 @@ typedef struct RemoveFuncStmt
List *name; /* qualified name of object to drop */ List *name; /* qualified name of object to drop */
List *args; /* types of the arguments */ List *args; /* types of the arguments */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */ DropBehavior behavior; /* RESTRICT or CASCADE behavior */
bool missing_ok; /* skip error if a missing? */ bool missing_ok; /* skip error if missing? */
} RemoveFuncStmt; } RemoveFuncStmt;
/* ---------------------- /* ----------------------
...@@ -1559,9 +1585,22 @@ typedef struct RemoveOpClassStmt ...@@ -1559,9 +1585,22 @@ typedef struct RemoveOpClassStmt
List *opclassname; /* qualified name (list of Value strings) */ List *opclassname; /* qualified name (list of Value strings) */
char *amname; /* name of index AM opclass is for */ char *amname; /* name of index AM opclass is for */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */ DropBehavior behavior; /* RESTRICT or CASCADE behavior */
bool missing_ok; /* skip error if a missing? */ bool missing_ok; /* skip error if missing? */
} RemoveOpClassStmt; } RemoveOpClassStmt;
/* ----------------------
* Drop Operator Family Statement
* ----------------------
*/
typedef struct RemoveOpFamilyStmt
{
NodeTag type;
List *opfamilyname; /* qualified name (list of Value strings) */
char *amname; /* name of index AM opfamily is for */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
bool missing_ok; /* skip error if missing? */
} RemoveOpFamilyStmt;
/* ---------------------- /* ----------------------
* Alter Object Rename Statement * Alter Object Rename Statement
* ---------------------- * ----------------------
...@@ -1917,7 +1956,7 @@ typedef struct DropCastStmt ...@@ -1917,7 +1956,7 @@ typedef struct DropCastStmt
TypeName *sourcetype; TypeName *sourcetype;
TypeName *targettype; TypeName *targettype;
DropBehavior behavior; DropBehavior behavior;
bool missing_ok; /* skip error if a missing? */ bool missing_ok; /* skip error if missing? */
} DropCastStmt; } DropCastStmt;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.99 2007/01/05 22:19:58 momjian Exp $ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.100 2007/01/23 05:07:18 tgl Exp $
* *
* NOTES * NOTES
* An ACL array is simply an array of AclItems, representing the union * An ACL array is simply an array of AclItems, representing the union
...@@ -178,6 +178,7 @@ typedef enum AclObjectKind ...@@ -178,6 +178,7 @@ typedef enum AclObjectKind
ACL_KIND_LANGUAGE, /* pg_language */ ACL_KIND_LANGUAGE, /* pg_language */
ACL_KIND_NAMESPACE, /* pg_namespace */ ACL_KIND_NAMESPACE, /* pg_namespace */
ACL_KIND_OPCLASS, /* pg_opclass */ ACL_KIND_OPCLASS, /* pg_opclass */
ACL_KIND_OPFAMILY, /* pg_opfamily */
ACL_KIND_CONVERSION, /* pg_conversion */ ACL_KIND_CONVERSION, /* pg_conversion */
ACL_KIND_TABLESPACE, /* pg_tablespace */ ACL_KIND_TABLESPACE, /* pg_tablespace */
MAX_ACL_KIND /* MUST BE LAST */ MAX_ACL_KIND /* MUST BE LAST */
...@@ -276,6 +277,7 @@ extern bool pg_proc_ownercheck(Oid proc_oid, Oid roleid); ...@@ -276,6 +277,7 @@ extern bool pg_proc_ownercheck(Oid proc_oid, Oid roleid);
extern bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid); extern bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid);
extern bool pg_tablespace_ownercheck(Oid spc_oid, Oid roleid); extern bool pg_tablespace_ownercheck(Oid spc_oid, Oid roleid);
extern bool pg_opclass_ownercheck(Oid opc_oid, Oid roleid); extern bool pg_opclass_ownercheck(Oid opc_oid, Oid roleid);
extern bool pg_opfamily_ownercheck(Oid opf_oid, Oid roleid);
extern bool pg_database_ownercheck(Oid db_oid, Oid roleid); extern bool pg_database_ownercheck(Oid db_oid, Oid roleid);
extern bool pg_conversion_ownercheck(Oid conv_oid, Oid roleid); extern bool pg_conversion_ownercheck(Oid conv_oid, Oid roleid);
......
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