diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2007-01-23 05:07:18 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2007-01-23 05:07:18 +0000 |
commit | a33cf1041f99ed5f19bb7d24584db79ada07d8a4 (patch) | |
tree | fc179c291b1289b39b69c25a988cf9cc414eaa05 /src | |
parent | 8502b68513923c43293bce5093eb44e285be2626 (diff) | |
download | postgresql-a33cf1041f99ed5f19bb7d24584db79ada07d8a4.tar.gz postgresql-a33cf1041f99ed5f19bb7d24584db79ada07d8a4.zip |
Add CREATE/ALTER/DROP OPERATOR FAMILY commands, also COMMENT ON OPERATOR
FAMILY; and add FAMILY option to CREATE OPERATOR CLASS to allow adding a
class to a pre-existing family. Per previous discussion. Man, what a
tedious lot of cutting and pasting ...
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/catalog/aclchk.c | 36 | ||||
-rw-r--r-- | src/backend/commands/alter.c | 10 | ||||
-rw-r--r-- | src/backend/commands/comment.c | 93 | ||||
-rw-r--r-- | src/backend/commands/opclasscmds.c | 868 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 49 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 43 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 192 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 3 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 47 | ||||
-rw-r--r-- | src/include/commands/defrem.h | 7 | ||||
-rw-r--r-- | src/include/nodes/nodes.h | 5 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 51 | ||||
-rw-r--r-- | src/include/utils/acl.h | 4 |
13 files changed, 1330 insertions, 78 deletions
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 */ @@ -2240,6 +2245,35 @@ pg_opclass_ownercheck(Oid opc_oid, Oid roleid) } /* + * 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). */ bool 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; @@ -1264,6 +1269,92 @@ CommentOpClass(List *qualname, List *arguments, char *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 -- * * This routine is used to add/drop any user-comments a user might 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)); @@ -935,6 +1412,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. */ @@ -998,6 +1556,70 @@ RemoveOpClass(RemoveOpClassStmt *stmt) } /* + * 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. */ void @@ -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 $ * *------------------------------------------------------------------------- */ @@ -1054,6 +1054,17 @@ _equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b) } 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) { COMPARE_SCALAR_FIELD(renameType); @@ -1199,12 +1210,33 @@ _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) { COMPARE_STRING_FIELD(dbname); @@ -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 <node> select_no_parens select_with_parens select_clause simple_select values_clause -%type <node> alter_column_default opclass_item alter_using +%type <node> alter_column_default opclass_item opclass_drop alter_using %type <ival> add_drop opt_asc_desc opt_nulls_order %type <node> 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 <range> 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_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); } ; -opt_recheck: RECHECK { $$ = TRUE; } - | /*EMPTY*/ { $$ = FALSE; } +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,11 +1363,36 @@ 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,10 +1585,23 @@ 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); |