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);