Implement CREATE/DROP OPERATOR CLASS. Work still remains: need more
authorTom Lane
Mon, 29 Jul 2002 22:14:11 +0000 (22:14 +0000)
committerTom Lane
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 4d9031f65324e89e3c7778e1e78b050b4bec1b5e..24a87cb0356ec5158bbf94e830143bec0535ff85 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 a37d58ab7d915bebc9c72b1905ba7b95a6f42938..1ee6f2f2004b07890a822b370d691d34c22150e7 100644 (file)
@@ -1,5 +1,5 @@
 
@@ -61,6 +61,7 @@ Complete list of usable sgml source files in this directory.
 
 
 
+
 
 
 
@@ -82,6 +83,7 @@ Complete list of usable sgml source files in this directory.
 
 
 
+
 
 
 
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 @@
+
+
+
+  CREATE OPERATOR CLASS
+  SQL - Language Statements
+  
+   CREATE OPERATOR CLASS
+  
+  
+   define a new operator class for indexes
+  
+  
+  
+   2002-07-28
+  
+  
+CREATE OPERATOR CLASS name [ DEFAULT ] FOR TYPE data_type USING access_method AS
+  {  OPERATOR strategy_number operator_id [ ( type, type ) ] [ RECHECK ]
+   | FUNCTION support_number func_name ( parameter_types )
+   | STORAGE storage_type
+  } [, ... ]
+  
+  
+  
+   
+    2002-07-28
+   
+   </div> <div class="diff add">+    Inputs</div> <div class="diff add">+   
+   
+
+    
+     
+      name
+      
+       
+   The name of the operator class to be created.
+   The name may be schema-qualified.
+       
+      
+     
+     
+      DEFAULT
+      
+       
+        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.
+       
+      
+     
+     
+      data_type
+      
+       
+        The column datatype that this operator class is for.
+       
+      
+     
+     
+      access_method
+      
+       
+   The name of the index access method this operator class is for.
+       
+      
+     
+     
+      strategy_number
+      
+       
+        The index access method's strategy number for an operator associated
+   with the operator class.
+       
+      
+     
+     
+      operator_id
+      
+       
+   The identifier (optionally schema-qualified) of an operator associated
+   with the operator class.
+       
+      
+     
+     
+      type
+      
+       
+        The input datatype(s) of an operator, or 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.
+       
+      
+     
+     
+      RECHECK
+      
+       
+        If present, the index is 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.
+       
+      
+     
+     
+      support_number
+      
+       
+        The index access method's support procedure number for a function
+   associated with the operator class.
+       
+      
+     
+     
+      func_name
+      
+       
+        The name (optionally schema-qualified) of a function that is
+   an index access method support procedure for the operator class.
+       
+      
+     
+     
+      parameter_types
+      
+       
+        The parameter datatype(s) of the function.
+       
+      
+     
+     
+      storage_type
+      
+       
+        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
+   STORAGE clause must be omitted unless the index access
+   method allows a different type to be used.
+       
+      
+     
+    
+   
+  
+
+  
+   
+    2002-07-28
+   
+   </div> <div class="diff add">+    Outputs</div> <div class="diff add">+   
+   
+    
+     
+      
+CREATE OPERATOR CLASS
+       
+      
+       
+   Message returned if the operator class is successfully created.
+       
+      
+     
+    
+   
+  
+
+  
+   2002-07-28
+  
+  </div> <div class="diff add">+   Description</div> <div class="diff add">+  
+  
+   CREATE OPERATOR CLASS defines a new operator class,
+   name.
+  
+  
+   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 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.
+  
+
+  
+   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 CURRENT_SCHEMA()).
+   Two operator classes in the same schema can have the same name only if they
+   are for different index access methods.
+  
+  
+   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.
+  
+
+  
+   CREATE OPERATOR CLASS 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.
+  
+
+  
+    Refer to the chapter on interfacing extensions to indexes in the
+    PostgreSQL Programmer's Guide
+    for further information.
+  
+  
+  
+   
+    2002-07-28
+   
+   </div> <div class="diff add">+    Notes</div> <div class="diff add">+   
+   
+    Refer to
+    
+    to delete user-defined operator classes from a database.
+   
+  
+  
+  </div> <div class="diff add">+   Usage</div> <div class="diff add">+  
+  
+   The following example command defines a GiST index operator class
+   for datatype _int4 (array of int4).  See
+   contrib/intarray/ for the complete example.
+  
+
+  
+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);
+    
+
+  
+   The OPERATOR, FUNCTION, and STORAGE
+   clauses may appear in any order.
+  
+  </div> <div class="diff add">+   Compatibility</div> <div class="diff add">+  
+  
+  
+   
+    2002-07-28
+   
+   </div> <div class="diff add">+    SQL92</div> <div class="diff add">+   
+
+   
+    CREATE OPERATOR CLASS
+    is a PostgreSQL extension.
+    There is no CREATE OPERATOR CLASS
+    statement in SQL92.
+   
+  
+
+
+
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 @@
+
+
+
+  DROP OPERATOR CLASS
+  SQL - Language Statements
+  
+   DROP OPERATOR CLASS
+  
+  
+   remove a user-defined operator class
+  
+  
+  
+   2002-07-28
+  
+  
+DROP OPERATOR CLASS name USING access_method [ CASCADE | RESTRICT ]
+  
+  
+  
+   
+    2002-07-28
+   
+   </div> <div class="diff add">+    Inputs</div> <div class="diff add">+   
+   
+    
+     
+      name
+      
+       
+   The name (optionally schema-qualified) of an existing operator class.
+       
+      
+     
+     
+      access_method
+      
+       
+   The name of the index access method the operator class is for.
+       
+      
+     
+     
+      CASCADE
+      
+       
+        Automatically drop objects that depend on the operator class.
+       
+      
+     
+     
+      RESTRICT
+      
+       
+        Refuse to drop the operator class if there are any dependent objects.
+   This is the default.
+       
+      
+     
+    
+   
+  
+
+  
+   
+    2002-07-28
+   
+   </div> <div class="diff add">+    Outputs</div> <div class="diff add">+   
+   
+
+    
+     
+      
+DROP OPERATOR CLASS
+       
+      
+       
+   The message returned if the command is successful.
+       
+      
+     
+    
+   
+  
+
+  
+   2002-07-28
+  
+  </div> <div class="diff add">+   Description</div> <div class="diff add">+  
+  
+   DROP OPERATOR CLASS drops an existing operator class
+   from the database.
+   To execute this command you must be the owner of the operator class.
+  
+
+  
+   
+    2002-07-28
+   
+   </div> <div class="diff add">+    Notes</div> <div class="diff add">+   
+   
+    The DROP OPERATOR CLASS statement is a 
+    PostgreSQL
+    language extension.
+   
+   
+    Refer to
+    
+    for information on how to create operator classes.
+   
+  
+
+  </div> <div class="diff add">+   Usage</div> <div class="diff add">+  
+  
+   Remove btree operator class widget_ops:
+
+   
+DROP OPERATOR CLASS widget_ops USING btree;
+   
+
+   This command will not execute if there are any existing indexes
+   that use the operator class.  Add CASCADE to drop
+   such indexes along with the operator class.
+  
+  </div> <div class="diff add">+   Compatibility</div> <div class="diff add">+  
+
+  
+   
+    2002-07-28
+   
+   </div> <div class="diff add">+    SQL92</div> <div class="diff add">+   
+   
+    There is no DROP OPERATOR CLASS in
+    SQL92.
+   
+  
+
+
+
index 1cfb824090c89b1f3e35ac1bbd46ad959693d4c0..edd99bd75e317ec513cc55a08a0278ec25bbe3ce 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -172,10 +172,6 @@ ERROR: RemoveOperator: right unary operator 'oper
     
     for information on how to create operators.
    
-   
-    It is the user's responsibility to remove any access method
-    operator classes that rely on the deleted operator.
-   
   
  
 
index e2491f540829b7b88a11869398a93facaafc8be9..2101dfe8a1b3b125810514add5f8ac44b56b3b92 100644 (file)
@@ -1,5 +1,5 @@
 
@@ -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 47f36858f9277811d10e7e93ddae1208c40e8701..af82154d8c7a650132fe83999b70e26cbf140d71 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
 worries about funny characters.
 -->
 
+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 5827915d8a50f8d85fd669f003fc618e0d42d3d3..e06065e218fede26cc6ced77c9c9be049fd431b1 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 8330fe42a6265c511b9752c918c453174075aab1..ae88c4bf0551b8e17b93525e4ee8a22c8370f3f0 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 0937367957c60b688962c72aa4e63f3c5a9620c0..38fe5cd8924076391fffa9a739f40c788476ed33 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 58e8fe20e2d3c5386c381cb1ad48c430ed883acb..92961049d775b57c8da00f9d9ecebfb51e004834 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 b9990473802470989786a39a5b29c468f2484388..f3c19635dfe62a15493bbacc666d1431c3887a87 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 419313c6101942ad4eb2ffed6fa74fd667cd0b5c..55beb563c8ae5b249ed2b57925680b085ea721b1 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)
@@ -1082,6 +1094,42 @@ _equalCreateDomainStmt(CreateDomainStmt *a, CreateDomainStmt *b)
    return true;
 }
 
+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)
 {
@@ -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 0dcecc9d5a56cbb689f5424fafe8d7111fd77f82..532cc1de0f6425a778eca36227bfa9bbedadd7d3 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    select_no_parens, select_with_parens, select_clause,
                simple_select
 
-%type    alter_column_default
+%type    alter_column_default, opclass_item
 %type    add_drop
 
 %type   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   into_clause, OptTempTableName
 
@@ -240,7 +240,7 @@ static void doNegateFloat(Value *v);
 
 %type  opt_instead, opt_cursor
 %type  index_opt_unique, opt_verbose, opt_full
-%type  opt_freeze, opt_default
+%type  opt_freeze, opt_default, opt_recheck
 %type  opt_binary, opt_oids, copy_delimiter
 
 %type  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
@@ -2265,6 +2267,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:
@@ -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 02c9fcdda93e2594c73dd92060880443b64d7752..32733d8f54617b6af3cacba93fa855159381f391 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 d9137368335d3b5cd7abb6fd233db48789019a75..8128487a2e57767aac94fb5356fc3b43fac0fbf6 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 2ec5f427d3f8a12745c45dc679d9c848306a7809..0eff1ad2b167beccc9df58263b45034eba22262e 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 7dfd26d2db12c452d72d97ec15caa531e131ecff..42dd50ccd703ec122f5bcfb2c7a82092e719567d 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 31a31f472b8e38270868c3de1b6f787e6d7ab321..007805992e51e4d9008264b49844a9ffc5b71e63 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 33421247622cd691f2daa0b349c68dc20ac0994a..66b2f2621f1c83ae71e87e28f18404404e8b1ef8 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 707ba1d1b819f6dd9707e4a9288e10695558b81e..a4af74ac5c5c64fbbf525df3e5451de86804d6ca 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 3583315a274a24f3a527877ef41c8a3d048adbaf..93a020a12e9e309e8b36df2e300d5edb58e9c0a7 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 842a0b93d798f6b3890d03137f313a8d6568d547..708e6ca19a586df965c1bd0d7b82f0b052d3fe87 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -1115,6 +1115,37 @@ typedef struct CreateDomainStmt
    List       *constraints;    /* constraints (list of Constraint nodes) */
 } 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
  * ----------------------
@@ -1288,6 +1319,18 @@ typedef struct RemoveOperStmt
    DropBehavior behavior;      /* RESTRICT or CASCADE behavior */
 } 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
  * ----------------------
index 709c4e78c6c0796f080c2b1b1bb8fcb5c17baa73..fff2c38c0f98a7b85f5e19b5268dd5fb856c9f30 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 02a537ca4ee63be6aed52dc70e4a84ee1d09be56..3abcc69dcd5e7591a656bc076e3a853dfefb3625 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);