diff --git a/contrib/intarray/_int.sql.in b/contrib/intarray/_int.sql.in
index 4d9031f653..24a87cb035 100644
--- a/contrib/intarray/_int.sql.in
+++ b/contrib/intarray/_int.sql.in
@@ -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);
+-- Create the operator class for indexing
-
--- 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 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;
diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml
index a37d58ab7d..1ee6f2f200 100644
--- a/doc/src/sgml/ref/allfiles.sgml
+++ b/doc/src/sgml/ref/allfiles.sgml
@@ -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
index 0000000000..6d00f081f8
--- /dev/null
+++ b/doc/src/sgml/ref/create_opclass.sgml
@@ -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
+
+
+ Inputs
+
+
+
+
+
+ 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
+
+
+ Outputs
+
+
+
+
+
+CREATE OPERATOR CLASS
+
+
+
+ Message returned if the operator class is successfully created.
+
+
+
+
+
+
+
+
+
+
+ 2002-07-28
+
+
+ Description
+
+
+ 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
+
+
+ Notes
+
+
+ Refer to
+
+ to delete user-defined operator classes from a database.
+
+
+
+
+
+
+ Usage
+
+
+ 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.
+
+
+
+
+
+ Compatibility
+
+
+
+
+ 2002-07-28
+
+
+ SQL92
+
+
+
+ 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
index 0000000000..631a45aaeb
--- /dev/null
+++ b/doc/src/sgml/ref/drop_opclass.sgml
@@ -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
+
+
+ Inputs
+
+
+
+
+ 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
+
+
+ Outputs
+
+
+
+
+
+
+DROP OPERATOR CLASS
+
+
+
+ The message returned if the command is successful.
+
+
+
+
+
+
+
+
+
+
+ 2002-07-28
+
+
+ Description
+
+
+ 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
+
+
+ Notes
+
+
+ The DROP OPERATOR CLASS statement is a
+ PostgreSQL
+ language extension.
+
+
+ Refer to
+
+ for information on how to create operator classes.
+
+
+
+
+
+
+ Usage
+
+
+ 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.
+
+
+
+
+
+ Compatibility
+
+
+
+
+ 2002-07-28
+
+
+ SQL92
+
+
+ There is no DROP OPERATOR CLASS in
+ SQL92.
+
+
+
+
+
+
diff --git a/doc/src/sgml/ref/drop_operator.sgml b/doc/src/sgml/ref/drop_operator.sgml
index 1cfb824090..edd99bd75e 100644
--- a/doc/src/sgml/ref/drop_operator.sgml
+++ b/doc/src/sgml/ref/drop_operator.sgml
@@ -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.
-
diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml
index e2491f5408..2101dfe8a1 100644
--- a/doc/src/sgml/reference.sgml
+++ b/doc/src/sgml/reference.sgml
@@ -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;
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index 47f36858f9..af82154d8c 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -1,5 +1,5 @@
@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters.
-->
opcowner;
+
+ ReleaseSysCache(tuple);
+
+ return userid == owner_id;
+}
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 8330fe42a6..ae88c4bf05 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -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 $
*
*-------------------------------------------------------------------------
*/
@@ -21,15 +21,16 @@
#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"
@@ -48,15 +50,16 @@
/* 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:
- {
- HeapTuple typeTup;
-
- typeTup = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(object->objectId),
- 0, 0, 0);
- if (!HeapTupleIsValid(typeTup))
- elog(ERROR, "getObjectDescription: Type %u does not exist",
- object->objectId);
appendStringInfo(&buffer, "type %s",
- NameStr(((Form_pg_type) GETSTRUCT(typeTup))->typname));
- ReleaseSysCache(typeTup);
+ format_type_be(object->objectId));
+ break;
+
+ case OCLASS_CAST:
+ {
+ Relation castDesc;
+ ScanKeyData skey[1];
+ SysScanDesc rcscan;
+ HeapTuple tup;
+ Form_pg_cast castForm;
+
+ 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);
+
+ 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,11 +1279,52 @@ 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:
{
Relation ruleDesc;
@@ -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;
}
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 0937367957..38fe5cd892 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -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))
{
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index 58e8fe20e2..92961049d7 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -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
index 0000000000..fb86c980b9
--- /dev/null
+++ b/src/backend/commands/opclasscmds.c
@@ -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);
+}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index b999047380..f3c19635df 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -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;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 419313c610..55beb563c8 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -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;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0dcecc9d5a..532cc1de0f 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -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
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index 02c9fcdda9..32733d8f54 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -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},
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index d913736833..8128487a2e 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -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));
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 2ec5f427d3..0eff1ad2b1 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -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));
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 7dfd26d2db..42dd50ccd7 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -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);
}
diff --git a/src/bin/initdb/initdb.sh b/src/bin/initdb/initdb.sh
index 31a31f472b..007805992e 100644
--- a/src/bin/initdb/initdb.sh
+++ b/src/bin/initdb/initdb.sh
@@ -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
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index 3342124762..66b2f2621f 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -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 */
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 707ba1d1b8..a4af74ac5c 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -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 */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 3583315a27..93a020a12e 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -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)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 842a0b93d7..708e6ca19a 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -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
* ----------------------
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 709c4e78c6..fff2c38c0f 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -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 */
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 02a537ca4e..3abcc69dcd 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -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);