OSDN Git Service

Implement CREATE/DROP OPERATOR CLASS. Work still remains: need more
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 29 Jul 2002 22:14:11 +0000 (22:14 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 29 Jul 2002 22:14:11 +0000 (22:14 +0000)
documentation (xindex.sgml should be rewritten), need to teach pg_dump
about it, need to update contrib modules that currently build pg_opclass
entries by hand.  Original patch by Bill Studenmund, grammar adjustments
and general update for 7.3 by Tom Lane.

26 files changed:
contrib/intarray/_int.sql.in
doc/src/sgml/ref/allfiles.sgml
doc/src/sgml/ref/create_opclass.sgml [new file with mode: 0644]
doc/src/sgml/ref/drop_opclass.sgml [new file with mode: 0644]
doc/src/sgml/ref/drop_operator.sgml
doc/src/sgml/reference.sgml
doc/src/sgml/release.sgml
src/backend/catalog/aclchk.c
src/backend/catalog/dependency.c
src/backend/catalog/index.c
src/backend/commands/Makefile
src/backend/commands/opclasscmds.c [new file with mode: 0644]
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/tcop/postgres.c
src/backend/tcop/utility.c
src/backend/utils/adt/regproc.c
src/bin/initdb/initdb.sh
src/include/catalog/pg_am.h
src/include/commands/defrem.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/utils/acl.h
src/include/utils/builtins.h

index 4d9031f..24a87cb 100644 (file)
@@ -2,6 +2,10 @@
 -- 
 BEGIN TRANSACTION;
 
+-- Adjust this setting to control where the operators, functions, and
+-- opclasses get created.
+SET search_path = public;
+
 -- Query type
 CREATE FUNCTION bqarr_in(opaque)
 RETURNS opaque
@@ -143,137 +147,22 @@ CREATE FUNCTION g_int_same(_int4, _int4, opaque) RETURNS opaque
        AS 'MODULE_PATHNAME' LANGUAGE 'c';
 
 
--- register the default opclass for indexing
-INSERT INTO pg_opclass (opcamid, opcname, opcnamespace, opcowner, opcintype, opcdefault, opckeytype)
-    VALUES (
-        (SELECT oid FROM pg_am WHERE amname = 'gist'),
-        'gist__int_ops',
-        (SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog'),
-        1,     -- UID of superuser is hardwired to 1 as of PG 7.3
-        (SELECT oid FROM pg_type WHERE typname = '_int4'),
-        true,
-        0);
-
-
--- get the comparators for _intments and store them in a tmp table
-SELECT o.oid AS opoid, o.oprname
-INTO TEMP TABLE _int_ops_tmp
-FROM pg_operator o, pg_type t, pg_type tq
-WHERE o.oprleft = t.oid and ( o.oprright = t.oid or o.oprright=tq.oid )
-   and t.typname = '_int4'
-   and tq.typname='query_int';
-
--- make sure we have the right operators
--- SELECT * from _int_ops_tmp;
-
--- using the tmp table, generate the amop entries 
-
--- _int_overlap
-INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
-   SELECT opcl.oid, 3, false, c.opoid
-   FROM pg_opclass opcl, _int_ops_tmp c
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__int_ops' 
-      and c.oprname = '&&';
-
--- _int_same
-INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
-   SELECT opcl.oid, 6, true, c.opoid
-   FROM pg_opclass opcl, _int_ops_tmp c
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__int_ops' 
-      and c.oprname = '=';
-
--- _int_contains
-INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
-   SELECT opcl.oid, 7, false, c.opoid
-   FROM pg_opclass opcl, _int_ops_tmp c
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__int_ops' 
-      and c.oprname = '@';
-
--- _int_contained
-INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
-   SELECT opcl.oid, 8, false, c.opoid
-   FROM pg_opclass opcl, _int_ops_tmp c
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__int_ops' 
-      and c.oprname = '~';
-
---boolean search
-INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
-   SELECT opcl.oid, 20, false, c.opoid
-   FROM pg_opclass opcl, _int_ops_tmp c
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__int_ops' 
-      and c.oprname = '@@';
-
-DROP TABLE _int_ops_tmp;
-
-
--- add the entries to amproc for the support methods
--- note the amprocnum numbers associated with each are specific!
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 1, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__int_ops'
-      and proname = 'g_int_consistent';
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 2, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__int_ops'
-      and proname = 'g_int_union';
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 3, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__int_ops'
-      and proname = 'g_int_compress';
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 4, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__int_ops'
-      and proname = 'g_int_decompress';
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 5, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__int_ops'
-      and proname = 'g_int_penalty';
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 6, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__int_ops'
-      and proname = 'g_int_picksplit';
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 7, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__int_ops'
-      and proname = 'g_int_same';
+-- Create the operator class for indexing
+
+CREATE OPERATOR CLASS gist__int_ops
+    DEFAULT FOR TYPE _int4 USING gist AS
+       OPERATOR        3       &&,
+       OPERATOR        6       =       RECHECK,
+       OPERATOR        7       @,
+       OPERATOR        8       ~,
+       OPERATOR        20      @@ (_int4, query_int),
+       FUNCTION        1       g_int_consistent (opaque, _int4, int4),
+       FUNCTION        2       g_int_union (bytea, opaque),
+       FUNCTION        3       g_int_compress (opaque),
+       FUNCTION        4       g_int_decompress (opaque),
+       FUNCTION        5       g_int_penalty (opaque, opaque, opaque),
+       FUNCTION        6       g_int_picksplit (opaque, opaque),
+       FUNCTION        7       g_int_same (_int4, _int4, opaque);
 
 
 ---------------------------------------------
@@ -302,136 +191,20 @@ CREATE FUNCTION g_intbig_same(_int4, _int4, opaque) RETURNS opaque
        AS 'MODULE_PATHNAME' LANGUAGE 'c';
 
 -- register the opclass for indexing (not as default)
-INSERT INTO pg_opclass (opcamid, opcname, opcnamespace, opcowner, opcintype, opcdefault, opckeytype)
-    VALUES (
-        (SELECT oid FROM pg_am WHERE amname = 'gist'),
-        'gist__intbig_ops',
-        (SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog'),
-        1,     -- UID of superuser is hardwired to 1 as of PG 7.3
-        (SELECT oid FROM pg_type WHERE typname = '_int4'),
-        false,
-        0);
-
-
--- get the comparators for _intments and store them in a tmp table
-SELECT o.oid AS opoid, o.oprname
-INTO TEMP TABLE _int_ops_tmp
-FROM pg_operator o, pg_type t, pg_type tq
-WHERE o.oprleft = t.oid and ( o.oprright = t.oid or o.oprright=tq.oid )
-   and t.typname = '_int4'
-   and tq.typname='query_int';
-
--- make sure we have the right operators
--- SELECT * from _int_ops_tmp;
-
--- using the tmp table, generate the amop entries 
--- note: these operators are all lossy
-
--- _int_overlap
-INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
-   SELECT opcl.oid, 3, true, c.opoid
-   FROM pg_opclass opcl, _int_ops_tmp c
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__intbig_ops' 
-      and c.oprname = '&&';
-
--- _int_contains
-INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
-   SELECT opcl.oid, 7, true, c.opoid
-   FROM pg_opclass opcl, _int_ops_tmp c
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__intbig_ops' 
-      and c.oprname = '@';
-
--- _int_contained
-INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
-   SELECT opcl.oid, 8, true, c.opoid
-   FROM pg_opclass opcl, _int_ops_tmp c
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__intbig_ops' 
-      and c.oprname = '~';
-
--- _int_same
-INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
-   SELECT opcl.oid, 6, true, c.opoid
-   FROM pg_opclass opcl, _int_ops_tmp c
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__intbig_ops' 
-      and c.oprname = '=';
-
---boolean search
-INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
-   SELECT opcl.oid, 20, true, c.opoid
-   FROM pg_opclass opcl, _int_ops_tmp c
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__intbig_ops' 
-      and c.oprname = '@@';
-
-DROP TABLE _int_ops_tmp;
-
-
--- add the entries to amproc for the support methods
--- note the amprocnum numbers associated with each are specific!
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 1, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__intbig_ops'
-      and proname = 'g_intbig_consistent';
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 2, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__intbig_ops'
-      and proname = 'g_intbig_union';
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 3, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__intbig_ops'
-      and proname = 'g_intbig_compress';
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 4, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__intbig_ops'
-      and proname = 'g_intbig_decompress';
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 5, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__intbig_ops'
-      and proname = 'g_intbig_penalty';
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 6, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__intbig_ops'
-      and proname = 'g_intbig_picksplit';
-
-INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
-   SELECT opcl.oid, 7, pro.oid
-   FROM pg_opclass opcl, pg_proc pro
-   WHERE
-      opcamid = (SELECT oid FROM pg_am WHERE amname = 'gist')
-      and opcname = 'gist__intbig_ops'
-      and proname = 'g_intbig_same';
+
+CREATE OPERATOR CLASS gist__intbig_ops
+    FOR TYPE _int4 USING gist AS
+       OPERATOR        3       &&      RECHECK,
+       OPERATOR        6       =       RECHECK,
+       OPERATOR        7       @       RECHECK,
+       OPERATOR        8       ~       RECHECK,
+       OPERATOR        20      @@ (_int4, query_int)   RECHECK,
+       FUNCTION        1       g_intbig_consistent (opaque, _int4, int4),
+       FUNCTION        2       g_intbig_union (bytea, opaque),
+       FUNCTION        3       g_intbig_compress (opaque),
+       FUNCTION        4       g_intbig_decompress (opaque),
+       FUNCTION        5       g_intbig_penalty (opaque, opaque, opaque),
+       FUNCTION        6       g_intbig_picksplit (opaque, opaque),
+       FUNCTION        7       g_intbig_same (_int4, _int4, opaque);
 
 END TRANSACTION;
index a37d58a..1ee6f2f 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.42 2002/07/22 08:57:15 ishii Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.43 2002/07/29 22:14:10 tgl Exp $
 PostgreSQL documentation
 Complete list of usable sgml source files in this directory.
 -->
@@ -61,6 +61,7 @@ Complete list of usable sgml source files in this directory.
 <!entity createIndex        system "create_index.sgml">
 <!entity createLanguage     system "create_language.sgml">
 <!entity createOperator     system "create_operator.sgml">
+<!entity createOperatorClass system "create_opclass.sgml">
 <!entity createRule         system "create_rule.sgml">
 <!entity createSchema       system "create_schema.sgml">
 <!entity createSequence     system "create_sequence.sgml">
@@ -82,6 +83,7 @@ Complete list of usable sgml source files in this directory.
 <!entity dropIndex          system "drop_index.sgml">
 <!entity dropLanguage       system "drop_language.sgml">
 <!entity dropOperator       system "drop_operator.sgml">
+<!entity dropOperatorClass  system "drop_opclass.sgml">
 <!entity dropRule           system "drop_rule.sgml">
 <!entity dropSchema         system "drop_schema.sgml">
 <!entity dropSequence       system "drop_sequence.sgml">
diff --git a/doc/src/sgml/ref/create_opclass.sgml b/doc/src/sgml/ref/create_opclass.sgml
new file mode 100644 (file)
index 0000000..6d00f08
--- /dev/null
@@ -0,0 +1,316 @@
+<!--
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_opclass.sgml,v 1.1 2002/07/29 22:14:10 tgl Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-CREATEOPCLASS">
+ <refmeta>
+  <refentrytitle id="sql-createopclass-title">CREATE OPERATOR CLASS</refentrytitle>
+  <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+  <refname>
+   CREATE OPERATOR CLASS
+  </refname>
+  <refpurpose>
+   define a new operator class for indexes
+  </refpurpose>
+  </refnamediv>
+ <refsynopsisdiv>
+  <refsynopsisdivinfo>
+   <date>2002-07-28</date>
+  </refsynopsisdivinfo>
+  <synopsis>
+CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAULT ] FOR TYPE <replaceable class="parameter">data_type</replaceable> USING <replaceable class="parameter">access_method</replaceable> AS
+  {  OPERATOR <replaceable class="parameter">strategy_number</replaceable> <replaceable class="parameter">operator_id</replaceable> [ ( <replaceable class="parameter">type</replaceable>, <replaceable class="parameter">type</replaceable> ) ] [ RECHECK ]
+   | FUNCTION <replaceable class="parameter">support_number</replaceable> <replaceable class="parameter">func_name</replaceable> ( <replaceable class="parameter">parameter_types</replaceable> )
+   | STORAGE <replaceable class="parameter">storage_type</replaceable>
+  } [, ... ]
+  </synopsis>
+  
+  <refsect2 id="R2-SQL-CREATEOPCLASS-1">
+   <refsect2info>
+    <date>2002-07-28</date>
+   </refsect2info>
+   <title>
+    Inputs
+   </title>
+   <para>
+
+    <variablelist>
+     <varlistentry>
+      <term><replaceable class="parameter">name</replaceable></term>
+      <listitem>
+       <para>
+       The name of the operator class to be created.
+       The name may be schema-qualified.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><literal>DEFAULT</></term>
+      <listitem>
+       <para>
+        If present, the operator class will become the default index
+       operator class for its datatype.  At most one operator class
+       can be the default for a specific datatype and access method.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><replaceable class="parameter">data_type</replaceable></term>
+      <listitem>
+       <para>
+        The column datatype that this operator class is for.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><replaceable class="parameter">access_method</replaceable></term>
+      <listitem>
+       <para>
+       The name of the index access method this operator class is for.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><replaceable class="parameter">strategy_number</replaceable></term>
+      <listitem>
+       <para>
+        The index access method's strategy number for an operator associated
+       with the operator class.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><replaceable class="parameter">operator_id</replaceable></term>
+      <listitem>
+       <para>
+       The identifier (optionally schema-qualified) of an operator associated
+       with the operator class.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><replaceable class="parameter">type</replaceable></term>
+      <listitem>
+       <para>
+        The input datatype(s) of an operator, or <literal>NONE</> to
+       signify a left-unary or right-unary operator.  The input datatypes
+       may be omitted in the normal case where they are the same as the
+       operator class's datatype.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><literal>RECHECK</></term>
+      <listitem>
+       <para>
+        If present, the index is <quote>lossy</> for this operator,
+       and so the tuples 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 access method's support procedure number for a function
+       associated with the operator class.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><replaceable class="parameter">func_name</replaceable></term>
+      <listitem>
+       <para>
+        The name (optionally schema-qualified) of a function that is
+       an index access method support procedure for the operator class.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><replaceable class="parameter">parameter_types</replaceable></term>
+      <listitem>
+       <para>
+        The parameter datatype(s) of the function.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><replaceable class="parameter">storage_type</replaceable></term>
+      <listitem>
+       <para>
+        The datatype actually stored in the index.  Normally this is the
+       same as the column datatype, but some index access methods (only
+       GIST at this writing) allow it to be different.  The
+       <literal>STORAGE</> clause must be omitted unless the index access
+       method allows a different type to be used.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </para>
+  </refsect2>
+
+  <refsect2 id="R2-SQL-CREATEOPCLASS-2">
+   <refsect2info>
+    <date>2002-07-28</date>
+   </refsect2info>
+   <title>
+    Outputs
+   </title>
+   <para>
+    <variablelist>
+     <varlistentry>
+      <term><computeroutput>
+CREATE OPERATOR CLASS
+       </computeroutput></term>
+      <listitem>
+       <para>
+       Message returned if the operator class is successfully created.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </para>
+  </refsect2>
+ </refsynopsisdiv>
+
+ <refsect1 id="R1-SQL-CREATEOPCLASS-1">
+  <refsect1info>
+   <date>2002-07-28</date>
+  </refsect1info>
+  <title>
+   Description
+  </title>
+  <para>
+   <command>CREATE OPERATOR CLASS</command> defines a new operator class,
+   <replaceable class="parameter">name</replaceable>.
+  </para>
+  <para>
+   An operator class defines how a particular datatype can be used with
+   an index.  The operator class specifies that certain operators will fill
+   particular roles or <quote>strategies</> for this datatype and this
+   access method.  The operator class also specifies the support procedures to
+   be used by 
+   the index access 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.
+  </para>
+
+  <para>
+   If a schema name is given then the operator class is created in the
+   specified schema.  Otherwise it is created in the current schema (the one
+   at the front of the search path; see <literal>CURRENT_SCHEMA()</>).
+   Two operator classes in the same schema can have the same name only if they
+   are for different index access methods.
+  </para>
+  <para>
+   The user who defines an operator class becomes its owner.  The user
+   must own the datatype for which the operator class is being defined,
+   and must have execute permission for all referenced operators and functions.
+  </para>
+
+  <para>
+   <command>CREATE OPERATOR CLASS</command> does not presently check
+   whether the class definition includes all the operators and functions
+   required by the index access method.  It is the user's
+   responsibility to define a valid operator class.
+  </para>
+
+  <para>
+    Refer to the chapter on interfacing extensions to indexes in the
+    <citetitle>PostgreSQL Programmer's Guide</citetitle>
+    for further information.
+  </para>
+  
+  <refsect2 id="R2-SQL-CREATEOPCLASS-3">
+   <refsect2info>
+    <date>2002-07-28</date>
+   </refsect2info>
+   <title>
+    Notes
+   </title>
+   <para>
+    Refer to
+    <xref linkend="sql-dropopclass" endterm="sql-dropopclass-title">
+    to delete user-defined operator classes from a database.
+   </para>
+  </refsect2>
+ </refsect1>
+  
+ <refsect1 id="R1-SQL-CREATEOPCLASS-2">
+  <title>
+   Usage
+  </title>
+  <para>
+   The following example command defines a GiST index operator class
+   for datatype <literal>_int4</> (array of int4).  See
+   <filename>contrib/intarray/</> for the complete example.
+  </para>
+
+  <programlisting>
+CREATE OPERATOR CLASS gist__int_ops
+    DEFAULT FOR TYPE _int4 USING gist AS
+        OPERATOR        3       &&,
+        OPERATOR        6       =       RECHECK,
+        OPERATOR        7       @,
+        OPERATOR        8       ~,
+        OPERATOR        20      @@ (_int4, query_int),
+        FUNCTION        1       g_int_consistent (opaque, _int4, int4),
+        FUNCTION        2       g_int_union (bytea, opaque),
+        FUNCTION        3       g_int_compress (opaque),
+        FUNCTION        4       g_int_decompress (opaque),
+        FUNCTION        5       g_int_penalty (opaque, opaque, opaque),
+        FUNCTION        6       g_int_picksplit (opaque, opaque),
+        FUNCTION        7       g_int_same (_int4, _int4, opaque);
+  </programlisting>  
+
+  <para>
+   The <literal>OPERATOR</>, <literal>FUNCTION</>, and <literal>STORAGE</>
+   clauses may appear in any order.
+  </para>
+ </refsect1>
+ <refsect1 id="R1-SQL-CREATEOPCLASS-3">
+  <title>
+   Compatibility
+  </title>
+  
+  <refsect2 id="R2-SQL-CREATEOPCLASS-4">
+   <refsect2info>
+    <date>2002-07-28</date>
+   </refsect2info>
+   <title>
+    SQL92
+   </title>
+
+   <para>
+    <command>CREATE OPERATOR CLASS</command>
+    is a <productname>PostgreSQL</productname> extension.
+    There is no <command>CREATE OPERATOR CLASS</command>
+    statement in <acronym>SQL92</acronym>.
+   </para>
+  </refsect2>
+ </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:nil
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:"../reference.ced"
+sgml-exposed-tags:nil
+sgml-local-catalogs:"/usr/lib/sgml/catalog"
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/src/sgml/ref/drop_opclass.sgml b/doc/src/sgml/ref/drop_opclass.sgml
new file mode 100644 (file)
index 0000000..631a45a
--- /dev/null
@@ -0,0 +1,184 @@
+<!--
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_opclass.sgml,v 1.1 2002/07/29 22:14:10 tgl Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-DROPOPCLASS">
+ <refmeta>
+  <refentrytitle id="SQL-DROPOPCLASS-TITLE">DROP OPERATOR CLASS</refentrytitle>
+  <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+  <refname>
+   DROP OPERATOR CLASS
+  </refname>
+  <refpurpose>
+   remove a user-defined operator class
+  </refpurpose>
+ </refnamediv>
+  
+ <refsynopsisdiv>
+  <refsynopsisdivinfo>
+   <date>2002-07-28</date>
+  </refsynopsisdivinfo>
+  <synopsis>
+DROP OPERATOR CLASS <replaceable class="PARAMETER">name</replaceable> USING <replaceable class="PARAMETER">access_method</replaceable> [ CASCADE | RESTRICT ]
+  </synopsis>
+  
+  <refsect2 id="R2-SQL-DROPOPCLASS-1">
+   <refsect2info>
+    <date>2002-07-28</date>
+   </refsect2info>
+   <title>
+    Inputs
+   </title>
+   <para>
+    <variablelist>
+     <varlistentry>
+      <term><replaceable class="parameter">name</replaceable></term>
+      <listitem>
+       <para>
+       The name (optionally schema-qualified) of an existing operator class.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term><replaceable class="parameter">access_method</replaceable></term>
+      <listitem>
+       <para>
+       The name of the index access method the operator class is for.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>CASCADE</term>
+      <listitem>
+       <para>
+        Automatically drop objects that depend on the operator class.
+       </para>
+      </listitem>
+     </varlistentry>
+     <varlistentry>
+      <term>RESTRICT</term>
+      <listitem>
+       <para>
+        Refuse to drop the operator class if there are any dependent objects.
+       This is the default.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </para>
+  </refsect2>
+
+  <refsect2 id="R2-SQL-DROPOPCLASS-2">
+   <refsect2info>
+    <date>2002-07-28</date>
+   </refsect2info>
+   <title>
+    Outputs
+   </title>
+   <para>
+
+    <variablelist>
+     <varlistentry>
+      <term><computeroutput>
+DROP OPERATOR CLASS
+       </computeroutput></term>
+      <listitem>
+       <para>
+       The message returned if the command is successful.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </para>
+  </refsect2>
+ </refsynopsisdiv>
+
+ <refsect1 id="R1-SQL-DROPOPCLASS-1">
+  <refsect1info>
+   <date>2002-07-28</date>
+  </refsect1info>
+  <title>
+   Description
+  </title>
+  <para>
+   <command>DROP OPERATOR CLASS</command> drops an existing operator class
+   from the database.
+   To execute this command you must be the owner of the operator class.
+  </para>
+
+  <refsect2 id="R2-SQL-DROPOPCLASS-3">
+   <refsect2info>
+    <date>2002-07-28</date>
+   </refsect2info>
+   <title>
+    Notes
+   </title>
+   <para>
+    The <command>DROP OPERATOR CLASS</command> statement is a 
+    <productname>PostgreSQL</productname>
+    language extension.
+   </para>
+   <para>
+    Refer to
+    <xref linkend="sql-createopclass" endterm="sql-createopclass-title">
+    for information on how to create operator classes.
+   </para>
+  </refsect2>
+ </refsect1>
+
+ <refsect1 id="R1-SQL-DROPOPCLASS-2">
+  <title>
+   Usage
+  </title>
+  <para>
+   Remove btree operator class <literal>widget_ops</literal>:
+
+   <programlisting>
+DROP OPERATOR CLASS widget_ops USING btree;
+   </programlisting>
+
+   This command will not execute if there are any existing indexes
+   that use the operator class.  Add <literal>CASCADE</> to drop
+   such indexes along with the operator class.
+  </para>
+ </refsect1>
+ <refsect1 id="R1-SQL-DROPOPCLASS-3">
+  <title>
+   Compatibility
+  </title>
+
+  <refsect2 id="R2-SQL-DROPOPCLASS-4">
+   <refsect2info>
+    <date>2002-07-28</date>
+   </refsect2info>
+   <title>
+    SQL92
+   </title>
+   <para>
+    There is no <command>DROP OPERATOR CLASS</command> in
+    <acronym>SQL92</acronym>.
+   </para>
+  </refsect2>
+ </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:nil
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:"../reference.ced"
+sgml-exposed-tags:nil
+sgml-local-catalogs:"/usr/lib/sgml/catalog"
+sgml-local-ecat-files:nil
+End:
+-->
index 1cfb824..edd99bd 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_operator.sgml,v 1.17 2002/07/12 18:43:13 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_operator.sgml,v 1.18 2002/07/29 22:14:10 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -172,10 +172,6 @@ ERROR: RemoveOperator: right unary operator '<replaceable class="PARAMETER">oper
     <xref linkend="sql-createoperator" endterm="sql-createoperator-title">
     for information on how to create operators.
    </para>
-   <para>
-    It is the user's responsibility to remove any access method
-    operator classes that rely on the deleted operator.
-   </para>
   </refsect2>
  </refsect1>
 
index e2491f5..2101dfe 100644 (file)
@@ -1,5 +1,5 @@
 <!-- reference.sgml
-$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.31 2002/07/22 08:57:15 ishii Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.32 2002/07/29 22:14:10 tgl Exp $
 
 PostgreSQL Reference Manual
 -->
@@ -70,6 +70,7 @@ PostgreSQL Reference Manual
    &createIndex;
    &createLanguage;
    &createOperator;
+   &createOperatorClass;
    &createRule;
    &createSchema;
    &createSequence;
@@ -91,6 +92,7 @@ PostgreSQL Reference Manual
    &dropIndex;
    &dropLanguage;
    &dropOperator;
+   &dropOperatorClass;
    &dropRule;
    &dropSchema;
    &dropSequence;
index 47f3685..af82154 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.143 2002/07/20 15:12:55 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.144 2002/07/29 22:14:10 tgl Exp $
 -->
 
 <appendix id="release">
@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
 worries about funny characters.
 -->
 <literallayout><![CDATA[
+CREATE OPERATOR CLASS/DROP OPERATOR CLASS
 CREATE CAST/DROP CAST
 Sequences created by SERIAL column definitions now auto-drop with the column
 Most forms of DROP now support RESTRICT and CASCADE options
index 5827915..e06065e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.71 2002/07/20 05:16:56 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.72 2002/07/29 22:14:10 tgl Exp $
  *
  * NOTES
  *       See acl.h.
@@ -26,6 +26,7 @@
 #include "catalog/pg_group.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_namespace.h"
+#include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_shadow.h"
@@ -1369,3 +1370,30 @@ pg_namespace_ownercheck(Oid nsp_oid, Oid userid)
 
        return userid == owner_id;
 }
+
+/*
+ * Ownership check for an operator class (specified by OID).
+ */
+bool
+pg_opclass_ownercheck(Oid opc_oid, Oid userid)
+{
+       HeapTuple       tuple;
+       AclId           owner_id;
+
+       /* Superusers bypass all permission checking. */
+       if (superuser_arg(userid))
+               return true;
+
+       tuple = SearchSysCache(CLAOID,
+                                                  ObjectIdGetDatum(opc_oid),
+                                                  0, 0, 0);
+       if (!HeapTupleIsValid(tuple))
+               elog(ERROR, "pg_opclass_ownercheck: operator class %u not found",
+                        opc_oid);
+
+       owner_id = ((Form_pg_opclass) GETSTRUCT(tuple))->opcowner;
+
+       ReleaseSysCache(tuple);
+
+       return userid == owner_id;
+}
index 8330fe4..ae88c4b 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.6 2002/07/25 10:07:10 ishii Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.7 2002/07/29 22:14:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/indexing.h"
+#include "catalog/namespace.h"
 #include "catalog/pg_attrdef.h"
+#include "catalog/pg_cast.h"
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_conversion.h"
 #include "catalog/pg_depend.h"
 #include "catalog/pg_language.h"
-#include "catalog/pg_namespace.h"
+#include "catalog/pg_opclass.h"
 #include "catalog/pg_rewrite.h"
 #include "catalog/pg_trigger.h"
-#include "catalog/pg_type.h"
 #include "commands/comment.h"
 #include "commands/defrem.h"
 #include "commands/proclang.h"
@@ -40,6 +41,7 @@
 #include "optimizer/clauses.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteRemove.h"
+#include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 /* This enum covers all system catalogs whose OIDs can appear in classid. */
 typedef enum ObjectClasses
 {
-       OCLASS_CAST,                            /* pg_cast */
        OCLASS_CLASS,                           /* pg_class */
        OCLASS_PROC,                            /* pg_proc */
        OCLASS_TYPE,                            /* pg_type */
+       OCLASS_CAST,                            /* pg_cast */
        OCLASS_CONSTRAINT,                      /* pg_constraint */
        OCLASS_CONVERSION,                      /* pg_conversion */
        OCLASS_DEFAULT,                         /* pg_attrdef */
        OCLASS_LANGUAGE,                        /* pg_language */
        OCLASS_OPERATOR,                        /* pg_operator */
+       OCLASS_OPCLASS,                         /* pg_opclass */
        OCLASS_REWRITE,                         /* pg_rewrite */
        OCLASS_TRIGGER,                         /* pg_trigger */
        OCLASS_SCHEMA,                          /* pg_namespace */
@@ -579,6 +582,10 @@ doDeletion(const ObjectAddress *object)
                        RemoveTypeById(object->objectId);
                        break;
 
+               case OCLASS_CAST:
+                       DropCastById(object->objectId);
+                       break;
+
                case OCLASS_CONSTRAINT:
                        RemoveConstraintById(object->objectId);
                        break;
@@ -599,6 +606,10 @@ doDeletion(const ObjectAddress *object)
                        RemoveOperatorById(object->objectId);
                        break;
 
+               case OCLASS_OPCLASS:
+                       RemoveOpClassById(object->objectId);
+                       break;
+
                case OCLASS_REWRITE:
                        RemoveRewriteRuleById(object->objectId);
                        break;
@@ -611,10 +622,6 @@ doDeletion(const ObjectAddress *object)
                        RemoveSchemaById(object->objectId);
                        break;
 
-               case OCLASS_CAST:
-                       DropCastById(object->objectId);
-                       break;
-
                default:
                        elog(ERROR, "doDeletion: Unsupported object class %u",
                                 object->classId);
@@ -990,15 +997,16 @@ term_object_addresses(ObjectAddresses *addrs)
 static void
 init_object_classes(void)
 {
-       object_classes[OCLASS_CAST] = get_system_catalog_relid(CastRelationName);
        object_classes[OCLASS_CLASS] = RelOid_pg_class;
        object_classes[OCLASS_PROC] = RelOid_pg_proc;
        object_classes[OCLASS_TYPE] = RelOid_pg_type;
+       object_classes[OCLASS_CAST] = get_system_catalog_relid(CastRelationName);
        object_classes[OCLASS_CONSTRAINT] = get_system_catalog_relid(ConstraintRelationName);
        object_classes[OCLASS_CONVERSION] = get_system_catalog_relid(ConversionRelationName);
        object_classes[OCLASS_DEFAULT] = get_system_catalog_relid(AttrDefaultRelationName);
        object_classes[OCLASS_LANGUAGE] = get_system_catalog_relid(LanguageRelationName);
        object_classes[OCLASS_OPERATOR] = get_system_catalog_relid(OperatorRelationName);
+       object_classes[OCLASS_OPCLASS] = get_system_catalog_relid(OperatorClassRelationName);
        object_classes[OCLASS_REWRITE] = get_system_catalog_relid(RewriteRelationName);
        object_classes[OCLASS_TRIGGER] = get_system_catalog_relid(TriggerRelationName);
        object_classes[OCLASS_SCHEMA] = get_system_catalog_relid(NamespaceRelationName);
@@ -1066,6 +1074,11 @@ getObjectClass(const ObjectAddress *object)
                Assert(object->objectSubId == 0);
                return OCLASS_OPERATOR;
        }
+       if (object->classId == object_classes[OCLASS_OPCLASS])
+       {
+               Assert(object->objectSubId == 0);
+               return OCLASS_OPCLASS;
+       }
        if (object->classId == object_classes[OCLASS_REWRITE])
        {
                Assert(object->objectSubId == 0);
@@ -1101,10 +1114,6 @@ getObjectDescription(const ObjectAddress *object)
 
        switch (getObjectClass(object))
        {
-               case OCLASS_CAST:
-                       appendStringInfo(&buffer, "cast");
-                       break;
-
                case OCLASS_CLASS:
                        getRelationDescription(&buffer, object->objectId);
                        if (object->objectSubId != 0)
@@ -1114,24 +1123,46 @@ getObjectDescription(const ObjectAddress *object)
                        break;
 
                case OCLASS_PROC:
-                       /* XXX could improve on this */
                        appendStringInfo(&buffer, "function %s",
-                                                        get_func_name(object->objectId));
+                                                        format_procedure(object->objectId));
                        break;
 
                case OCLASS_TYPE:
+                       appendStringInfo(&buffer, "type %s",
+                                                        format_type_be(object->objectId));
+                       break;
+
+               case OCLASS_CAST:
                {
-                       HeapTuple               typeTup;
+                       Relation                castDesc;
+                       ScanKeyData             skey[1];
+                       SysScanDesc             rcscan;
+                       HeapTuple               tup;
+                       Form_pg_cast    castForm;
 
-                       typeTup = SearchSysCache(TYPEOID,
-                                                                        ObjectIdGetDatum(object->objectId),
-                                                                        0, 0, 0);
-                       if (!HeapTupleIsValid(typeTup))
-                               elog(ERROR, "getObjectDescription: Type %u does not exist",
+                       castDesc = heap_openr(CastRelationName, AccessShareLock);
+
+                       ScanKeyEntryInitialize(&skey[0], 0x0,
+                                                                  ObjectIdAttributeNumber, F_OIDEQ,
+                                                                  ObjectIdGetDatum(object->objectId));
+
+                       rcscan = systable_beginscan(castDesc, CastOidIndex, true,
+                                                                               SnapshotNow, 1, skey);
+
+                       tup = systable_getnext(rcscan);
+
+                       if (!HeapTupleIsValid(tup))
+                               elog(ERROR, "getObjectDescription: Cast %u does not exist",
                                         object->objectId);
-                       appendStringInfo(&buffer, "type %s",
-                                                        NameStr(((Form_pg_type) GETSTRUCT(typeTup))->typname));
-                       ReleaseSysCache(typeTup);
+
+                       castForm = (Form_pg_cast) GETSTRUCT(tup);
+
+                       appendStringInfo(&buffer, "cast from %s to %s",
+                                                        format_type_be(castForm->castsource),
+                                                        format_type_be(castForm->casttarget));
+
+                       systable_endscan(rcscan);
+                       heap_close(castDesc, AccessShareLock);
                        break;
                }
 
@@ -1248,10 +1279,51 @@ getObjectDescription(const ObjectAddress *object)
                }
 
                case OCLASS_OPERATOR:
-                       /* XXX could improve on this */
                        appendStringInfo(&buffer, "operator %s",
-                                                        get_opname(object->objectId));
+                                                        format_operator(object->objectId));
+                       break;
+
+               case OCLASS_OPCLASS:
+               {
+                       HeapTuple       opcTup;
+                       Form_pg_opclass opcForm;
+                       HeapTuple       amTup;
+                       Form_pg_am      amForm;
+                       char       *nspname;
+
+                       opcTup = SearchSysCache(CLAOID,
+                                                                       ObjectIdGetDatum(object->objectId),
+                                                                       0, 0, 0);
+                       if (!HeapTupleIsValid(opcTup))
+                               elog(ERROR, "cache lookup of opclass %u failed",
+                                        object->objectId);
+                       opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
+
+                       /* Qualify the name if not visible in search path */
+                       if (OpclassIsVisible(object->objectId))
+                               nspname = NULL;
+                       else
+                               nspname = get_namespace_name(opcForm->opcnamespace);
+
+                       appendStringInfo(&buffer, "operator class %s",
+                                                        quote_qualified_identifier(nspname,
+                                                                                                               NameStr(opcForm->opcname)));
+
+                       amTup = SearchSysCache(AMOID,
+                                                                  ObjectIdGetDatum(opcForm->opcamid),
+                                                                  0, 0, 0);
+                       if (!HeapTupleIsValid(amTup))
+                               elog(ERROR, "syscache lookup for AM %u failed",
+                                        opcForm->opcamid);
+                       amForm = (Form_pg_am) GETSTRUCT(amTup);
+
+                       appendStringInfo(&buffer, " for %s",
+                                                        NameStr(amForm->amname));
+
+                       ReleaseSysCache(amTup);
+                       ReleaseSysCache(opcTup);
                        break;
+               }
 
                case OCLASS_REWRITE:
                {
@@ -1323,17 +1395,13 @@ getObjectDescription(const ObjectAddress *object)
 
                case OCLASS_SCHEMA:
                {
-                       HeapTuple               schemaTup;
+                       char       *nspname;
 
-                       schemaTup = SearchSysCache(NAMESPACEOID,
-                                                                          ObjectIdGetDatum(object->objectId),
-                                                                          0, 0, 0);
-                       if (!HeapTupleIsValid(schemaTup))
+                       nspname = get_namespace_name(object->objectId);
+                       if (!nspname)
                                elog(ERROR, "getObjectDescription: Schema %u does not exist",
                                         object->objectId);
-                       appendStringInfo(&buffer, "schema %s",
-                                                        NameStr(((Form_pg_namespace) GETSTRUCT(schemaTup))->nspname));
-                       ReleaseSysCache(schemaTup);
+                       appendStringInfo(&buffer, "schema %s", nspname);
                        break;
                }
 
@@ -1356,49 +1424,58 @@ getRelationDescription(StringInfo buffer, Oid relid)
 {
        HeapTuple       relTup;
        Form_pg_class   relForm;
+       char       *nspname;
+       char       *relname;
 
        relTup = SearchSysCache(RELOID,
                                                        ObjectIdGetDatum(relid),
                                                        0, 0, 0);
        if (!HeapTupleIsValid(relTup))
-               elog(ERROR, "getObjectDescription: Relation %u does not exist",
-                        relid);
+               elog(ERROR, "cache lookup of relation %u failed", relid);
        relForm = (Form_pg_class) GETSTRUCT(relTup);
 
+       /* Qualify the name if not visible in search path */
+       if (RelationIsVisible(relid))
+               nspname = NULL;
+       else
+               nspname = get_namespace_name(relForm->relnamespace);
+
+       relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
+
        switch (relForm->relkind)
        {
                case RELKIND_RELATION:
                        appendStringInfo(buffer, "table %s",
-                                                        NameStr(relForm->relname));
+                                                        relname);
                        break;
                case RELKIND_INDEX:
                        appendStringInfo(buffer, "index %s",
-                                                        NameStr(relForm->relname));
+                                                        relname);
                        break;
                case RELKIND_SPECIAL:
                        appendStringInfo(buffer, "special system relation %s",
-                                                        NameStr(relForm->relname));
+                                                        relname);
                        break;
                case RELKIND_SEQUENCE:
                        appendStringInfo(buffer, "sequence %s",
-                                                        NameStr(relForm->relname));
+                                                        relname);
                        break;
                case RELKIND_UNCATALOGED:
                        appendStringInfo(buffer, "uncataloged table %s",
-                                                        NameStr(relForm->relname));
+                                                        relname);
                        break;
                case RELKIND_TOASTVALUE:
                        appendStringInfo(buffer, "toast table %s",
-                                                        NameStr(relForm->relname));
+                                                        relname);
                        break;
                case RELKIND_VIEW:
                        appendStringInfo(buffer, "view %s",
-                                                        NameStr(relForm->relname));
+                                                        relname);
                        break;
                default:
                        /* shouldn't get here */
                        appendStringInfo(buffer, "relation %s",
-                                                        NameStr(relForm->relname));
+                                                        relname);
                        break;
        }
 
index 0937367..38fe5cd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.186 2002/07/20 05:16:56 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.187 2002/07/29 22:14:10 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -712,7 +712,7 @@ index_create(Oid heapRelationId,
                                                                                   false, /* isDeferred */
                                                                                   heapRelationId,
                                                                                   indexInfo->ii_KeyAttrNumbers,
-                                                                                  indexInfo->ii_NumIndexAttrs,
+                                                                                  indexInfo->ii_NumKeyAttrs,
                                                                                   InvalidOid, /* no domain */
                                                                                   InvalidOid, /* no foreign key */
                                                                                   NULL,
@@ -732,7 +732,7 @@ index_create(Oid heapRelationId,
                }
                else
                {
-                       for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+                       for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
                        {
                                referenced.classId = RelOid_pg_class;
                                referenced.objectId = heapRelationId;
@@ -742,6 +742,16 @@ index_create(Oid heapRelationId,
                        }
                }
 
+               /* Store dependency on operator classes */
+               referenced.classId = get_system_catalog_relid(OperatorClassRelationName);
+               for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+               {
+                       referenced.objectId = classObjectId[i];
+                       referenced.objectSubId = 0;
+
+                       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+               }
+
                /* Store the dependency on the function (if appropriate) */
                if (OidIsValid(indexInfo->ii_FuncOid))
                {
index 58e8fe2..9296104 100644 (file)
@@ -4,7 +4,7 @@
 #    Makefile for backend/commands
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.29 2002/07/11 07:39:27 ishii Exp $
+#    $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.30 2002/07/29 22:14:10 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -15,7 +15,8 @@ include $(top_builddir)/src/Makefile.global
 OBJS = aggregatecmds.o analyze.o async.o cluster.o comment.o  \
        conversioncmds.o copy.o \
        dbcommands.o define.o explain.o functioncmds.o \
-       indexcmds.o lockcmds.o operatorcmds.o portalcmds.o proclang.o \
+       indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
+       portalcmds.o proclang.o \
        schemacmds.o sequence.o tablecmds.o trigger.o typecmds.o user.o \
        vacuum.o vacuumlazy.o variable.o view.o
 
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
new file mode 100644 (file)
index 0000000..fb86c98
--- /dev/null
@@ -0,0 +1,639 @@
+/*-------------------------------------------------------------------------
+ *
+ * opclasscmds.c
+ *
+ *       Routines for opclass manipulation commands
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *       $Header: /cvsroot/pgsql/src/backend/commands/opclasscmds.c,v 1.1 2002/07/29 22:14:10 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/catname.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_am.h"
+#include "catalog/pg_amop.h"
+#include "catalog/pg_amproc.h"
+#include "catalog/pg_opclass.h"
+#include "commands/defrem.h"
+#include "miscadmin.h"
+#include "parser/parse_func.h"
+#include "parser/parse_oper.h"
+#include "parser/parse_type.h"
+#include "utils/acl.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+
+
+static void storeOperators(Oid opclassoid, int numOperators,
+                                                  Oid *operators, bool *recheck);
+static void storeProcedures(Oid opclassoid, int numProcs, Oid *procedures);
+
+
+/*
+ * DefineOpClass
+ *             Define a new index operator class.
+ */
+void
+DefineOpClass(CreateOpClassStmt *stmt)
+{
+       char       *opcname;            /* name of opclass we're creating */
+       Oid                     amoid,                  /* our AM's oid */
+                               typeoid,                /* indexable datatype oid */
+                               storageoid,             /* storage datatype oid, if any */
+                               namespaceoid,   /* namespace to create opclass in */
+                               opclassoid;             /* oid of opclass we create */
+       int                     numOperators,   /* amstrategies value */
+                               numProcs;               /* amsupport value */
+       Oid                *operators,          /* oids of operators, by strategy num */
+                          *procedures;         /* oids of support procs */
+       bool       *recheck;            /* do operators need recheck */
+       List       *iteml;
+       Relation        rel;
+       HeapTuple       tup;
+       Datum           values[Natts_pg_opclass];
+       char            nulls[Natts_pg_opclass];
+       AclResult       aclresult;
+       NameData        opcName;
+       int                     i;
+       ObjectAddress   myself,
+                                       referenced;
+
+       /* Convert list of names to a name and namespace */
+       namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
+                                                                                                        &opcname);
+
+       /* Check we have creation rights in target namespace */
+       aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
+       if (aclresult != ACLCHECK_OK)
+               aclcheck_error(aclresult, get_namespace_name(namespaceoid));
+
+       /* Get necessary info about access method */
+       tup = SearchSysCache(AMNAME,
+                                                CStringGetDatum(stmt->amname),
+                                                0, 0, 0);
+       if (!HeapTupleIsValid(tup))
+               elog(ERROR, "DefineOpClass: access method \"%s\" not found",
+                        stmt->amname);
+
+       amoid = HeapTupleGetOid(tup);
+       numOperators = ((Form_pg_am) GETSTRUCT(tup))->amstrategies;
+       numProcs = ((Form_pg_am) GETSTRUCT(tup))->amsupport;
+
+       /* XXX Should we make any privilege check against the AM? */
+
+       ReleaseSysCache(tup);
+
+       /* Look up the datatype */
+       typeoid = typenameTypeId(stmt->datatype);
+
+       /* Check we have ownership of the datatype */
+       if (!pg_type_ownercheck(typeoid, GetUserId()))
+               aclcheck_error(ACLCHECK_NOT_OWNER, format_type_be(typeoid));
+
+       /* Storage datatype is optional */
+       storageoid = InvalidOid;
+
+       /*
+        * Create work arrays to hold info about operators and procedures.
+        * We do this mainly so that we can detect duplicate strategy
+        * numbers and support-proc numbers.
+        */
+       operators = (Oid *) palloc(sizeof(Oid) * numOperators);
+       MemSet(operators, 0, sizeof(Oid) * numOperators);
+       procedures = (Oid *) palloc(sizeof(Oid) * numProcs);
+       MemSet(procedures, 0, sizeof(Oid) * numProcs);
+       recheck = (bool *) palloc(sizeof(bool) * numOperators);
+       MemSet(recheck, 0, sizeof(bool) * numOperators);
+
+       /*
+        * Scan the "items" list to obtain additional info.
+        */
+       foreach(iteml, stmt->items)
+       {
+               CreateOpClassItem *item = lfirst(iteml);
+               Oid                     operOid;
+               Oid                     funcOid;
+               AclResult       aclresult;
+
+               Assert(IsA(item, CreateOpClassItem));
+               switch (item->itemtype)
+               {
+                       case OPCLASS_ITEM_OPERATOR:
+                               if (item->number <= 0 || item->number > numOperators)
+                                       elog(ERROR, "DefineOpClass: invalid operator number %d,"
+                                                " must be between 1 and %d",
+                                                item->number, numOperators);
+                               if (operators[item->number - 1] != InvalidOid)
+                                       elog(ERROR, "DefineOpClass: operator number %d appears more than once",
+                                                item->number);
+                               if (item->args != NIL)
+                               {
+                                       TypeName *typeName1 = (TypeName *) lfirst(item->args);
+                                       TypeName *typeName2 = (TypeName *) lsecond(item->args);
+
+                                       operOid = LookupOperNameTypeNames(item->name,
+                                                                                                         typeName1, typeName2,
+                                                                                                         "DefineOpClass");
+                                       /* No need to check for error */
+                               }
+                               else
+                               {
+                                       /* Default to binary op on input datatype */
+                                       operOid = LookupOperName(item->name, typeoid, typeoid);
+                                       if (!OidIsValid(operOid))
+                                               elog(ERROR, "DefineOpClass: Operator '%s' for types '%s' and '%s' does not exist",
+                                                        NameListToString(item->name),
+                                                        format_type_be(typeoid),
+                                                        format_type_be(typeoid));
+                               }
+                               /* Caller must have execute permission on operators */
+                               funcOid = get_opcode(operOid);
+                               aclresult = pg_proc_aclcheck(funcOid, GetUserId(),
+                                                                                        ACL_EXECUTE);
+                               if (aclresult != ACLCHECK_OK)
+                                       aclcheck_error(aclresult, get_func_name(funcOid));
+                               operators[item->number - 1] = operOid;
+                               recheck[item->number - 1] = item->recheck;
+                               break;
+                       case OPCLASS_ITEM_FUNCTION:
+                               if (item->number <= 0 || item->number > numProcs)
+                                       elog(ERROR, "DefineOpClass: invalid procedure number %d,"
+                                                " must be between 1 and %d",
+                                                item->number, numProcs);
+                               if (procedures[item->number - 1] != InvalidOid)
+                                       elog(ERROR, "DefineOpClass: procedure number %d appears more than once",
+                                                item->number);
+                               funcOid = LookupFuncNameTypeNames(item->name, item->args,
+                                                                                                 true, "DefineOpClass");
+                               /* Caller must have execute permission on functions */
+                               aclresult = pg_proc_aclcheck(funcOid, GetUserId(),
+                                                                                        ACL_EXECUTE);
+                               if (aclresult != ACLCHECK_OK)
+                                       aclcheck_error(aclresult, get_func_name(funcOid));
+                               procedures[item->number - 1] = funcOid;
+                               break;
+                       case OPCLASS_ITEM_STORAGETYPE:
+                               if (OidIsValid(storageoid))
+                                       elog(ERROR, "DefineOpClass: storage type specified more than once");
+                               storageoid = typenameTypeId(item->storedtype);
+                               break;
+                       default:
+                               elog(ERROR, "DefineOpClass: bogus item type %d",
+                                        item->itemtype);
+                               break;
+               }
+       }
+
+       /*
+        * If storagetype is specified, make sure it's legal.
+        */
+       if (OidIsValid(storageoid))
+       {
+               /* Just drop the spec if same as column datatype */
+               if (storageoid == typeoid)
+                       storageoid = InvalidOid;
+               else
+               {
+                       /*
+                        * Currently, only GiST allows storagetype different from
+                        * datatype.  This hardcoded test should be eliminated in
+                        * favor of adding another boolean column to pg_am ...
+                        */
+                       if (amoid != GIST_AM_OID)
+                               elog(ERROR, "Storage type may not be different from datatype for access method %s",
+                                        stmt->amname);
+               }
+       }
+
+       rel = heap_openr(OperatorClassRelationName, RowExclusiveLock);
+
+       /*
+        * Make sure there is no existing opclass of this name (this is
+        * just to give a more friendly error message than "duplicate key").
+        */
+       if (SearchSysCacheExists(CLAAMNAMENSP,
+                                                        ObjectIdGetDatum(amoid),
+                                                        CStringGetDatum(opcname),
+                                                        ObjectIdGetDatum(namespaceoid),
+                                                        0))
+               elog(ERROR, "Operator class \"%s\" already exists for access method \"%s\"",
+                        opcname, stmt->amname);
+
+       /*
+        * If we are creating a default opclass, check there isn't one already.
+        * (XXX should we restrict this test to visible opclasses?)
+        */
+       if (stmt->isDefault)
+       {
+               ScanKeyData     skey[1];
+               SysScanDesc scan;
+
+               ScanKeyEntryInitialize(&skey[0], 0x0,
+                                                          Anum_pg_opclass_opcamid, F_OIDEQ,
+                                                          ObjectIdGetDatum(amoid));
+
+               scan = systable_beginscan(rel, OpclassAmNameNspIndex, true,
+                                                                 SnapshotNow, 1, skey);
+
+               while (HeapTupleIsValid(tup = systable_getnext(scan)))
+               {
+                       Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
+
+                       if (opclass->opcintype == typeoid && opclass->opcdefault)
+                               elog(ERROR, "Can't add class \"%s\" as default for type %s"
+                                        "\n\tclass \"%s\" already is the default",
+                                        opcname,
+                                        TypeNameToString(stmt->datatype),
+                                        NameStr(opclass->opcname));
+               }
+
+               systable_endscan(scan);
+       }
+
+       /*
+        * Okay, let's create the pg_opclass entry.
+        */
+       for (i = 0; i < Natts_pg_opclass; ++i)
+       {
+               nulls[i] = ' ';
+               values[i] = (Datum) NULL;               /* redundant, but safe */
+       }
+
+       i = 0;
+       values[i++] = ObjectIdGetDatum(amoid);          /* opcamid */
+       namestrcpy(&opcName, opcname);
+       values[i++] = NameGetDatum(&opcName);           /* opcname */
+       values[i++] = ObjectIdGetDatum(namespaceoid);   /* opcnamespace */
+       values[i++] = Int32GetDatum(GetUserId());       /* opcowner */
+       values[i++] = ObjectIdGetDatum(typeoid);        /* opcintype */
+       values[i++] = BoolGetDatum(stmt->isDefault);    /* opcdefault */
+       values[i++] = ObjectIdGetDatum(storageoid);     /* opckeytype */
+
+       tup = heap_formtuple(rel->rd_att, values, nulls);
+
+       opclassoid = simple_heap_insert(rel, tup);
+
+       if (RelationGetForm(rel)->relhasindex)
+       {
+               Relation        idescs[Num_pg_opclass_indices];
+
+               CatalogOpenIndices(Num_pg_opclass_indices, Name_pg_opclass_indices,
+                                                  idescs);
+               CatalogIndexInsert(idescs, Num_pg_opclass_indices, rel, tup);
+               CatalogCloseIndices(Num_pg_opclass_indices, idescs);
+       }
+
+       heap_freetuple(tup);
+
+       /*
+        * Now add tuples to pg_amop and pg_amproc tying in the
+        * operators and functions.
+        */
+       storeOperators(opclassoid, numOperators, operators, recheck);
+       storeProcedures(opclassoid, numProcs, procedures);
+
+       /*
+        * Create dependencies.  Note: we do not create a dependency link to
+        * the AM, because we don't currently support DROP ACCESS METHOD.
+        */
+       myself.classId = RelationGetRelid(rel);
+       myself.objectId = opclassoid;
+       myself.objectSubId = 0;
+
+       /* dependency on namespace */
+       referenced.classId = get_system_catalog_relid(NamespaceRelationName);
+       referenced.objectId = namespaceoid;
+       referenced.objectSubId = 0;
+       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+       /* dependency on indexed datatype */
+       referenced.classId = RelOid_pg_type;
+       referenced.objectId = typeoid;
+       referenced.objectSubId = 0;
+       recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+       /* dependency on storage datatype */
+       if (OidIsValid(storageoid))
+       {
+               referenced.classId = RelOid_pg_type;
+               referenced.objectId = storageoid;
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+       }
+
+       /* dependencies on operators */
+       referenced.classId = get_system_catalog_relid(OperatorRelationName);
+       for (i = 0; i < numOperators; i++)
+       {
+               if (operators[i] == InvalidOid)
+                       continue;
+               referenced.objectId = operators[i];
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+       }
+
+       /* dependencies on procedures */
+       for (i = 0; i < numProcs; i++)
+       {
+               if (procedures[i] == InvalidOid)
+                       continue;
+               referenced.classId = RelOid_pg_proc;
+               referenced.objectId = procedures[i];
+               referenced.objectSubId = 0;
+               recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+       }
+
+       heap_close(rel, RowExclusiveLock);
+}
+
+/*
+ * Dump the operators to pg_amop
+ */
+static void
+storeOperators(Oid opclassoid, int numOperators,
+                          Oid *operators, bool *recheck)
+{
+       Relation                rel;
+       Datum                   values[Natts_pg_amop];
+       char                    nulls[Natts_pg_amop];
+       HeapTuple               tup;
+       int                             i, j;
+
+       rel = heap_openr(AccessMethodOperatorRelationName, RowExclusiveLock);
+
+       for (j = 0; j < numOperators; j++)
+       {
+               if (operators[j] == InvalidOid)
+                       continue;
+
+               for (i = 0; i < Natts_pg_amop; ++i)
+               {
+                       nulls[i] = ' ';
+                       values[i] = (Datum) NULL;
+               }
+
+               i = 0;
+               values[i++] = ObjectIdGetDatum(opclassoid);                     /* amopclaid */
+               values[i++] = Int16GetDatum(j + 1);                                     /* amopstrategy */
+               values[i++] = BoolGetDatum(recheck[j]);         /* amopreqcheck */
+               values[i++] = ObjectIdGetDatum(operators[j]);   /* amopopr */
+
+               tup = heap_formtuple(rel->rd_att, values, nulls);
+
+               simple_heap_insert(rel, tup);
+
+               if (RelationGetForm(rel)->relhasindex)
+               {
+                       Relation        idescs[Num_pg_amop_indices];
+
+                       CatalogOpenIndices(Num_pg_amop_indices, Name_pg_amop_indices,
+                                                          idescs);
+                       CatalogIndexInsert(idescs, Num_pg_amop_indices, rel, tup);
+                       CatalogCloseIndices(Num_pg_amop_indices, idescs);
+               }
+               heap_freetuple(tup);
+       }
+
+       heap_close(rel, RowExclusiveLock);
+}
+
+/*
+ * Dump the procedures (support routines) to pg_amproc
+ */
+static void
+storeProcedures(Oid opclassoid, int numProcs, Oid *procedures)
+{
+       Relation                rel;
+       Datum                   values[Natts_pg_amproc];
+       char                    nulls[Natts_pg_amproc];
+       HeapTuple               tup;
+       int                             i, j;
+
+       rel = heap_openr(AccessMethodProcedureRelationName, RowExclusiveLock);
+
+       for (j = 0; j < numProcs; j++)
+       {
+               if (procedures[j] == InvalidOid)
+                       continue;
+
+               for (i = 0; i < Natts_pg_amproc; ++i)
+               {
+                       nulls[i] = ' ';
+                       values[i] = (Datum) NULL;
+               }
+
+               i = 0;
+               values[i++] = ObjectIdGetDatum(opclassoid);                     /* amopclaid */
+               values[i++] = Int16GetDatum(j + 1);                                     /* amprocnum */
+               values[i++] = ObjectIdGetDatum(procedures[j]);          /* amproc */
+
+               tup = heap_formtuple(rel->rd_att, values, nulls);
+
+               simple_heap_insert(rel, tup);
+
+               if (RelationGetForm(rel)->relhasindex)
+               {
+                       Relation        idescs[Num_pg_amproc_indices];
+
+                       CatalogOpenIndices(Num_pg_amproc_indices, Name_pg_amproc_indices,
+                                                          idescs);
+                       CatalogIndexInsert(idescs, Num_pg_amproc_indices, rel, tup);
+                       CatalogCloseIndices(Num_pg_amproc_indices, idescs);
+               }
+               heap_freetuple(tup);
+       }
+
+       heap_close(rel, RowExclusiveLock);
+}
+
+
+/*
+ * RemoveOpClass
+ *             Deletes an opclass.
+ */
+void
+RemoveOpClass(RemoveOpClassStmt *stmt)
+{
+       Oid                             amID, opcID;
+       char       *catalogname;
+       char       *schemaname = NULL;
+       char       *opcname = NULL;
+       HeapTuple       tuple;
+       ObjectAddress object;
+
+       /*
+        *      Get the access method's OID.
+        */
+       amID = GetSysCacheOid(AMNAME,
+                                                 CStringGetDatum(stmt->amname),
+                                                 0, 0, 0);
+       if (!OidIsValid(amID))
+               elog(ERROR, "RemoveOpClass: access method \"%s\" not found",
+                        stmt->amname);
+
+       /*
+        * Look up the opclass.
+        */
+
+       /* deconstruct the name list */
+       switch (length(stmt->opclassname))
+       {
+               case 1:
+                       opcname = strVal(lfirst(stmt->opclassname));
+                       break;
+               case 2:
+                       schemaname = strVal(lfirst(stmt->opclassname));
+                       opcname = strVal(lsecond(stmt->opclassname));
+                       break;
+               case 3:
+                       catalogname = strVal(lfirst(stmt->opclassname));
+                       schemaname = strVal(lsecond(stmt->opclassname));
+                       opcname = strVal(lfirst(lnext(lnext(stmt->opclassname))));
+                       /*
+                        * We check the catalog name and then ignore it.
+                        */
+                       if (strcmp(catalogname, DatabaseName) != 0)
+                               elog(ERROR, "Cross-database references are not implemented");
+                       break;
+               default:
+                       elog(ERROR, "Improper opclass name (too many dotted names): %s",
+                                NameListToString(stmt->opclassname));
+                       break;
+       }
+
+       if (schemaname)
+       {
+               /* Look in specific schema only */
+               Oid             namespaceId;
+
+               namespaceId = GetSysCacheOid(NAMESPACENAME,
+                                                                        CStringGetDatum(schemaname),
+                                                                        0, 0, 0);
+               if (!OidIsValid(namespaceId))
+                       elog(ERROR, "Namespace \"%s\" does not exist",
+                                schemaname);
+               tuple = SearchSysCache(CLAAMNAMENSP,
+                                                          ObjectIdGetDatum(amID),
+                                                          PointerGetDatum(opcname),
+                                                          ObjectIdGetDatum(namespaceId),
+                                                          0);
+       }
+       else
+       {
+               /* Unqualified opclass name, so search the search path */
+               opcID = OpclassnameGetOpcid(amID, opcname);
+               if (!OidIsValid(opcID))
+                       elog(ERROR, "RemoveOpClass: operator class \"%s\" not supported by access method \"%s\"",
+                                opcname, stmt->amname);
+               tuple = SearchSysCache(CLAOID,
+                                                          ObjectIdGetDatum(opcID),
+                                                          0, 0, 0);
+       }
+
+       if (!HeapTupleIsValid(tuple))
+               elog(ERROR, "RemoveOpClass: operator class \"%s\" not supported by access method \"%s\"",
+                        NameListToString(stmt->opclassname), stmt->amname);
+
+       opcID = HeapTupleGetOid(tuple);
+
+       /* Permission check: must own opclass or its namespace */
+       if (!pg_opclass_ownercheck(opcID, GetUserId()) &&
+               !pg_namespace_ownercheck(((Form_pg_opclass) GETSTRUCT(tuple))->opcnamespace,
+                                                                GetUserId()))
+               aclcheck_error(ACLCHECK_NOT_OWNER,
+                                          NameListToString(stmt->opclassname));
+
+       ReleaseSysCache(tuple);
+
+       /*
+        * Do the deletion
+        */
+       object.classId = get_system_catalog_relid(OperatorClassRelationName);
+       object.objectId = opcID;
+       object.objectSubId = 0;
+
+       performDeletion(&object, stmt->behavior);
+}
+
+/*
+ * Guts of opclass deletion.
+ */
+void
+RemoveOpClassById(Oid opclassOid)
+{
+       Relation                rel;
+       HeapTuple               tup;
+       ScanKeyData             skey[1];
+       SysScanDesc             scan;
+
+       /*
+        * First remove the pg_opclass entry itself.
+        */
+       rel = heap_openr(OperatorClassRelationName, RowExclusiveLock);
+
+       tup = SearchSysCache(CLAOID,
+                                                ObjectIdGetDatum(opclassOid),
+                                                0, 0, 0);
+       if (!HeapTupleIsValid(tup))     /* should not happen */
+               elog(ERROR, "RemoveOpClassById: couldn't find pg_class entry %u",
+                        opclassOid);
+
+       simple_heap_delete(rel, &tup->t_self);
+
+       ReleaseSysCache(tup);
+
+       heap_close(rel, RowExclusiveLock);
+
+       /*
+        * Remove associated entries in pg_amop.
+        */
+       ScanKeyEntryInitialize(&skey[0], 0,
+                                                  Anum_pg_amop_amopclaid, F_OIDEQ,
+                                                  ObjectIdGetDatum(opclassOid));
+
+       rel = heap_openr(AccessMethodOperatorRelationName, RowExclusiveLock);
+
+       scan = systable_beginscan(rel, AccessMethodStrategyIndex, true,
+                                                         SnapshotNow, 1, skey);
+
+       while (HeapTupleIsValid(tup = systable_getnext(scan)))
+       {
+               simple_heap_delete(rel, &tup->t_self);
+       }
+
+       systable_endscan(scan);
+       heap_close(rel, RowExclusiveLock);
+
+       /*
+        * Remove associated entries in pg_amproc.
+        */
+       ScanKeyEntryInitialize(&skey[0], 0,
+                                                  Anum_pg_amproc_amopclaid, F_OIDEQ,
+                                                  ObjectIdGetDatum(opclassOid));
+
+       rel = heap_openr(AccessMethodProcedureRelationName, RowExclusiveLock);
+
+       scan = systable_beginscan(rel, AccessMethodProcedureIndex, true,
+                                                         SnapshotNow, 1, skey);
+
+       while (HeapTupleIsValid(tup = systable_getnext(scan)))
+       {
+               simple_heap_delete(rel, &tup->t_self);
+       }
+
+       systable_endscan(scan);
+       heap_close(rel, RowExclusiveLock);
+}
index b999047..f3c1963 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.197 2002/07/24 19:11:10 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.198 2002/07/29 22:14:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2147,6 +2147,19 @@ _copyRemoveOperStmt(RemoveOperStmt *from)
        return newnode;
 }
 
+static RemoveOpClassStmt *
+_copyRemoveOpClassStmt(RemoveOpClassStmt *from)
+{
+       RemoveOpClassStmt *newnode = makeNode(RemoveOpClassStmt);
+
+       Node_Copy(from, newnode, opclassname);
+       if (from->amname)
+               newnode->amname = pstrdup(from->amname);
+       newnode->behavior = from->behavior;
+
+       return newnode;
+}
+
 static RenameStmt *
 _copyRenameStmt(RenameStmt *from)
 {
@@ -2252,6 +2265,36 @@ _copyCreateDomainStmt(CreateDomainStmt *from)
        return newnode;
 }
 
+static CreateOpClassStmt *
+_copyCreateOpClassStmt(CreateOpClassStmt *from)
+{
+       CreateOpClassStmt *newnode = makeNode(CreateOpClassStmt);
+
+       Node_Copy(from, newnode, opclassname);
+       if (from->amname)
+               newnode->amname = pstrdup(from->amname);
+       Node_Copy(from, newnode, datatype);
+       Node_Copy(from, newnode, items);
+       newnode->isDefault = from->isDefault;
+
+       return newnode;
+}
+
+static CreateOpClassItem *
+_copyCreateOpClassItem(CreateOpClassItem *from)
+{
+       CreateOpClassItem *newnode = makeNode(CreateOpClassItem);
+
+       newnode->itemtype = from->itemtype;
+       Node_Copy(from, newnode, name);
+       Node_Copy(from, newnode, args);
+       newnode->number = from->number;
+       newnode->recheck = from->recheck;
+       Node_Copy(from, newnode, storedtype);
+
+       return newnode;
+}
+
 static CreatedbStmt *
 _copyCreatedbStmt(CreatedbStmt *from)
 {
@@ -2872,6 +2915,9 @@ copyObject(void *from)
                case T_RemoveOperStmt:
                        retval = _copyRemoveOperStmt(from);
                        break;
+               case T_RemoveOpClassStmt:
+                       retval = _copyRemoveOpClassStmt(from);
+                       break;
                case T_RenameStmt:
                        retval = _copyRenameStmt(from);
                        break;
@@ -2899,6 +2945,12 @@ copyObject(void *from)
                case T_CreateDomainStmt:
                        retval = _copyCreateDomainStmt(from);
                        break;
+               case T_CreateOpClassStmt:
+                       retval = _copyCreateOpClassStmt(from);
+                       break;
+               case T_CreateOpClassItem:
+                       retval = _copyCreateOpClassItem(from);
+                       break;
                case T_CreatedbStmt:
                        retval = _copyCreatedbStmt(from);
                        break;
index 419313c..55beb56 100644 (file)
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.144 2002/07/24 19:11:10 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.145 2002/07/29 22:14:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -976,6 +976,18 @@ _equalRemoveOperStmt(RemoveOperStmt *a, RemoveOperStmt *b)
        return true;
 }
 
+static bool
+_equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b)
+{
+       if (!equal(a->opclassname, b->opclassname))
+               return false;
+       if (!equalstr(a->amname, b->amname))
+               return false;
+       if (a->behavior != b->behavior)
+               return false;
+
+       return true;
+}
 
 static bool
 _equalRenameStmt(RenameStmt *a, RenameStmt *b)
@@ -1083,6 +1095,42 @@ _equalCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b)
 }
 
 static bool
+_equalCreateOpClassStmt(CreateOpClassStmt *a, CreateOpClassStmt *b)
+{
+       if (!equal(a->opclassname, b->opclassname))
+               return false;
+       if (!equalstr(a->amname, b->amname))
+               return false;
+       if (!equal(a->datatype, b->datatype))
+               return false;
+       if (!equal(a->items, b->items))
+               return false;
+       if (a->isDefault != b->isDefault)
+               return false;
+
+       return true;
+}
+
+static bool
+_equalCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *b)
+{
+       if (a->itemtype != b->itemtype)
+               return false;
+       if (!equal(a->name, b->name))
+               return false;
+       if (!equal(a->args, b->args))
+               return false;
+       if (a->number != b->number)
+               return false;
+       if (a->recheck != b->recheck)
+               return false;
+       if (!equal(a->storedtype, b->storedtype))
+               return false;
+
+       return true;
+}
+
+static bool
 _equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
 {
        if (!equalstr(a->dbname, b->dbname))
@@ -2036,6 +2084,9 @@ equal(void *a, void *b)
                case T_RemoveOperStmt:
                        retval = _equalRemoveOperStmt(a, b);
                        break;
+               case T_RemoveOpClassStmt:
+                       retval = _equalRemoveOpClassStmt(a, b);
+                       break;
                case T_RenameStmt:
                        retval = _equalRenameStmt(a, b);
                        break;
@@ -2063,6 +2114,12 @@ equal(void *a, void *b)
                case T_CreateDomainStmt:
                        retval = _equalCreateDomainStmt(a, b);
                        break;
+               case T_CreateOpClassStmt:
+                       retval = _equalCreateOpClassStmt(a, b);
+                       break;
+               case T_CreateOpClassItem:
+                       retval = _equalCreateOpClassItem(a, b);
+                       break;
                case T_CreatedbStmt:
                        retval = _equalCreatedbStmt(a, b);
                        break;
index 0dcecc9..532cc1d 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.349 2002/07/24 19:11:10 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.350 2002/07/29 22:14:10 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -136,11 +136,11 @@ static void doNegateFloat(Value *v);
                AlterTableStmt, AlterUserStmt, AlterUserSetStmt,
                AnalyzeStmt, ClosePortalStmt, ClusterStmt, CommentStmt,
                ConstraintsSetStmt, CopyStmt, CreateAsStmt, CreateCastStmt,
-               CreateDomainStmt, CreateGroupStmt, CreatePLangStmt,
+               CreateDomainStmt, CreateGroupStmt, CreateOpClassStmt, CreatePLangStmt,
                CreateSchemaStmt, CreateSeqStmt, CreateStmt,
                CreateAssertStmt, CreateTrigStmt, CreateUserStmt,
                CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
-               DropGroupStmt, DropPLangStmt, DropStmt,
+               DropGroupStmt, DropOpClassStmt, DropPLangStmt, DropStmt,
                DropAssertStmt, DropTrigStmt, DropRuleStmt, DropCastStmt,
                DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
                GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt,
@@ -156,7 +156,7 @@ static void doNegateFloat(Value *v);
 %type <node>   select_no_parens, select_with_parens, select_clause,
                                simple_select
 
-%type <node>   alter_column_default
+%type <node>   alter_column_default, opclass_item
 %type <ival>   add_drop
 
 %type <dbehavior>      opt_drop_behavior
@@ -218,7 +218,7 @@ static void doNegateFloat(Value *v);
                                target_list, update_target_list, insert_column_list,
                                insert_target_list, def_list, opt_indirection,
                                group_clause, TriggerFuncArgs, select_limit,
-                               opt_select_limit
+                               opt_select_limit, opclass_item_list
 
 %type <range>  into_clause, OptTempTableName
 
@@ -240,7 +240,7 @@ static void doNegateFloat(Value *v);
 
 %type <boolean> opt_instead, opt_cursor
 %type <boolean> index_opt_unique, opt_verbose, opt_full
-%type <boolean> opt_freeze, opt_default
+%type <boolean> opt_freeze, opt_default, opt_recheck
 %type <defelt> opt_binary, opt_oids, copy_delimiter
 
 %type <boolean> copy_from
@@ -326,7 +326,7 @@ static void doNegateFloat(Value *v);
        BOOLEAN, BY,
 
        CACHE, CALLED, CASCADE, CASE, CAST, CHAIN, CHAR_P,
-       CHARACTER, CHARACTERISTICS, CHECK, CHECKPOINT, CLOSE,
+       CHARACTER, CHARACTERISTICS, CHECK, CHECKPOINT, CLASS, CLOSE,
        CLUSTER, COALESCE, COLLATE, COLUMN, COMMENT, COMMIT,
        COMMITTED, CONSTRAINT, CONSTRAINTS, CONVERSION_P, COPY, CREATE, CREATEDB,
        CREATEUSER, CROSS, CURRENT_DATE, CURRENT_TIME,
@@ -371,7 +371,7 @@ static void doNegateFloat(Value *v);
        PRECISION, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE,
        PROCEDURAL,
 
-       READ, REAL, REFERENCES, REINDEX, RELATIVE, RENAME, REPLACE,
+       READ, REAL, RECHECK, REFERENCES, REINDEX, RELATIVE, RENAME, REPLACE,
        RESET, RESTRICT, RETURNS, REVOKE, RIGHT, ROLLBACK, ROW,
        RULE,
 
@@ -481,6 +481,7 @@ stmt :
                        | CreateSchemaStmt
                        | CreateGroupStmt
                        | CreateSeqStmt
+                       | CreateOpClassStmt
                        | CreatePLangStmt
                        | CreateAssertStmt
                        | CreateTrigStmt
@@ -492,6 +493,7 @@ stmt :
                        | CommentStmt
                        | DropCastStmt
                        | DropGroupStmt
+                       | DropOpClassStmt
                        | DropPLangStmt
                        | DropAssertStmt
                        | DropTrigStmt
@@ -2267,6 +2269,93 @@ def_arg: func_return                                             { $$ = (Node *)$1; }
 
 /*****************************************************************************
  *
+ *             QUERIES :
+ *                             CREATE OPERATOR CLASS ...
+ *                             DROP OPERATOR CLASS ...
+ *
+ *****************************************************************************/
+
+CreateOpClassStmt:
+                       CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename
+                       USING access_method AS opclass_item_list
+                               {
+                                       CreateOpClassStmt *n = makeNode(CreateOpClassStmt);
+                                       n->opclassname = $4;
+                                       n->isDefault = $5;
+                                       n->datatype = $8;
+                                       n->amname = $10;
+                                       n->items = $12;
+                                       $$ = (Node *) n;
+                               }
+               ;
+
+opclass_item_list:
+                       opclass_item                                                    { $$ = makeList1($1); }
+                       | opclass_item_list ',' opclass_item    { $$ = lappend($1, $3); }
+               ;
+
+opclass_item:
+                       OPERATOR Iconst any_operator opt_recheck
+                               {
+                                       CreateOpClassItem *n = makeNode(CreateOpClassItem);
+                                       n->itemtype = OPCLASS_ITEM_OPERATOR;
+                                       n->name = $3;
+                                       n->args = NIL;
+                                       n->number = $2;
+                                       n->recheck = $4;
+                                       $$ = (Node *) n;
+                               }
+                       | OPERATOR Iconst any_operator '(' oper_argtypes ')' opt_recheck
+                               {
+                                       CreateOpClassItem *n = makeNode(CreateOpClassItem);
+                                       n->itemtype = OPCLASS_ITEM_OPERATOR;
+                                       n->name = $3;
+                                       n->args = $5;
+                                       n->number = $2;
+                                       n->recheck = $7;
+                                       $$ = (Node *) n;
+                               }
+                       | FUNCTION Iconst func_name func_args
+                               {
+                                       CreateOpClassItem *n = makeNode(CreateOpClassItem);
+                                       n->itemtype = OPCLASS_ITEM_FUNCTION;
+                                       n->name = $3;
+                                       n->args = $4;
+                                       n->number = $2;
+                                       $$ = (Node *) n;
+                               }
+                       | STORAGE Typename
+                               {
+                                       CreateOpClassItem *n = makeNode(CreateOpClassItem);
+                                       n->itemtype = OPCLASS_ITEM_STORAGETYPE;
+                                       n->storedtype = $2;
+                                       $$ = (Node *) n;
+                               }
+               ;
+
+opt_default:   DEFAULT { $$ = TRUE; }
+                       | /*EMPTY*/     { $$ = FALSE; }
+               ;
+
+opt_recheck:   RECHECK { $$ = TRUE; }
+                       | /*EMPTY*/     { $$ = FALSE; }
+               ;
+
+
+DropOpClassStmt:
+                       DROP OPERATOR CLASS any_name USING access_method opt_drop_behavior
+                               {
+                                       RemoveOpClassStmt *n = makeNode(RemoveOpClassStmt);
+                                       n->opclassname = $4;
+                                       n->amname = $6;
+                                       n->behavior = $7;
+                                       $$ = (Node *) n;
+                               }
+               ;
+
+
+/*****************************************************************************
+ *
  *             QUERY:
  *
  *             DROP itemtype itemname [, itemname ...] [ RESTRICT | CASCADE ]
@@ -3655,10 +3744,6 @@ CreateConversionStmt:
                        }
                ;
 
-opt_default:   DEFAULT { $$ = TRUE; }
-                       | /*EMPTY*/     { $$ = FALSE; }
-               ;
-
 /*****************************************************************************
  *
  *             QUERY:
@@ -6624,6 +6709,7 @@ unreserved_keyword:
                        | CHAIN
                        | CHARACTERISTICS
                        | CHECKPOINT
+                       | CLASS
                        | CLOSE
                        | CLUSTER
                        | COMMENT
@@ -6715,6 +6801,7 @@ unreserved_keyword:
                        | PROCEDURAL
                        | PROCEDURE
                        | READ
+                       | RECHECK
                        | REINDEX
                        | RELATIVE
                        | RENAME
index 02c9fcd..32733d8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.122 2002/07/18 23:11:28 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.123 2002/07/29 22:14:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -68,6 +68,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"characteristics", CHARACTERISTICS},
        {"check", CHECK},
        {"checkpoint", CHECKPOINT},
+       {"class", CLASS},
        {"close", CLOSE},
        {"cluster", CLUSTER},
        {"coalesce", COALESCE},
@@ -232,6 +233,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"procedure", PROCEDURE},
        {"read", READ},
        {"real", REAL},
+       {"recheck", RECHECK},
        {"references", REFERENCES},
        {"reindex", REINDEX},
        {"relative", RELATIVE},
index d913736..8128487 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.272 2002/07/18 23:11:28 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.273 2002/07/29 22:14:11 tgl Exp $
  *
  * NOTES
  *       this is the "main" module of the postgres backend and
@@ -1693,7 +1693,7 @@ PostgresMain(int argc, char *argv[], const char *username)
        if (!IsUnderPostmaster)
        {
                puts("\nPOSTGRES backend interactive interface ");
-               puts("$Revision: 1.272 $ $Date: 2002/07/18 23:11:28 $\n");
+               puts("$Revision: 1.273 $ $Date: 2002/07/29 22:14:11 $\n");
        }
 
        /*
@@ -2452,6 +2452,14 @@ CreateCommandTag(Node *parsetree)
                        tag = "DROP CAST";
                        break;
 
+               case T_CreateOpClassStmt:
+                       tag = "CREATE OPERATOR CLASS";
+                       break;
+
+               case T_RemoveOpClassStmt:
+                       tag = "DROP OPERATOR CLASS";
+                       break;
+
                default:
                        elog(LOG, "CreateCommandTag: unknown parse node type %d",
                                 nodeTag(parsetree));
index 2ec5f42..0eff1ad 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.165 2002/07/25 10:07:11 ishii Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.166 2002/07/29 22:14:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -836,6 +836,14 @@ ProcessUtility(Node *parsetree,
                        DropCast((DropCastStmt *) parsetree);
                        break;
 
+               case T_CreateOpClassStmt:
+                       DefineOpClass((CreateOpClassStmt *) parsetree);
+                       break;
+
+               case T_RemoveOpClassStmt:
+                       RemoveOpClass((RemoveOpClassStmt *) parsetree);
+                       break;
+
                default:
                        elog(ERROR, "ProcessUtility: command #%d unsupported",
                                 nodeTag(parsetree));
index 7dfd26d..42dd50c 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.71 2002/07/20 05:16:58 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.72 2002/07/29 22:14:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -280,23 +280,19 @@ regprocedurein(PG_FUNCTION_ARGS)
 }
 
 /*
- * regprocedureout             - converts proc OID to "pro_name(args)"
+ * format_procedure            - converts proc OID to "pro_name(args)"
+ *
+ * This exports the useful functionality of regprocedureout for use
+ * in other backend modules.  The result is a palloc'd string.
  */
-Datum
-regprocedureout(PG_FUNCTION_ARGS)
+char *
+format_procedure(Oid procedure_oid)
 {
-       RegProcedure proid = PG_GETARG_OID(0);
        char       *result;
        HeapTuple       proctup;
 
-       if (proid == InvalidOid)
-       {
-               result = pstrdup("-");
-               PG_RETURN_CSTRING(result);
-       }
-
        proctup = SearchSysCache(PROCOID,
-                                                        ObjectIdGetDatum(proid),
+                                                        ObjectIdGetDatum(procedure_oid),
                                                         0, 0, 0);
 
        if (HeapTupleIsValid(proctup))
@@ -316,7 +312,7 @@ regprocedureout(PG_FUNCTION_ARGS)
                 * Would this proc be found (given the right args) by regprocedurein?
                 * If not, we need to qualify it.
                 */
-               if (FunctionIsVisible(proid))
+               if (FunctionIsVisible(procedure_oid))
                        nspname = NULL;
                else
                        nspname = get_namespace_name(procform->pronamespace);
@@ -344,9 +340,26 @@ regprocedureout(PG_FUNCTION_ARGS)
        {
                /* If OID doesn't match any pg_proc entry, return it numerically */
                result = (char *) palloc(NAMEDATALEN);
-               snprintf(result, NAMEDATALEN, "%u", proid);
+               snprintf(result, NAMEDATALEN, "%u", procedure_oid);
        }
 
+       return result;
+}
+
+/*
+ * regprocedureout             - converts proc OID to "pro_name(args)"
+ */
+Datum
+regprocedureout(PG_FUNCTION_ARGS)
+{
+       RegProcedure proid = PG_GETARG_OID(0);
+       char       *result;
+
+       if (proid == InvalidOid)
+               result = pstrdup("-");
+       else
+               result = format_procedure(proid);
+
        PG_RETURN_CSTRING(result);
 }
 
@@ -602,23 +615,19 @@ regoperatorin(PG_FUNCTION_ARGS)
 }
 
 /*
- * regoperatorout              - converts operator OID to "opr_name(args)"
+ * format_operator             - converts operator OID to "opr_name(args)"
+ *
+ * This exports the useful functionality of regoperatorout for use
+ * in other backend modules.  The result is a palloc'd string.
  */
-Datum
-regoperatorout(PG_FUNCTION_ARGS)
+char *
+format_operator(Oid operator_oid)
 {
-       Oid                     oprid = PG_GETARG_OID(0);
        char       *result;
        HeapTuple       opertup;
 
-       if (oprid == InvalidOid)
-       {
-               result = pstrdup("0");
-               PG_RETURN_CSTRING(result);
-       }
-
        opertup = SearchSysCache(OPEROID,
-                                                        ObjectIdGetDatum(oprid),
+                                                        ObjectIdGetDatum(operator_oid),
                                                         0, 0, 0);
 
        if (HeapTupleIsValid(opertup))
@@ -636,7 +645,7 @@ regoperatorout(PG_FUNCTION_ARGS)
                 * Would this oper be found (given the right args) by regoperatorin?
                 * If not, we need to qualify it.
                 */
-               if (!OperatorIsVisible(oprid))
+               if (!OperatorIsVisible(operator_oid))
                {
                        nspname = get_namespace_name(operform->oprnamespace);
                        appendStringInfo(&buf, "%s.",
@@ -665,9 +674,26 @@ regoperatorout(PG_FUNCTION_ARGS)
        {
                /* If OID doesn't match any pg_operator entry, return it numerically */
                result = (char *) palloc(NAMEDATALEN);
-               snprintf(result, NAMEDATALEN, "%u", oprid);
+               snprintf(result, NAMEDATALEN, "%u", operator_oid);
        }
 
+       return result;
+}
+
+/*
+ * regoperatorout              - converts operator OID to "opr_name(args)"
+ */
+Datum
+regoperatorout(PG_FUNCTION_ARGS)
+{
+       Oid                     oprid = PG_GETARG_OID(0);
+       char       *result;
+
+       if (oprid == InvalidOid)
+               result = pstrdup("0");
+       else
+               result = format_operator(oprid);
+
        PG_RETURN_CSTRING(result);
 }
 
index 31a31f4..0078059 100644 (file)
@@ -27,7 +27,7 @@
 # Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
 # Portions Copyright (c) 1994, Regents of the University of California
 #
-# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.162 2002/07/24 19:11:11 petere Exp $
+# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.163 2002/07/29 22:14:11 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -708,14 +708,15 @@ $ECHO_N "initializing pg_depend... "$ECHO_C
 -- First delete any already-made entries; PINs override all else, and must
 -- be the only entries for their objects.
 DELETE FROM pg_depend;
-INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_cast;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_class;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_proc;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_type;
+INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_cast;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_constraint;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_attrdef;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_language;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_operator;
+INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_opclass;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_rewrite;
 INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_trigger;
 -- restriction here to avoid pinning the public namespace
index 3342124..66b2f26 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_am.h,v 1.22 2002/06/20 20:29:43 momjian Exp $
+ * $Id: pg_am.h,v 1.23 2002/07/29 22:14:11 tgl Exp $
  *
  * NOTES
  *             the genbki.sh script reads this file and generates .bki
@@ -107,5 +107,6 @@ DATA(insert OID = 405 (  hash       PGUID   1 1 0 f f f t hashgettuple hashinsert hashbe
 DESCR("hash index access method");
 DATA(insert OID = 783 (  gist  PGUID 100 7 0 f t f f gistgettuple gistinsert gistbeginscan gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistcostestimate ));
 DESCR("GiST index access method");
+#define GIST_AM_OID 783
 
 #endif   /* PG_AM_H */
index 707ba1d..a4af74a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: defrem.h,v 1.42 2002/07/18 23:11:32 petere Exp $
+ * $Id: defrem.h,v 1.43 2002/07/29 22:14:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,6 +59,10 @@ extern void RemoveTypeById(Oid typeOid);
 extern void DefineDomain(CreateDomainStmt *stmt);
 extern void RemoveDomain(List *names, DropBehavior behavior);
 
+extern void DefineOpClass(CreateOpClassStmt *stmt);
+extern void RemoveOpClass(RemoveOpClassStmt *stmt);
+extern void RemoveOpClassById(Oid opclassOid);
+
 
 /* support routines in commands/define.c */
 
index 3583315..93a020a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.113 2002/07/18 23:11:32 petere Exp $
+ * $Id: nodes.h,v 1.114 2002/07/29 22:14:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -201,6 +201,8 @@ typedef enum NodeTag
        T_CreateConversionStmt,
        T_CreateCastStmt,
        T_DropCastStmt,
+       T_CreateOpClassStmt,
+       T_RemoveOpClassStmt,
 
        T_A_Expr = 700,
        T_ColumnRef,
@@ -235,6 +237,7 @@ typedef enum NodeTag
        T_FuncWithArgs,
        T_PrivTarget,
        T_InsertDefault,
+       T_CreateOpClassItem,
 
        /*
         * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
index 842a0b9..708e6ca 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.194 2002/07/24 19:11:14 petere Exp $
+ * $Id: parsenodes.h,v 1.195 2002/07/29 22:14:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1116,6 +1116,37 @@ typedef struct CreateDomainStmt
 } CreateDomainStmt;
 
 /* ----------------------
+ *             Create Operator Class Statement
+ * ----------------------
+ */
+typedef struct CreateOpClassStmt
+{
+       NodeTag         type;
+       List       *opclassname;        /* qualified name (list of Value strings) */
+       char       *amname;                     /* name of index AM opclass is for */
+       TypeName   *datatype;           /* datatype of indexed column */
+       List       *items;                      /* List of CreateOpClassItem nodes */
+       bool            isDefault;              /* Should be marked as default for type? */
+} CreateOpClassStmt;
+
+#define OPCLASS_ITEM_OPERATOR          1
+#define OPCLASS_ITEM_FUNCTION          2
+#define OPCLASS_ITEM_STORAGETYPE       3
+
+typedef struct CreateOpClassItem
+{
+       NodeTag         type;
+       int                     itemtype;               /* see codes above */
+       /* fields used for an operator or function item: */
+       List       *name;                       /* operator or function name */
+       List       *args;                       /* argument types */
+       int                     number;                 /* strategy num or support proc num */
+       bool            recheck;                /* only used for operators */
+       /* fields used for a storagetype item: */
+       TypeName   *storedtype;         /* datatype stored in index */
+} CreateOpClassItem;
+
+/* ----------------------
  *             Drop Table|Sequence|View|Index|Type|Domain|Conversion|Schema Statement
  * ----------------------
  */
@@ -1289,6 +1320,18 @@ typedef struct RemoveOperStmt
 } RemoveOperStmt;
 
 /* ----------------------
+ *             Drop Operator Class Statement
+ * ----------------------
+ */
+typedef struct RemoveOpClassStmt
+{
+       NodeTag         type;
+       List       *opclassname;        /* qualified name (list of Value strings) */
+       char       *amname;                     /* name of index AM opclass is for */
+       DropBehavior behavior;          /* RESTRICT or CASCADE behavior */
+} RemoveOpClassStmt;
+
+/* ----------------------
  *             Alter Object Rename Statement
  * ----------------------
  * Currently supports renaming tables, table columns, and triggers.
index 709c4e7..fff2c38 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: acl.h,v 1.45 2002/06/20 20:29:52 momjian Exp $
+ * $Id: acl.h,v 1.46 2002/07/29 22:14:11 tgl Exp $
  *
  * NOTES
  *       For backward-compatibility purposes we have to allow there
@@ -209,5 +209,6 @@ extern bool pg_type_ownercheck(Oid type_oid, Oid userid);
 extern bool pg_oper_ownercheck(Oid oper_oid, Oid userid);
 extern bool pg_proc_ownercheck(Oid proc_oid, Oid userid);
 extern bool pg_namespace_ownercheck(Oid nsp_oid, Oid userid);
+extern bool pg_opclass_ownercheck(Oid opc_oid, Oid userid);
 
 #endif   /* ACL_H */
index 02a537c..3abcc69 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.187 2002/07/20 05:49:28 momjian Exp $
+ * $Id: builtins.h,v 1.188 2002/07/29 22:14:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -343,6 +343,8 @@ extern Datum regclassout(PG_FUNCTION_ARGS);
 extern Datum regtypein(PG_FUNCTION_ARGS);
 extern Datum regtypeout(PG_FUNCTION_ARGS);
 extern List *stringToQualifiedNameList(const char *string, const char *caller);
+extern char *format_procedure(Oid procedure_oid);
+extern char *format_operator(Oid operator_oid);
 
 /* ruleutils.c */
 extern Datum pg_get_ruledef(PG_FUNCTION_ARGS);