Add CREATE/ALTER/DROP OPERATOR FAMILY commands, also COMMENT ON OPERATOR
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 23 Jan 2007 05:07:18 +0000 (05:07 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 23 Jan 2007 05:07:18 +0000 (05:07 +0000)
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 ...

22 files changed:
doc/src/sgml/ref/allfiles.sgml
doc/src/sgml/ref/alter_opclass.sgml
doc/src/sgml/ref/alter_opfamily.sgml [new file with mode: 0644]
doc/src/sgml/ref/comment.sgml
doc/src/sgml/ref/create_opclass.sgml
doc/src/sgml/ref/create_opfamily.sgml [new file with mode: 0644]
doc/src/sgml/ref/drop_opclass.sgml
doc/src/sgml/ref/drop_opfamily.sgml [new file with mode: 0644]
doc/src/sgml/reference.sgml
src/backend/catalog/aclchk.c
src/backend/commands/alter.c
src/backend/commands/comment.c
src/backend/commands/opclasscmds.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/tcop/utility.c
src/include/commands/defrem.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/utils/acl.h

index a481500525a49fa609fee03bab81a8636bdf6b64..3b9b8b952ee832c5fb1da5c469170ebdf1032277 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$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.
 -->
@@ -16,6 +16,7 @@ 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">
@@ -45,6 +46,7 @@ Complete list of usable sgml source files in this directory.
 <!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">
@@ -70,6 +72,7 @@ Complete list of usable sgml source files in this directory.
 <!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">
index aa79f5704a95e94fffd8d1d61fdf37a25707ca8b..586d54940c37ab5e217fbda2bb451cd9a8fd2fde 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$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
 -->
 
@@ -102,6 +102,7 @@ ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="p
   <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>
diff --git a/doc/src/sgml/ref/alter_opfamily.sgml b/doc/src/sgml/ref/alter_opfamily.sgml
new file mode 100644 (file)
index 0000000..0990648
--- /dev/null
@@ -0,0 +1,312 @@
+<!--
+$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>
index d2cf39a20c41b10dca99e55c3ca7ec9026ca1d27..bc3ab8f26d87f82cb7d17af8acde1d2b6a56cf4a 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$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
 -->
 
@@ -35,6 +35,7 @@ COMMENT ON
   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> |
@@ -92,7 +93,7 @@ COMMENT ON
      <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>
@@ -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 - (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';
index 524be85f97858d5c86934e189ffb7b9f0ffe0274..85a31e3b19500fe8fcb8f91363e07e313c3670be 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$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
 -->
 
@@ -20,9 +20,10 @@ 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>
@@ -40,7 +41,7 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
    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>
@@ -65,6 +66,15 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
    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>
@@ -113,6 +123,17 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
     </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>
@@ -137,11 +158,24 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
     <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>
 
@@ -192,7 +226,7 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL
      <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>
@@ -268,6 +302,8 @@ CREATE OPERATOR CLASS gist__int_ops
   <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>
diff --git a/doc/src/sgml/ref/create_opfamily.sgml b/doc/src/sgml/ref/create_opfamily.sgml
new file mode 100644 (file)
index 0000000..d8ddb68
--- /dev/null
@@ -0,0 +1,125 @@
+<!--
+$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>
index 42cc1cd0f8db6816cde4fc85fa924d3bd6f1b79a..ce00ff40fd52caa950e009fe35140c06af674149 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$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
 -->
 
@@ -31,6 +31,13 @@ DROP OPERATOR CLASS [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceab
    <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>
@@ -86,6 +93,20 @@ DROP OPERATOR CLASS [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceab
    </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>
@@ -118,6 +139,7 @@ DROP OPERATOR CLASS widget_ops USING btree;
   <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>
 
diff --git a/doc/src/sgml/ref/drop_opfamily.sgml b/doc/src/sgml/ref/drop_opfamily.sgml
new file mode 100644 (file)
index 0000000..e2dcaf7
--- /dev/null
@@ -0,0 +1,135 @@
+<!--
+$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>
index 64330928c4e677bb9ff32f22cc466984f1c7f458..9b3cbda575e6cf62438a3ceb6db01eef30ed2f81 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $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>
@@ -44,6 +44,7 @@
    &alterLanguage;
    &alterOperator;
    &alterOperatorClass;
+   &alterOperatorFamily;
    &alterRole;
    &alterSchema;
    &alterSequence;
@@ -73,6 +74,7 @@
    &createLanguage;
    &createOperator;
    &createOperatorClass;
+   &createOperatorFamily;
    &createRole;
    &createRule;
    &createSchema;
    &dropLanguage;
    &dropOperator;
    &dropOperatorClass;
+   &dropOperatorFamily;
    &dropOwned;
    &dropRole;
    &dropRule;
index fcef0593b0afdc32817b3e24ee8514827fa239d4..328f8ccfda7e9b249c66365b41d6839c569d6c79 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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.
@@ -30,6 +30,7 @@
 #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"
@@ -1413,6 +1414,8 @@ static const char *const no_priv_msg[MAX_ACL_KIND] =
    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 */
@@ -1439,6 +1442,8 @@ static const char *const not_owner_msg[MAX_ACL_KIND] =
    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 */
@@ -2239,6 +2244,35 @@ pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
    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).
  */
index bf806f76fc2bb670221f63484009fd58a7216b61..30b7ebde00213eec88531f243adcb70753abbdd5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
            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;
@@ -211,6 +215,10 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
            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;
index 6d6eff7f48d5f8b05cdcb6144b6900d7dfafedd9..2f6a38d42d2364e407b2a99d48ff6facce2e68b1 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,6 +28,7 @@
 #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"
@@ -72,6 +73,7 @@ static void CommentConstraint(List *qualname, char *comment);
 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);
@@ -134,6 +136,9 @@ CommentObject(CommentStmt *stmt)
        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;
@@ -1263,6 +1268,92 @@ CommentOpClass(List *qualname, List *arguments, char *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 --
  *
index 24e4f832c42ecdff22039e546e261eeee64d10b5..802b6909525301946b7f95f1cbef1469f12178cf 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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
 } 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);
 
 
 /*
@@ -452,6 +467,12 @@ DefineOpClass(CreateOpClassStmt *stmt)
                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;
@@ -570,8 +591,10 @@ DefineOpClass(CreateOpClassStmt *stmt)
     * 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
@@ -615,151 +638,565 @@ DefineOpClass(CreateOpClassStmt *stmt)
    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,
@@ -781,7 +1218,9 @@ addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
  * 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];
@@ -798,6 +1237,24 @@ storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators)
    {
        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));
@@ -862,7 +1319,9 @@ storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators)
  * 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];
@@ -879,6 +1338,24 @@ storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures)
    {
        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));
@@ -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
  *     Deletes an opclass.
@@ -997,6 +1555,70 @@ RemoveOpClass(RemoveOpClassStmt *stmt)
    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.
  */
@@ -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
-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
@@ -1352,3 +2049,130 @@ AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid 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);
+   }
+}
index 1237dc7fe642c8797651cce727d689dbbf720845..f213f216de461cbe0f7a3ec8cccc10b4bbb63e29 100644 (file)
@@ -15,7 +15,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -2158,6 +2158,19 @@ _copyRemoveOpClassStmt(RemoveOpClassStmt *from)
    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)
 {
@@ -2332,11 +2345,36 @@ _copyCreateOpClassItem(CreateOpClassItem *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)
 {
@@ -3163,6 +3201,9 @@ copyObject(void *from)
        case T_RemoveOpClassStmt:
            retval = _copyRemoveOpClassStmt(from);
            break;
+       case T_RemoveOpFamilyStmt:
+           retval = _copyRemoveOpFamilyStmt(from);
+           break;
        case T_RenameStmt:
            retval = _copyRenameStmt(from);
            break;
@@ -3205,6 +3246,12 @@ copyObject(void *from)
        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;
index 40a91a2b0ed5ff06dac67200dfca7a210cc519e3..31754a7bc023f47e6e5bbefd67da0849ef041cf9 100644 (file)
@@ -18,7 +18,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -1053,6 +1053,17 @@ _equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b)
    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)
 {
@@ -1199,11 +1210,32 @@ _equalCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *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)
 {
@@ -2148,6 +2180,9 @@ equal(void *a, void *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;
@@ -2190,6 +2225,12 @@ equal(void *a, void *b)
        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;
index cf32e9125394081b84f6c2978b0ab557e8889b0c..217b1a0465961e14ea434e5d0d7eeb6c47f893b3 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * 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
@@ -152,11 +152,12 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
        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
@@ -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
                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
@@ -229,7 +230,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
                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
@@ -240,10 +241,10 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
                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
@@ -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
    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
@@ -548,6 +549,8 @@ stmt :
            | CreateFunctionStmt
            | CreateGroupStmt
            | CreateOpClassStmt
+           | CreateOpFamilyStmt
+           | AlterOpFamilyStmt
            | CreatePLangStmt
            | CreateSchemaStmt
            | CreateSeqStmt
@@ -565,6 +568,7 @@ stmt :
            | DropCastStmt
            | DropGroupStmt
            | DropOpClassStmt
+           | DropOpFamilyStmt
            | DropOwnedStmt
            | DropPLangStmt
            | DropRuleStmt
@@ -929,7 +933,7 @@ AlterGroupStmt:
                }
        ;
 
-add_drop:  ADD_P                                       { $$ = +1; }
+add_drop:  ADD_P                                   { $$ = +1; }
            | DROP                                  { $$ = -1; }
        ;
 
@@ -2879,15 +2883,10 @@ def_arg:    func_type                       { $$ = (Node *)$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; }
        ;
 
@@ -2906,20 +2905,24 @@ old_aggr_elem:  IDENT '=' def_arg
  *
  *     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;
                }
        ;
@@ -2959,6 +2962,16 @@ opclass_item:
                    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);
@@ -2968,12 +2981,72 @@ opclass_item:
                }
        ;
 
-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;
+               }
        ;
 
 
@@ -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:
@@ -3201,6 +3296,15 @@ CommentStmt:
                    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);
@@ -4115,9 +4219,9 @@ oper_argtypes:
                }
            | 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); }
        ;
 
@@ -4174,8 +4278,8 @@ DropCastStmt: DROP CAST opt_if_exists '(' Typename AS Typename ')' opt_drop_beha
                }
        ;
 
-opt_if_exists: IF_P EXISTS                     { $$ = true; }
-       | /*EMPTY*/                             { $$ = false; }
+opt_if_exists: IF_P EXISTS                     { $$ = TRUE; }
+       | /*EMPTY*/                             { $$ = FALSE; }
        ;
 
 
@@ -4294,6 +4398,15 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
                    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);
@@ -4493,6 +4606,15 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
                    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);
@@ -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; }
        ;
 
-prep_type_list: Typename           { $$ = list_make1($1); }
-             | prep_type_list ',' Typename
-                                   { $$ = lappend($1, $3); }
-       ;
-
 PreparableStmt:
            SelectStmt
            | InsertStmt
@@ -7968,14 +8085,8 @@ extract_list:
            | /*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
@@ -8604,6 +8715,7 @@ unreserved_keyword:
            | EXECUTE
            | EXPLAIN
            | EXTERNAL
+           | FAMILY
            | FETCH
            | FIRST_P
            | FORCE
index 5e858d10b0aff5f2b072dab8a63f421c507fbc40..b8607c7c002a3dab01c139212df2a4b808d3ba18 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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[] = {
    {"external", EXTERNAL},
    {"extract", EXTRACT},
    {"false", FALSE_P},
+   {"family", FAMILY},
    {"fetch", FETCH},
    {"first", FIRST_P},
    {"float", FLOAT_P},
index 19b89916bf1518274817ecbb64253eb15bac4d53..613ef653d19323d4ea078647915704d5ff5f67ee 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * 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)
        case T_IndexStmt:
        case T_CreatePLangStmt:
        case T_CreateOpClassStmt:
+       case T_CreateOpFamilyStmt:
+       case T_AlterOpFamilyStmt:
        case T_RuleStmt:
        case T_CreateSchemaStmt:
        case T_CreateSeqStmt:
@@ -338,6 +340,7 @@ check_xact_readonly(Node *parsetree)
        case T_DropRoleStmt:
        case T_DropPLangStmt:
        case T_RemoveOpClassStmt:
+       case T_RemoveOpFamilyStmt:
        case T_DropPropertyStmt:
        case T_GrantStmt:
        case T_GrantRoleStmt:
@@ -1099,10 +1102,22 @@ ProcessUtility(Node *parsetree,
            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));
@@ -1445,6 +1460,9 @@ CreateCommandTag(Node *parsetree)
                case OBJECT_OPCLASS:
                    tag = "ALTER OPERATOR CLASS";
                    break;
+               case OBJECT_OPFAMILY:
+                   tag = "ALTER OPERATOR FAMILY";
+                   break;
                case OBJECT_ROLE:
                    tag = "ALTER ROLE";
                    break;
@@ -1518,6 +1536,9 @@ CreateCommandTag(Node *parsetree)
                case OBJECT_OPCLASS:
                    tag = "ALTER OPERATOR CLASS";
                    break;
+               case OBJECT_OPFAMILY:
+                   tag = "ALTER OPERATOR FAMILY";
+                   break;
                case OBJECT_SCHEMA:
                    tag = "ALTER SCHEMA";
                    break;
@@ -1777,10 +1798,22 @@ CreateCommandTag(Node *parsetree)
            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;
@@ -2147,10 +2180,22 @@ GetCommandLogLevel(Node *parsetree)
            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;
index 9c254b0b4813608a318a5c60a86fb32142e2a26e..3d665ff5c2cb9b2a907511693c107e282e01a1ed 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -79,13 +79,18 @@ extern void AlterAggregateOwner(List *name, List *args, Oid newOwnerId);
 
 /* 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 */
 
index d3e84bdf69a94021782b31b76b8c5652923e0c89..f3762facdd629ad7d4dda2b1f0a7dad98a360b0a 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -286,7 +286,10 @@ typedef enum NodeTag
    T_CreateCastStmt,
    T_DropCastStmt,
    T_CreateOpClassStmt,
+   T_CreateOpFamilyStmt,
+   T_AlterOpFamilyStmt,
    T_RemoveOpClassStmt,
+   T_RemoveOpFamilyStmt,
    T_PrepareStmt,
    T_ExecuteStmt,
    T_DeallocateStmt,
index d11f9ae6eadff7cdaba69de6a540c0c12786672a..a252308bdb26b4966924c78d6d340b3556e2c2f2 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -852,6 +852,7 @@ typedef enum ObjectType
    OBJECT_LARGEOBJECT,
    OBJECT_OPCLASS,
    OBJECT_OPERATOR,
+   OBJECT_OPFAMILY,
    OBJECT_ROLE,
    OBJECT_RULE,
    OBJECT_SCHEMA,
@@ -1194,7 +1195,7 @@ typedef struct DropTableSpaceStmt
 {
    NodeTag     type;
    char       *tablespacename;
-   bool        missing_ok;     /* skip error if missing? */
+   bool        missing_ok;     /* skip error if missing? */
 } DropTableSpaceStmt;
 
 /* ----------------------
@@ -1362,10 +1363,35 @@ typedef struct CreateOpClassItem
    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
  * ----------------------
@@ -1395,7 +1421,7 @@ typedef struct DropPropertyStmt
    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 missing? */
+   bool        missing_ok;     /* skip error if missing? */
 } DropPropertyStmt;
 
 /* ----------------------
@@ -1546,7 +1572,7 @@ typedef struct RemoveFuncStmt
    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 missing? */
+   bool        missing_ok;     /* skip error if missing? */
 } RemoveFuncStmt;
 
 /* ----------------------
@@ -1559,9 +1585,22 @@ typedef struct RemoveOpClassStmt
    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 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
  * ----------------------
@@ -1917,7 +1956,7 @@ typedef struct DropCastStmt
    TypeName   *sourcetype;
    TypeName   *targettype;
    DropBehavior behavior;
-   bool        missing_ok;     /* skip error if missing? */
+   bool        missing_ok;     /* skip error if missing? */
 } DropCastStmt;
 
 
index 2076a69f3de6a7eb2d1397ac51761cd03aae2acf..14522bc6fb19ac60dcc30f6dcdcb1ef4522af8b9 100644 (file)
@@ -7,7 +7,7 @@
  * 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
@@ -178,6 +178,7 @@ typedef enum AclObjectKind
    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 */
@@ -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_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);