<!--
-$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
Complete list of usable sgml source files in this directory.
-->
<!entity alterLanguage system "alter_language.sgml">
<!entity alterOperator system "alter_operator.sgml">
<!entity alterOperatorClass system "alter_opclass.sgml">
+<!entity alterOperatorFamily system "alter_opfamily.sgml">
<!entity alterRole system "alter_role.sgml">
<!entity alterSchema system "alter_schema.sgml">
<!entity alterSequence system "alter_sequence.sgml">
<!entity createLanguage system "create_language.sgml">
<!entity createOperator system "create_operator.sgml">
<!entity createOperatorClass system "create_opclass.sgml">
+<!entity createOperatorFamily system "create_opfamily.sgml">
<!entity createRole system "create_role.sgml">
<!entity createRule system "create_rule.sgml">
<!entity createSchema system "create_schema.sgml">
<!entity dropLanguage system "drop_language.sgml">
<!entity dropOperator system "drop_operator.sgml">
<!entity dropOperatorClass system "drop_opclass.sgml">
+<!entity dropOperatorFamily system "drop_opfamily.sgml">
<!entity dropOwned system "drop_owned.sgml">
<!entity dropRole system "drop_role.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
-->
<simplelist type="inline">
<member><xref linkend="sql-createopclass" endterm="sql-createopclass-title"></member>
<member><xref linkend="sql-dropopclass" endterm="sql-dropopclass-title"></member>
+ <member><xref linkend="sql-alteropfamily" endterm="sql-alteropfamily-title"></member>
</simplelist>
</refsect1>
</refentry>
--- /dev/null
+<!--
+$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 < (int4, int2) ,
+ OPERATOR 2 <= (int4, int2) ,
+ OPERATOR 3 = (int4, int2) ,
+ OPERATOR 4 >= (int4, int2) ,
+ OPERATOR 5 > (int4, int2) ,
+ FUNCTION 1 btint42cmp(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 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
-->
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 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> |
ROLE <replaceable class="PARAMETER">object_name</replaceable> |
RULE <replaceable class="PARAMETER">rule_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
<para>
The name of the object to be commented. Names of tables,
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>
</listitem>
</varlistentry>
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 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 RULE my_rule ON my_table IS 'Logs updates of employee records';
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
-->
<refsynopsisdiv>
<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 ]
- | 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>
} [, ... ]
</synopsis>
be used by
the index method when the operator class is selected for an
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>
responsibility to define a valid operator class.
</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>
Refer to <xref linkend="xindex"> for further information.
</para>
</listitem>
</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>
<term><replaceable class="parameter">strategy_number</replaceable></term>
<listitem>
<term><replaceable class="parameter">op_type</replaceable></term>
<listitem>
<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
types may be omitted in the normal case where they are the same
as the operator class's data type.
</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>
</varlistentry>
<para>
The data type actually stored in the index. Normally this is
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
method allows a different type to be used.
</para>
<simplelist type="inline">
<member><xref linkend="sql-alteropclass" endterm="sql-alteropclass-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>
</refsect1>
</refentry>
--- /dev/null
+<!--
+$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
-->
<command>DROP OPERATOR CLASS</command> drops an existing operator class.
To execute this command you must be the owner of the operator class.
</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>
</varlistentry>
</variablelist>
</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>
<title>Examples</title>
<simplelist type="inline">
<member><xref linkend="sql-alteropclass" endterm="sql-alteropclass-title"></member>
<member><xref linkend="sql-createopclass" endterm="sql-createopclass-title"></member>
+ <member><xref linkend="sql-dropopfamily" endterm="sql-dropopfamily-title"></member>
</simplelist>
</refsect1>
--- /dev/null
+<!--
+$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">
<title>Reference</title>
&alterLanguage;
&alterOperator;
&alterOperatorClass;
+ &alterOperatorFamily;
&alterRole;
&alterSchema;
&alterSequence;
&createLanguage;
&createOperator;
&createOperatorClass;
+ &createOperatorFamily;
&createRole;
&createRule;
&createSchema;
&dropLanguage;
&dropOperator;
&dropOperatorClass;
+ &dropOperatorFamily;
&dropOwned;
&dropRole;
&dropRule;
*
*
* 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
* See acl.h.
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
+#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
gettext_noop("permission denied for schema %s"),
/* ACL_KIND_OPCLASS */
gettext_noop("permission denied for operator class %s"),
+ /* ACL_KIND_OPFAMILY */
+ gettext_noop("permission denied for operator family %s"),
/* ACL_KIND_CONVERSION */
gettext_noop("permission denied for conversion %s"),
/* ACL_KIND_TABLESPACE */
gettext_noop("must be owner of schema %s"),
/* ACL_KIND_OPCLASS */
gettext_noop("must be owner of operator class %s"),
+ /* ACL_KIND_OPFAMILY */
+ gettext_noop("must be owner of operator family %s"),
/* ACL_KIND_CONVERSION */
gettext_noop("must be owner of conversion %s"),
/* ACL_KIND_TABLESPACE */
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).
*/
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
RenameOpClass(stmt->object, stmt->subname, stmt->newname);
break;
+ case OBJECT_OPFAMILY:
+ RenameOpFamily(stmt->object, stmt->subname, stmt->newname);
+ break;
+
case OBJECT_ROLE:
RenameRole(stmt->subname, stmt->newname);
break;
AlterOpClassOwner(stmt->object, stmt->addname, newowner);
break;
+ case OBJECT_OPFAMILY:
+ AlterOpFamilyOwner(stmt->object, stmt->addname, newowner);
+ break;
+
case OBJECT_SCHEMA:
AlterSchemaOwner((char *) linitial(stmt->object), newowner);
break;
* Copyright (c) 1996-2007, PostgreSQL Global Development Group
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
+#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_shdescription.h"
static void CommentConversion(List *qualname, char *comment);
static void CommentLanguage(List *qualname, 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 CommentCast(List *qualname, List *arguments, char *comment);
static void CommentTablespace(List *qualname, char *comment);
case OBJECT_OPCLASS:
CommentOpClass(stmt->objname, stmt->objargs, stmt->comment);
break;
+ case OBJECT_OPFAMILY:
+ CommentOpFamily(stmt->objname, stmt->objargs, stmt->comment);
+ break;
case OBJECT_LARGEOBJECT:
CommentLargeObject(stmt->objname, stmt->comment);
break;
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 --
*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
} 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 assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc);
-static void storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid,
- List *operators);
-static void storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid,
- List *procedures);
+static void storeOperators(List *opfamilyname, Oid amoid,
+ Oid opfamilyoid, Oid opclassoid,
+ List *operators, bool isAdd);
+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,
Oid newOwnerId);
+static void AlterOpFamilyOwner_internal(Relation rel, HeapTuple tuple,
+ Oid newOwnerId);
/*
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, typeoid);
addFamilyMember(&procedures, member, true);
break;
* Now add tuples to pg_amop and pg_amproc tying in the operators and
* functions. Dependencies on them are inserted, too.
*/
- storeOperators(amoid, opfamilyoid, opclassoid, operators);
- storeProcedures(amoid, opfamilyoid, opclassoid, procedures);
+ storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
+ opclassoid, operators, false);
+ storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
+ opclassoid, procedures, false);
/*
* Create dependencies for the opclass proper. Note: we do not create a
heap_close(rel, RowExclusiveLock);
}
+
/*
- * Determine the lefttype/righttype to assign to an operator,
- * and do any validity checking we can manage.
+ * DefineOpFamily
+ * Define a new index operator family.
*/
-static void
-assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
+void
+DefineOpFamily(CreateOpFamilyStmt *stmt)
{
- Operator optup;
- Form_pg_operator opform;
+ char *opfname; /* name of opfamily we're creating */
+ 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 */
- 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);
+ /* Convert list of names to a name and namespace */
+ namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
+ &opfname);
+
+ /* Check we have creation rights in target namespace */
+ aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
+ 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,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("index operators must be binary")));
- if (opform->oprresult != BOOLOID)
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to create an operator family")));
+
+ 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,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("index operators must return boolean")));
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ 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))
- member->lefttype = opform->oprleft;
- if (!OidIsValid(member->righttype))
- member->righttype = opform->oprright;
+ memset(values, 0, sizeof(values));
+ memset(nulls, ' ', sizeof(nulls));
- 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,
- * and do any validity checking we can manage.
+ * AlterOpFamily
+ * 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
-assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
+void
+AlterOpFamily(AlterOpFamilyStmt *stmt)
{
- HeapTuple proctup;
- Form_pg_proc procform;
+ Oid amoid, /* our AM's oid */
+ opfamilyoid; /* oid of opfamily */
+ int maxOpNumber, /* amstrategies value */
+ maxProcNumber; /* amsupport value */
+ HeapTuple tup;
+ Form_pg_am pg_am;
- /* 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);
+ /* 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);
+ 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
- * procs must be 1-arg procs returning int4; otherwise we don't know.
+ * Currently, we require superuser privileges to alter an opfamily.
+ *
+ * XXX re-enable NOT_USED code sections below if you remove this test.
*/
- 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 (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to alter an operator family")));
- /*
- * 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];
- }
+ /*
+ * ADD and DROP cases need separate code from here on down.
+ */
+ if (stmt->isDrop)
+ AlterOpFamilyDrop(stmt->opfamilyname, amoid, opfamilyoid,
+ maxOpNumber, maxProcNumber,
+ stmt->items);
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);
+ AlterOpFamilyAdd(stmt->opfamilyname, amoid, opfamilyoid,
+ maxOpNumber, maxProcNumber,
+ stmt->items);
}
/*
- * Add a new family member to the appropriate list, after checking for
- * duplicated strategy or proc number.
+ * ADD part of ALTER OP FAMILY
*/
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;
- 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 &&
- old->lefttype == member->lefttype &&
- old->righttype == member->righttype)
+ Assert(IsA(item, CreateOpClassItem));
+ switch (item->itemtype)
{
- 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),
+ 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)));
+ 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))));
else
ereport(ERROR,
* else make an AUTO dependency on the opfamily.
*/
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;
Datum values[Natts_pg_amop];
{
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 */
memset(values, 0, sizeof(values));
memset(nulls, ' ', sizeof(nulls));
* else make an AUTO dependency on the opfamily.
*/
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;
Datum values[Natts_pg_amproc];
{
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 */
memset(values, 0, sizeof(values));
memset(nulls, ' ', sizeof(nulls));
}
+/*
+ * 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
* Deletes an opclass.
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.
*/
}
/*
- * Change opclass owner by oid
+ * Rename opfamily
*/
-#ifdef NOT_USED
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;
+ 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,
- ObjectIdGetDatum(opcOid),
- 0, 0, 0);
- if (!HeapTupleIsValid(tup)) /* shouldn't happen */
- elog(ERROR, "cache lookup failed for opclass %u", opcOid);
+ rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
- 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_freetuple(tup);
}
-#endif
/*
* Change opclass owner by name
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);
+ }
+}
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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 *
_copyRenameStmt(RenameStmt *from)
{
COPY_NODE_FIELD(args);
COPY_SCALAR_FIELD(number);
COPY_SCALAR_FIELD(recheck);
+ COPY_NODE_FIELD(class_args);
COPY_NODE_FIELD(storedtype);
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 *
_copyCreatedbStmt(CreatedbStmt *from)
{
case T_RemoveOpClassStmt:
retval = _copyRemoveOpClassStmt(from);
break;
+ case T_RemoveOpFamilyStmt:
+ retval = _copyRemoveOpFamilyStmt(from);
+ break;
case T_RenameStmt:
retval = _copyRenameStmt(from);
break;
case T_CreateOpClassItem:
retval = _copyCreateOpClassItem(from);
break;
+ case T_CreateOpFamilyStmt:
+ retval = _copyCreateOpFamilyStmt(from);
+ break;
+ case T_AlterOpFamilyStmt:
+ retval = _copyAlterOpFamilyStmt(from);
+ break;
case T_CreatedbStmt:
retval = _copyCreatedbStmt(from);
break;
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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
_equalRenameStmt(RenameStmt *a, RenameStmt *b)
{
COMPARE_NODE_FIELD(args);
COMPARE_SCALAR_FIELD(number);
COMPARE_SCALAR_FIELD(recheck);
+ COMPARE_NODE_FIELD(class_args);
COMPARE_NODE_FIELD(storedtype);
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
_equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
{
case T_RemoveOpClassStmt:
retval = _equalRemoveOpClassStmt(a, b);
break;
+ case T_RemoveOpFamilyStmt:
+ retval = _equalRemoveOpFamilyStmt(a, b);
+ break;
case T_RenameStmt:
retval = _equalRenameStmt(a, b);
break;
case T_CreateOpClassItem:
retval = _equalCreateOpClassItem(a, b);
break;
+ case T_CreateOpFamilyStmt:
+ retval = _equalCreateOpFamilyStmt(a, b);
+ break;
+ case T_AlterOpFamilyStmt:
+ retval = _equalAlterOpFamilyStmt(a, b);
+ break;
case T_CreatedbStmt:
retval = _equalCreatedbStmt(a, b);
break;
*
*
* 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
* AUTHOR DATE MAJOR EVENT
AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
- CreateDomainStmt CreateGroupStmt CreateOpClassStmt CreatePLangStmt
+ CreateDomainStmt CreateGroupStmt CreateOpClassStmt
+ CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateAssertStmt CreateTrigStmt CreateUserStmt CreateRoleStmt
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt
- DropGroupStmt DropOpClassStmt DropPLangStmt DropStmt
+ DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
DropUserStmt DropdbStmt DropTableSpaceStmt ExplainStmt FetchStmt
GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
%type <node> select_no_parens select_with_parens select_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 <node> alter_table_cmd alter_rel_cmd
OptTableElementList TableElementList OptInherit definition
OptWith opt_distinct opt_definition func_args func_args_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
opt_column_list columnList opt_name_list
sort_clause opt_sort_clause sortby_list index_params
set_clause_list set_clause multiple_set_clause
ctext_expr_list ctext_row def_list indirection opt_indirection
group_clause TriggerFuncArgs select_limit
- opt_select_limit opclass_item_list
- transaction_mode_list_or_empty
+ opt_select_limit opclass_item_list opclass_drop_list
+ opt_opfamily transaction_mode_list_or_empty
TableFuncElementList opt_type_modifiers
- prep_type_clause prep_type_list
+ prep_type_clause
execute_param_clause using_clause returning_clause
%type <range> into_clause OptTempTableName
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
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
GLOBAL GRANT GRANTED GREATEST GROUP_P
| CreateFunctionStmt
| CreateGroupStmt
| CreateOpClassStmt
+ | CreateOpFamilyStmt
+ | AlterOpFamilyStmt
| CreatePLangStmt
| CreateSchemaStmt
| CreateSeqStmt
| DropCastStmt
| DropGroupStmt
| DropOpClassStmt
+ | DropOpFamilyStmt
| DropOwnedStmt
| DropPLangStmt
| DropRuleStmt
}
;
-add_drop: ADD_P { $$ = +1; }
+add_drop: ADD_P { $$ = +1; }
| DROP { $$ = -1; }
;
| Sconst { $$ = (Node *)makeString($1); }
;
-aggr_args: '(' aggr_args_list ')' { $$ = $2; }
+aggr_args: '(' type_list ')' { $$ = $2; }
| '(' '*' ')' { $$ = NIL; }
;
-aggr_args_list:
- Typename { $$ = list_make1($1); }
- | aggr_args_list ',' Typename { $$ = lappend($1, $3); }
- ;
-
old_aggr_definition: '(' old_aggr_list ')' { $$ = $2; }
;
*
* QUERIES :
* CREATE OPERATOR CLASS ...
+ * CREATE OPERATOR FAMILY ...
+ * ALTER OPERATOR FAMILY ...
* DROP OPERATOR CLASS ...
+ * DROP OPERATOR FAMILY ...
*
*****************************************************************************/
CreateOpClassStmt:
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);
n->opclassname = $4;
n->isDefault = $5;
n->datatype = $8;
n->amname = $10;
- n->items = $12;
+ n->opfamilyname = $11;
+ n->items = $13;
$$ = (Node *) n;
}
;
n->number = $2;
$$ = (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
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
}
;
-opt_default: DEFAULT { $$ = TRUE; }
- | /*EMPTY*/ { $$ = FALSE; }
+opt_default: DEFAULT { $$ = TRUE; }
+ | /*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; }
- | /*EMPTY*/ { $$ = FALSE; }
+opclass_drop:
+ 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;
+ }
;
}
;
+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:
n->comment = $9;
$$ = (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
{
CommentStmt *n = makeNode(CommentStmt);
}
| Typename ',' Typename
{ $$ = list_make2($1, $3); }
- | NONE ',' Typename /* left unary */
+ | NONE ',' Typename /* left unary */
{ $$ = list_make2(NULL, $3); }
- | Typename ',' NONE /* right unary */
+ | Typename ',' NONE /* right unary */
{ $$ = list_make2($1, NULL); }
;
}
;
-opt_if_exists: IF_P EXISTS { $$ = true; }
- | /*EMPTY*/ { $$ = false; }
+opt_if_exists: IF_P EXISTS { $$ = TRUE; }
+ | /*EMPTY*/ { $$ = FALSE; }
;
n->newname = $9;
$$ = (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
{
RenameStmt *n = makeNode(RenameStmt);
n->newowner = $9;
$$ = (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
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
}
;
-prep_type_clause: '(' prep_type_list ')' { $$ = $2; }
+prep_type_clause: '(' type_list ')' { $$ = $2; }
| /* EMPTY */ { $$ = NIL; }
;
-prep_type_list: Typename { $$ = list_make1($1); }
- | prep_type_list ',' Typename
- { $$ = lappend($1, $3); }
- ;
-
PreparableStmt:
SelectStmt
| InsertStmt
| /*EMPTY*/ { $$ = NIL; }
;
-type_list: type_list ',' Typename
- {
- $$ = lappend($1, $3);
- }
- | Typename
- {
- $$ = list_make1($1);
- }
+type_list: Typename { $$ = list_make1($1); }
+ | type_list ',' Typename { $$ = lappend($1, $3); }
;
array_expr_list: array_expr
| EXECUTE
| EXPLAIN
| EXTERNAL
+ | FAMILY
| FETCH
| FIRST_P
| FORCE
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{"external", EXTERNAL},
{"extract", EXTRACT},
{"false", FALSE_P},
+ {"family", FAMILY},
{"fetch", FETCH},
{"first", FIRST_P},
{"float", FLOAT_P},
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
case T_IndexStmt:
case T_CreatePLangStmt:
case T_CreateOpClassStmt:
+ case T_CreateOpFamilyStmt:
+ case T_AlterOpFamilyStmt:
case T_RuleStmt:
case T_CreateSchemaStmt:
case T_CreateSeqStmt:
case T_DropRoleStmt:
case T_DropPLangStmt:
case T_RemoveOpClassStmt:
+ case T_RemoveOpFamilyStmt:
case T_DropPropertyStmt:
case T_GrantStmt:
case T_GrantRoleStmt:
DefineOpClass((CreateOpClassStmt *) parsetree);
break;
+ case T_CreateOpFamilyStmt:
+ DefineOpFamily((CreateOpFamilyStmt *) parsetree);
+ break;
+
+ case T_AlterOpFamilyStmt:
+ AlterOpFamily((AlterOpFamilyStmt *) parsetree);
+ break;
+
case T_RemoveOpClassStmt:
RemoveOpClass((RemoveOpClassStmt *) parsetree);
break;
+ case T_RemoveOpFamilyStmt:
+ RemoveOpFamily((RemoveOpFamilyStmt *) parsetree);
+ break;
+
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(parsetree));
case OBJECT_OPCLASS:
tag = "ALTER OPERATOR CLASS";
break;
+ case OBJECT_OPFAMILY:
+ tag = "ALTER OPERATOR FAMILY";
+ break;
case OBJECT_ROLE:
tag = "ALTER ROLE";
break;
case OBJECT_OPCLASS:
tag = "ALTER OPERATOR CLASS";
break;
+ case OBJECT_OPFAMILY:
+ tag = "ALTER OPERATOR FAMILY";
+ break;
case OBJECT_SCHEMA:
tag = "ALTER SCHEMA";
break;
tag = "CREATE OPERATOR CLASS";
break;
+ case T_CreateOpFamilyStmt:
+ tag = "CREATE OPERATOR FAMILY";
+ break;
+
+ case T_AlterOpFamilyStmt:
+ tag = "ALTER OPERATOR FAMILY";
+ break;
+
case T_RemoveOpClassStmt:
tag = "DROP OPERATOR CLASS";
break;
+ case T_RemoveOpFamilyStmt:
+ tag = "DROP OPERATOR FAMILY";
+ break;
+
case T_PrepareStmt:
tag = "PREPARE";
break;
lev = LOGSTMT_DDL;
break;
+ case T_CreateOpFamilyStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
+ case T_AlterOpFamilyStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_RemoveOpClassStmt:
lev = LOGSTMT_DDL;
break;
+ case T_RemoveOpFamilyStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_PrepareStmt:
{
PrepareStmt *stmt = (PrepareStmt *) parsetree;
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
/* commands/opclasscmds.c */
extern void DefineOpClass(CreateOpClassStmt *stmt);
+extern void DefineOpFamily(CreateOpFamilyStmt *stmt);
+extern void AlterOpFamily(AlterOpFamilyStmt *stmt);
extern void RemoveOpClass(RemoveOpClassStmt *stmt);
+extern void RemoveOpFamily(RemoveOpFamilyStmt *stmt);
extern void RemoveOpClassById(Oid opclassOid);
extern void RemoveOpFamilyById(Oid opfamilyOid);
extern void RemoveAmOpEntryById(Oid entryOid);
extern void RemoveAmProcEntryById(Oid entryOid);
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 AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
/* support routines in commands/define.c */
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
T_CreateCastStmt,
T_DropCastStmt,
T_CreateOpClassStmt,
+ T_CreateOpFamilyStmt,
+ T_AlterOpFamilyStmt,
T_RemoveOpClassStmt,
+ T_RemoveOpFamilyStmt,
T_PrepareStmt,
T_ExecuteStmt,
T_DeallocateStmt,
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
OBJECT_LARGEOBJECT,
OBJECT_OPCLASS,
OBJECT_OPERATOR,
+ OBJECT_OPFAMILY,
OBJECT_ROLE,
OBJECT_RULE,
OBJECT_SCHEMA,
{
NodeTag type;
char *tablespacename;
- bool missing_ok; /* skip error if a missing? */
+ bool missing_ok; /* skip error if missing? */
} DropTableSpaceStmt;
/* ----------------------
List *args; /* argument types */
int number; /* strategy num or support proc num */
bool recheck; /* only used for operators */
+ List *class_args; /* only used for functions */
/* fields used for a storagetype item: */
TypeName *storedtype; /* datatype stored in index */
} 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
* ----------------------
char *property; /* name of rule, trigger, etc */
ObjectType removeType; /* OBJECT_RULE or OBJECT_TRIGGER */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
- bool missing_ok; /* skip error if a missing? */
+ bool missing_ok; /* skip error if missing? */
} DropPropertyStmt;
/* ----------------------
List *name; /* qualified name of object to drop */
List *args; /* types of the arguments */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
- bool missing_ok; /* skip error if a missing? */
+ bool missing_ok; /* skip error if missing? */
} RemoveFuncStmt;
/* ----------------------
List *opclassname; /* qualified name (list of Value strings) */
char *amname; /* name of index AM opclass is for */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
- bool missing_ok; /* skip error if a missing? */
+ bool missing_ok; /* skip error if missing? */
} 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
* ----------------------
TypeName *sourcetype;
TypeName *targettype;
DropBehavior behavior;
- bool missing_ok; /* skip error if a missing? */
+ bool missing_ok; /* skip error if missing? */
} DropCastStmt;
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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
* An ACL array is simply an array of AclItems, representing the union
ACL_KIND_LANGUAGE, /* pg_language */
ACL_KIND_NAMESPACE, /* pg_namespace */
ACL_KIND_OPCLASS, /* pg_opclass */
+ ACL_KIND_OPFAMILY, /* pg_opfamily */
ACL_KIND_CONVERSION, /* pg_conversion */
ACL_KIND_TABLESPACE, /* pg_tablespace */
MAX_ACL_KIND /* MUST BE LAST */
extern bool pg_namespace_ownercheck(Oid nsp_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_opfamily_ownercheck(Oid opf_oid, Oid roleid);
extern bool pg_database_ownercheck(Oid db_oid, Oid roleid);
extern bool pg_conversion_ownercheck(Oid conv_oid, Oid roleid);