diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml
index a481500525a..3b9b8b952ee 100644
--- a/doc/src/sgml/ref/allfiles.sgml
+++ b/doc/src/sgml/ref/allfiles.sgml
@@ -1,5 +1,5 @@
@@ -16,6 +16,7 @@ Complete list of usable sgml source files in this directory.
+
@@ -45,6 +46,7 @@ Complete list of usable sgml source files in this directory.
+
@@ -70,6 +72,7 @@ Complete list of usable sgml source files in this directory.
+
diff --git a/doc/src/sgml/ref/alter_opclass.sgml b/doc/src/sgml/ref/alter_opclass.sgml
index aa79f5704a9..586d54940c3 100644
--- a/doc/src/sgml/ref/alter_opclass.sgml
+++ b/doc/src/sgml/ref/alter_opclass.sgml
@@ -1,5 +1,5 @@
@@ -102,6 +102,7 @@ ALTER OPERATOR CLASS name USING
+
diff --git a/doc/src/sgml/ref/alter_opfamily.sgml b/doc/src/sgml/ref/alter_opfamily.sgml
new file mode 100644
index 00000000000..09906488e94
--- /dev/null
+++ b/doc/src/sgml/ref/alter_opfamily.sgml
@@ -0,0 +1,312 @@
+
+
+
+
+ ALTER OPERATOR FAMILY
+ SQL - Language Statements
+
+
+
+ ALTER OPERATOR FAMILY
+ change the definition of an operator family
+
+
+
+ ALTER OPERATOR FAMILY
+
+
+
+
+ALTER OPERATOR FAMILY name USING index_method ADD
+ { OPERATOR strategy_number operator_name ( op_type, op_type ) [ RECHECK ]
+ | FUNCTION support_number [ ( op_type [ , op_type ] ) ] funcname ( argument_type [, ...] )
+ } [, ... ]
+ALTER OPERATOR FAMILY name USING index_method DROP
+ { OPERATOR strategy_number ( op_type [ , op_type ] )
+ | FUNCTION support_number ( op_type [ , op_type ] )
+ } [, ... ]
+ALTER OPERATOR FAMILY name USING index_method RENAME TO newname
+ALTER OPERATOR FAMILY name USING index_method OWNER TO newowner
+
+
+
+
+ Description
+
+
+ ALTER OPERATOR FAMILY changes the definition of
+ an operator family. You can add operators and support functions
+ to the family, remove them from the family,
+ or change the family's name or owner.
+
+
+
+ When operators and support functions are added to a family with
+ ALTER OPERATOR FAMILY, they are not part of any
+ specific operator class within the family, but are just loose>
+ within the family. This indicates that these operators and functions
+ are compatible with the family's semantics, but are not required for
+ correct functioning of any specific index. (Operators and functions
+ that are so required should be declared as part of an operator class,
+ instead; see .)
+ PostgreSQL will allow loose members of a
+ family to be dropped from the family at any time, but members of an
+ operator class cannot be dropped without dropping the whole class and
+ any indexes that depend on it.
+ Typically, single-data-type operators
+ and functions are part of operator classes because they are needed to
+ support an index on that specific data type, while cross-data-type
+ operators and functions are made loose members of the family.
+
+
+
+ You must be a superuser to use ALTER OPERATOR FAMILY>.
+
+
+
+
+ Parameters
+
+
+
+ name
+
+
+ The name (optionally schema-qualified) of an existing operator
+ family.
+
+
+
+
+
+ index_method
+
+
+ The name of the index method this operator family is for.
+
+
+
+
+
+ strategy_number
+
+
+ The index method's strategy number for an operator
+ associated with the operator family.
+
+
+
+
+
+ operator_name
+
+
+ The name (optionally schema-qualified) of an operator associated
+ with the operator family.
+
+
+
+
+
+ op_type
+
+
+ In an OPERATOR> clause,
+ the operand data type(s) of the operator, or NONE> to
+ signify a left-unary or right-unary operator. Unlike the comparable
+ syntax in CREATE OPERATOR CLASS>, the operand data types
+ must always be specified.
+
+
+
+ In an ADD FUNCTION> clause, the operand data type(s) the
+ function is intended to support, if different from
+ the input data type(s) of the function. For B-tree and hash indexes
+ it is not necessary to specify op_type since the function's input
+ data type(s) are always the correct ones to use. For GIN and GiST
+ indexes it is necessary to specify the input data type the function
+ is to be used with.
+
+
+
+ In a DROP FUNCTION> clause, the operand data type(s) the
+ function is intended to support must be specified.
+
+
+
+
+
+ RECHECK>
+
+
+ If present, the index is lossy> for this operator, and
+ so the rows retrieved using the index must be rechecked to
+ verify that they actually satisfy the qualification clause
+ involving this operator.
+
+
+
+
+
+ support_number
+
+
+ The index method's support procedure number for a
+ function associated with the operator family.
+
+
+
+
+
+ funcname
+
+
+ The name (optionally schema-qualified) of a function that is an
+ index method support procedure for the operator family.
+
+
+
+
+
+ argument_types
+
+
+ The parameter data type(s) of the function.
+
+
+
+
+
+ newname
+
+
+ The new name of the operator family.
+
+
+
+
+
+ newowner
+
+
+ The new owner of the operator family.
+
+
+
+
+
+
+ The OPERATOR> and FUNCTION>
+ clauses may appear in any order.
+
+
+
+
+
+ Notes
+
+
+ Notice that the DROP> syntax only specifies the slot>
+ in the operator family, by strategy or support number and input data
+ type(s). The name of the operator or function occupying the slot is not
+ mentioned. Also, for DROP FUNCTION> the type(s) to specify
+ are the input data type(s) the function is intended to support; for
+ GIN and GiST indexes this may have nothing to do with the actual input
+ argument types of the function.
+
+
+
+ Because the index machinery does not check access permissions on functions
+ before using them, including a function or operator in an operator family
+ is tantamount to granting public execute permission on it. This is usually
+ not an issue for the sorts of functions that are useful in an operator
+ family.
+
+
+
+ The operators should not be defined by SQL functions. A SQL function
+ is likely to be inlined into the calling query, which will prevent
+ the optimizer from recognizing that the query matches an index.
+
+
+
+
+ Examples
+
+
+ The following example command adds cross-data-type operators and
+ support functions to an operator family that already contains B-tree
+ operator classes for data types int4> and int2>.
+
+
+
+ALTER OPERATOR FAMILY integer_ops USING btree ADD
+
+ -- int4 vs int2
+ OPERATOR 1 < (int4, int2) ,
+ OPERATOR 2 <= (int4, int2) ,
+ OPERATOR 3 = (int4, int2) ,
+ OPERATOR 4 >= (int4, int2) ,
+ OPERATOR 5 > (int4, int2) ,
+ FUNCTION 1 btint42cmp(int4, int2) ,
+
+ -- int2 vs int4
+ OPERATOR 1 < (int2, int4) ,
+ OPERATOR 2 <= (int2, int4) ,
+ OPERATOR 3 = (int2, int4) ,
+ OPERATOR 4 >= (int2, int4) ,
+ OPERATOR 5 > (int2, int4) ,
+ FUNCTION 1 btint24cmp(int2, int4) ;
+
+
+
+ To remove these entries again:
+
+
+
+ALTER OPERATOR FAMILY integer_ops USING btree DROP
+
+ -- int4 vs int2
+ OPERATOR 1 (int4, int2) ,
+ OPERATOR 2 (int4, int2) ,
+ OPERATOR 3 (int4, int2) ,
+ OPERATOR 4 (int4, int2) ,
+ OPERATOR 5 (int4, int2) ,
+ FUNCTION 1 (int4, int2) ,
+
+ -- int2 vs int4
+ OPERATOR 1 (int2, int4) ,
+ OPERATOR 2 (int2, int4) ,
+ OPERATOR 3 (int2, int4) ,
+ OPERATOR 4 (int2, int4) ,
+ OPERATOR 5 (int2, int4) ,
+ FUNCTION 1 (int2, int4) ;
+
+
+
+
+ Compatibility
+
+
+ There is no ALTER OPERATOR FAMILY statement in
+ the SQL standard.
+
+
+
+
+ See Also
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index d2cf39a20c4..bc3ab8f26d8 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -1,5 +1,5 @@
@@ -35,6 +35,7 @@ COMMENT ON
LARGE OBJECT large_object_oid |
OPERATOR op (leftoperand_type, rightoperand_type) |
OPERATOR CLASS object_name USING index_method |
+ OPERATOR FAMILY object_name USING index_method |
[ PROCEDURAL ] LANGUAGE object_name |
ROLE object_name |
RULE rule_name ON table_name |
@@ -92,7 +93,7 @@ COMMENT ON
The name of the object to be commented. Names of tables,
aggregates, domains, functions, indexes, operators, operator classes,
- sequences, types, and views may be schema-qualified.
+ operator families, sequences, types, and views may be schema-qualified.
@@ -247,6 +248,7 @@ COMMENT ON LARGE OBJECT 346344 IS 'Planning document';
COMMENT ON OPERATOR ^ (text, text) IS 'Performs intersection of two texts';
COMMENT ON OPERATOR - (NONE, text) IS 'This is a prefix operator on text';
COMMENT ON OPERATOR CLASS int4ops USING btree IS '4 byte integer operators for btrees';
+COMMENT ON OPERATOR FAMILY integer_ops USING btree IS 'all integer operators for btrees';
COMMENT ON ROLE my_role IS 'Administration group for finance tables';
COMMENT ON RULE my_rule ON my_table IS 'Logs updates of employee records';
COMMENT ON SCHEMA my_schema IS 'Departmental data';
diff --git a/doc/src/sgml/ref/create_opclass.sgml b/doc/src/sgml/ref/create_opclass.sgml
index 524be85f978..85a31e3b195 100644
--- a/doc/src/sgml/ref/create_opclass.sgml
+++ b/doc/src/sgml/ref/create_opclass.sgml
@@ -1,5 +1,5 @@
@@ -20,9 +20,10 @@ PostgreSQL documentation
-CREATE OPERATOR CLASS name [ DEFAULT ] FOR TYPE data_type USING index_method AS
+CREATE OPERATOR CLASS name [ DEFAULT ] FOR TYPE data_type
+ USING index_method [ FAMILY family_name ] AS
{ OPERATOR strategy_number operator_name [ ( op_type, op_type ) ] [ RECHECK ]
- | FUNCTION support_number funcname ( argument_type [, ...] )
+ | FUNCTION support_number [ ( op_type [ , op_type ] ) ] funcname ( argument_type [, ...] )
| STORAGE storage_type
} [, ... ]
@@ -40,7 +41,7 @@ CREATE OPERATOR CLASS name [ DEFAUL
be used by
the index method when the operator class is selected for an
index column. All the operators and functions used by an operator
- class must be defined before the operator class is created.
+ class must be defined before the operator class can be created.
@@ -65,6 +66,15 @@ CREATE OPERATOR CLASS name [ DEFAUL
responsibility to define a valid operator class.
+
+ Related operator classes can be grouped into operator
+ families>. To add a new operator class to an existing family,
+ specify the FAMILY> option in CREATE OPERATOR
+ CLASS. Without this option, the new class is placed into
+ a family named the same as the new class (creating that family if
+ it doesn't already exist).
+
+
Refer to for further information.
@@ -113,6 +123,17 @@ CREATE OPERATOR CLASS name [ DEFAUL
+
+ family_name
+
+
+ The name of the existing operator family to add this operator class to.
+ If not specified, a family named the same as the operator class is
+ used (creating it, if it doesn't already exist).
+
+
+
+
strategy_number
@@ -137,11 +158,24 @@ CREATE OPERATOR CLASS name [ DEFAUL
op_type
- The operand data type(s) of an operator, or NONE> to
+ In an OPERATOR> clause,
+ the operand data type(s) of the operator, or NONE> to
signify a left-unary or right-unary operator. The operand data
types may be omitted in the normal case where they are the same
as the operator class's data type.
+
+
+ In a FUNCTION> clause, the operand data type(s) the
+ function is intended to support, if different from
+ the input data type(s) of the function (for B-tree and hash indexes)
+ or the class's data type (for GIN and GiST indexes). These defaults
+ are always correct, so there is no point in specifying op_type in a FUNCTION> clause
+ in CREATE OPERATOR CLASS>, but the option is provided
+ for consistency with the comparable syntax in
+ ALTER OPERATOR FAMILY>.
+
@@ -192,7 +226,7 @@ CREATE OPERATOR CLASS name [ DEFAUL
The data type actually stored in the index. Normally this is
the same as the column data type, but some index methods
- (GIN and GiST for now) allow it to be different. The
+ (currently GIN and GiST) allow it to be different. The
STORAGE> clause must be omitted unless the index
method allows a different type to be used.
@@ -268,6 +302,8 @@ CREATE OPERATOR CLASS gist__int_ops
+
+
diff --git a/doc/src/sgml/ref/create_opfamily.sgml b/doc/src/sgml/ref/create_opfamily.sgml
new file mode 100644
index 00000000000..d8ddb683b9e
--- /dev/null
+++ b/doc/src/sgml/ref/create_opfamily.sgml
@@ -0,0 +1,125 @@
+
+
+
+
+ CREATE OPERATOR FAMILY
+ SQL - Language Statements
+
+
+
+ CREATE OPERATOR FAMILY
+ define a new operator family
+
+
+
+ CREATE OPERATOR FAMILY
+
+
+
+
+CREATE OPERATOR FAMILY name USING index_method
+
+
+
+
+ Description
+
+
+ CREATE OPERATOR FAMILY creates a new operator family.
+ An operator family defines a collection of related operator classes,
+ and perhaps some additional operators and support functions that are
+ compatible with these operator classes but not essential for the
+ functioning of any individual index. (Operators and functions that
+ are essential to indexes should be grouped within the relevant operator
+ class, rather than being loose> in the operator family.
+ Typically, single-data-type operators are bound to operator classes,
+ while cross-data-type operators can be loose in an operator family
+ containing operator classes for both data types.)
+
+
+
+ The new operator family is initially empty. It should be populated
+ by issuing subsequent CREATE OPERATOR CLASS commands
+ to add contained operator classes, and optionally
+ ALTER OPERATOR FAMILY commands to add loose>
+ operators and their corresponding support functions.
+
+
+
+ If a schema name is given then the operator family is created in the
+ specified schema. Otherwise it is created in the current schema.
+ Two operator families in the same schema can have the same name only if they
+ are for different index methods.
+
+
+
+ The user who defines an operator family becomes its owner. Presently,
+ the creating user must be a superuser. (This restriction is made because
+ an erroneous operator family definition could confuse or even crash the
+ server.)
+
+
+
+ CREATE OPERATOR FAMILY does not presently check
+ whether the operator family definition includes all the operators and
+ functions required by the index method, nor whether the operators and
+ functions form a self-consistent set. It is the user's
+ responsibility to define a valid operator family.
+
+
+
+ Refer to for further information.
+
+
+
+
+ Parameters
+
+
+
+ name
+
+
+ The name of the operator family to be created. The name may be
+ schema-qualified.
+
+
+
+
+
+ index_method
+
+
+ The name of the index method this operator family is for.
+
+
+
+
+
+
+
+ Compatibility
+
+
+ CREATE OPERATOR FAMILY is a
+ PostgreSQL extension. There is no
+ CREATE OPERATOR FAMILY statement in the SQL
+ standard.
+
+
+
+
+ See Also
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/src/sgml/ref/drop_opclass.sgml b/doc/src/sgml/ref/drop_opclass.sgml
index 42cc1cd0f8d..ce00ff40fd5 100644
--- a/doc/src/sgml/ref/drop_opclass.sgml
+++ b/doc/src/sgml/ref/drop_opclass.sgml
@@ -1,5 +1,5 @@
@@ -31,6 +31,13 @@ DROP OPERATOR CLASS [ IF EXISTS ] nameDROP OPERATOR CLASS drops an existing operator class.
To execute this command you must be the owner of the operator class.
+
+
+ DROP OPERATOR CLASS does not drop any of the operators
+ or functions referenced by the class. If there are any indexes depending
+ on the operator class, you will need to specify
+ CASCADE> for the drop to complete.
+
@@ -86,6 +93,20 @@ DROP OPERATOR CLASS [ IF EXISTS ] name
+
+
+ Notes
+
+
+ DROP OPERATOR CLASS> will not drop the operator family
+ containing the class, even if there is nothing else left in the
+ family (in particular, in the case where the family was implicitly
+ created by CREATE OPERATOR CLASS>). An empty operator
+ family is harmless, but for the sake of tidiness you may wish to
+ remove the family with DROP OPERATOR FAMILY>; or perhaps
+ better, use DROP OPERATOR FAMILY> in the first place.
+
+
Examples
@@ -118,6 +139,7 @@ DROP OPERATOR CLASS widget_ops USING btree;
+
diff --git a/doc/src/sgml/ref/drop_opfamily.sgml b/doc/src/sgml/ref/drop_opfamily.sgml
new file mode 100644
index 00000000000..e2dcaf72af1
--- /dev/null
+++ b/doc/src/sgml/ref/drop_opfamily.sgml
@@ -0,0 +1,135 @@
+
+
+
+
+ DROP OPERATOR FAMILY
+ SQL - Language Statements
+
+
+
+ DROP OPERATOR FAMILY
+ remove an operator family
+
+
+
+ DROP OPERATOR FAMILY
+
+
+
+
+DROP OPERATOR FAMILY [ IF EXISTS ] name USING index_method [ CASCADE | RESTRICT ]
+
+
+
+
+ Description
+
+
+ DROP OPERATOR FAMILY drops an existing operator family.
+ To execute this command you must be the owner of the operator family.
+
+
+
+ DROP OPERATOR FAMILY includes dropping any operator
+ classes contained in the family, but it does not drop any of the operators
+ or functions referenced by the family. If there are any indexes depending
+ on operator classes within the family, you will need to specify
+ CASCADE> for the drop to complete.
+
+
+
+
+ Parameters
+
+
+
+
+ IF EXISTS
+
+
+ Do not throw an error if the operator family does not exist.
+ A notice is issued in this case.
+
+
+
+
+
+ name
+
+
+ The name (optionally schema-qualified) of an existing operator family.
+
+
+
+
+
+ index_method
+
+
+ The name of the index access method the operator family is for.
+
+
+
+
+
+ CASCADE
+
+
+ Automatically drop objects that depend on the operator family.
+
+
+
+
+
+ RESTRICT
+
+
+ Refuse to drop the operator family if any objects depend on it.
+ This is the default.
+
+
+
+
+
+
+
+ Examples
+
+
+ Remove the B-tree operator family float_ops:
+
+
+DROP OPERATOR FAMILY float_ops USING btree;
+
+
+ This command will not succeed if there are any existing indexes
+ that use operator classes within the family. Add CASCADE> to
+ drop such indexes along with the operator family.
+
+
+
+
+ Compatibility
+
+
+ There is no DROP OPERATOR FAMILY statement in the
+ SQL standard.
+
+
+
+
+ See Also
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml
index 64330928c4e..9b3cbda575e 100644
--- a/doc/src/sgml/reference.sgml
+++ b/doc/src/sgml/reference.sgml
@@ -1,4 +1,4 @@
-
+
Reference
@@ -44,6 +44,7 @@
&alterLanguage;
&alterOperator;
&alterOperatorClass;
+ &alterOperatorFamily;
&alterRole;
&alterSchema;
&alterSequence;
@@ -73,6 +74,7 @@
&createLanguage;
&createOperator;
&createOperatorClass;
+ &createOperatorFamily;
&createRole;
&createRule;
&createSchema;
@@ -98,6 +100,7 @@
&dropLanguage;
&dropOperator;
&dropOperatorClass;
+ &dropOperatorFamily;
&dropOwned;
&dropRole;
&dropRule;
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index fcef0593b0a..328f8ccfda7 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.134 2007/01/05 22:19:24 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.135 2007/01/23 05:07:17 tgl Exp $
*
* NOTES
* See acl.h.
@@ -30,6 +30,7 @@
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
+#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
@@ -1413,6 +1414,8 @@ static const char *const no_priv_msg[MAX_ACL_KIND] =
gettext_noop("permission denied for schema %s"),
/* ACL_KIND_OPCLASS */
gettext_noop("permission denied for operator class %s"),
+ /* ACL_KIND_OPFAMILY */
+ gettext_noop("permission denied for operator family %s"),
/* ACL_KIND_CONVERSION */
gettext_noop("permission denied for conversion %s"),
/* ACL_KIND_TABLESPACE */
@@ -1439,6 +1442,8 @@ static const char *const not_owner_msg[MAX_ACL_KIND] =
gettext_noop("must be owner of schema %s"),
/* ACL_KIND_OPCLASS */
gettext_noop("must be owner of operator class %s"),
+ /* ACL_KIND_OPFAMILY */
+ gettext_noop("must be owner of operator family %s"),
/* ACL_KIND_CONVERSION */
gettext_noop("must be owner of conversion %s"),
/* ACL_KIND_TABLESPACE */
@@ -2239,6 +2244,35 @@ pg_opclass_ownercheck(Oid opc_oid, Oid roleid)
return has_privs_of_role(roleid, ownerId);
}
+/*
+ * Ownership check for an operator family (specified by OID).
+ */
+bool
+pg_opfamily_ownercheck(Oid opf_oid, Oid roleid)
+{
+ HeapTuple tuple;
+ Oid ownerId;
+
+ /* Superusers bypass all permission checking. */
+ if (superuser_arg(roleid))
+ return true;
+
+ tuple = SearchSysCache(OPFAMILYOID,
+ ObjectIdGetDatum(opf_oid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("operator family with OID %u does not exist",
+ opf_oid)));
+
+ ownerId = ((Form_pg_opfamily) GETSTRUCT(tuple))->opfowner;
+
+ ReleaseSysCache(tuple);
+
+ return has_privs_of_role(roleid, ownerId);
+}
+
/*
* Ownership check for a database (specified by OID).
*/
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index bf806f76fc2..30b7ebde002 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.21 2007/01/05 22:19:25 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.22 2007/01/23 05:07:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -66,6 +66,10 @@ ExecRenameStmt(RenameStmt *stmt)
RenameOpClass(stmt->object, stmt->subname, stmt->newname);
break;
+ case OBJECT_OPFAMILY:
+ RenameOpFamily(stmt->object, stmt->subname, stmt->newname);
+ break;
+
case OBJECT_ROLE:
RenameRole(stmt->subname, stmt->newname);
break;
@@ -211,6 +215,10 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
AlterOpClassOwner(stmt->object, stmt->addname, newowner);
break;
+ case OBJECT_OPFAMILY:
+ AlterOpFamilyOwner(stmt->object, stmt->addname, newowner);
+ break;
+
case OBJECT_SCHEMA:
AlterSchemaOwner((char *) linitial(stmt->object), newowner);
break;
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 6d6eff7f48d..2f6a38d42d2 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -7,7 +7,7 @@
* Copyright (c) 1996-2007, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.94 2007/01/05 22:19:25 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.95 2007/01/23 05:07:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,6 +28,7 @@
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
+#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_shdescription.h"
@@ -72,6 +73,7 @@ static void CommentConstraint(List *qualname, char *comment);
static void CommentConversion(List *qualname, char *comment);
static void CommentLanguage(List *qualname, char *comment);
static void CommentOpClass(List *qualname, List *arguments, char *comment);
+static void CommentOpFamily(List *qualname, List *arguments, char *comment);
static void CommentLargeObject(List *qualname, char *comment);
static void CommentCast(List *qualname, List *arguments, char *comment);
static void CommentTablespace(List *qualname, char *comment);
@@ -134,6 +136,9 @@ CommentObject(CommentStmt *stmt)
case OBJECT_OPCLASS:
CommentOpClass(stmt->objname, stmt->objargs, stmt->comment);
break;
+ case OBJECT_OPFAMILY:
+ CommentOpFamily(stmt->objname, stmt->objargs, stmt->comment);
+ break;
case OBJECT_LARGEOBJECT:
CommentLargeObject(stmt->objname, stmt->comment);
break;
@@ -1263,6 +1268,92 @@ CommentOpClass(List *qualname, List *arguments, char *comment)
CreateComments(opcID, OperatorClassRelationId, 0, comment);
}
+/*
+ * CommentOpFamily --
+ *
+ * This routine is used to allow a user to provide comments on an
+ * operator family. The operator family for commenting is determined by both
+ * its name and its argument list which defines the index method
+ * the operator family is used for. The argument list is expected to contain
+ * a single name (represented as a string Value node).
+ */
+static void
+CommentOpFamily(List *qualname, List *arguments, char *comment)
+{
+ char *amname;
+ char *schemaname;
+ char *opfname;
+ Oid amID;
+ Oid opfID;
+ HeapTuple tuple;
+
+ Assert(list_length(arguments) == 1);
+ amname = strVal(linitial(arguments));
+
+ /*
+ * Get the access method's OID.
+ */
+ amID = GetSysCacheOid(AMNAME,
+ CStringGetDatum(amname),
+ 0, 0, 0);
+ if (!OidIsValid(amID))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("access method \"%s\" does not exist",
+ amname)));
+
+ /*
+ * Look up the opfamily.
+ */
+
+ /* deconstruct the name list */
+ DeconstructQualifiedName(qualname, &schemaname, &opfname);
+
+ if (schemaname)
+ {
+ /* Look in specific schema only */
+ Oid namespaceId;
+
+ namespaceId = LookupExplicitNamespace(schemaname);
+ tuple = SearchSysCache(OPFAMILYAMNAMENSP,
+ ObjectIdGetDatum(amID),
+ PointerGetDatum(opfname),
+ ObjectIdGetDatum(namespaceId),
+ 0);
+ }
+ else
+ {
+ /* Unqualified opfamily name, so search the search path */
+ opfID = OpfamilynameGetOpfid(amID, opfname);
+ if (!OidIsValid(opfID))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ opfname, amname)));
+ tuple = SearchSysCache(OPFAMILYOID,
+ ObjectIdGetDatum(opfID),
+ 0, 0, 0);
+ }
+
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ NameListToString(qualname), amname)));
+
+ opfID = HeapTupleGetOid(tuple);
+
+ /* Permission check: must own opfamily */
+ if (!pg_opfamily_ownercheck(opfID, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
+ NameListToString(qualname));
+
+ ReleaseSysCache(tuple);
+
+ /* Call CreateComments() to create/drop the comments */
+ CreateComments(opfID, OperatorFamilyRelationId, 0, comment);
+}
+
/*
* CommentLargeObject --
*
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 24e4f832c42..802b6909525 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.52 2007/01/05 22:19:26 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.53 2007/01/23 05:07:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -55,15 +55,30 @@ typedef struct
} OpFamilyMember;
+static void AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
+ int maxOpNumber, int maxProcNumber,
+ List *items);
+static void AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
+ int maxOpNumber, int maxProcNumber,
+ List *items);
+static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype);
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc);
-static void storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid,
- List *operators);
-static void storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid,
- List *procedures);
+static void storeOperators(List *opfamilyname, Oid amoid,
+ Oid opfamilyoid, Oid opclassoid,
+ List *operators, bool isAdd);
+static void storeProcedures(List *opfamilyname, Oid amoid,
+ Oid opfamilyoid, Oid opclassoid,
+ List *procedures, bool isAdd);
+static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
+ List *operators);
+static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
+ List *procedures);
static void AlterOpClassOwner_internal(Relation rel, HeapTuple tuple,
Oid newOwnerId);
+static void AlterOpFamilyOwner_internal(Relation rel, HeapTuple tuple,
+ Oid newOwnerId);
/*
@@ -452,6 +467,12 @@ DefineOpClass(CreateOpClassStmt *stmt)
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->object = funcOid;
member->number = item->number;
+
+ /* allow overriding of the function's actual arg types */
+ if (item->class_args)
+ processTypesSpec(item->class_args,
+ &member->lefttype, &member->righttype);
+
assignProcTypes(member, amoid, typeoid);
addFamilyMember(&procedures, member, true);
break;
@@ -570,8 +591,10 @@ DefineOpClass(CreateOpClassStmt *stmt)
* Now add tuples to pg_amop and pg_amproc tying in the operators and
* functions. Dependencies on them are inserted, too.
*/
- storeOperators(amoid, opfamilyoid, opclassoid, operators);
- storeProcedures(amoid, opfamilyoid, opclassoid, procedures);
+ storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
+ opclassoid, operators, false);
+ storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
+ opclassoid, procedures, false);
/*
* Create dependencies for the opclass proper. Note: we do not create a
@@ -615,6 +638,420 @@ DefineOpClass(CreateOpClassStmt *stmt)
heap_close(rel, RowExclusiveLock);
}
+
+/*
+ * DefineOpFamily
+ * Define a new index operator family.
+ */
+void
+DefineOpFamily(CreateOpFamilyStmt *stmt)
+{
+ char *opfname; /* name of opfamily we're creating */
+ Oid amoid, /* our AM's oid */
+ namespaceoid, /* namespace to create opfamily in */
+ opfamilyoid; /* oid of opfamily we create */
+ Relation rel;
+ HeapTuple tup;
+ Datum values[Natts_pg_opfamily];
+ char nulls[Natts_pg_opfamily];
+ AclResult aclresult;
+ NameData opfName;
+ ObjectAddress myself,
+ referenced;
+
+ /* Convert list of names to a name and namespace */
+ namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
+ &opfname);
+
+ /* Check we have creation rights in target namespace */
+ aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ get_namespace_name(namespaceoid));
+
+ /* Get necessary info about access method */
+ tup = SearchSysCache(AMNAME,
+ CStringGetDatum(stmt->amname),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("access method \"%s\" does not exist",
+ stmt->amname)));
+
+ amoid = HeapTupleGetOid(tup);
+
+ /* XXX Should we make any privilege check against the AM? */
+
+ ReleaseSysCache(tup);
+
+ /*
+ * Currently, we require superuser privileges to create an opfamily.
+ * See comments in DefineOpClass.
+ *
+ * XXX re-enable NOT_USED code sections below if you remove this test.
+ */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to create an operator family")));
+
+ rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+
+ /*
+ * Make sure there is no existing opfamily of this name (this is just to
+ * give a more friendly error message than "duplicate key").
+ */
+ if (SearchSysCacheExists(OPFAMILYAMNAMENSP,
+ ObjectIdGetDatum(amoid),
+ CStringGetDatum(opfname),
+ ObjectIdGetDatum(namespaceoid),
+ 0))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("operator family \"%s\" for access method \"%s\" already exists",
+ opfname, stmt->amname)));
+
+ /*
+ * Okay, let's create the pg_opfamily entry.
+ */
+ memset(values, 0, sizeof(values));
+ memset(nulls, ' ', sizeof(nulls));
+
+ values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
+ namestrcpy(&opfName, opfname);
+ values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
+ values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
+ values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
+
+ tup = heap_formtuple(rel->rd_att, values, nulls);
+
+ opfamilyoid = simple_heap_insert(rel, tup);
+
+ CatalogUpdateIndexes(rel, tup);
+
+ heap_freetuple(tup);
+
+ /*
+ * Create dependencies for the opfamily proper. Note: we do not create a
+ * dependency link to the AM, because we don't currently support DROP
+ * ACCESS METHOD.
+ */
+ myself.classId = OperatorFamilyRelationId;
+ myself.objectId = opfamilyoid;
+ myself.objectSubId = 0;
+
+ /* dependency on namespace */
+ referenced.classId = NamespaceRelationId;
+ referenced.objectId = namespaceoid;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ /* dependency on owner */
+ recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
+
+ heap_close(rel, RowExclusiveLock);
+}
+
+
+/*
+ * AlterOpFamily
+ * Add or remove operators/procedures within an existing operator family.
+ *
+ * Note: this implements only ALTER OPERATOR FAMILY ... ADD/DROP. Some
+ * other commands called ALTER OPERATOR FAMILY exist, but go through
+ * different code paths.
+ */
+void
+AlterOpFamily(AlterOpFamilyStmt *stmt)
+{
+ Oid amoid, /* our AM's oid */
+ opfamilyoid; /* oid of opfamily */
+ int maxOpNumber, /* amstrategies value */
+ maxProcNumber; /* amsupport value */
+ HeapTuple tup;
+ Form_pg_am pg_am;
+
+ /* Get necessary info about access method */
+ tup = SearchSysCache(AMNAME,
+ CStringGetDatum(stmt->amname),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("access method \"%s\" does not exist",
+ stmt->amname)));
+
+ amoid = HeapTupleGetOid(tup);
+ pg_am = (Form_pg_am) GETSTRUCT(tup);
+ maxOpNumber = pg_am->amstrategies;
+ /* if amstrategies is zero, just enforce that op numbers fit in int16 */
+ if (maxOpNumber <= 0)
+ maxOpNumber = SHRT_MAX;
+ maxProcNumber = pg_am->amsupport;
+
+ /* XXX Should we make any privilege check against the AM? */
+
+ ReleaseSysCache(tup);
+
+ /* Look up the opfamily */
+ tup = OpFamilyCacheLookup(amoid, stmt->opfamilyname);
+ if (!HeapTupleIsValid(tup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ NameListToString(stmt->opfamilyname), stmt->amname)));
+ opfamilyoid = HeapTupleGetOid(tup);
+ ReleaseSysCache(tup);
+
+ /*
+ * Currently, we require superuser privileges to alter an opfamily.
+ *
+ * XXX re-enable NOT_USED code sections below if you remove this test.
+ */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to alter an operator family")));
+
+ /*
+ * ADD and DROP cases need separate code from here on down.
+ */
+ if (stmt->isDrop)
+ AlterOpFamilyDrop(stmt->opfamilyname, amoid, opfamilyoid,
+ maxOpNumber, maxProcNumber,
+ stmt->items);
+ else
+ AlterOpFamilyAdd(stmt->opfamilyname, amoid, opfamilyoid,
+ maxOpNumber, maxProcNumber,
+ stmt->items);
+}
+
+/*
+ * ADD part of ALTER OP FAMILY
+ */
+static void
+AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
+ int maxOpNumber, int maxProcNumber,
+ List *items)
+{
+ List *operators; /* OpFamilyMember list for operators */
+ List *procedures; /* OpFamilyMember list for support procs */
+ ListCell *l;
+
+ operators = NIL;
+ procedures = NIL;
+
+ /*
+ * Scan the "items" list to obtain additional info.
+ */
+ foreach(l, items)
+ {
+ CreateOpClassItem *item = lfirst(l);
+ Oid operOid;
+ Oid funcOid;
+ OpFamilyMember *member;
+
+ Assert(IsA(item, CreateOpClassItem));
+ switch (item->itemtype)
+ {
+ case OPCLASS_ITEM_OPERATOR:
+ if (item->number <= 0 || item->number > maxOpNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid operator number %d,"
+ " must be between 1 and %d",
+ item->number, maxOpNumber)));
+ if (item->args != NIL)
+ {
+ TypeName *typeName1 = (TypeName *) linitial(item->args);
+ TypeName *typeName2 = (TypeName *) lsecond(item->args);
+
+ operOid = LookupOperNameTypeNames(NULL, item->name,
+ typeName1, typeName2,
+ false, -1);
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
+ operOid = InvalidOid; /* keep compiler quiet */
+ }
+
+#ifdef NOT_USED
+ /* XXX this is unnecessary given the superuser check above */
+ /* Caller must own operator and its underlying function */
+ if (!pg_oper_ownercheck(operOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
+ get_opname(operOid));
+ funcOid = get_opcode(operOid);
+ if (!pg_proc_ownercheck(funcOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+ get_func_name(funcOid));
+#endif
+
+ /* Save the info */
+ member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+ member->object = operOid;
+ member->number = item->number;
+ member->recheck = item->recheck;
+ assignOperTypes(member, amoid, InvalidOid);
+ addFamilyMember(&operators, member, false);
+ break;
+ case OPCLASS_ITEM_FUNCTION:
+ if (item->number <= 0 || item->number > maxProcNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid procedure number %d,"
+ " must be between 1 and %d",
+ item->number, maxProcNumber)));
+ funcOid = LookupFuncNameTypeNames(item->name, item->args,
+ false);
+#ifdef NOT_USED
+ /* XXX this is unnecessary given the superuser check above */
+ /* Caller must own function */
+ if (!pg_proc_ownercheck(funcOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+ get_func_name(funcOid));
+#endif
+
+ /* Save the info */
+ member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+ member->object = funcOid;
+ member->number = item->number;
+
+ /* allow overriding of the function's actual arg types */
+ if (item->class_args)
+ processTypesSpec(item->class_args,
+ &member->lefttype, &member->righttype);
+
+ assignProcTypes(member, amoid, InvalidOid);
+ addFamilyMember(&procedures, member, true);
+ break;
+ case OPCLASS_ITEM_STORAGETYPE:
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("STORAGE may not be specified in ALTER OPERATOR FAMILY")));
+ break;
+ default:
+ elog(ERROR, "unrecognized item type: %d", item->itemtype);
+ break;
+ }
+ }
+
+ /*
+ * Add tuples to pg_amop and pg_amproc tying in the operators and
+ * functions. Dependencies on them are inserted, too.
+ */
+ storeOperators(opfamilyname, amoid, opfamilyoid,
+ InvalidOid, operators, true);
+ storeProcedures(opfamilyname, amoid, opfamilyoid,
+ InvalidOid, procedures, true);
+}
+
+/*
+ * DROP part of ALTER OP FAMILY
+ */
+static void
+AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
+ int maxOpNumber, int maxProcNumber,
+ List *items)
+{
+ List *operators; /* OpFamilyMember list for operators */
+ List *procedures; /* OpFamilyMember list for support procs */
+ ListCell *l;
+
+ operators = NIL;
+ procedures = NIL;
+
+ /*
+ * Scan the "items" list to obtain additional info.
+ */
+ foreach(l, items)
+ {
+ CreateOpClassItem *item = lfirst(l);
+ Oid lefttype,
+ righttype;
+ OpFamilyMember *member;
+
+ Assert(IsA(item, CreateOpClassItem));
+ switch (item->itemtype)
+ {
+ case OPCLASS_ITEM_OPERATOR:
+ if (item->number <= 0 || item->number > maxOpNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid operator number %d,"
+ " must be between 1 and %d",
+ item->number, maxOpNumber)));
+ processTypesSpec(item->args, &lefttype, &righttype);
+ /* Save the info */
+ member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+ member->number = item->number;
+ member->lefttype = lefttype;
+ member->righttype = righttype;
+ addFamilyMember(&operators, member, false);
+ break;
+ case OPCLASS_ITEM_FUNCTION:
+ if (item->number <= 0 || item->number > maxProcNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("invalid procedure number %d,"
+ " must be between 1 and %d",
+ item->number, maxProcNumber)));
+ processTypesSpec(item->args, &lefttype, &righttype);
+ /* Save the info */
+ member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
+ member->number = item->number;
+ member->lefttype = lefttype;
+ member->righttype = righttype;
+ addFamilyMember(&procedures, member, true);
+ break;
+ case OPCLASS_ITEM_STORAGETYPE:
+ /* grammar prevents this from appearing */
+ default:
+ elog(ERROR, "unrecognized item type: %d", item->itemtype);
+ break;
+ }
+ }
+
+ /*
+ * Remove tuples from pg_amop and pg_amproc.
+ */
+ dropOperators(opfamilyname, amoid, opfamilyoid, operators);
+ dropProcedures(opfamilyname, amoid, opfamilyoid, procedures);
+}
+
+
+/*
+ * Deal with explicit arg types used in ALTER ADD/DROP
+ */
+static void
+processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
+{
+ TypeName *typeName;
+
+ Assert(args != NIL);
+
+ typeName = (TypeName *) linitial(args);
+ *lefttype = typenameTypeId(NULL, typeName);
+
+ if (list_length(args) > 1)
+ {
+ typeName = (TypeName *) lsecond(args);
+ *righttype = typenameTypeId(NULL, typeName);
+ }
+ else
+ *righttype = *lefttype;
+
+ if (list_length(args) > 2)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("one or two argument types must be specified")));
+}
+
+
/*
* Determine the lefttype/righttype to assign to an operator,
* and do any validity checking we can manage.
@@ -781,7 +1218,9 @@ addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
* else make an AUTO dependency on the opfamily.
*/
static void
-storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators)
+storeOperators(List *opfamilyname, Oid amoid,
+ Oid opfamilyoid, Oid opclassoid,
+ List *operators, bool isAdd)
{
Relation rel;
Datum values[Natts_pg_amop];
@@ -798,6 +1237,24 @@ storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators)
{
OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
+ /*
+ * If adding to an existing family, check for conflict with an
+ * existing pg_amop entry (just to give a nicer error message)
+ */
+ if (isAdd &&
+ SearchSysCacheExists(AMOPSTRATEGY,
+ ObjectIdGetDatum(opfamilyoid),
+ ObjectIdGetDatum(op->lefttype),
+ ObjectIdGetDatum(op->righttype),
+ Int16GetDatum(op->number)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
+ op->number,
+ format_type_be(op->lefttype),
+ format_type_be(op->righttype),
+ NameListToString(opfamilyname))));
+
/* Create the pg_amop entry */
memset(values, 0, sizeof(values));
memset(nulls, ' ', sizeof(nulls));
@@ -862,7 +1319,9 @@ storeOperators(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators)
* else make an AUTO dependency on the opfamily.
*/
static void
-storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures)
+storeProcedures(List *opfamilyname, Oid amoid,
+ Oid opfamilyoid, Oid opclassoid,
+ List *procedures, bool isAdd)
{
Relation rel;
Datum values[Natts_pg_amproc];
@@ -879,6 +1338,24 @@ storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures)
{
OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
+ /*
+ * If adding to an existing family, check for conflict with an
+ * existing pg_amproc entry (just to give a nicer error message)
+ */
+ if (isAdd &&
+ SearchSysCacheExists(AMPROCNUM,
+ ObjectIdGetDatum(opfamilyoid),
+ ObjectIdGetDatum(proc->lefttype),
+ ObjectIdGetDatum(proc->righttype),
+ Int16GetDatum(proc->number)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
+ proc->number,
+ format_type_be(proc->lefttype),
+ format_type_be(proc->righttype),
+ NameListToString(opfamilyname))));
+
/* Create the pg_amproc entry */
memset(values, 0, sizeof(values));
memset(nulls, ' ', sizeof(nulls));
@@ -934,6 +1411,87 @@ storeProcedures(Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures)
}
+/*
+ * Remove operator entries from an opfamily.
+ *
+ * Note: this is only allowed for "loose" members of an opfamily, hence
+ * behavior is always RESTRICT.
+ */
+static void
+dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
+ List *operators)
+{
+ ListCell *l;
+
+ foreach(l, operators)
+ {
+ OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
+ Oid amopid;
+ ObjectAddress object;
+
+ amopid = GetSysCacheOid(AMOPSTRATEGY,
+ ObjectIdGetDatum(opfamilyoid),
+ ObjectIdGetDatum(op->lefttype),
+ ObjectIdGetDatum(op->righttype),
+ Int16GetDatum(op->number));
+ if (!OidIsValid(amopid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
+ op->number,
+ format_type_be(op->lefttype),
+ format_type_be(op->righttype),
+ NameListToString(opfamilyname))));
+
+ object.classId = AccessMethodOperatorRelationId;
+ object.objectId = amopid;
+ object.objectSubId = 0;
+
+ performDeletion(&object, DROP_RESTRICT);
+ }
+}
+
+/*
+ * Remove procedure entries from an opfamily.
+ *
+ * Note: this is only allowed for "loose" members of an opfamily, hence
+ * behavior is always RESTRICT.
+ */
+static void
+dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
+ List *procedures)
+{
+ ListCell *l;
+
+ foreach(l, procedures)
+ {
+ OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
+ Oid amprocid;
+ ObjectAddress object;
+
+ amprocid = GetSysCacheOid(AMPROCNUM,
+ ObjectIdGetDatum(opfamilyoid),
+ ObjectIdGetDatum(op->lefttype),
+ ObjectIdGetDatum(op->righttype),
+ Int16GetDatum(op->number));
+ if (!OidIsValid(amprocid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
+ op->number,
+ format_type_be(op->lefttype),
+ format_type_be(op->righttype),
+ NameListToString(opfamilyname))));
+
+ object.classId = AccessMethodProcedureRelationId;
+ object.objectId = amprocid;
+ object.objectSubId = 0;
+
+ performDeletion(&object, DROP_RESTRICT);
+ }
+}
+
+
/*
* RemoveOpClass
* Deletes an opclass.
@@ -997,6 +1555,70 @@ RemoveOpClass(RemoveOpClassStmt *stmt)
performDeletion(&object, stmt->behavior);
}
+/*
+ * RemoveOpFamily
+ * Deletes an opfamily.
+ */
+void
+RemoveOpFamily(RemoveOpFamilyStmt *stmt)
+{
+ Oid amID,
+ opfID;
+ HeapTuple tuple;
+ ObjectAddress object;
+
+ /*
+ * Get the access method's OID.
+ */
+ amID = GetSysCacheOid(AMNAME,
+ CStringGetDatum(stmt->amname),
+ 0, 0, 0);
+ if (!OidIsValid(amID))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("access method \"%s\" does not exist",
+ stmt->amname)));
+
+ /*
+ * Look up the opfamily.
+ */
+ tuple = OpFamilyCacheLookup(amID, stmt->opfamilyname);
+ if (!HeapTupleIsValid(tuple))
+ {
+ if (!stmt->missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ NameListToString(stmt->opfamilyname), stmt->amname)));
+ else
+ ereport(NOTICE,
+ (errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ NameListToString(stmt->opfamilyname), stmt->amname)));
+ return;
+ }
+
+ opfID = HeapTupleGetOid(tuple);
+
+ /* Permission check: must own opfamily or its namespace */
+ if (!pg_opfamily_ownercheck(opfID, GetUserId()) &&
+ !pg_namespace_ownercheck(((Form_pg_opfamily) GETSTRUCT(tuple))->opfnamespace,
+ GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
+ NameListToString(stmt->opfamilyname));
+
+ ReleaseSysCache(tuple);
+
+ /*
+ * Do the deletion
+ */
+ object.classId = OperatorFamilyRelationId;
+ object.objectId = opfID;
+ object.objectSubId = 0;
+
+ performDeletion(&object, stmt->behavior);
+}
+
+
/*
* Deletion subroutines for use by dependency.c.
*/
@@ -1202,29 +1824,104 @@ RenameOpClass(List *name, const char *access_method, const char *newname)
}
/*
- * Change opclass owner by oid
+ * Rename opfamily
*/
-#ifdef NOT_USED
void
-AlterOpClassOwner_oid(Oid opcOid, Oid newOwnerId)
+RenameOpFamily(List *name, const char *access_method, const char *newname)
{
- Relation rel;
+ Oid opfOid;
+ Oid amOid;
+ Oid namespaceOid;
+ char *schemaname;
+ char *opfname;
HeapTuple tup;
+ Relation rel;
+ AclResult aclresult;
- rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
+ amOid = GetSysCacheOid(AMNAME,
+ CStringGetDatum(access_method),
+ 0, 0, 0);
+ if (!OidIsValid(amOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("access method \"%s\" does not exist",
+ access_method)));
- tup = SearchSysCacheCopy(CLAOID,
- ObjectIdGetDatum(opcOid),
- 0, 0, 0);
- if (!HeapTupleIsValid(tup)) /* shouldn't happen */
- elog(ERROR, "cache lookup failed for opclass %u", opcOid);
+ rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
- AlterOpClassOwner_internal(rel, tup, newOwnerId);
+ /*
+ * Look up the opfamily
+ */
+ DeconstructQualifiedName(name, &schemaname, &opfname);
+
+ if (schemaname)
+ {
+ namespaceOid = LookupExplicitNamespace(schemaname);
+
+ tup = SearchSysCacheCopy(OPFAMILYAMNAMENSP,
+ ObjectIdGetDatum(amOid),
+ PointerGetDatum(opfname),
+ ObjectIdGetDatum(namespaceOid),
+ 0);
+ if (!HeapTupleIsValid(tup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ opfname, access_method)));
+
+ opfOid = HeapTupleGetOid(tup);
+ }
+ else
+ {
+ opfOid = OpfamilynameGetOpfid(amOid, opfname);
+ if (!OidIsValid(opfOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ opfname, access_method)));
+
+ tup = SearchSysCacheCopy(OPFAMILYOID,
+ ObjectIdGetDatum(opfOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup)) /* should not happen */
+ elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
+
+ namespaceOid = ((Form_pg_opfamily) GETSTRUCT(tup))->opfnamespace;
+ }
+
+ /* make sure the new name doesn't exist */
+ if (SearchSysCacheExists(OPFAMILYAMNAMENSP,
+ ObjectIdGetDatum(amOid),
+ CStringGetDatum(newname),
+ ObjectIdGetDatum(namespaceOid),
+ 0))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
+ newname, access_method,
+ get_namespace_name(namespaceOid))));
+ }
+
+ /* must be owner */
+ if (!pg_opfamily_ownercheck(opfOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
+ NameListToString(name));
+
+ /* must have CREATE privilege on namespace */
+ aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ get_namespace_name(namespaceOid));
+
+ /* rename */
+ namestrcpy(&(((Form_pg_opfamily) GETSTRUCT(tup))->opfname), newname);
+ simple_heap_update(rel, &tup->t_self, tup);
+ CatalogUpdateIndexes(rel, tup);
- heap_freetuple(tup);
heap_close(rel, NoLock);
+ heap_freetuple(tup);
}
-#endif
/*
* Change opclass owner by name
@@ -1352,3 +2049,130 @@ AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
newOwnerId);
}
}
+
+/*
+ * Change opfamily owner by name
+ */
+void
+AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId)
+{
+ Oid amOid;
+ Relation rel;
+ HeapTuple tup;
+ char *opfname;
+ char *schemaname;
+
+ amOid = GetSysCacheOid(AMNAME,
+ CStringGetDatum(access_method),
+ 0, 0, 0);
+ if (!OidIsValid(amOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("access method \"%s\" does not exist",
+ access_method)));
+
+ rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
+
+ /*
+ * Look up the opfamily
+ */
+ DeconstructQualifiedName(name, &schemaname, &opfname);
+
+ if (schemaname)
+ {
+ Oid namespaceOid;
+
+ namespaceOid = LookupExplicitNamespace(schemaname);
+
+ tup = SearchSysCacheCopy(OPFAMILYAMNAMENSP,
+ ObjectIdGetDatum(amOid),
+ PointerGetDatum(opfname),
+ ObjectIdGetDatum(namespaceOid),
+ 0);
+ if (!HeapTupleIsValid(tup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ opfname, access_method)));
+ }
+ else
+ {
+ Oid opfOid;
+
+ opfOid = OpfamilynameGetOpfid(amOid, opfname);
+ if (!OidIsValid(opfOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("operator family \"%s\" does not exist for access method \"%s\"",
+ opfname, access_method)));
+
+ tup = SearchSysCacheCopy(OPFAMILYOID,
+ ObjectIdGetDatum(opfOid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup)) /* should not happen */
+ elog(ERROR, "cache lookup failed for opfamily %u", opfOid);
+ }
+
+ AlterOpFamilyOwner_internal(rel, tup, newOwnerId);
+
+ heap_freetuple(tup);
+ heap_close(rel, NoLock);
+}
+
+/*
+ * The first parameter is pg_opfamily, opened and suitably locked. The second
+ * parameter is a copy of the tuple from pg_opfamily we want to modify.
+ */
+static void
+AlterOpFamilyOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
+{
+ Oid namespaceOid;
+ AclResult aclresult;
+ Form_pg_opfamily opfForm;
+
+ Assert(tup->t_tableOid == OperatorFamilyRelationId);
+ Assert(RelationGetRelid(rel) == OperatorFamilyRelationId);
+
+ opfForm = (Form_pg_opfamily) GETSTRUCT(tup);
+
+ namespaceOid = opfForm->opfnamespace;
+
+ /*
+ * If the new owner is the same as the existing owner, consider the
+ * command to have succeeded. This is for dump restoration purposes.
+ */
+ if (opfForm->opfowner != newOwnerId)
+ {
+ /* Superusers can always do it */
+ if (!superuser())
+ {
+ /* Otherwise, must be owner of the existing object */
+ if (!pg_opfamily_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
+ NameStr(opfForm->opfname));
+
+ /* Must be able to become new owner */
+ check_is_member_of_role(GetUserId(), newOwnerId);
+
+ /* New owner must have CREATE privilege on namespace */
+ aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
+ ACL_CREATE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ get_namespace_name(namespaceOid));
+ }
+
+ /*
+ * Modify the owner --- okay to scribble on tup because it's a copy
+ */
+ opfForm->opfowner = newOwnerId;
+
+ simple_heap_update(rel, &tup->t_self, tup);
+
+ CatalogUpdateIndexes(rel, tup);
+
+ /* Update owner dependency reference */
+ changeDependencyOnOwner(OperatorFamilyRelationId, HeapTupleGetOid(tup),
+ newOwnerId);
+ }
+}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 1237dc7fe64..f213f216de4 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
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.363 2007/01/22 20:00:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.364 2007/01/23 05:07:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2158,6 +2158,19 @@ _copyRemoveOpClassStmt(RemoveOpClassStmt *from)
return newnode;
}
+static RemoveOpFamilyStmt *
+_copyRemoveOpFamilyStmt(RemoveOpFamilyStmt *from)
+{
+ RemoveOpFamilyStmt *newnode = makeNode(RemoveOpFamilyStmt);
+
+ COPY_NODE_FIELD(opfamilyname);
+ COPY_STRING_FIELD(amname);
+ COPY_SCALAR_FIELD(behavior);
+ COPY_SCALAR_FIELD(missing_ok);
+
+ return newnode;
+}
+
static RenameStmt *
_copyRenameStmt(RenameStmt *from)
{
@@ -2332,11 +2345,36 @@ _copyCreateOpClassItem(CreateOpClassItem *from)
COPY_NODE_FIELD(args);
COPY_SCALAR_FIELD(number);
COPY_SCALAR_FIELD(recheck);
+ COPY_NODE_FIELD(class_args);
COPY_NODE_FIELD(storedtype);
return newnode;
}
+static CreateOpFamilyStmt *
+_copyCreateOpFamilyStmt(CreateOpFamilyStmt *from)
+{
+ CreateOpFamilyStmt *newnode = makeNode(CreateOpFamilyStmt);
+
+ COPY_NODE_FIELD(opfamilyname);
+ COPY_STRING_FIELD(amname);
+
+ return newnode;
+}
+
+static AlterOpFamilyStmt *
+_copyAlterOpFamilyStmt(AlterOpFamilyStmt *from)
+{
+ AlterOpFamilyStmt *newnode = makeNode(AlterOpFamilyStmt);
+
+ COPY_NODE_FIELD(opfamilyname);
+ COPY_STRING_FIELD(amname);
+ COPY_SCALAR_FIELD(isDrop);
+ COPY_NODE_FIELD(items);
+
+ return newnode;
+}
+
static CreatedbStmt *
_copyCreatedbStmt(CreatedbStmt *from)
{
@@ -3163,6 +3201,9 @@ copyObject(void *from)
case T_RemoveOpClassStmt:
retval = _copyRemoveOpClassStmt(from);
break;
+ case T_RemoveOpFamilyStmt:
+ retval = _copyRemoveOpFamilyStmt(from);
+ break;
case T_RenameStmt:
retval = _copyRenameStmt(from);
break;
@@ -3205,6 +3246,12 @@ copyObject(void *from)
case T_CreateOpClassItem:
retval = _copyCreateOpClassItem(from);
break;
+ case T_CreateOpFamilyStmt:
+ retval = _copyCreateOpFamilyStmt(from);
+ break;
+ case T_AlterOpFamilyStmt:
+ retval = _copyAlterOpFamilyStmt(from);
+ break;
case T_CreatedbStmt:
retval = _copyCreatedbStmt(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 40a91a2b0ed..31754a7bc02 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.296 2007/01/20 20:45:38 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.297 2007/01/23 05:07:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1053,6 +1053,17 @@ _equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b)
return true;
}
+static bool
+_equalRemoveOpFamilyStmt(RemoveOpFamilyStmt *a, RemoveOpFamilyStmt *b)
+{
+ COMPARE_NODE_FIELD(opfamilyname);
+ COMPARE_STRING_FIELD(amname);
+ COMPARE_SCALAR_FIELD(behavior);
+ COMPARE_SCALAR_FIELD(missing_ok);
+
+ return true;
+}
+
static bool
_equalRenameStmt(RenameStmt *a, RenameStmt *b)
{
@@ -1199,11 +1210,32 @@ _equalCreateOpClassItem(CreateOpClassItem *a, CreateOpClassItem *b)
COMPARE_NODE_FIELD(args);
COMPARE_SCALAR_FIELD(number);
COMPARE_SCALAR_FIELD(recheck);
+ COMPARE_NODE_FIELD(class_args);
COMPARE_NODE_FIELD(storedtype);
return true;
}
+static bool
+_equalCreateOpFamilyStmt(CreateOpFamilyStmt *a, CreateOpFamilyStmt *b)
+{
+ COMPARE_NODE_FIELD(opfamilyname);
+ COMPARE_STRING_FIELD(amname);
+
+ return true;
+}
+
+static bool
+_equalAlterOpFamilyStmt(AlterOpFamilyStmt *a, AlterOpFamilyStmt *b)
+{
+ COMPARE_NODE_FIELD(opfamilyname);
+ COMPARE_STRING_FIELD(amname);
+ COMPARE_SCALAR_FIELD(isDrop);
+ COMPARE_NODE_FIELD(items);
+
+ return true;
+}
+
static bool
_equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
{
@@ -2148,6 +2180,9 @@ equal(void *a, void *b)
case T_RemoveOpClassStmt:
retval = _equalRemoveOpClassStmt(a, b);
break;
+ case T_RemoveOpFamilyStmt:
+ retval = _equalRemoveOpFamilyStmt(a, b);
+ break;
case T_RenameStmt:
retval = _equalRenameStmt(a, b);
break;
@@ -2190,6 +2225,12 @@ equal(void *a, void *b)
case T_CreateOpClassItem:
retval = _equalCreateOpClassItem(a, b);
break;
+ case T_CreateOpFamilyStmt:
+ retval = _equalCreateOpFamilyStmt(a, b);
+ break;
+ case T_AlterOpFamilyStmt:
+ retval = _equalAlterOpFamilyStmt(a, b);
+ break;
case T_CreatedbStmt:
retval = _equalCreatedbStmt(a, b);
break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index cf32e912539..217b1a04659 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.575 2007/01/22 01:35:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.576 2007/01/23 05:07:17 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -152,11 +152,12 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
- CreateDomainStmt CreateGroupStmt CreateOpClassStmt CreatePLangStmt
+ CreateDomainStmt CreateGroupStmt CreateOpClassStmt
+ CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateAssertStmt CreateTrigStmt CreateUserStmt CreateRoleStmt
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt
- DropGroupStmt DropOpClassStmt DropPLangStmt DropStmt
+ DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
DropUserStmt DropdbStmt DropTableSpaceStmt ExplainStmt FetchStmt
GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
@@ -174,7 +175,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
%type select_no_parens select_with_parens select_clause
simple_select values_clause
-%type alter_column_default opclass_item alter_using
+%type alter_column_default opclass_item opclass_drop alter_using
%type add_drop opt_asc_desc opt_nulls_order
%type alter_table_cmd alter_rel_cmd
@@ -229,7 +230,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
OptTableElementList TableElementList OptInherit definition
OptWith opt_distinct opt_definition func_args func_args_list
func_as createfunc_opt_list alterfunc_opt_list
- aggr_args aggr_args_list old_aggr_definition old_aggr_list
+ aggr_args old_aggr_definition old_aggr_list
oper_argtypes RuleActionList RuleActionMulti
opt_column_list columnList opt_name_list
sort_clause opt_sort_clause sortby_list index_params
@@ -240,10 +241,10 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
set_clause_list set_clause multiple_set_clause
ctext_expr_list ctext_row def_list indirection opt_indirection
group_clause TriggerFuncArgs select_limit
- opt_select_limit opclass_item_list
- transaction_mode_list_or_empty
+ opt_select_limit opclass_item_list opclass_drop_list
+ opt_opfamily transaction_mode_list_or_empty
TableFuncElementList opt_type_modifiers
- prep_type_clause prep_type_list
+ prep_type_clause
execute_param_clause using_clause returning_clause
%type into_clause OptTempTableName
@@ -381,7 +382,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
- FALSE_P FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
+ FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
FREEZE FROM FULL FUNCTION
GLOBAL GRANT GRANTED GREATEST GROUP_P
@@ -548,6 +549,8 @@ stmt :
| CreateFunctionStmt
| CreateGroupStmt
| CreateOpClassStmt
+ | CreateOpFamilyStmt
+ | AlterOpFamilyStmt
| CreatePLangStmt
| CreateSchemaStmt
| CreateSeqStmt
@@ -565,6 +568,7 @@ stmt :
| DropCastStmt
| DropGroupStmt
| DropOpClassStmt
+ | DropOpFamilyStmt
| DropOwnedStmt
| DropPLangStmt
| DropRuleStmt
@@ -929,7 +933,7 @@ AlterGroupStmt:
}
;
-add_drop: ADD_P { $$ = +1; }
+add_drop: ADD_P { $$ = +1; }
| DROP { $$ = -1; }
;
@@ -2879,15 +2883,10 @@ def_arg: func_type { $$ = (Node *)$1; }
| Sconst { $$ = (Node *)makeString($1); }
;
-aggr_args: '(' aggr_args_list ')' { $$ = $2; }
+aggr_args: '(' type_list ')' { $$ = $2; }
| '(' '*' ')' { $$ = NIL; }
;
-aggr_args_list:
- Typename { $$ = list_make1($1); }
- | aggr_args_list ',' Typename { $$ = lappend($1, $3); }
- ;
-
old_aggr_definition: '(' old_aggr_list ')' { $$ = $2; }
;
@@ -2906,20 +2905,24 @@ old_aggr_elem: IDENT '=' def_arg
*
* QUERIES :
* CREATE OPERATOR CLASS ...
+ * CREATE OPERATOR FAMILY ...
+ * ALTER OPERATOR FAMILY ...
* DROP OPERATOR CLASS ...
+ * DROP OPERATOR FAMILY ...
*
*****************************************************************************/
CreateOpClassStmt:
CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename
- USING access_method AS opclass_item_list
+ USING access_method opt_opfamily AS opclass_item_list
{
CreateOpClassStmt *n = makeNode(CreateOpClassStmt);
n->opclassname = $4;
n->isDefault = $5;
n->datatype = $8;
n->amname = $10;
- n->items = $12;
+ n->opfamilyname = $11;
+ n->items = $13;
$$ = (Node *) n;
}
;
@@ -2959,6 +2962,16 @@ opclass_item:
n->number = $2;
$$ = (Node *) n;
}
+ | FUNCTION Iconst '(' type_list ')' func_name func_args
+ {
+ CreateOpClassItem *n = makeNode(CreateOpClassItem);
+ n->itemtype = OPCLASS_ITEM_FUNCTION;
+ n->name = $6;
+ n->args = extractArgTypes($7);
+ n->number = $2;
+ n->class_args = $4;
+ $$ = (Node *) n;
+ }
| STORAGE Typename
{
CreateOpClassItem *n = makeNode(CreateOpClassItem);
@@ -2968,12 +2981,72 @@ opclass_item:
}
;
-opt_default: DEFAULT { $$ = TRUE; }
- | /*EMPTY*/ { $$ = FALSE; }
+opt_default: DEFAULT { $$ = TRUE; }
+ | /*EMPTY*/ { $$ = FALSE; }
;
-opt_recheck: RECHECK { $$ = TRUE; }
- | /*EMPTY*/ { $$ = FALSE; }
+opt_opfamily: FAMILY any_name { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+opt_recheck: RECHECK { $$ = TRUE; }
+ | /*EMPTY*/ { $$ = FALSE; }
+ ;
+
+
+CreateOpFamilyStmt:
+ CREATE OPERATOR FAMILY any_name USING access_method
+ {
+ CreateOpFamilyStmt *n = makeNode(CreateOpFamilyStmt);
+ n->opfamilyname = $4;
+ n->amname = $6;
+ $$ = (Node *) n;
+ }
+ ;
+
+AlterOpFamilyStmt:
+ ALTER OPERATOR FAMILY any_name USING access_method ADD_P opclass_item_list
+ {
+ AlterOpFamilyStmt *n = makeNode(AlterOpFamilyStmt);
+ n->opfamilyname = $4;
+ n->amname = $6;
+ n->isDrop = false;
+ n->items = $8;
+ $$ = (Node *) n;
+ }
+ | ALTER OPERATOR FAMILY any_name USING access_method DROP opclass_drop_list
+ {
+ AlterOpFamilyStmt *n = makeNode(AlterOpFamilyStmt);
+ n->opfamilyname = $4;
+ n->amname = $6;
+ n->isDrop = true;
+ n->items = $8;
+ $$ = (Node *) n;
+ }
+ ;
+
+opclass_drop_list:
+ opclass_drop { $$ = list_make1($1); }
+ | opclass_drop_list ',' opclass_drop { $$ = lappend($1, $3); }
+ ;
+
+opclass_drop:
+ OPERATOR Iconst '(' type_list ')'
+ {
+ CreateOpClassItem *n = makeNode(CreateOpClassItem);
+ n->itemtype = OPCLASS_ITEM_OPERATOR;
+ n->number = $2;
+ n->args = $4;
+ $$ = (Node *) n;
+ }
+ | FUNCTION Iconst '(' type_list ')'
+ {
+ CreateOpClassItem *n = makeNode(CreateOpClassItem);
+ n->itemtype = OPCLASS_ITEM_FUNCTION;
+ n->number = $2;
+ n->args = $4;
+ $$ = (Node *) n;
+ }
;
@@ -2998,6 +3071,28 @@ DropOpClassStmt:
}
;
+DropOpFamilyStmt:
+ DROP OPERATOR FAMILY any_name USING access_method opt_drop_behavior
+ {
+ RemoveOpFamilyStmt *n = makeNode(RemoveOpFamilyStmt);
+ n->opfamilyname = $4;
+ n->amname = $6;
+ n->behavior = $7;
+ n->missing_ok = false;
+ $$ = (Node *) n;
+ }
+ | DROP OPERATOR FAMILY IF_P EXISTS any_name USING access_method opt_drop_behavior
+ {
+ RemoveOpFamilyStmt *n = makeNode(RemoveOpFamilyStmt);
+ n->opfamilyname = $6;
+ n->amname = $8;
+ n->behavior = $9;
+ n->missing_ok = true;
+ $$ = (Node *) n;
+ }
+ ;
+
+
/*****************************************************************************
*
* QUERY:
@@ -3201,6 +3296,15 @@ CommentStmt:
n->comment = $9;
$$ = (Node *) n;
}
+ | COMMENT ON OPERATOR FAMILY any_name USING access_method IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_OPFAMILY;
+ n->objname = $5;
+ n->objargs = list_make1(makeString($7));
+ n->comment = $9;
+ $$ = (Node *) n;
+ }
| COMMENT ON LARGE_P OBJECT_P NumericOnly IS comment_text
{
CommentStmt *n = makeNode(CommentStmt);
@@ -4115,9 +4219,9 @@ oper_argtypes:
}
| Typename ',' Typename
{ $$ = list_make2($1, $3); }
- | NONE ',' Typename /* left unary */
+ | NONE ',' Typename /* left unary */
{ $$ = list_make2(NULL, $3); }
- | Typename ',' NONE /* right unary */
+ | Typename ',' NONE /* right unary */
{ $$ = list_make2($1, NULL); }
;
@@ -4174,8 +4278,8 @@ DropCastStmt: DROP CAST opt_if_exists '(' Typename AS Typename ')' opt_drop_beha
}
;
-opt_if_exists: IF_P EXISTS { $$ = true; }
- | /*EMPTY*/ { $$ = false; }
+opt_if_exists: IF_P EXISTS { $$ = TRUE; }
+ | /*EMPTY*/ { $$ = FALSE; }
;
@@ -4294,6 +4398,15 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
n->newname = $9;
$$ = (Node *)n;
}
+ | ALTER OPERATOR FAMILY any_name USING access_method RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_OPFAMILY;
+ n->object = $4;
+ n->subname = $6;
+ n->newname = $9;
+ $$ = (Node *)n;
+ }
| ALTER SCHEMA name RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
@@ -4493,6 +4606,15 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
+ | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_OPFAMILY;
+ n->object = $4;
+ n->addname = $6;
+ n->newowner = $9;
+ $$ = (Node *)n;
+ }
| ALTER SCHEMA name OWNER TO RoleId
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
@@ -5302,15 +5424,10 @@ PrepareStmt: PREPARE name prep_type_clause AS PreparableStmt
}
;
-prep_type_clause: '(' prep_type_list ')' { $$ = $2; }
+prep_type_clause: '(' type_list ')' { $$ = $2; }
| /* EMPTY */ { $$ = NIL; }
;
-prep_type_list: Typename { $$ = list_make1($1); }
- | prep_type_list ',' Typename
- { $$ = lappend($1, $3); }
- ;
-
PreparableStmt:
SelectStmt
| InsertStmt
@@ -7968,14 +8085,8 @@ extract_list:
| /*EMPTY*/ { $$ = NIL; }
;
-type_list: type_list ',' Typename
- {
- $$ = lappend($1, $3);
- }
- | Typename
- {
- $$ = list_make1($1);
- }
+type_list: Typename { $$ = list_make1($1); }
+ | type_list ',' Typename { $$ = lappend($1, $3); }
;
array_expr_list: array_expr
@@ -8604,6 +8715,7 @@ unreserved_keyword:
| EXECUTE
| EXPLAIN
| EXTERNAL
+ | FAMILY
| FETCH
| FIRST_P
| FORCE
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index 5e858d10b0a..b8607c7c002 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.182 2007/01/22 01:35:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.183 2007/01/23 05:07:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -145,6 +145,7 @@ static const ScanKeyword ScanKeywords[] = {
{"external", EXTERNAL},
{"extract", EXTRACT},
{"false", FALSE_P},
+ {"family", FAMILY},
{"fetch", FETCH},
{"first", FIRST_P},
{"float", FLOAT_P},
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 19b89916bf1..613ef653d19 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.270 2007/01/05 22:19:39 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.271 2007/01/23 05:07:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -322,6 +322,8 @@ check_xact_readonly(Node *parsetree)
case T_IndexStmt:
case T_CreatePLangStmt:
case T_CreateOpClassStmt:
+ case T_CreateOpFamilyStmt:
+ case T_AlterOpFamilyStmt:
case T_RuleStmt:
case T_CreateSchemaStmt:
case T_CreateSeqStmt:
@@ -338,6 +340,7 @@ check_xact_readonly(Node *parsetree)
case T_DropRoleStmt:
case T_DropPLangStmt:
case T_RemoveOpClassStmt:
+ case T_RemoveOpFamilyStmt:
case T_DropPropertyStmt:
case T_GrantStmt:
case T_GrantRoleStmt:
@@ -1099,10 +1102,22 @@ ProcessUtility(Node *parsetree,
DefineOpClass((CreateOpClassStmt *) parsetree);
break;
+ case T_CreateOpFamilyStmt:
+ DefineOpFamily((CreateOpFamilyStmt *) parsetree);
+ break;
+
+ case T_AlterOpFamilyStmt:
+ AlterOpFamily((AlterOpFamilyStmt *) parsetree);
+ break;
+
case T_RemoveOpClassStmt:
RemoveOpClass((RemoveOpClassStmt *) parsetree);
break;
+ case T_RemoveOpFamilyStmt:
+ RemoveOpFamily((RemoveOpFamilyStmt *) parsetree);
+ break;
+
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(parsetree));
@@ -1445,6 +1460,9 @@ CreateCommandTag(Node *parsetree)
case OBJECT_OPCLASS:
tag = "ALTER OPERATOR CLASS";
break;
+ case OBJECT_OPFAMILY:
+ tag = "ALTER OPERATOR FAMILY";
+ break;
case OBJECT_ROLE:
tag = "ALTER ROLE";
break;
@@ -1518,6 +1536,9 @@ CreateCommandTag(Node *parsetree)
case OBJECT_OPCLASS:
tag = "ALTER OPERATOR CLASS";
break;
+ case OBJECT_OPFAMILY:
+ tag = "ALTER OPERATOR FAMILY";
+ break;
case OBJECT_SCHEMA:
tag = "ALTER SCHEMA";
break;
@@ -1777,10 +1798,22 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE OPERATOR CLASS";
break;
+ case T_CreateOpFamilyStmt:
+ tag = "CREATE OPERATOR FAMILY";
+ break;
+
+ case T_AlterOpFamilyStmt:
+ tag = "ALTER OPERATOR FAMILY";
+ break;
+
case T_RemoveOpClassStmt:
tag = "DROP OPERATOR CLASS";
break;
+ case T_RemoveOpFamilyStmt:
+ tag = "DROP OPERATOR FAMILY";
+ break;
+
case T_PrepareStmt:
tag = "PREPARE";
break;
@@ -2147,10 +2180,22 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_DDL;
break;
+ case T_CreateOpFamilyStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
+ case T_AlterOpFamilyStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_RemoveOpClassStmt:
lev = LOGSTMT_DDL;
break;
+ case T_RemoveOpFamilyStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_PrepareStmt:
{
PrepareStmt *stmt = (PrepareStmt *) parsetree;
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 9c254b0b481..3d665ff5c2c 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.79 2007/01/05 22:19:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.80 2007/01/23 05:07:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -79,13 +79,18 @@ extern void AlterAggregateOwner(List *name, List *args, Oid newOwnerId);
/* commands/opclasscmds.c */
extern void DefineOpClass(CreateOpClassStmt *stmt);
+extern void DefineOpFamily(CreateOpFamilyStmt *stmt);
+extern void AlterOpFamily(AlterOpFamilyStmt *stmt);
extern void RemoveOpClass(RemoveOpClassStmt *stmt);
+extern void RemoveOpFamily(RemoveOpFamilyStmt *stmt);
extern void RemoveOpClassById(Oid opclassOid);
extern void RemoveOpFamilyById(Oid opfamilyOid);
extern void RemoveAmOpEntryById(Oid entryOid);
extern void RemoveAmProcEntryById(Oid entryOid);
extern void RenameOpClass(List *name, const char *access_method, const char *newname);
+extern void RenameOpFamily(List *name, const char *access_method, const char *newname);
extern void AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId);
+extern void AlterOpFamilyOwner(List *name, const char *access_method, Oid newOwnerId);
/* support routines in commands/define.c */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index d3e84bdf69a..f3762facdd6 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.192 2007/01/20 20:45:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.193 2007/01/23 05:07:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -286,7 +286,10 @@ typedef enum NodeTag
T_CreateCastStmt,
T_DropCastStmt,
T_CreateOpClassStmt,
+ T_CreateOpFamilyStmt,
+ T_AlterOpFamilyStmt,
T_RemoveOpClassStmt,
+ T_RemoveOpFamilyStmt,
T_PrepareStmt,
T_ExecuteStmt,
T_DeallocateStmt,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index d11f9ae6ead..a252308bdb2 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.338 2007/01/09 02:14:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.339 2007/01/23 05:07:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -852,6 +852,7 @@ typedef enum ObjectType
OBJECT_LARGEOBJECT,
OBJECT_OPCLASS,
OBJECT_OPERATOR,
+ OBJECT_OPFAMILY,
OBJECT_ROLE,
OBJECT_RULE,
OBJECT_SCHEMA,
@@ -1194,7 +1195,7 @@ typedef struct DropTableSpaceStmt
{
NodeTag type;
char *tablespacename;
- bool missing_ok; /* skip error if a missing? */
+ bool missing_ok; /* skip error if missing? */
} DropTableSpaceStmt;
/* ----------------------
@@ -1362,10 +1363,35 @@ typedef struct CreateOpClassItem
List *args; /* argument types */
int number; /* strategy num or support proc num */
bool recheck; /* only used for operators */
+ List *class_args; /* only used for functions */
/* fields used for a storagetype item: */
TypeName *storedtype; /* datatype stored in index */
} CreateOpClassItem;
+/* ----------------------
+ * Create Operator Family Statement
+ * ----------------------
+ */
+typedef struct CreateOpFamilyStmt
+{
+ NodeTag type;
+ List *opfamilyname; /* qualified name (list of Value strings) */
+ char *amname; /* name of index AM opfamily is for */
+} CreateOpFamilyStmt;
+
+/* ----------------------
+ * Alter Operator Family Statement
+ * ----------------------
+ */
+typedef struct AlterOpFamilyStmt
+{
+ NodeTag type;
+ List *opfamilyname; /* qualified name (list of Value strings) */
+ char *amname; /* name of index AM opfamily is for */
+ bool isDrop; /* ADD or DROP the items? */
+ List *items; /* List of CreateOpClassItem nodes */
+} AlterOpFamilyStmt;
+
/* ----------------------
* Drop Table|Sequence|View|Index|Type|Domain|Conversion|Schema Statement
* ----------------------
@@ -1395,7 +1421,7 @@ typedef struct DropPropertyStmt
char *property; /* name of rule, trigger, etc */
ObjectType removeType; /* OBJECT_RULE or OBJECT_TRIGGER */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
- bool missing_ok; /* skip error if a missing? */
+ bool missing_ok; /* skip error if missing? */
} DropPropertyStmt;
/* ----------------------
@@ -1546,7 +1572,7 @@ typedef struct RemoveFuncStmt
List *name; /* qualified name of object to drop */
List *args; /* types of the arguments */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
- bool missing_ok; /* skip error if a missing? */
+ bool missing_ok; /* skip error if missing? */
} RemoveFuncStmt;
/* ----------------------
@@ -1559,9 +1585,22 @@ typedef struct RemoveOpClassStmt
List *opclassname; /* qualified name (list of Value strings) */
char *amname; /* name of index AM opclass is for */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */
- bool missing_ok; /* skip error if a missing? */
+ bool missing_ok; /* skip error if missing? */
} RemoveOpClassStmt;
+/* ----------------------
+ * Drop Operator Family Statement
+ * ----------------------
+ */
+typedef struct RemoveOpFamilyStmt
+{
+ NodeTag type;
+ List *opfamilyname; /* qualified name (list of Value strings) */
+ char *amname; /* name of index AM opfamily is for */
+ DropBehavior behavior; /* RESTRICT or CASCADE behavior */
+ bool missing_ok; /* skip error if missing? */
+} RemoveOpFamilyStmt;
+
/* ----------------------
* Alter Object Rename Statement
* ----------------------
@@ -1917,7 +1956,7 @@ typedef struct DropCastStmt
TypeName *sourcetype;
TypeName *targettype;
DropBehavior behavior;
- bool missing_ok; /* skip error if a missing? */
+ bool missing_ok; /* skip error if missing? */
} DropCastStmt;
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 2076a69f3de..14522bc6fb1 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.99 2007/01/05 22:19:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.100 2007/01/23 05:07:18 tgl Exp $
*
* NOTES
* An ACL array is simply an array of AclItems, representing the union
@@ -178,6 +178,7 @@ typedef enum AclObjectKind
ACL_KIND_LANGUAGE, /* pg_language */
ACL_KIND_NAMESPACE, /* pg_namespace */
ACL_KIND_OPCLASS, /* pg_opclass */
+ ACL_KIND_OPFAMILY, /* pg_opfamily */
ACL_KIND_CONVERSION, /* pg_conversion */
ACL_KIND_TABLESPACE, /* pg_tablespace */
MAX_ACL_KIND /* MUST BE LAST */
@@ -276,6 +277,7 @@ extern bool pg_proc_ownercheck(Oid proc_oid, Oid roleid);
extern bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid);
extern bool pg_tablespace_ownercheck(Oid spc_oid, Oid roleid);
extern bool pg_opclass_ownercheck(Oid opc_oid, Oid roleid);
+extern bool pg_opfamily_ownercheck(Oid opf_oid, Oid roleid);
extern bool pg_database_ownercheck(Oid db_oid, Oid roleid);
extern bool pg_conversion_ownercheck(Oid conv_oid, Oid roleid);